Cmake install (FILES ...) doesn't seem to work

I have a project written in C ++ and I am using cmake to create it. The project has many subprojects, one of which is lib which is required for other subprojects. I can compile and move the .so to the build directory using add_library and INSTALL (TARGETS) ...

However, I also need the lib header files to be installed in the include directory of the dir directory. I use install (FILES ...) to do this, but it seems like it just doesn't do anything.

To demonstrate this, I created a test project via qtcreator,

& ls test
CMakeLists.txt empty.hh main.cpp

$ cat test/CMakeLists.txt
project(test)
cmake_minimum_required(VERSION 2.8)
install(FILES empty.hh DESTINATION include)
aux_source_directory(. SRC_LIST)
add_executable(${PROJECT_NAME} ${SRC_LIST})

$ cat test/main.cpp
#include

using namespace std;

int main()
{
cout << "Hello World!" << endl;
return 0;
}

$ cat test/empty.hh
#ifndef EMPTY_HH
#define EMPTY_HH

#endif // EMPTY_HH

If the files under "test" qtcreator will compile (by default) the files to test-build.
$ ls test-build/
CMakeCache.txt CMakeFiles Makefile cmake_install.cmake test test.cbp
$ ./test-build/test
Hello World!

      

As you can see, there is no include directory or empty.hh file. Also tried using

install(FILES empty.hh DESTINATION ${CMAKE_CURRENT_BINARY_DIR})

      

But you still don't see the header files.

$ cmake --help
cmake version 2.8.12

      

If you have any ideas please let me know.

+3


source to share


1 answer


Using the command install

to move files during build is usually a bad approach. The command is for setting files and targets to be set when the user executes make install

or equivalent. Since you are not using make install

, I expect the command is install(FILES ...)

not working.

You have several slightly different approaches to this work.

I would recommend not moving the headers around unless you need to. Let's say your library is called MyLib

, then you can make those headers available as part of the target MyLib

via : target_include_directories

target_include_directories(MyLib PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}")

      

This means that if there is a dependent goal, for example MyExe

:

target_link_libraries(MyExe MyLib)

      

then it automatically accesses the MyLib

original directory.


This may be less desirable if the library's directory structure does not allow for the separation of API headers from other sources and headers. Let's say it MyLib

consists of the following files: my_lib.cpp, my_lib_api.hh (API header - for inclusion by other projects) and my_lib_detail.hh (not for inclusion by other projects). The ideal structure would keep the API header separate from the rest, eg.

/my_lib
   - CMakeLists.txt
   - src/
       - my_lib.cpp
       - my_lib_detail.hh
   - include/
       - my_lib/
            - my_lib_api.hh

      

With this structure, you can simply specify

target_include_directories(MyLib PUBLIC  "${CMAKE_CURRENT_SOURCE_DIR}/include"
                                 PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/src")

      



Sources

and MyLib

can contain #include "my_lib_detail.hh"

and #include "my_lib/my_lib_api.hh"

, but sources of dependent targets can contain #include "my_lib/my_lib_api.hh"

.


So, if MyLib

it only has a flat structure, or does not separate the internal headers from the API, you can copy the API headers to a location in the build tree and add that path to the call target_include_directories

. In this case, if MyLib

itself does not need access to the copied files (only originals in the source tree), you can use INTERFACE

instead PUBLIC

in the call target_include_directories

.

However, the gist of it (and it seems to fit the answer to your real question) is to copy those files as part of the setup process (when CMake starts) or the build process (when a run is done) - not like part of the installation process.

So, let's say it MyLib

doesn't have the useful directory structure shown above, but is instead flat (i.e. CMakeLists.txt and the three source files are in the same directory). We could use the post-build command to copy the API header into the build tree:

project(my_lib)
cmake_minimum_required(VERSION 2.8.12.2)  # for 'target_include_directories'
add_library(MyLib SHARED my_lib.cpp my_lib_api.hh my_lib_detail.hh)
target_include_directories(MyLib INTERFACE "${CMAKE_BINARY_DIR}/include"
                                 PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}")

file(MAKE_DIRECTORY "${CMAKE_BINARY_DIR}/include/my_lib")
add_custom_command(TARGET MyLib POST_BUILD
    COMMAND ${CMAKE_COMMAND} -E copy_if_different
        "${CMAKE_CURRENT_SOURCE_DIR}/my_lib_api.hh"
        "${CMAKE_BINARY_DIR}/include/my_lib"
    COMMENT "Copying MyLib public headers to ${CMAKE_BINARY_DIR}/include/my_lib"
    VERBATIM)

      

Then for MyExe

CMakeLists.txt you can simply do:

project(my_exe)
cmake_minimum_required(VERSION 2.8.12.2)
add_executable(MyExe main.cpp)
target_link_libraries(MyExe MyLib)

# Copy MyLib.so to this build dir to allow MyExe to find it at runtime
add_custom_command(TARGET MyExe POST_BUILD
    COMMAND ${CMAKE_COMMAND} -E copy_if_different
        "$<TARGET_FILE:MyLib>"
        "$<TARGET_FILE_DIR:MyExe>"
    VERBATIM)

      


This won't work as-for MSVC - you will need to handle the Windows export libraries (see the CMake wiki and docs for more information), but that will just involve something like adding the following to CMakeLists.txt: GenerateExportHeader

MyLib

include(GenerateExportHeader)
generate_export_header(MyLib
    BASE_NAME MyLib
    EXPORT_MACRO_NAME MyLib_EXPORT
    EXPORT_FILE_NAME "${CMAKE_BINARY_DIR}/include/my_lib/my_lib_export.hh"
    STATIC_DEFINE MyLib_BUILT_AS_STATIC)

      

If you need this, you will need to change INTERFACE

to PUBLIC

in target_include_directories(MyLib ...)

, as MyLib

it will itself need access to the generated file "${CMAKE_BINARY_DIR}/include/my_lib/my_lib_export.hh"

.

+8


source







All Articles