cmake cannot set path variable to previous directory - cmake

I am trying to set the environment variable path in cmake by first getting the directory, then setting the variable:
message(STATUS "Setting PICO_SDK_PATH...")
get_filename_component(PICO_SDK_DIRECTORY "${CMAKE_SOURCE_DIR}/../pico-sdk" ABSOLUTE)
message(STATUS "PICO_SDK_DIRECTORY is set at: ${PICO_SDK_DIRECTORY}")
set({PICO_SDK_PATH} "${PICO_SDK_DIRECTORY}")
message(STATUS "PICO_SDK_PATH is set at: ${PICO_SDK_PATH}")
The output shows that I get the correct PICO_SDK_DIRECTORY
-- Setting PICO_SDK_PATH...
-- PICO_SDK_DIRECTORY is set at: /mnt/c/repos/RP2040/pico-sdk
-- PICO_SDK_PATH is set at:
Looks like PICO_SDK_PATH is not set properly. Does anyone know what issue I am encountering?

I turn #vre's comment into an answer: Do not use curly braces to set CMake variables, see the CMake documentation.

Related

How to assign cmake variables in the CMakeLists.txt

I can use cmake like this:
cmake -DPYTHON_EXECUTABLE=~/build/python ..
How could I write this in my CMakeLists.txt so that I could simply run this:
cmake ..
Include
set(PYTHON_EXECUTABLE $ENV{HOME}/build/python CACHE FILEPATH "")
in your CMakeLists.txt. For more information about the set command see the online documentation or run cmake --help set.
EDIT: The CACHE FILEPATH "" part here is mandatory, as pointed out below.

Value from CMakeCache.txt not used consistently during makefile generation [duplicate]

I'm having trouble setting a configuration variable via the command line. I can't determine it from the system, so I expect the user to specify:
cmake -DCMAKE_TOOLCHAIN_FILE=../android.toolchain -DANDROID_ABI:STRING="arm64" ..
Inside my android.toolchain, I have the following:
message(STATUS "Android ABI: ${ANDROID_ABI}")
if( "${ANDROID_ABI}" STREQUAL "" )
message(FATAL_ERROR "Please specifiy ABI at cmake call -DANDROID_ABI:STRING=armeabi or -DANDROID_ABI:STRING=arm64")
endif()
No matter what, it fails at this line EVEN THOUGH it prints out the correct arm64:
-- Android ABI: arm64
CMake Error at yaml-cpp/android.toolchain:45 (message):
Please specifiy ABI at cmake call -DANDROID_ABI:STRING=armeabi or -DANDROID_ABI:STRING=arm64
Could anyone direct me to what I'm doing wrong?
I think this has to do with:
-D adds a cache variable instead of a normal variable
This is in a toolchain file... it seems to ignore cache variables
Any thoughts or suggestions?
I don't pretend to fully understand what's going on behind the scenes, but here's a workaround that works for me:
# Problem: CMake runs toolchain files multiple times, but can't read cache variables on some runs.
# Workaround: On first run (in which cache variables are always accessible), set an intermediary environment variable.
if (FOO)
# Environment variables are always preserved.
set(ENV{_FOO} "${FOO}")
else ()
set(FOO "$ENV{_FOO}")
endif ()
CMake 3.6 introduces variable CMAKE_TRY_COMPILE_PLATFORM_VARIABLES which contains a list of variables, automatically passed from the main project to the project, created with try_compile.
A toolchain may add its variables to that list, so they could be extracted in a subproject:
message(STATUS "Android ABI: ${ANDROID_ABI}")
if( "${ANDROID_ABI}" STREQUAL "" )
message(FATAL_ERROR "Please specifiy ABI at cmake call -DANDROID_ABI:STRING=armeabi or -DANDROID_ABI:STRING=arm64")
endif()
# propagate the variable into "inner" subprojects.
list(APPEND CMAKE_TRY_COMPILE_PLATFORM_VARIABLES "ANDROID_ABI")
Caveats:
This approach affects only to source flow of try_compile command. It won't work when try_compile is used for create fully-fledged CMake project with signature
try_compile(<resultVar> <bindir> <srcdir> <projectName> ...)
(Approach with setting environment variable, as described in the #sorbet answer, works perfectly in this case.)
This approach won't work for a subproject, created with ExternalProject_Add.
(Approach with setting environment variable fails in that case too.)

Why does CMake ignore exported CXX and CC environment variables?

I am running a CMake (3.4.3) like this as explained in the CMake FAQ's:
export CC="cc_args.py $PWD/../bin/gcc"
export CXX="cc_args.py $PWD/../bin/g++"
cmake -DCMAKE_BUILD_TYPE=Debug ..
However when I print CMAKE_CXX_COMPILER and CMAKE_C_COMPILER it still points to the system's default compilers in /usr/bin. It only works when I explicitly read-in the environment variables like this:
IF (NOT $ENV{CC} STREQUAL "")
SET(CMAKE_C_COMPILER $ENV{CC})
ENDIF ()
IF (NOT $ENV{CXX} STREQUAL "")
SET(CMAKE_CXX_COMPILER $ENV{CXX})
ENDIF ()
But even then the building fails with this message:
/bin/sh: 1: /home/peterg/bin/cc_args.py /home/peterg/Code/build/../bin/g++: not found
However I am certain that all paths are correct since executing just the path between the two colons outputs this as expected:
g++: fatal error: no input files
compilation terminated.
Update:
It seems the compiling process does not like spaces in the compiler paths. I've now created two scripts (one for GCC and one for CC) which wrap the commands and propagate the arguments and that seems to work. But it still seems I am doing something fundamentally wrong because CMake would also not accept the exported CC=proxy_script_cc.sh and GCC=proxy_script_gcc.sh variables without spaces by itself.
Turning my comment into an answer
Problem
I've given you code a try and could reproduce your problem
CMake Error at [...]/cmake-3.5/Modules/CMakeDetermineCXXCompiler.cmake:56 (message):
Could not find compiler set in environment variable CXX:
cc_args.py [... PWD ...]/../bin/g++.
If I look at CMakeDetermineCXXCompiler.cmake code and at get_filename_component() documentation, it just means that it didn't find cc_args.py in "the system search path" or relative to your binary output directory.
Solution
So it does work when you give a full path or a relative path to your binary output dir with something like
export CC="../cc_args.py ../bin/gcc"
export CXX="../cc_args.py ../bin/g++"
Alternative
CMake does allow to define "launcher scripts" e.g. with CMAKE_<LANG>_COMPILER_LAUNCHER
$ cmake -DCMAKE_BUILD_TYPE=Debug
-DCMAKE_C_COMPILER_LAUNCHER=../cc_args.py
-DCMAKE_CXX_COMPILER_LAUNCHER=../cc_args.py
..
References
How to Use CCache with CMake?
Save and reprint warnings for successfully-compiled files on subsequent builds?
Pass -DCMAKE_CXX_COMPILER=<path/to/compiler> to your CMake call. That's less error prone compared to fiddling with shell variables.

cmake - get the used commandline flags "-D"

i recently switched a few projects from autotools to cmake.
one common thing i liked on autotools is that - if i go into the src build directory. there is config.log/config.status - where at the top the ./configure --params command is listed - so it is easy to rerun the former used commandline flags.
(like after compiling some stuff - i want to add a another --enable-this - so copy & paste from config.log/status - and rerun the ./configure --old-params --enable-this)
in cmake - i have a bunch of -D flags - how can i find the used commandline like in config.log/status - with a cmake project?
i know there is the CMakeCache... - but its hard to extract the used flags
edit:
i came up with the following solution:
#save commandline to rebuild this :)
set(USED_CMD_LINE "cmake ")
set(MY_CMAKE_FLAGS CMAKE_BUILD_TYPE CMAKE_INSTALL_PREFIX ENABLE_SSL ENABLE_LUA ENABLE_SSH ENABLE_SNMP MYSQL_USER MYSQL_PASS MYSQL_HOST MYSQL_DB FULL_FEATURES USE_COVERAGE)
FOREACH(cmd_line_loop IN ITEMS ${MY_CMAKE_FLAGS})
if(${cmd_line_loop})
STRING(CONCAT USED_CMD_LINE ${USED_CMD_LINE} "-D" ${cmd_line_loop} "=" ${${cmd_line_loop}} " ")
endif()
ENDFOREACH(cmd_line_loop)
STRING(CONCAT USED_CMD_LINE ${USED_CMD_LINE} " .. ")
#store to a file aka "config.status"
FILE(WRITE ${CMAKE_CURRENT_BINARY_DIR}/config.status ${USED_CMD_LINE} )
creates a file config.status in the build folder - containing all set cmake params.
pro:
seems to solve my problem
seems to work on subsequent cmake calls
con:
unable to set chmod on FILE(write ? the variable
MY_CMAKE_FLAGScontains the known flags - needs to be manually
updated if a new flag is added
regards
Cmake does not give you easy way to list all used -D flags (defines). However, for correctly written CMakeLists, it is not needed to know the full command line with all -D flags to change one particular define/option.
Consider this snipplet:
SET(my_var_1 TRUE CACHE BOOL "my var 1")
SET(my_var_2 TRUE CACHE BOOL "my var 2")
message(STATUS "my_var_1 ${my_var_1}")
message(STATUS "my_var_2 ${my_var_2}")
First cmake invocation:
>cmake .. -Dmy_var_1=FALSE
-- my_var_1 FALSE
-- my_var_2 TRUE
-- Configuring done
-- Generating done
-- Build files have been written to: out
Second cmake invocation:
>cmake .. -Dmy_var_2=FALSE
-- my_var_1 FALSE
-- my_var_2 FALSE
-- Configuring done
-- Generating done
-- Build files have been written to: out
Note that my_var_1=FALSE even it is not explicitely stated (taken from cache)
One feature that may be helpful is turning on the flag CMAKE_EXPORT_COMPILE_COMMANDS in the project's CMake cache. During build, this will make CMake generate a JSON file compile_commands.json in the binary directory that contains the exact compiler calls for all translation units.
You may want to take a look at what is done in the bootstrap script in CMake's source code:
# Write our default settings to Bootstrap${_cmk}/InitialCacheFlags.cmake.
echo '
# Generated by '"${cmake_source_dir}"'/bootstrap
# Default cmake settings. These may be overridden any settings below.
set (CMAKE_INSTALL_PREFIX "'"${cmake_prefix_dir}"'" CACHE PATH "Install path prefix, prepended onto install directories." FORCE)
set (CMAKE_DOC_DIR "'"${cmake_doc_dir}"'" CACHE PATH "Install location for documentation (relative to prefix)." FORCE)
set (CMAKE_MAN_DIR "'"${cmake_man_dir}"'" CACHE PATH "Install location for man pages (relative to prefix)." FORCE)
set (CMAKE_DATA_DIR "'"${cmake_data_dir}"'" CACHE PATH "Install location for data (relative to prefix)." FORCE)
' > "${cmake_bootstrap_dir}/InitialCacheFlags.cmake"
[...]
"${cmake_bootstrap_dir}/cmake" "${cmake_source_dir}" "-C${cmake_bootstrap_dir}/InitialCacheFlags.cmake" "-G${cmake_bootstrap_generator}" ${cmake_options} ${cmake_bootstrap_system_libs} "$#"
The boostrap script is generating a InitialCacheFlags.cmake file and is then preloading it with the cmake -C option.
And - if you additionally want to output the values to stdout - this initial-cache CMake script also accepts message() commands besides the set(... CACHE) commands.
See also How to store CMake build settings

Check CMake Cache Variable in Toolchain File

I'm having trouble setting a configuration variable via the command line. I can't determine it from the system, so I expect the user to specify:
cmake -DCMAKE_TOOLCHAIN_FILE=../android.toolchain -DANDROID_ABI:STRING="arm64" ..
Inside my android.toolchain, I have the following:
message(STATUS "Android ABI: ${ANDROID_ABI}")
if( "${ANDROID_ABI}" STREQUAL "" )
message(FATAL_ERROR "Please specifiy ABI at cmake call -DANDROID_ABI:STRING=armeabi or -DANDROID_ABI:STRING=arm64")
endif()
No matter what, it fails at this line EVEN THOUGH it prints out the correct arm64:
-- Android ABI: arm64
CMake Error at yaml-cpp/android.toolchain:45 (message):
Please specifiy ABI at cmake call -DANDROID_ABI:STRING=armeabi or -DANDROID_ABI:STRING=arm64
Could anyone direct me to what I'm doing wrong?
I think this has to do with:
-D adds a cache variable instead of a normal variable
This is in a toolchain file... it seems to ignore cache variables
Any thoughts or suggestions?
I don't pretend to fully understand what's going on behind the scenes, but here's a workaround that works for me:
# Problem: CMake runs toolchain files multiple times, but can't read cache variables on some runs.
# Workaround: On first run (in which cache variables are always accessible), set an intermediary environment variable.
if (FOO)
# Environment variables are always preserved.
set(ENV{_FOO} "${FOO}")
else ()
set(FOO "$ENV{_FOO}")
endif ()
CMake 3.6 introduces variable CMAKE_TRY_COMPILE_PLATFORM_VARIABLES which contains a list of variables, automatically passed from the main project to the project, created with try_compile.
A toolchain may add its variables to that list, so they could be extracted in a subproject:
message(STATUS "Android ABI: ${ANDROID_ABI}")
if( "${ANDROID_ABI}" STREQUAL "" )
message(FATAL_ERROR "Please specifiy ABI at cmake call -DANDROID_ABI:STRING=armeabi or -DANDROID_ABI:STRING=arm64")
endif()
# propagate the variable into "inner" subprojects.
list(APPEND CMAKE_TRY_COMPILE_PLATFORM_VARIABLES "ANDROID_ABI")
Caveats:
This approach affects only to source flow of try_compile command. It won't work when try_compile is used for create fully-fledged CMake project with signature
try_compile(<resultVar> <bindir> <srcdir> <projectName> ...)
(Approach with setting environment variable, as described in the #sorbet answer, works perfectly in this case.)
This approach won't work for a subproject, created with ExternalProject_Add.
(Approach with setting environment variable fails in that case too.)