146

What is the meaning of the keyword PUBLIC, PRIVATE, and INTERFACE related to CMake's target_include_directories?

usr1234567
  • 21,601
  • 16
  • 108
  • 128
Sirish
  • 9,183
  • 22
  • 72
  • 107

2 Answers2

185

These keywords are used to tell when the list of include directories you're passing to the target are needed. By when, it means if those include directories are needed:

  • To compile that target itself.
  • To compile other targets that depend on that target (like using its public headers).
  • In both of the above situations.

When CMake is compiling a target, it uses the targets INCLUDE_DIRECTORIES, COMPILE_DEFINITIONS, and COMPILE_OPTIONS properties. When you use the PRIVATE keyword in target_include_directories() and alike, you tell CMake to populate those target properties.

When CMake detects a dependency between a target A and another target B (like when you use the target_link_libraries(A B) command), it transitively propagates B usage requirements to the A target. Those target usage requirements are the include directories, compile definitions, etc. that any target that depends on B must meet. They are specified by the INTERFACE_* version of the properties listed above (like INTERFACE_INCLUDE_DIRECTORIES), and are populated by using the INTERFACE keyword when calling the target_*() commands.

The PUBLIC keyword means roughly PRIVATE + INTERFACE.

Therefore, suppose you are creating a library A that uses some Boost headers. You would do:

  • target_include_directories(A PRIVATE ${Boost_INCLUDE_DIRS}) if you only use those Boost headers inside your source files (.cpp) or private header files (.h).
  • target_include_directories(A INTERFACE ${Boost_INCLUDE_DIRS}) if you don't use those Boost headers inside your source files (therefore, not needing them to compile A). I can't actually think of a real-world example for this.
  • target_include_directories(A PUBLIC ${Boost_INCLUDE_DIRS}) if you use those Boost headers in your public header files, which are included BOTH in some of A's source files and might also be included in any other client of your A library.

CMake 3.0 documentation has more details on this build specification and usage requirements properties.

starball
  • 20,030
  • 7
  • 43
  • 238
TManhente
  • 2,526
  • 1
  • 15
  • 11
  • 42
    In regard to a real-world example of `INTERFACE`. `target_include_directories(libname INTERFACE include PRIVATE include/libname)`. This means that within your library you can include files directly, but as a user of the library you have to insert `libname/` first. – KaareZ Dec 16 '17 at 14:39
  • 2
    This answers makes sense to me for creating libraries. But how about calling target_include_directories for an target that is an executable ? – Norman Pellet May 04 '20 at 11:14
  • 1
    @NormanPellet: You may call `target_include_directories()` for an executable target if you need to set include directories where header files that are used by those executables are to be found (for instance: Boost::Program_options, if you use it to parse arguments in your `main()` function). You would probably use the `PRIVATE` keyword in this case, as these files are needed to compile the executable itself. I don't know if there is some use for `INTERFACE` or `PUBLIC` on an executable, though. – TManhente May 11 '20 at 21:52
  • "This means that within your library you can include files directly, but as a user of the library you have to insert libname/ first." This may be true for implementation files within your library. However, it won't work for other "public" header files within your library. If `include/libname/file1.h` includes `include/libname/file2.h` using just `#include `, it will break when the executable using your library includes `file1.h` (via `#include `). `include/libname` won't be in the executable's include search path, so it won't be able to find `file2.h`. – ToddR Sep 22 '21 at 19:18
  • @ KaareZ "but as a user of the library you have to insert libname/ first. "? What's that? Could you please explain that in more detail for me? – John Oct 05 '21 at 06:32
  • 1
    The INTERFACE option might be useful if one set of headers were needed for compilation of the library itself, but different versions of the same header files were desired to be included with the library for distribution. The release headers might have information stripped out for protecting IP, etc. - `foo/interface/a.h` - This would be provided to consumers of the library, and have only what is needed to use the library - `foo/include/a.h` - This would be used internally to build the library, and would have contents similar to `foo/interface/a.h`, but with additional content. – Vinny Mar 30 '22 at 21:45
18

The INTERFACE, PUBLIC and PRIVATE keywords are required to specify the scope of the following arguments. PRIVATE and PUBLIC items will populate the INCLUDE_DIRECTORIES property of < target >. PUBLIC and INTERFACE items will populate the INTERFACE_INCLUDE_DIRECTORIES property of < target >. The following arguments specify include directories.

From the documentation: http://www.cmake.org/cmake/help/v3.0/command/target_include_directories.html

To rephrase the documentation with my own words:

  • you want to add a directory to list of include directory for a target
  • with PRIVATE the directory is added to the target's include directories
  • with INTERFACE the target is not modified, but the INTERFACE_INCLUDE_DIRECTORIES is extended by the directory. The variable is a list of public include directories for a library.
  • with PUBLIC both actions from PRIVATE and INTERFACE are performed.
TManhente
  • 2,526
  • 1
  • 15
  • 11
usr1234567
  • 21,601
  • 16
  • 108
  • 128
  • 6
    I went through the CMAKE documentation, but I still did not get what do they actually mean and in what context(make files or how they compiled)? – Sirish Oct 07 '14 at 19:25
  • @Sirish: I tried to rephrase the documentation, hope that helps. – usr1234567 Oct 20 '14 at 12:16
  • 2
    @usr1234567 What is the *default value* of the keyword if we don't specify one? I saw a lot of projects just use `target_link_libraries` or `target_include_directories` without specifying `PRIVATE`, `PUBLIC`, or `INTERFACE` keyword. – IgNite Feb 10 '21 at 09:51
  • 1
    @IgNite See https://cmake.org/pipermail/cmake/2016-May/063400.html, second last paragraph. It's complicated :-) – usr1234567 Apr 01 '21 at 20:20