0

I have a CMake project that installs things to a system according to the install command as follows:

install (
    TARGETS myTarget
    RUNTIME DESTINATION bin
    LIBRARY DESTINATION lib
)

make install works perfectly. And then I want to have a binary archive:

set(CPACK_GENERATOR "TGZ")

make package produces an tar.gz file with the same folder structure as the install command specified. However, I want to have a flat structure, that is, put everything (both executables and libraries) in "prefix", without the "bin" and "lib" directory.

Is that possible? May be with some clever use of the component system, the build type system, or CPACK_PROJECT_CONFIG_FILE?

Andy Li
  • 5,894
  • 6
  • 37
  • 47
  • Are you aware of `make package_source`? Maybe it does what you want. – usr1234567 Apr 13 '16 at 08:49
  • 1
    `However, I want to have a flat structure, that is, put everything (both executables and libraries) in "prefix", without the "bin" and "lib" directory.` - Then you need to install targets directly to "prefix". Probably, `DESTINATION .` should work. – Tsyvarev Apr 13 '16 at 08:51
  • @usr1234567 Yes, but `make package_source` is for packing source archive, which is unrelated to my question. Or did you mean it can be abused to solve my problem in some way? – Andy Li Apr 14 '16 at 01:37
  • @Tsyvarev But `DESTINATION .` will also affect `make install`, not just `make package`. I still want `make install` to use "bin"/"lib" folders. – Andy Li Apr 14 '16 at 01:39
  • @AndyLi It gets you the flat structure. But you are right, it cannot include executables or libraries. – usr1234567 Apr 14 '16 at 04:52
  • CPack is intended for pack the project deliverables for future unpacking them with **the same structure**. Flatterned archive doesn't contain information about the structure, so it is useless from the CPack sence. For simple archiving you may install your project somewhere with `make DESTDIR= install` and create an archive which you want. – Tsyvarev Apr 14 '16 at 07:23

1 Answers1

1

At the end I added a custom install script, which detects whether it is run by CPack by looking at CMAKE_INSTALL_PREFIX, and restructure the install tree if necessary.

Here is my solution:

In CMakeLists.txt, after all the install() commands, add

install(SCRIPT "${CMAKE_SOURCE_DIR}/cmake/flatten.cmake")

Add a file, "cmake/flatten.cmake", with content as follows

# Detect if the install is run by CPack.
if (${CMAKE_INSTALL_PREFIX} MATCHES "/_CPack_Packages/.*/(TGZ|ZIP)/")
    # Flatten the directory structure such that everything except the header files is placed in root.
    file(GLOB bin_files LIST_DIRECTORIES FALSE ${CMAKE_INSTALL_PREFIX}/bin/*)
    file(GLOB lib_files LIST_DIRECTORIES FALSE ${CMAKE_INSTALL_PREFIX}/lib/*)
    foreach(file ${bin_files} ${lib_files})
        get_filename_component(file_name ${file} NAME)
        execute_process(
            COMMAND ${CMAKE_COMMAND} -E rename
            ${file}
            ${CMAKE_INSTALL_PREFIX}/${file_name}
        )
    endforeach()
    execute_process( COMMAND ${CMAKE_COMMAND} -E remove_directory ${CMAKE_INSTALL_PREFIX}/bin)
    execute_process( COMMAND ${CMAKE_COMMAND} -E remove_directory ${CMAKE_INSTALL_PREFIX}/lib)
endif()
Andy Li
  • 5,894
  • 6
  • 37
  • 47
  • With CMake 3.22, CMAKE_INSTALL_PREFIX is always /usr/local regardless of whether the install is being run by a CPack generator or not. – msc May 08 '23 at 09:40