Last modified: June 26, 2012

Cmake/CPack for Windows: When you want it "to-go"

In an academic setting we rarely distribute our code and data to a large group of lay people. Most often, we provide colleagues with source code and some sample datasets. This tutorial addresses those rare occasions when you want to provide a decent package that includes both executables and data in an appealing package.

The following describes a step by step process of creating an installer for the windows operating system using Cmake/Cpack. If you're impatient, the final project is here.

0. The Project

Our project consists of the source code and configuration files for two programs, and data which includes a pdf file and a CT data set. The complete project is here.

The project CMakeLists.txt looks like this:
project(Example)

cmake_minimum_required(VERSION 2.8)

add_subdirectory(hello)
add_subdirectory(world)
The CMakeLists.txt for the "hello" program looks like this:
project(Hello)

cmake_minimum_required(VERSION 2.8)


set( Hello_SRCS
     main.cxx
   )

add_executable( hello ${Hello_SRCS} )

1. Adding a program icon

Windows users expect to see an icon associated with your program. With Cmake it is easy to satisfy this expectation. Download the complete project from here.

  1. Create an icon image for your program using an image editing application (gimp should do nicely). Remember that you want a square image and not a rectangular one. Save your masterpiece as a windows icon (.ico) file.
  2. Create a resource script file for visual studio (just an ascii file), in our case I named it "hello.rc", and it has the following content:
    IDI_ICON1 ICON DISCARDABLE "H.ico"
    
    "H.ico" is the path to the icon file, in this case just the file name.
  3. Now modify the program's CmakeLists.txt to:
    project(Hello)
    
    cmake_minimum_required(VERSION 2.8)
    
    
    set( Hello_SRCS
         main.cxx
       )
    
     set(WIN_RESOURCE_FILE hello.rc)
    
    add_executable( hello ${Hello_SRCS}  ${WIN_RESOURCE_FILE} )
    

2. Installing the project

We now add the Cmake installation settings. As we intend to use CPack to package our project we will also provide the optional COMPONENT settings in each installation setup. Download the complete project from here.

  1. Modify the project's CMakeLists.txt, add the installation setup for the data elements. Note that each of the data elements belongs to a different component, "CTData" and "instructionData". This is intentional and will be used later on by CPack so that the user can choose not to install each of these data components.
    project(Example)
    
    cmake_minimum_required(VERSION 2.8)
    
    add_subdirectory(hello)
    add_subdirectory(world)
    
    
    set(CT_DATA_FILE_DIR data/CT)
    file(GLOB CT_FILES "${CMAKE_SOURCE_DIR}/${CT_DATA_FILE_DIR}/*")
    install(FILES ${CT_FILES}
            DESTINATION ${CT_DATA_FILE_DIR}
            COMPONENT CTData)
    
    install(FILES "${CMAKE_SOURCE_DIR}/data/example.pdf"
            DESTINATION data
            COMPONENT instructionData)
    
    
  2. Now modify the "hello" program's CmakeLists.txt to (same for "world"):
    project(Hello)
    
    cmake_minimum_required(VERSION 2.8)
    
    
    set( Hello_SRCS
         main.cxx
       )
    
    set(WIN_RESOURCE_FILE hello.rc)
    
    add_executable( hello ${Hello_SRCS} ${WIN_RESOURCE_FILE} )
    
    
    install(TARGETS hello
            RUNTIME
            DESTINATION programs
            COMPONENT applications)
    
    

3. Packing the project

Finally, we add the CPack settings to the project's CMakeLists.txt. Download the complete project from here.

  1. We start by telling CMake to install the windows runtime libraries and that these belong to the applications component.
    set(CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS_SKIP TRUE)
    include(InstallRequiredSystemLibraries)
    install(PROGRAMS ${CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS}
            DESTINATION programs
            COMPONENT applications)
    
  2. Generic CPack settings (self explanatory?).
    set(CPACK_PACKAGE_NAME "CPackExampleInstaller")
    set(CPACK_PACKAGE_VENDOR "Ziv Yaniv")
    set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Example showing CPack in action")
    set(CPACK_PACKAGE_VERSION_MAJOR "1")
    set(CPACK_PACKAGE_VERSION_MINOR "0")
    set(CPACK_PACKAGE_VERSION_PATCH "0")
    set(CPACK_PACKAGE_VERSION "${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH}")
    set(CPACK_PACKAGE_INSTALL_DIRECTORY "CPackExample")
    
  3. Tell CPack about the components and provide component descriptions.
    set(CPACK_COMPONENTS_ALL applications CTData instructionData)
    set(CPACK_COMPONENT_CTDATA_GROUP "data")
    set(CPACK_COMPONENT_INSTRUCTIONDATA_GROUP "data")
    
    set(CPACK_COMPONENT_APPLICATIONS_DISPLAY_NAME "applications (hello & world)")
    set(CPACK_COMPONENT_GROUP_DATA_DESCRIPTION "data (CT and instructions)")
    
  4. Tell CPack about the file containing the licensing information which is displayed in the installer wizard.
    set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_SOURCE_DIR}/license.txt")
    
  5. Create an icon which will be displayed inside the installation wizard, and an icon for the installer and uninstaller. Tell CPack about these icons.
    set(CPACK_PACKAGE_ICON "${CMAKE_SOURCE_DIR}\\\\hw.bmp")
    set(CPACK_NSIS_MUI_ICON "${CMAKE_SOURCE_DIR}/hw.ico")
    set(CPACK_NSIS_MUI_UNIICON "${CMAKE_SOURCE_DIR}/hw.ico")
    
  6. Set the programs, directories and files, displayed under the Start menu shortcut.
    set(CPACK_NSIS_MENU_LINKS "programs\\hello" "Hello"
                              "programs\\world" "World"
                              ${CT_DATA_FILE_DIR} "CT Data"
                              "data\\example.pdf" "documentation")
    
  7. Last line, invoke/include CPack.
    include(CPack)