16

I have set up a CMake project whose directory structure looks as follows:

src/
--CMakeLists.txt
--libA/
----CMakeLists.txt
----foo.h
----foo.cpp
--main/
----CMakeLists.txt
----main.cpp

src/CMakeLists.txt uses add_subdirectory to pull in libA and main. libA/CMakeLists.txt uses add_library to define a library called libA, which exports foo.h via target_include_directories. If I now link against libA in main using target_link_library, I can include foo.h via #include <foo.h> in main.cpp.

Question: Is it possible to provide the public interface of libA with a prefix, so that I can (and have to) write #include <libA/foo.h> in main.cpp instead?

Fabian Meumertzheim
  • 1,569
  • 1
  • 11
  • 21
  • 2
    this link may help: http://stackoverflow.com/questions/19460707/how-to-set-include-directories-from-a-cmakelists-txt-file – Wei Guo Aug 11 '16 at 04:25
  • What's wrong with including the root directory instead of `libA` with `target_include_directories`? – usr1234567 Aug 16 '16 at 11:15
  • @usr1234567 because for example you want to have option to switch between using subdirectory that don't provide prefix and using system package that has that prefix. For example when using Bullet library it would be convenient to not use ugly `#ifdef`s to distinguish between `#include ` and `#include `. – Mateusz Drost Oct 23 '17 at 21:05
  • @MateuszDrost That might be convenient, but it is bad style. – usr1234567 Oct 24 '17 at 04:18
  • Sorry, I'm a bit late to the party but interested in this now. @usr1234567, can you elaborate more on why this is bad style? I am using a third party library which otherwise forces me to use `#include `, but `foo.h` is too generic and might conflict with other headers I have, so I would prefer to prefix it, like `#inlcude `. – Boyan Hristov Aug 01 '23 at 11:56
  • 1
    @BoyanHristov Then the third party library makes you life miserable, they should use the prefix. In you local copy, you can do what you like. – usr1234567 Aug 02 '23 at 20:16

2 Answers2

3

This is an old question but I was having exactly the same issue. I ended up getting around this by adding an export_headers() function that creates symbolic links to the headers within the binary:

function(export_headers TARGET HEADER_SOURCE_DIR HEADER_DEST_DIR)

    # Put all headers that are in the source directory into EXPORT_HEADERS variable
    file(GLOB_RECURSE EXPORT_HEADERS CONFIGURE_DEPENDS 
        RELATIVE "${HEADER_SOURCE_DIR}" 
        "${HEADER_SOURCE_DIR}/*.h"
    )

    # For each header that will be exported
    foreach(HEADER ${EXPORT_HEADERS})

        # Get the directory portion that needs to be created        
        get_filename_component(HEADER_DIRECTORY "${HEADER}" DIRECTORY)

        # Create the directory  
        add_custom_command(TARGET ${TARGET} POST_BUILD
            COMMAND ${CMAKE_COMMAND} -E make_directory "${HEADER_DEST_DIR}/${HEADER_DIRECTORY}"
        )

        if (MSVC)

            # Make a hard link to the file
            add_custom_command(TARGET ${TARGET} POST_BUILD
                COMMAND if not exist "${HEADER_DEST_DIR}/${HEADER}" \( mklink /h "${HEADER_DEST_DIR}/${HEADER}" "${HEADER_SOURCE_DIR}/${HEADER}" \) 
            )

        else()

            # Make a symbolic link to the file
            add_custom_command(TARGET ${TARGET} POST_BUILD
                COMMAND ln -sf "${HEADER_SOURCE_DIR}/${HEADER}" "${HEADER_DEST_DIR}/${HEADER}"
            )

        endif()


    endforeach(HEADER)

endfunction()

You would call this with something like:

add_library(libA STATIC ${LIBA_SOURCES}
export_headers(libA ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR}/include/libA)
target_include_directories(libA INTERFACE ${CMAKE_CURRENT_BINARY_DIR}/include)

Then, if you link to libA, you will be able to #include <libA/foo.h>.

jonahwell
  • 126
  • 9
2

You can use the root source directory (or some other directory which is a parent to libA) in the target_include_directories() call. This will allow the INTERFACE_INCLUDE_DIRECTORIES target property to be defined with respect to another directory (in this example, the CMAKE_SOURCE_DIR). So it would look something like this:

In libA/CMakeLists.txt:

add_library(libA foo.cpp)
# Define the include files with respect to the directory above this.
target_include_directories(libA PUBLIC ${CMAKE_SOURCE_DIR})

The main/main.cpp file:

#include <iostream>
#include <libA/foo.h>

int main() {

    FooClass fooclass;
    fooclass.myFunction();

    std::cout << "Hello World!" << std::endl;
    return 0;
}
Kevin
  • 16,549
  • 8
  • 60
  • 74