I want to see what the current set of compiler definitions is in my CMake file. Ones automatically specified and the ones I'd added would be great. The COMPILE_DEFINITIONS macro doesn't appear to contain -- despite what the documentation says.
For example, in the below setup the message never includes GUI_BUILD
add_definitions( -DGUI_BUILD )
message( "COMPILE_DEFINITIONS = ${COMPILE_DEFINITIONS}" )
I don't need to see them in their final form, I just want a quick output to help verify that everything has been configured correctly.
You want to extract the COMPILE_DEFINITIONS property from the directory. E.g. use the following:
add_definitions( -DDebug )
get_directory_property( DirDefs DIRECTORY ${CMAKE_SOURCE_DIR} COMPILE_DEFINITIONS )
Then you can simply iterate over them, e.g.:
foreach( d ${DirDefs} )
message( STATUS "Found Define: " ${d} )
endforeach()
message( STATUS "DirDefs: " ${DirDefs} )
Note that definitions may also be associated with targets or source-files instead of directories. And note that they can differ between configurations. Depending on your requirements, you may need to check a large set of different properties.
Related
I am now trying run a CMake script in this post. With this script, CMake will print all the properties of a target. However, when it tries to retrieve the LOCATION property of the target, the following error is observed:
The LOCATION property may not be read from target "abc". Use the target
name directly with add_custom_command, or use the generator expression
$<TARGET_FILE>, as appropriate.
Then I tried to print the property with message($<TARGET_FILE:abc>), but it does not work either. Any ideas?
To expand on #Florian's comment, reading the LOCATION property of a target is an error by default in today's CMake versions. The documentation for CMake Policy 0026 clearly describes why this is the case:
CMake 2.8.12 and lower allowed reading the LOCATION target property (and configuration-specific variants) to determine the eventual location of build targets. This relies on the assumption that all necessary information is available at configure-time to determine the final location and filename of the target. However, this property is not fully determined until later at generate-time.
After reading the LOCATION property, it can later be changed using generator expressions. CMake allows you to disable this policy, by setting it to the OLD behavior explicitly:
cmake_policy(SET CMP0026 OLD)
Just take the result with a grain of salt, as it may change!
If you're going to change the policy (instead of simply removing LOCATION from the list of properties), it is best to use OLD CMake policies in isolation. When we're done using the OLD behavior, we can POP the old policy off the CMake policy stack to resume using the NEW behavior. Here's the example you referred to, modified to demonstrate usage of the policy change:
function(echo_target tgt)
if(NOT TARGET ${tgt})
message("There is no target named '${tgt}'")
return()
endif()
set(props
DEBUG_OUTPUT_NAME
DEBUG_POSTFIX
RELEASE_OUTPUT_NAME
...
LINK_SEARCH_START_STATIC
LOCATION
LOCATION_DEBUG
...
WIN32_EXECUTABLE
XCODE_ATTRIBUTE_WHATEVER
)
message(STATUS "======================== ${tgt} ========================")
# Push the current (NEW) CMake policy onto the stack, and apply the OLD policy.
cmake_policy(PUSH)
cmake_policy(SET CMP0026 OLD)
foreach(p ${props})
# v for value, d for defined, s for set
get_property(v TARGET ${tgt} PROPERTY ${p})
get_property(d TARGET ${tgt} PROPERTY ${p} DEFINED)
get_property(s TARGET ${tgt} PROPERTY ${p} SET)
# only produce output for values that are set
if(s)
message(STATUS "tgt='${tgt}' p='${p}'")
message(STATUS " value='${v}'")
message(STATUS " defined='${d}'")
message(STATUS " set='${s}'")
message(STATUS "")
endif()
endforeach()
# Pop the previous policy from the stack to re-apply the NEW behavior.
cmake_policy(POP)
message(STATUS "")
endfunction()
For users that are using cmake 3.15 or later and are also using Ninja as a generator, I want to set the new JOB_POOL argument to some large add_custom_command() blocks. For other users, I want to keep my add_custom_command() the same (no JOB_POOL).
In earlier steps, I check the version and the generator and set ${JOB_POOLS} and I also set a variable such that users who should use a pool will see (something like):
For historical reasons, I leave this here, although #Tsyvarev
points out that this is the source of my problem!
The double-quotes are NOT wanted here!
set(USE_POOL "JOB_POOL pool_A")
Users that are not using a pool will not have that variable set.
Now how to leverage that variable in my custom command...?
1.) Generator expressions don't work, just including the text with the previous line...
add_custom_command(
...
$<USE_POOL>
)
2.) I can't seem to simply place the variable in the command, again just including the variable contents on the previous line. For example, when ${JOB_POOL} is set to the string "JOB_POOL pool_A", this code...
For historical reasons, I leave this here, although #Tsyvarev
points out that this is the source of my problem!
Don't use a STRING! No double-quotes!
add_custom_command(
OUTPUT foo
DEPENDS bar
# Comment line here...
${USE_POOL}
COMMAND
${CMAKE_COMMAND} -E ...
)
gives this error...
ninja: error: '../path/to/src/dir/JOB_POOL pool_A', needed by 'path/to/src/dir/foo', missing and no known rule to make it
It simply considers the ${JOB_POOL} string to be another dependency!
3.) I can't use the "APPEND" feature of add_custom_command(). It's just ignored...
if (${USE_POOL})
add_custom_command(
...
APPEND
JOB_POOL pool_A
)
endif()
The only thing that seems to work is to put an "if" around my
entire command, which offends my sensibility since I don't like to duplicate so much code...
if(${USE_POOL})
add_custom_command(
...many lines...
JOB_POOL pool_A
)
else()
add_custom_command(
...many lines...
)
endif()
Do you have a better idea...?
Here's a standalone example for #tsyvarev:
cmake_minimum_required(VERSION 3.15)
project foo
set_property(GLOBAL PROPERTY JOB_POOLS pool_A=2)
# For historical reasons, I leave this here, although #Tsyvarev
# points out that this is the source of my problem!
# Don't use a STRING! No double-quotes!
set(USE_POOL "JOB_POOL pool_A")
add_custom_command(
OUTPUT foo.out
DEPENDS foo.in
${USE_POOL}
COMMAND
${CMAKE_COMMAND} -E copy foo.in foo.out
COMMENT "Converting foo.in -> foo.out"
VERBATIM
)
add_custom_target(foo-out
DEPENDS foo.out
)
% cmake -GNinja .
% ninja foo-out
ninja: error: 'JOB_POOL pool_A', needed by 'foo.out', missing and no known rule to make it
It considers the string to be a dependency... If I move the USE_POOL to after the comment, it considers it part of the comment... If I move it to after the command, it considers it part of the command...
Your JOB_POOL option serves for the user's choice. You may create another variable which contains sequence of related parameters for add_custom_command:
if(JOB_POOL)
set(JOB_POOL_PARAMS JOB_POOL pool_A) # Will add 'JOB_POOL pool_A' sequence of params
else()
set(JOB_POOL_PARAMS) # Will add nothing
endif()
Then use new variable directly in add_custom_command call:
add_custom_command(
...
${JOB_POOL_PARAMS} # Will expand to additional parameters when needed
)
I would like to have a command or option to list all the modified cache variables of the current build configuration. While cmake -L[AH] is nice, it is also quite overwhelming and doesn't show which are non-default values.
There seems to be a variable property MODIFIED that sounds exactly like what I'm looking for - but the documentation is not very reassuring:
Internal management property. Do not set or get.
This is an internal cache entry property managed by CMake to track interactive user modification of entries. Ignore it.
This question also didn't help: CMAKE: Print out all accessible variables in a script
There are so many ways you could change or initialize variables in CMake (command line, environment variables, script files, etc.) that you won't be able to cover them all.
I just came up with the following script that covers the command line switches. Put the following file in your CMake project's root folder and you get the modified variables printed:
PreLoad.cmake
set(_file "${CMAKE_BINARY_DIR}/UserModifiedVars.txt")
get_directory_property(_vars CACHE_VARIABLES)
list(FIND _vars "CMAKE_BACKWARDS_COMPATIBILITY" _idx)
if (_idx EQUAL -1)
list(REMOVE_ITEM _vars "CMAKE_COMMAND" "CMAKE_CPACK_COMMAND" "CMAKE_CTEST_COMMAND" "CMAKE_ROOT")
file(WRITE "${_file}" "${_vars}")
else()
file(READ "${_file}" _vars)
endif()
foreach(_var IN LISTS _vars)
message(STATUS "User modified ${_var} = ${${_var}}")
endforeach()
This will load before anything else and therefore can relatively easily identify the user modified variables and store them into a file for later reference.
The CMAKE_BACKWARDS_COMPATIBILITY is a cached variable set by CMake at the end of a configuration run and therefor is used here to identify an already configured CMake project.
Reference
CMake: In which Order are Files parsed (Cache, Toolchain, …)?
I'm trying to call add_library for all files with certain endings.
The dir structure is:
src
| - CMakeLists.txt (1)
| - main.cpp
| - gui
| - CMakeLists.txt (2)
| - some source and header files
So currently all cc files are in the gui directory.
(1) CMakeLists.txt:
file( GLOB_RECURSE my_sources *.cc )
message(STATUS "my_sources = ${my_sources}")
add_subdirectory( gui )
add_library( my_src ${my_SOURCES} )
target_link_libraries( my_src
my_gui
)
qt5_use_modules( my_src Core Gui Widgets)
(2) CMakeLists.txt:
file( GLOB my_gui_sources *.cc)
add_library( my_gui ${my_gui_sources} )
qt5_use_modules( my_gui Core Gui Widgets)
But I keep getting this output:
You have called ADD_LIBRARY for library my_src without any source files. This typically indicates a problem with your CMakeLists.txt file
-- my_sources = /home/bla/bla/src/gui/BorderLayout.cc;...;/home/bla/bla/my/src/gui/MainWindow.cc
-- my_gui_sources = /home/bla/bla/my/src/gui/BorderLayout.cc;...;/home/bla/bla/my/src/gui/MainWindow.cc
-- Configuring done
-- Generating done
-- Build files have been written to: /home/bla/bla/my/build
I know that I currently don't need the add_library in the first CMakeLists.txt, but later I will. I changed the first GLOB to GLOB_RECURSE, so that it finds at least anything.
For some reason your
file( GLOB my_gui_sources *.cc *.h)
Is not finding any file. To debug, you can print:
message(STATUS "my_gui_sources = ${my_gui_sources}")
Probably you want to use GLOB_RECURSE, which search in sub-directories:
file( GLOB_RECURSE my_gui_sources *.cc *.h)
Note that you don't need to add headers files to the source list.
Take care that you will have to rerun cmake every time you add a file to your project (cmake won't be called automatically, thing that instead happens if you touch one of the cmake files).
Link to documentation of command "file"
Edit:
The actual problem is that in your first CMakeLists.txt file you are using inconsistent naming for your variable (note that casing is important), therefore you have to change your add_library command to:
add_library( my_src ${my_sources} )
Note (off the records :-) ): the fact that casing is important for variable names might be confusing because, on the other hand, in cmake command names are case insensitive. It's also sometimes weird to notice that the character - (minus) might be used as part of the variable name: using _ (underscore) is most of the time preferable.
I am trying to write a macro which goes through a given list of libraries. However the message call in the macro prints only the first item of the list. What am I doing wrong here?
Code:
macro( FindLibs LIBRARY_NAMES_LIST )
message( "inside ${LIBRARY_NAMES_LIST}" )
endmacro()
set( LIBRARY_NAMES_LIST lib1 lib2 lib3)
message( "outside ${LIBRARY_NAMES_LIST}" )
FindLibs(${LIBRARY_NAMES_LIST})
Output:
message( "outside lib1 lib2 lib3" )
message( "inside lib1" )
Quote the variable as you pass it to the macro:
FindLibs("${LIBRARY_NAMES_LIST}")
The provided answers by others are correct. The best solution is indeed to provide the list in double quotes like this:
FindLibs( "${LIBRARY_NAMES_LIST}" )
But if you really don't want to force the user to use double quotes and also want to see the LIBRARY_NAMES_LIST argument in your macro declaration, here's how I would do it:
macro( FindLibs LIBRARY_NAMES_LIST )
set( _LIBRARY_NAMES_LIST ${LIBRARY_NAMES_LIST} ${ARGN} ) # Merge them together
message( "inside ${_LIBRARY_NAMES_LIST}" )
endmacro()
And it would be used like this (your expectation):
FindLibs( ${LIBRARY_NAMES_LIST} )
This is nice, because it will force the user to provide at least one library. Calling it like
FindLibs()
won't work. CMake will report the following error:
FindLibs Macro invoked with incorrect arguments for macro named: FindLibs
If you are using CMake 2.8.3 or newer, another option is to use the CmakeParseArguments, but it will require you to put a keyword argument in front of your list. But this technique is probably the easiest way to manage more than one list, and provides high flexibility. For that reason, it is very handy to know. It is also my preferred way of doing it. Here's how to do it:
include( CMakeParseArguments )
macro( FindLibs )
set( _OPTIONS_ARGS )
set( _ONE_VALUE_ARGS )
set( _MULTI_VALUE_ARGS NAMES DEPENDS )
cmake_parse_arguments( _FINDLIBS "${_OPTIONS_ARGS}" "${_ONE_VALUE_ARGS}" "${_MULTI_VALUE_ARGS}" ${ARGN} )
# Mandatory
if( _FINDLIBS_NAMES )
message( STATUS "inside NAMES=${_FINDLIBS_NAMES}" )
else()
message( FATAL_ERROR "FindLibs: 'NAMES' argument required." )
endif()
# Optional
if( _FINDLIBS_DEPENDS )
message( STATUS "inside DEPENDS=${_FINDLIBS_DEPENDS}" )
endif()
endmacro()
Unfortunately, you have to do your argument enforcement yourself, but at least it gives you the option to chose which arguments are mandatory, and which ones are not (DEPENDS is optional in my example above).
And it would be used like this:
FindLibs( NAMES ${LIBRARY_NAMES_LIST} )
FindLibs( NAMES ${LIBRARY_NAMES_LIST} DEPENDS ${LIBRARY_DEPENDENCY_LIST} )
# You can change the order
FindLibs( DEPENDS ${LIBRARY_DEPENDENCY_LIST} NAMES ${LIBRARY_NAMES_LIST} )
# You can even build your lists on the fly
FindLibs(
NAMES
zlib
png
jpeg
DEPENDS
otherProject1
otherProject2
)
And if I do this:
FindLibs()
# or that:
FindLibs( DEPENDS ${LIBRARY_DEPENDENCY_LIST} )
Then I would get my custom error message:
error: FindLibs: 'NAMES' argument required.
And here the link to the CMakeParseArguments documentation if you want to learn more about it.
I hope it helps :-)
Your macro should look like this:
macro(FindLibs list_var_name)
message( "inside ${${list_var_name}}" )
endmacro()
and call the macro like this:
FindLibs(LIBRARY_NAMES_LIST)
So inside the macro: ${list_var_name} = LIBRARY_NAMES_LIST, ${${list_var_name}} = ${LIBRARY_NAMES_LIST} = your list.
Another solution could be (somewhat more obscure):
macro(FindLibs)
message( "inside ${ARGN}" )
endmacro()
FindLibs(${LIBRARY_NAMES_LIST})
In the first solution you pass only the name of the list-variable to the macro (one argument). In the second solution you expand the list before calling the macro and pass N parameters (N = length of the list).
According to (almost) current CMake documentation, the ${ARGV} symbol should expand to the entire list of arguments. This should keep things simpler at the calling location.