5

I've been browsing my /usr/include folder trying to get acquainted with the layout and I've noticed that there are multiple copies of header files (at least by name, I didn't actually diff them to see if they were exact copies) found in several sub directories of /usr/include. This is especially the case for standard C and C++ header files as well as POSIX/LSB standard header files.

Some examples include (note ./ refers to /usr/include):

./asm-generic/unistd.h
./linux/unistd.h
./unistd.h
./x86_64-linux-gnu/sys/unistd.h
./x86_64-linux-gnu/bits/unistd.h
./x86_64-linux-gnu/asm/unistd.h

./stdlib.h
./x86_64-linux-gnu/bits/stdlib.h
./c++/7/stdlib.h
./c++/7/tr1/stdlib.h

./c++/7/cmath
./c++/7/ext/cmath
./c++/7/tr1/cmath

./asm-generic/termios.h
./linux/termios.h
./x86_64-linux-gnu/sys/termios.h
./x86_64-linux-gnu/bits/termios.h
./x86_64-linux-gnu/asm/termios.h
./termios.h

./linux/time.h
./time.h
./x86_64-linux-gnu/sys/time.h
./x86_64-linux-gnu/bits/time.h

Why is this? And why do some C standard headers show up in C++ locations?

I only have one compiler installed (GCC 7).

4

No, they aren't exact copies.

If you care to investigate, you'll find that the files at the top level /usr/include will normally have a lot of #ifdefs or other conditionals, and they'll only define the architecture-independent parts and will #include other stuff from architecture-specific directories deeper within the hierarchy. As some architecture-specific parts may in turn depend on some architecture-independent parts, there may be multiple layers of inclusion on top of each other.

Likewise, the files under /usr/include/c++ will have the additional declarations that will only make sense for C++, and #includes for the corresponding C include files where appropriate.

The name of the game is deduplication for maintainability: the aim is that when a glibc developer needs to add something new that only affects the ABI between the application and glibc and has no architecture-specific parts, the addition ideally needs to happen at just one location in the tree of include files, and it will take effect for all hardware architectures that use glibc. Or, say, when a new system call is added to the Linux kernel, there will be a place to add it without interfering with *BSD or GNU Hurd system call definitions, for example. Or if you're porting glibc to yet another hardware/kernel architecture, you'll find places you can plug in the necessary kernel ABI definitions without disturbing architecture-independent stuff any more than absolutely necessary.

Yes, it's pretty complicated.

I don't have any easy references for you, since the entire /usr/include layout is a sum of ISO C and POSIX standards requirements and the choices made by both the GCC and glibc projects.

I'd suggest you make a note of your architecture triplet (x86_64-linux-gnu in your case; obtainable with gcc -dumpmachine on any architecture supported by GCC) and then study the compiler's default #include <...> file search paths.

You can see the search paths with:

  • cpp -v /dev/null -o /dev/null for plain C
  • cpp -x c++ -v /dev/null -o /dev/null for C++

I don't have a system with GCC 7 at hand here, but for GCC 6, the list of include paths looks like this for C:

...
#include <...> search starts here:
 /usr/lib/gcc/x86_64-linux-gnu/6/include
 /usr/local/include
 /usr/lib/gcc/x86_64-linux-gnu/6/include-fixed
 /usr/include/x86_64-linux-gnu
 /usr/include
End of search list.
...

... and like this for C++:

...
#include <...> search starts here:
 /usr/include/c++/6
 /usr/include/x86_64-linux-gnu/c++/6
 /usr/include/c++/6/backward
 /usr/lib/gcc/x86_64-linux-gnu/6/include
 /usr/local/include
 /usr/lib/gcc/x86_64-linux-gnu/6/include-fixed
 /usr/include/x86_64-linux-gnu
 /usr/include
End of search list.
...

If the /usr/local/include/<architecture triplet> directory existed, it would get added in the lists, just before /usr/local/include.

So, it would seem that for your own projects, if you need to have architecture-specific versions of an include file, you could put them under /usr/[local/]include/<architecture triplet>/, and the regular architecture-agnostic include files to /usr/[local/]include/. I wouldn't touch any include directories whose path name includes the major version number of the compiler without a very good reason.

If you plan to modify glibc, and you cannot find what you need in the glibc developer documentation, you'd better ask for advice on the glibc development mailing list; glibc is extra complicated because it is usable also on architectures that use a compiler other than GCC, and so might not have the architecture triplet convention as standard.

  • Thank you! This was very informative. I would like to investigate further. Do you have any references I can look to for further information about the way /use/include is organized in order to achieve the goals you’ve described? I would like to know which regions of this tree are designated for the specific purposes you’ve mentioned. – Adam Sperry Nov 19 '18 at 14:10

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.