Search code examples
c++cmakeinstallationpackagingcpack

CPack empty CPACK_PACKAGE_DIRECTORY


I am really struggling to get CPack to act the way I am imagining it should. I have a small example setup below that I have been trying to get work before applying it to a much larger project. Essentially I am trying to use fixup_bundle to collect all dependencies and copy them to the packaging directory to be combined into an installer (and zip).

main.cpp:

int main(unsigned int argc, const char* argv[])
{
    return 0;
}

CMakeLists.txt:

cmake_minimum_required(VERSION 3.1.0)

find_package(Qt5 REQUIRED COMPONENTS Core Gui Multimedia Widgets AxContainer OpenGL)

add_executable(TEST main.cpp)

target_link_libraries(TEST
    Qt5::AxContainer
    Qt5::Core
    Qt5::Multimedia
    Qt5::Gui
    Qt5::Widgets
    Qt5::OpenGL
    )

install(
    TARGETS TEST
    RUNTIME DESTINATION bin
    LIBRARY DESTINATION lib
    ARCHIVE DESTINATION lib
    COMPONENT Runtime
    )

install(CODE "MESSAGE(\"CPACK_PACKAGING_PREFIX=${CPACK_PACKAGING_PREFIX}\")")
install(CODE "MESSAGE(\"CMAKE_INSTALL_PREFIX=${CMAKE_INSTALL_PREFIX}\")")
install(CODE "MESSAGE(\"CPACK_INSTALL_PREFIX=${CPACK_INSTALL_PREFIX}\")")
install(CODE "MESSAGE(\"CPACK_INSTALL_DIRECTORY=${CPACK_INSTALL_DIRECTORY}\")")
install(CODE "MESSAGE(\"CPACK_PACKAGE_INSTALL_DIRECTORY=${CPACK_PACKAGE_INSTALL_DIRECTORY}\")")
install(CODE "MESSAGE(\"CPACK_PACKAGING_INSTALL_PREFIX=${CPACK_PACKAGING_INSTALL_PREFIX}\")")
install(CODE "MESSAGE(\"CPACK_PACKAGE_DIRECTORY=${CPACK_PACKAGE_DIRECTORY}\")")
install(CODE "MESSAGE(\"CPACK_TOPLEVEL_DIRECTORY=${CPACK_TOPLEVEL_DIRECTORY}\")")
install(CODE "MESSAGE(\"CPACK_TEMPORARY_DIRECTORY=${CPACK_TEMPORARY_DIRECTORY}\")")
install(CODE "MESSAGE(\"CPACK_OUTPUT_FILE_NAME=${CPACK_OUTPUT_FILE_NAME}\")")
install(CODE "MESSAGE(\"CPACK_OUTPUT_FILE_PATH=${CPACK_OUTPUT_FILE_PATH}\")")
install(CODE "MESSAGE(\"CPACK_TEMPORARY_PACKAGE_FILE_NAME=${CPACK_TEMPORARY_PACKAGE_FILE_NAME}\")")
install(CODE "MESSAGE(\"CPACK_NATIVE_INSTALL_DIRECTORY=${CPACK_NATIVE_INSTALL_DIRECTORY}\")")
install(CODE "MESSAGE(\"CPACK_TEMPORARY_INSTALL_DIRECTORY=${CPACK_TEMPORARY_INSTALL_DIRECTORY}\")")


install(CODE "
   include(BundleUtilities)
   fixup_bundle(\"${CPACK_PACKAGE_DIRECTORY}/TEST${CMAKE_EXECUTABLE_SUFFIX}\"   \"\"   \"${DIRS}\")
   " COMPONENT Runtime)

set(CPACK_GENERATOR "ZIP" "NSIS")

include(CPack)

And the output is always a bunch of empty variables:

CPACK_PACKAGING_PREFIX=
CMAKE_INSTALL_PREFIX=C:/Program Files (x86)/Project
CPACK_INSTALL_PREFIX=
CPACK_INSTALL_DIRECTORY=
CPACK_PACKAGE_INSTALL_DIRECTORY=
CPACK_PACKAGING_INSTALL_PREFIX=
CPACK_PACKAGE_DIRECTORY=
CPACK_TOPLEVEL_DIRECTORY=
CPACK_TEMPORARY_DIRECTORY=
CPACK_OUTPUT_FILE_NAME=
CPACK_OUTPUT_FILE_PATH=
CPACK_TEMPORARY_PACKAGE_FILE_NAME=
CPACK_NATIVE_INSTALL_DIRECTORY=
CPACK_TEMPORARY_INSTALL_DIRECTORY=
CMake Error at C:/Program Files (x86)/CMake/share/cmake-3.4/Modules/BundleUtilities.cmake:861 (message):
  error: fixup_bundle: not a valid bundle, app: /TEST.exe

Obviously it won't find the right executable. I am expecting CPACK_PACKAGE_DIRECTORY to be something like:

${CMAKE_BINARY_DIR}/_CPack_Packages/${CPACK_SYSTEM_NAME}/${CPACK_GENERATOR}/${CPACK_PACKAGE_FILE_NAME}

Update 2016-06-23

Thanks to @Tsyvarev for helping identify problem + solution. The issue is pre-mature expansion of the variables inside the install commands. CMake will do a first level expansion for any ${} variables in the text lines. Escaping the variable as \${} avoids this expansion and will later be expanded correctly by CPack.

Even with the above, all of the variables are still empty except for one. Fortunately it is the right one:

install(CODE "MESSAGE(\"CMAKE_INSTALL_PREFIX=\${CMAKE_INSTALL_PREFIX}\")")

results in:

CMAKE_INSTALL_PREFIX=C:/Users/User/Documents/dev/build-test_deploy-Desktop_Qt_5_5_1_MSVC2012_32bit-Default/_CPack_Packages/win32/ZIP/Project-0.1.1-win32

Now the bundling will work as such:

install(CODE "
   include(BundleUtilities)
   fixup_bundle(\"\${CMAKE_INSTALL_PREFIX}/bin/TEST${CMAKE_EXECUTABLE_SUFFIX}\"   \"\"   \"\")
   " COMPONENT Runtime)

Maybe one more important note, since the fixup_bundle is using a set of fixed strings you are going to have to have a pretty ridge install structure. Essentially the above will only work for monolithic installs:

set(CPACK_MONOLITHIC_INSTALL on)

I'd be interested in a better solution than the above, but I can work with this.


Solution

  • Correct way for use CPack variables, defined at install time, with install(CODE) command:

    install(CODE " 
        include(CPack)
        MESSAGE(\"CPACK_PACKAGE_DIRECTORY=\${CPACK_PACKAGE_DIRECTORY}\")
    ")
    

    Main points here:

    1. Expansion of the variable should be escaped: \${...}. Otherwise, variable is expanded immediately on configure stage, when it has not defined yet.

    2. Install code still needs to include(CPack) for make CPack variable's available.