I know it is possible to specify #include
filepaths either relative to the directory the file is located in, as an absolute file path, or relative to any of the directories in the $PATH
system variable. Is there a way to instead specify it relative to the user's current directory when the program is compiled? Let's say I have the following file structure:
|--dir_a/
| |--a.c
| |--a.h
|--dir_b/
| |--b.c
| |--b.h
|--makefile
Now let's say I want to #include
the file dir_a/a.h
from dir_b/b.h
. Using the location of dir_b/b.h
, this can be written like this:
#include ../dir_a/a.h
However, this approach has a major flaw in my opinion since it hardcodes the locations of files relative to each other, meaning that relocating a file would require updating the file path everywhere that file was included from.
Using absolute file paths would avoid this problem, but would instead hardcode the location of the project within the filesystem, which seems like bad practice.
Finally, using the <>
tags to specify the file path isn't feasible either since I can't assume the project will be listed in the $PATH
variable.
So what I want to do is to be able to specify the paths relative to where the user compiles from (or even better, from the location of the makefile). In the above example, this would let me use the following statement to #include
dir_a/a.h
from dir_b/b.h
:
#include dir_a/a.h
This I think would be the ideal solution. It would make the #include
statements more consistent and easier to follow, as well as avoid the drawbacks I listed above. Is it possible to do this in any way, eg. with a compiler flag or something? I'm using gcc
as my compiler.
If you consistently use <>
includes, then the -I
options in the makefile should be enough. The directory layout shows only one makefile
, in the parent directory. That could use
-Idir_a -Idir_b
in the compiler options, and the .c files could just do
#include <a.h>
#include <b.h>
One of the problems with quoted includes is that their behavior with other compilers may differ, as noted in What is the difference between #include <filename>
and #include “filename”
? (the standard was not explicit enough). Using a gcc extension probably does not improve that situation.
I managed to solve my problem.
The first part of the solution involves specifying the -iquote
flag in gcc
when compiling. From man gcc
:
-iquotedir
Add the directory dir to the head of the list of directories to be searched for header files only for the case of #include "file"; they are not searched for #include <file>, otherwise just like -I.
The second part of the puzzle was how to get the path to the makefile
within the makefile
itself. This answer worked for me. I'm pasting the solution here for convenience:
ROOT_DIR = $(shell dirname $(realpath $(lastword $(MAKEFILE_LIST))))
edit: While this approach works, this answer is more cross-compiler friendly, so I'm personally going to use that.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With