Where does cmake look for .cmake scripts? - cmake

I am trying to execute_process in cmake like this
execute_process(COMMAND ${CMAKE_COMMAND} -P myScript.cmake
This only works if the file, myScript.cmake is in the same working directory.
Three related questions:
Does cmake have a standard location to look for .cmake scripts?
Is there a cmake variable I can define to tell cmake where to look? or
Should I always give a full path to the script (i.e., -P ${PATH_VAR}/myScript.cmake)?

Does cmake have a standard location to look for .cmake scripts?
For execute_process, no. The find_XXX commands (e.g. find_file) and include do though.
Is there a cmake variable I can define to tell cmake where to look?
Again, for execute_process, no. For find_xxx or include, you can set the variable CMAKE_MODULE_PATH.
Should I always give a full path to the script (i.e., -P ${PATH_VAR}/myScript.cmake)?
That's a good option; passing a full path leaves no room for uncertainty. However, you can get away with a relative path too. The default working directory for execute_process is the CMAKE_BINARY_DIR, so you can pass the path to the script relative to that.
Alternatively you can specify the WORKING_DIRECTORY in the execute_process call either as a full path or relative to the CMAKE_BINARY_DIR.
If you feel your script is in a standard location, you could consider "finding" it first using a call to find_file. This would yield the full path to the script if found and that variable can be used in your execute_process call.

Related

Cmake get/query/print build settings on the command line?

Let's assume I have a Cmake C project, and I have something like this in the project:
project(my_project C CXX ASM)
set(my_executable_sources
main.c
file_one.c
)
set(my_executable_sources ${my_executable_sources} file_two.c)
add_executable(my_executable
${my_executable_sources}
file_three.c
)
Let's assume I'm in the ./build subfolder, and cmake ../ -G "Unix Makefiles" has passed successfully.
Can I somehow query build information from the command line using cmake?
For instance, I'm interested here in the final list of source files for my_executable; is there a command that would easily retrieve them? Say, like the following pseudocode:
$ cmake --pseudo-query-build --project="my_project" --target="my_executable" --query="source_files"
my_executable source files:
main.c
file_one.c
file_two.c
file_three.c
I don't see any cmake-generator-independent way of achieving this and even if you know the generator in use the project files generated.
You could modify your project to include a custom target that prints the sources though:
add_custom_target(print_my_executable_sources COMMAND ${CMAKE_COMMAND} -E echo "$<TARGET_PROPERTY:my_executable,SOURCES>" COMMAND_EXPAND_LISTS)
this allows you to use
cmake --build <binary_dir> [--config <configuration>] --target print_my_executable_sources
to print the sources, even if generator expressions are used in the sources.
Note: This does print all files in a single line; to get all the file names on separate lines, you could instead run cmake with the -P option passing the soures via -D and add logic to print one file name per line in the cmake script file.
Alternatively setting the CMAKE_EXPORT_COMPILE_COMMANDS variable to True during configuration could result in the generation of json files that would allow for the extraction of the information, but you'd need a json parser to extract the info. Furthermore this approach only works for the Makefile and Ninja CMake generators. Also I'm not sure you can tell which target a source file belongs to in all cases.
Start by obtaining the target's sources via this line (after add_executable):
get_target_property(MY_TARGET_SOURCES my_executable SOURCES)
And then proceed with a simple line at the end of the file (after add_executable)
message(STATUS ${MY_TARGET_SOURCES})
EDIT: For a full list of available target properties refer to this link.
EDIT2: As I've noticed now that you probably intend to just use it within the CLI, then for my solution you would also have to encapsulate it with a if/endif that checks for a definition e.g. if(SOURCES_DEBUG_INFO) and then run it with -DSOURCES_DEBUG_INFO=TRUE

How to get the working directory of the cmake process?

How to get the working directory from which cmake was called?
I know that I can run execute_process() at the beginning of my CMake code but maybe there is some better way like a built-in variable to the working directory of the CMake process.
What I want to achieve is to convert a relative path given in a CMake variable (given with -D...) to an absolute path in CMake.
What I want to achieve is to convert a relative path given in a CMake variable (given with -D...) to an absolute path in CMake.
Then simply create a cache variable of type PATH (for directories) or FILEPATH in your CMakeLists.txt. CMake will convert untyped command line arguments to absolute paths automatically.
$ cat CMakeLists.txt
cmake_minimum_required(VERSION 3.22)
project(test NONE)
set(input_file "" CACHE FILEPATH "some input file")
message(STATUS "${input_file}")
$ cmake -S . -B build -Dinput_file=foo.txt
-- /path/to/foo.txt
-- Configuring done
-- Generating done
-- Build files have been written to: /path/to/build
See the documentation:
It is possible for the cache entry to exist prior to the call but have no type set if it was created on the cmake(1) command line by a user through the -D<var>=<value> option without specifying a type. In this case the set command will add the type. Furthermore, if the <type> is PATH or FILEPATH and the <value> provided on the command line is a relative path, then the set command will treat the path as relative to the current working directory and convert it to an absolute path.
Here: https://cmake.org/cmake/help/latest/command/set.html?highlight=current%20working%20directory
Relatedly, when running in script mode (rather than project mode), several of the usual variables are set to the current working directory:
When run in -P script mode, CMake sets the variables CMAKE_BINARY_DIR, CMAKE_SOURCE_DIR, CMAKE_CURRENT_BINARY_DIR and CMAKE_CURRENT_SOURCE_DIR to the current working directory.
https://cmake.org/cmake/help/latest/variable/CMAKE_SOURCE_DIR.html

CMake custom command always executes

In my CMakeLists.txt, I define a custom target and command:
add_custom_command(
OUTPUT
${CMAKE_CURRENT_SOURCE_DIR}/input.csv
${CMAKE_CURRENT_SOURCE_DIR}/output1.csv
${CMAKE_CURRENT_SOURCE_DIR}/output2.csv
COMMAND python3
${CMAKE_CURRENT_SOURCE_DIR}/tests/genVectors.py)
add_custom_target(TEST_VECTORS
DEPENDS
${CMAKE_CURRENT_SOURCE_DIR}/input.csv
${CMAKE_CURRENT_SOURCE_DIR}/output1.csv
${CMAKE_CURRENT_SOURCE_DIR}/output2.csv)
add_executable(VectorTest tests/VectorTest.cpp)
add_dependencies(VectorTest TEST_VECTORS)
It always generates new CSV files even though the files exist. I only need to generate the vectors (with genVectors.py python file) if they do not exist. Is that something wrong with my configuration?
The OUTPUT option of add_custom_command does not guarantee that the generated files are placed here; it just tells CMake that the generated files are expected to be placed there. It is likely that your python script is generating files at a relative path, so they are just being placed somewhere in your CMake binary directory (your build folder). So while your files may be generated correctly, your custom target doesn't see them because it is looking in CMAKE_CURRENT_SOURCE_DIR. Thus, the custom target will always trigger the custom command to re-run.
CMake runs add_custom_command from the CMAKE_CURRENT_BINARY_DIR by default, but you can change it to run from CMAKE_CURRENT_SOURCE_DIR by adding the WORKING_DIRECTORY option. This way, the generated files will be placed at the expected location, and achieve your desired behavior. Try something like this:
add_custom_command(
OUTPUT
${CMAKE_CURRENT_SOURCE_DIR}/input.csv
${CMAKE_CURRENT_SOURCE_DIR}/output1.csv
${CMAKE_CURRENT_SOURCE_DIR}/output2.csv
COMMAND python3
${CMAKE_CURRENT_SOURCE_DIR}/tests/genVectors.py
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
add_custom_target(TEST_VECTORS
DEPENDS
${CMAKE_CURRENT_SOURCE_DIR}/input.csv
${CMAKE_CURRENT_SOURCE_DIR}/output1.csv
${CMAKE_CURRENT_SOURCE_DIR}/output2.csv)
add_executable(VectorTest tests/VectorTest.cpp)
add_dependencies(VectorTest TEST_VECTORS)
You can try to generate your file at time of configuration(i.e. while calling cmake). By this way it will created only once.
You can remove add_custom_command and use execute_process to create your files.

How to load additional parameter in CMAKE using ${CMAKE_CURRENT_SOURCE_DIR}?

I want to pass an additional parameter to cmake relative to where it is.
My libraries are in:
C:/bla/imgui
C:/bla/imgui-integration
From
C:/bla/imgui-integration/build folder I want to refer to C:/bla/imgui in a parameter named IMGUI_DIR :
cmake .. -DIMGUI_DIR="${CMAKE_CURRENT_SOURCE_DIR}/../imgui"
The problem is that I tried every combination of :
-DIMGUI_DIR="${CMAKE_CURRENT_SOURCE_DIR}/../../imgui"
-DIMGUI_DIR="${CMAKE_CURRENT_SOURCE_DIR}/imgui"
And none of them works.
Only works if I directly use:
-DIMGUI_DIR="C:/bla/imgui"
What am I doing wrong exactly?
As Tsyvarev said in a comment:
CMAKE_CURRENT_SOURCE_DIR is a CMake variable, which is set by CMake
when it interprets your project. But when running cmake <..> you use
shell scripting. You need to use abilities of the shell for prepare
needed parameters
I can't use cmake variables in the shell that will be interpreted inside cmake.

Run custom shell script with CMake

I am having the following directory structure:
/CMakeLists.txt
/component-a/CMakeLists.txt
/...
/component-b/CMakeLists.txt
/...
/doc/CMakeLists.txt
/create-doc.sh
The shell script create-doc.sh creates a documentation file (doc.pdf). How can I use CMake to execute this shell script at build time and copy the file doc.pdf to the build directory?
I tried it by using add_custom_command in the CMakeLists.txt file inside the directory doc:
add_custom_command ( OUTPUT doc.pdf
COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/create-doc.sh
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/)
Unfortunately the command is never run.
I also tried execute_process:
execute_process ( COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/create-doc.sh
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/ )
Now the script is executed during the configuration phase, but not at build time.
You got almost there with add_custom_command. This is indeed the correct way to tell CMake how to generate a file. However, CMake will only run that when something depends on that file.
When, as in your case, the file itself is the end product and is not used any further by subsequent build steps, the usual approach is to create a custom target to drive the relevant custom command(s):
add_custom_target(
BuildDocs ALL
DEPENDS doc.pdf
)
This (custom target driver for custom commands) is a very common idiom in CMake.
You can of course play around with arguments for add_custom_target (e.g. ALL, COMMENT) as it suits you.