3.17.9. CMAKE_INSTALL_PREFIX

CMake documentation

CMAKE_INSTALL_PREFIX variable can be used to control destination directory of install procedure:

cmake_minimum_required(VERSION 2.8)
project(foo)

add_library(foo foo.cpp)

install(TARGETS foo DESTINATION lib)
[install-examples]> rm -rf _builds
[install-examples]> cmake -Hsimple -B_builds -DCMAKE_INSTALL_PREFIX=_install/config-A
[install-examples]> cmake --build _builds --target install
Scanning dependencies of target foo
[ 50%] Building CXX object CMakeFiles/foo.dir/foo.cpp.o
[100%] Linking CXX static library libfoo.a
[100%] Built target foo
Install the project...
-- Install configuration: ""
-- Installing: /.../install-examples/_install/config-A/lib/libfoo.a

[install-examples]> cmake -Hsimple -B_builds -DCMAKE_INSTALL_PREFIX=_install/config-B
[install-examples]> cmake --build _builds --target install
[100%] Built target foo
Install the project...
-- Install configuration: ""
-- Installing: /.../install-examples/_install/config-B/lib/libfoo.a

3.17.9.1. Modify

This variable is designed to be modified on user side. Do not force it in code!

cmake_minimum_required(VERSION 2.8)
project(foo)

set(CMAKE_INSTALL_PREFIX "${CMAKE_CURRENT_BINARY_DIR}/3rdParty/root") # BAD CODE!

add_library(foo foo.cpp)

install(TARGETS foo DESTINATION lib)
[install-examples]> rm -rf _builds
[install-examples]> cmake -Hmodify-bad -B_builds -DCMAKE_INSTALL_PREFIX="`pwd`/_install"
-- The C compiler identification is GNU 5.4.0
-- The CXX compiler identification is GNU 5.4.0
-- Check for working C compiler: /usr/bin/cc
-- Check for working C compiler: /usr/bin/cc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Detecting C compile features
-- Detecting C compile features - done
-- Check for working CXX compiler: /usr/bin/c++
-- Check for working CXX compiler: /usr/bin/c++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: /.../install-examples/_builds

Library unexpectedly installed to 3rdparty/root instead of _install:

[install-examples]> cmake --build _builds --target install
Scanning dependencies of target foo
[ 50%] Building CXX object CMakeFiles/foo.dir/foo.cpp.o
[100%] Linking CXX static library libfoo.a
[100%] Built target foo
Install the project...
-- Install configuration: ""
-- Installing: /.../install-examples/_builds/3rdParty/root/lib/libfoo.a

Note

Use CACHE in such case

3.17.9.2. On the fly

Make do support changing of install directory on the fly by DESTDIR:

[install-examples]> rm -rf _builds
[install-examples]> cmake -Hsimple -B_builds -DCMAKE_INSTALL_PREFIX=""
[install-examples]> make -C _builds DESTDIR="`pwd`/_install/config-A" install
...
Install the project...
-- Install configuration: ""
-- Installing: /.../install-examples/_install/config-A/lib/libfoo.a
make: Leaving directory '/.../install-examples/_builds'

[install-examples]> make -C _builds DESTDIR="`pwd`/_install/config-B" install
...
Install the project...
-- Install configuration: ""
-- Installing: /.../install-examples/_install/config-B/lib/libfoo.a
make: Leaving directory '/.../install-examples/_builds'

3.17.9.3. Read

Because of the DESTDIR feature, CPack functionality, different nature of build and install stages often usage of CMAKE_INSTALL_PREFIX variable on configure step is an indicator of wrongly written code:

cmake_minimum_required(VERSION 2.8)
project(foo)

add_library(foo foo.cpp)

install(TARGETS foo DESTINATION lib)

# BAD CODE!
file(
    COPY
    "${CMAKE_CURRENT_LIST_DIR}/README"
    DESTINATION
    "${CMAKE_INSTALL_PREFIX}/share/foo"
)

include(CPack)

User may not want to install such project at all, so copying of file to root is something unintended and quite surprising. If you’re lucky you will get problems with permissions on configure step instead of a silent copy:

[install-examples]> rm -rf _builds
[install-examples]> cmake -Hwrong-usage -B_builds
-- The C compiler identification is GNU 5.4.0
-- The CXX compiler identification is GNU 5.4.0
-- Check for working C compiler: /usr/bin/cc
-- Check for working C compiler: /usr/bin/cc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Detecting C compile features
-- Detecting C compile features - done
-- Check for working CXX compiler: /usr/bin/c++
-- Check for working CXX compiler: /usr/bin/c++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Detecting CXX compile features
-- Detecting CXX compile features - done
CMake Error at CMakeLists.txt:9 (file):
  file COPY cannot copy file
  "/.../install-examples/wrong-usage/README"
  to "/usr/local/share/foo/README".

-- Configuring incomplete, errors occurred!
See also "/.../install-examples/_builds/CMakeFiles/CMakeOutput.log".

CPack will use separate directory for install so README will not be included in archive:

[install-examples]> rm -rf _builds _install
[install-examples]> cmake -Hwrong-usage -B_builds -DCMAKE_INSTALL_PREFIX="`pwd`/_install"
[install-examples]> (cd _builds && cpack -G TGZ)
CPack: Create package using TGZ
CPack: Install projects
CPack: - Run preinstall target for: foo
CPack: - Install project: foo
CPack: Create package
CPack: - package: /.../install-examples/_builds/foo-0.1.1-Linux.tar.gz generated.
[install-examples]> tar xf _builds/foo-0.1.1-Linux.tar.gz
[install-examples]> find foo-0.1.1-Linux -type f
foo-0.1.1-Linux/lib/libfoo.a

3.17.9.4. Implicit read

All work should be delegated to install command instead, in such case CMAKE_INSTALL_PREFIX will be read implicitly:

cmake_minimum_required(VERSION 2.8)
project(foo)

add_library(foo foo.cpp)

install(TARGETS foo DESTINATION lib)
install(FILES README DESTINATION share/foo)

include(CPack)
[install-examples]> rm -rf _builds _install
[install-examples]> cmake -Hright-usage -B_builds -DCMAKE_INSTALL_PREFIX="`pwd`/_install"
-- The C compiler identification is GNU 5.4.0
-- The CXX compiler identification is GNU 5.4.0
-- Check for working C compiler: /usr/bin/cc
-- Check for working C compiler: /usr/bin/cc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Detecting C compile features
-- Detecting C compile features - done
-- Check for working CXX compiler: /usr/bin/c++
-- Check for working CXX compiler: /usr/bin/c++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: /.../install-examples/_builds

Correct install directory:

[install-examples]> cmake --build _builds --target install
Scanning dependencies of target foo
[ 50%] Building CXX object CMakeFiles/foo.dir/foo.cpp.o
[100%] Linking CXX static library libfoo.a
[100%] Built target foo
Install the project...
-- Install configuration: ""
-- Installing: /.../install-examples/_install/lib/libfoo.a
-- Installing: /.../install-examples/_install/share/foo/README

Correct packing:

[install-examples]> (cd _builds && cpack -G TGZ)
CPack: Create package using TGZ
CPack: Install projects
CPack: - Run preinstall target for: foo
CPack: - Install project: foo
CPack: Create package
CPack: - package: /.../install-examples/_builds/foo-0.1.1-Linux.tar.gz generated.
[install-examples]> tar xf _builds/foo-0.1.1-Linux.tar.gz
[install-examples]> find foo-0.1.1-Linux -type f
foo-0.1.1-Linux/share/foo/README
foo-0.1.1-Linux/lib/libfoo.a

3.17.9.5. Install script

Same logic can be applied if CMAKE_INSTALL_PREFIX used in script created by configure_file command:

# Top-level CMakeLists.txt

cmake_minimum_required(VERSION 2.8)
project(foo)

set(script "${CMAKE_CURRENT_BINARY_DIR}/script.cmake")
configure_file(script.cmake.in "${script}" @ONLY)

install(SCRIPT "${script}")

include(CPack)
# script.cmake.in

cmake_minimum_required(VERSION 2.8)

set(correct "$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}")

message("Incorrect value: '@CMAKE_INSTALL_PREFIX@'")
message("Correct value: '${correct}'")

file(WRITE "${correct}/share/foo/info" "Some info")

Configure for DESTDIR usage:

[install-examples]> rm -rf _builds _install foo-0.1.1-Linux
[install-examples]> cmake -Hconfigure -B_builds -DCMAKE_INSTALL_PREFIX=""
-- The C compiler identification is GNU 5.4.0
-- The CXX compiler identification is GNU 5.4.0
-- Check for working C compiler: /usr/bin/cc
-- Check for working C compiler: /usr/bin/cc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Detecting C compile features
-- Detecting C compile features - done
-- Check for working CXX compiler: /usr/bin/c++
-- Check for working CXX compiler: /usr/bin/c++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: /.../install-examples/_builds

DESTDIR read correctly:

[install-examples]> make DESTDIR="`pwd`/_install/config-A" -C _builds install
make: Entering directory '/.../install-examples/_builds'
Install the project...
-- Install configuration: ""
Incorrect value: ''
Correct value: '/.../install-examples/_install/config-A'
make: Leaving directory '/.../install-examples/_builds'
[install-examples]> find _install/config-A -type f
_install/config-A/share/foo/info

Changing directory on the fly:

[install-examples]> make DESTDIR="`pwd`/_install/config-B" -C _builds install
make: Entering directory '/.../install-examples/_builds'
Install the project...
-- Install configuration: ""
Incorrect value: ''
Correct value: '/.../install-examples/_install/config-B'
make: Leaving directory '/.../install-examples/_builds'
[install-examples]> find _install/config-B -type f
_install/config-B/share/foo/info

Regular install:

[install-examples]> rm -rf _builds _install
[install-examples]> cmake -Hconfigure -B_builds -DCMAKE_INSTALL_PREFIX="`pwd`/_install"
-- The C compiler identification is GNU 5.4.0
-- The CXX compiler identification is GNU 5.4.0
-- Check for working C compiler: /usr/bin/cc
-- Check for working C compiler: /usr/bin/cc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Detecting C compile features
-- Detecting C compile features - done
-- Check for working CXX compiler: /usr/bin/c++
-- Check for working CXX compiler: /usr/bin/c++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: /.../install-examples/_builds
[install-examples]> cmake --build _builds --target install
Install the project...
-- Install configuration: ""
Incorrect value: '/.../install-examples/_install'
Correct value: '/.../install-examples/_install'
[install-examples]> find _install -type f
_install/share/foo/info

Packing:

[install-examples]> (cd _builds && cpack -G TGZ)
CPack: Create package using TGZ
CPack: Install projects
CPack: - Run preinstall target for: foo
CPack: - Install project: foo
Incorrect value: '/.../install-examples/_install'
Correct value: '/.../install-examples/_builds/_CPack_Packages/Linux/TGZ/foo-0.1.1-Linux'
CPack: Create package
CPack: - package: /.../install-examples/_builds/foo-0.1.1-Linux.tar.gz generated.
[install-examples]> tar xf _builds/foo-0.1.1-Linux.tar.gz
[install-examples]> find foo-0.1.1-Linux -type f
foo-0.1.1-Linux/share/foo/info

3.17.9.6. Summary

  • Do not force value of CMAKE_INSTALL_PREFIX

  • Use of CMAKE_INSTALL_PREFIX on configure, generate, build steps is an indicator of badly designed code

  • Use install instead of CMAKE_INSTALL_PREFIX

  • Respect DESTDIR