How to prohibit private includes to other libraries when using merged header placement

238 Views Asked by At

I am in favour of merged header placement for a C++ project layout because of several reasons also mentioned in the proposal P1204R0. Also I am trying to adhere to the Pitchfork guidlines. I am using CMake to define the libraries and also the install step.

A merged header placement would look like this:

<root>/
    src/
        libA/      
            A.h. 
            A.cpp. # accidentially includes `libB/B-internal.h` or `libB/details/BB.h` !
            A-internal.h
        libB/
            B.h. # includes BB.h)
            B.cpp
            details/
                BB.h # is an internal 'libB'-only file but 
                     # gets installed because its needed.
            B-internal.h

One problem which I face is that, with merged header placement,

  • one needs a special suffix to determine which headers are internal only and also won't get installed, in this case -internal.h.
  • the other more important problem is that, libA when using and linking to libB, uses the include directory <root>/src/libB which makes developers able to accidentially include #include <libB/B-internal.h> which is really bad. The split header placement doesn't has this inherent problem (but still for libB/details/Bb.h).

I am wondering what ways do exists (maybe CMake, CI, clang-tidy? or by any other means) to somehow prohibit inter-library includes to private headers (because architecturally you really don't want this?)

The only way I see is, to write some scripts (not sure if include-what-you-use can do this?) which could check every source/header file for potential such bad includes which is possible when you stick to a proper libA/... or libB/... include style.

1

There are 1 best solutions below

4
On

am wondering what ways do exists (maybe CMake, CI, clang-tidy? or by any other means) to somehow prohibit inter-library includes to private headers (because architecturally you really don't want this?)

Move private include files into private directory.

├── libA
│   ├── include
│   │   └── A.cpp
│   └── src
│       ├── A-internal.h
│       └── A.cpp
└── libB
    ├── include
    │   ├── B.h
    │   └── details
    │       └── BB.h
    └── src
        ├── B-internal.h
        └── B.cpp

Add include dirs to includes and use #include "B-internal.cpp" inclusion style for internal files.


You would preferably do:

├── libA
│   ├── include
│   │   └── libA
│   │       └── A.cpp
│   └── src
│       ├── A-internal.h
│       └── A.cpp
└── libB
    ├── include
    │   └── libB
    │       ├── B.h
    │       └── details
    │           └── BB.h
    └── src
        ├── B-internal.cpp
        └── B.cpp

So that all includes for library named libB are inside direcotry libB. You may interest yourself in reading the whole sections around "Similarly, if we want to include hello.hpp from libhello..." from http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p1204r0.html#src-dir you mentioned.