3
votes

Whenever I start developing a new shared library in C++ I come across the same question:

Should I use includes relative to the position of the current file or includes relative to the (potential) include paths (-I) to refer to other header files within my project, i.e. the same library?

I checked with some of the library headers installed on my system.

  • boost appears to use includes relative to the include path and <>brackets to include other boost headers, i.e. #include <boost/move/move.hpp>
  • poppler on the other hand appears to use some weird relative paths with "", sometimes relative to the current location and sometimes relative to its base (I didn't even know that this works), .e.g. in fofi/FoFiEncodings.hthere is an #include "goo/gtypes.h" where fofi and goo are directories on the same level
  • many others simply include files with "" and their location relative paths, mainly files in the same directory

Does it depend on the directory structure (i.e. its complexity) of the shared library itself, i.e. location relative paths work well with simple layouts but have drawbacks with more cross references like in boost? Are there any technical reasons or pitfalls why one might work but the other doesn't (portability, compiler dependent behavior, ...)?

2
by 'absolute' do you really mean absolute paths ? or you just mean the quoted #include"" VS bracket #include<> forms ? note that, strictly speaking, the path-wise interpretation of both of them is implementation defined, and most (all?) compilers offer settings for them to behave as you like.Massimiliano Janes
I edited the question to better reflect what I mean... of course, I shouldn't have used the term "absolute path" since I only meant "relative to some kind of include path" in contrast to "relative to the location of the current file". My mistake.rocktale

2 Answers

0
votes

Boost uses brackets instead of quotes. This means that it isn't an absolute path, but that the search starts relative to the list of linclude directories that was provided to the compiler. So it's a variant of the relative path.

A really absolute path is a bad idea because if another developper installs the source code at another location, he/she'll not be able to compile unless he/she changes all the header references in the sources.

Edit:

If you develop a library that is general enough and designed to be shared across several (possibly unrelated) projects, the bracket option should be the preferred one. This lets you the freedom to install the library wherever you want, and also to switch libraries (different versions for different projects) very easily.

If you develop a more specific library in the context of a larger solution, mainly to isolate reusable code, the quoted relative path is an option. If later you want to reuse that library in another context, you would have to install its sources in the new solutions directory so that the relative paths still work. So the use case is a little different (narrow sharing and occasional reuse in the context of very specific projects).

0
votes

In your source file, do whatever you want/prefer.

For public headers, relative path is the preferred way, as user might place your headers in a specific place and use not exactly the same include directive.

I mean, suppose that your hierarchy is:

lib/headers/sub1/h1.h
lib/headers/sub2/h2.h
lib/headers/lib.h
lib/src/..

with directive to set include path to lib, user should do #include <headers/lib.h>, but then your lib.h should look like:

#include "headers/sub1/h1.h"
#include "headers/sub2/h2.h"

and sub1/h1.h to

#include "headers/sub2/h2.h"

With directive to set include path to lib/headers,

user should do #include <lib.h>, but then your lib.h should look like:

#include "sub1/h1.h"
#include "sub2/h2.h"

and sub1/h1.h to

#include "sub2/h2.h"

So depending of directive set by user, your code won't compile for user.

With relative path, for both above directives, your files would be identical

lib.h:

#include "sub1/h1.h"
#include "sub2/h2.h"

and sub1/h1.h to

#include "../sub2/h2.h"