tags:

views:

1758

answers:

5

I've reviewed questions How to use include directive correctly and C++ #include semantics and neither addresses this - nor do the others suggested by SO when I typed the title...

What, if any, are the benefits of writing:

#include "../include/someheader.h"
#include "../otherdir/another.h"

compared with using just a plain file name:

#include "someheader.h"
#include "another.h"

or perhaps a relative name without the '..':

#include "include/someheader.h"
#include "otherdir/another.h"

The problems I see are:

  • You can't move a header without worrying about which source files include it.
  • You can end up with very long paths for headers in dependencies and error reports. I had one today with "../dir1/include/../../include/../dir2/../include/header.h".

The only merit I can see is that while you do not need to move files around, you might be able to get away without always using '-I' directives to find headers, but the loss of flexibility, and the complexity of compiling in sub-sub-directories, etc seems to outweigh the benefit.

So, am I overlooking a benefit?


Thanks for the inputs. I think the consensus is that there aren't any major benefits to the notation using ".." that I'm overlooking. In general terms, I like the "somewhere/header.h" notation; I do use it in new projects. The one I'm working on is anything but new.

One of the problems is that there are various sets of headers, often with a prefix such as rspqr.h, rsabc.h, rsdef.h, rsxyz.h. These are all related to code in the rsmp directory, but some of the headers are in rsmp and others are in the central include directory, which does not have sub-directories such as rsmp in it. (And repeat for the various other areas of the code; there are headers in multiple locations, needed randomly by other bits of code.) Moving stuff around is a major problem because the code has gotten so convoluted over the years. And the makefiles are not consistent in which -I options are provided. All in all, it is a sad story of not-so-benign neglect over a period of decades. Fixing it all without breaking anything is going to be a long, tedious job.

A: 

Because then you place the file relative to the root of the project, and when you check it into source control and another developer checks it out to a different location on their local system things still work.

Joel Coehoorn
I see this as an argument against absolute path names - but I wasn't asking about those (they're unequivocally bad AFAIAC). I'm not convinced that this is an argument for - or against - any of the variants of relative name.
Jonathan Leffler
+5  A: 

I prefer the path syntax as it makes it very clear what namespace or module the header file belongs to.

#include "Physics/Solver.h"

Is very self-describing without requiring every module to prefix their name to header files.

I almost never use the ".." syntax though, instead I have my project includes specify the correct base locations.

Andrew Grant
A: 

Think of your source tree as a nested namespace and the include path is allowing you to pull directories into the root of this namespace. The question is then one of forming a logical namespace for your code base irrespective of how the code is organised on disk.

I would avoid paths like:

  • "include/foo/bar.h" - the "include" seems illogical and redundant
  • "../foo/bar.h" - the ".." assumes relative location and is fragile
  • "bar.h" - unless bar.h is in the current directory, this pollutes the global namespace and is asking for ambiguities.

Personally, I tend to add a path like the following to my projcts include path - "..;../..;../../..;../../../.."

This allows you to apply a sort of hiding rule to your #includes and allows some freedom of moving headers without breaking other code. Of course this is at the expense of introducing a risk of binding to the wrong header file if you are not careful as non-fully qualified names may be (or become over time) ambiguous.

I tend to fully qualify #includes in public headers so any third parties consuming my code do not need to add the "..;../..;../../..;../../../.." to their project - it's just a convenience for my private code and build system.

Daniel Paull
+2  A: 

IANALL, but I don't think you should be putting ..'s in actual c or c++ source files, because that's not portable and the standard does not support it. This is similar to using \'s on windows. Only do it if your compiler can't work with any other method.

TokenMacGuy
Good point. The standard doesn't even seem to guarantee that you can use forward-slashes. "The implementation provides unique mappings for sequences consisting of one or more nondigits (lex.name) followed by a period (.) and a single nondigit." It defines nondigit as basically [_a-zA-Z] or \uNNNN.
bk1e
This is true - but the software in question has been compiling on a wide range of platforms for a number of years (more than twenty of them), so it is more a theoretical than a practical liability.
Jonathan Leffler
+1  A: 

The problem with #include "../include/header.h" is that it will often work by accident, and then a seemingly unrelated change will make it stop working later.

For example, consider the following source layout:

./include/header.h
./lib/library.c
./lib/feature/feature.c

And let's say that you're running the compiler with an include path of -I. -I./lib. What happens?

  • ./lib/library.c can do #include "../include/header.h", which makes sense.
  • ./lib/feature/feature.c can also do #include "../include/header.h", even though it doesn't make sense. This is because the compiler will try the #include directive relative to the location of the current file, and if that fails, it will try the #include directive relative to each -I entry in the #include path.

Furthermore, if you later remove -I./lib from the #include path, then you break ./lib/feature/feature.c.

I find something like the following to be preferable:

./projectname/include/header.h
./projectname/lib/library.c
./projectname/lib/feature/feature.c

I wouldn't add any include path entries other than -I., and then both library.c and feature.c would use #include "projectname/include/header.h". Assuming that "projectname" is likely to be unique, this should not result in name collisions or ambiguities in most circumstances. You can also use the include path and/or make's VPATH feature to split the project's physical layout across multiple directories if absolutely necessary (to accommodate platform-specific auto-generated code, for instance; this is something that really breaks down when you use #include "../../somefile.h").

bk1e
yeah that thing using "projectname/include/header.h" was what i used in my last project (but started from include/ instead). i always put only one -I that points to the include/ path and then i include based on that. but i didn't analyze the ".." problems in depth yet. You have good points.
Johannes Schaub - litb