How to Get The System Home Directory in Cmake on Linux

Can I get the system home directory in CMake on Linux?

Home directory is referred to by the HOME environment variable, so you can access it in CMake script by:

$ENV{HOME}

How do I get project root dir in the cmake install [code] section?

Is it a bug? Or I do something wrong?

No, it's just that not all variables are available in install(CODE) segments. Here's a simple demo of detecting all the variables available there:

cmake_minimum_required(VERSION 3.24)
project(example)

install(CODE [[
get_property(vars DIRECTORY PROPERTY VARIABLES)
foreach (var IN LISTS vars)
message(STATUS "${var} = ${${var}}")
endforeach ()
]])

See in the terminal:

$ cmake -S . -B build
-- Install configuration: ""
-- CMAKE_ARGC = 4
-- CMAKE_ARGV0 = /home/reinking/.local/lib/python3.9/site-packages/cmake/data/bin/cmake
-- CMAKE_ARGV1 = -DCMAKE_INSTALL_PREFIX=foo
-- CMAKE_ARGV2 = -P
-- CMAKE_ARGV3 = /path/to/build/cmake_install.cmake
-- CMAKE_BINARY_DIR = /path/to
-- CMAKE_COMMAND = /home/reinking/.local/lib/python3.9/site-packages/cmake/data/bin/cmake
-- CMAKE_CPACK_COMMAND = /home/reinking/.local/lib/python3.9/site-packages/cmake/data/bin/cpack
-- CMAKE_CROSSCOMPILING = FALSE
-- CMAKE_CTEST_COMMAND = /home/reinking/.local/lib/python3.9/site-packages/cmake/data/bin/ctest
-- CMAKE_CURRENT_BINARY_DIR = /path/to
-- CMAKE_CURRENT_LIST_DIR = /path/to/build
-- CMAKE_CURRENT_LIST_FILE = /path/to/build/cmake_install.cmake
-- CMAKE_CURRENT_SOURCE_DIR = /path/to
-- CMAKE_FILES_DIRECTORY = /CMakeFiles
-- CMAKE_HOST_SYSTEM_NAME = Linux
-- CMAKE_HOST_UNIX = 1
-- CMAKE_INSTALL_CONFIG_NAME =
-- CMAKE_INSTALL_PREFIX = foo
-- CMAKE_INSTALL_PREFIX = foo
-- CMAKE_INSTALL_SO_NO_EXE = 1
-- CMAKE_MAJOR_VERSION = 3
-- CMAKE_MINOR_VERSION = 24
-- CMAKE_OBJDUMP = /usr/bin/objdump
-- CMAKE_PATCH_VERSION = 1
-- CMAKE_ROOT = /home/reinking/.local/lib/python3.9/site-packages/cmake/data/share/cmake-3.24
-- CMAKE_SCRIPT_MODE_FILE = /path/to/build/cmake_install.cmake
-- CMAKE_SOURCE_DIR = /path/to
-- CMAKE_TWEAK_VERSION = 0
-- CMAKE_VERSION = 3.24.1
-- UNIX = 1

So if you want to bake a variable into your install script, you'll have to generate the file. Here's one technique:

string(CONFIGURE [[
set(PROJECT_SOURCE_DIR "@PROJECT_SOURCE_DIR@")

message(STATUS "PROJECT_SOURCE_DIR: ${PROJECT_SOURCE_DIR}")
message(STATUS "CMAKE_BINARY_DIR: ${CMAKE_BINARY_DIR}")
message(STATUS "CMAKE_SOURCE_DIR: ${CMAKE_SOURCE_DIR}")
]] install_script @ONLY)

install(CODE "${install_script}")

How to specify the path where CMake is installed in the CMakeLists.txt

CMake will use whatever path the running CMake executable is in. Furthermore, it may get confused if you switch paths between runs without clearing the cache.

So what you have to do is simply instead of running cmake <path_to_src> from the command line, run ~/usr/cmake-path/bin/cmake <path_to_src>.

You may want to add an alias or a shell script to the path that is a little more typeable (so you only have to type my_cmake <path_to_src> or something like that).

Note that there is no clean way to solve this by just editing the CMakeLists.txt. While in theory you could have CMake 2.6 run an outer CMake script that does nothing but running an inner CMake script from a 3.0 executable, that's just a dirty hack. Just run the correct executable from the command line and you should be fine.

How to install binaries to user's home directory by CPack?

You may use environment variable HOME for refer to user's home directory:

set(CPACK_PACKAGING_INSTALL_PREFIX "$ENV{HOME}/${CPACK_PACKAGE_NAME}")

Finding the source root directory in CMake for ROS

Disclaimer: the question is still a bit unclear to me, so apologies in advance if the answer does not reflect your needs.

If the problem you want to solve is that you have a lot of directories like src in which the same top-level CMakeLists.txt is linked and you want to include a specific CMakeExtras.txt that resides in each particular directory, then you can solve this by adding:

include(${CMAKE_CURRENT_SOURCE_DIR}/CMakeExtras.txt)

to your top-level CMakeLists.txt. According to the documentation:

This the full path to the source directory that is currently being processed by cmake

and should solve this issue (i.e. the variable refers to the directory being processed, not to the CMakeLists.txt where it is used).

If instead your issue is how to compute the src path, given that a link to the top level CMakelists.txt is there, then you simply want to use PROJECT_SOURCE_DIR which:

is the source directory of the most recent project() command.

CMAKE include src and install directories on different OS

On windows usually the install prefix is something like C:/Program Files/<Package Name>, the usual install prefix on Unix being /usr/local. Usually this directory contains subdirectories like include containing the headers, lib containing (import) libraries, ect..

Using MSVC for the Windows targets those include directories are not automatically available to the compiler.

This is the reason why you should try to use find_package, if package configuration scripts or find scripts are provided by the installation which has the added benefit of also adding any dependencies with just 2 commands in your cmake project (find_package and target_link_libraries). If the package is installed in the default location, find_package should be able to locate the scripts to load without specifying the install location manually.

For packages not providing this kind of info, writing a find script of your own creating imported targets allows for easy reuse.



Can something like this work?

install(FILES include/sort/sort.hpp DESTINATION ${CMAKE_INSTALL_PREFIX}/include/${CMAKE_PROJECT_NAME}/sort)

In general you should avoid hardcoding absolute destination paths into your install paths. Instead use destination paths relative to the install prefix, since the install prefix may be overwritten, e.g. if the user runs the installation via cmake --install <build dir> --prefix <install directory> or when using cpack to generate a package.

Usually you place public headers of your library in a separate directory, even in your sources (which you seem to be doing) and install the directory with

install(DIRECTORY include/sort TYPE INCLUDE)

Resulting in cmake choosing the exact location based on its defaults for the include files for the target system.

Using cmake: General use of directories and especially default location of output binaries

Build directory is UNRELATED to the place, where deliverable files will be installed.

Build directory is a working directory, where compiler, linker and other tools generate deliverable files with some other auxiliary files. E.g., object files (.o) are auxiliary files: they are produced by compiler, used by the linker and are never installed. Also, build directory contains Makefiles and some other files, used by make.

When install files, make install takes deliverable files from build directory, and place them into their final locations. After that project is ready for use, and build directory can be removed.

Place, where deliverable files are installed, is controlled by variable

CMAKE_INSTALL_PREFIX

which you can set in cmake gui tool after the first configuration occures. Normally, binary files are installed into bin/ subdirectory relative to that prefix, so you may set CMAKE_INSTALL_PREFIX to /usr/local for get executables being installed into /usr/local/bin/.

As for build directory, you may create it anywhere. Usually, it is created in the directory where user has write access, so neither configuration nor build requires root priveleges. E.g., you may choose /home/<user>/cmake-build.

How to make cmake output to the build directory?

The usual way to do this, rather than changing variables to set the path, is simply to create the output directory, change to it, and run cmake from there. So instead of cmake . you usually have cmake .. or similar.

I understand the initial impulse to say "But I expect my build system to write output somewhere else." But CMake is not usually used in the way you were initially expecting, and other people who run your CMake build won't expect what you were expecting, so it's probably best to just use the built-in, default behavior, which is to put the output wherever cmake was run.

Put another way: You are fighting against the tool. Don't do that.



Related Topics



Leave a reply



Submit