Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to specify a #include file path relative to the user's current directory when compiling?

Tags:

c

include

path

gcc

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.

like image 414
PandaConda Avatar asked Apr 12 '15 11:04

PandaConda


2 Answers

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.

like image 184
Thomas Dickey Avatar answered Oct 15 '22 00:10

Thomas Dickey


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.

like image 36
PandaConda Avatar answered Oct 14 '22 22:10

PandaConda