Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Header files with prefix in CMake project

Tags:

build

cmake

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?

like image 508
Fabian Meumertzheim Avatar asked Aug 10 '16 17:08

Fabian Meumertzheim


2 Answers

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>.

like image 168
jonahwell Avatar answered Oct 06 '22 14:10

jonahwell


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;
}
like image 40
Kevin Avatar answered Oct 06 '22 12:10

Kevin