cmake warnings about line break with backslash - cmake

I want to have a nice clean 80 column CMakeLists.txt. I tried to use line break in one of the lines but then I got a warning about it (3rd line below):
else()
target_compile_definitions(${PROJECT_NAME} PUBLIC
QT_MESSAGE_PATTERN="%{time dd:MM:yyyy-h:mm:ss:zzz} %{type} \
%{pid}\t%{message}"
)
endif()
And here is the warning:
CMake Warning (dev) at CMakeLists.txt:78:
Syntax Warning in cmake code at column 28
Argument not separated from preceding token by whitespace.
How can I fix this? or do it properly?

Your issue is with the quoting not with the line break. The error message points at line 78, column 28 (there's a quote next to this position). You need to enclose the entire argument in quotes and escape the inner quotes , so your target_compile_definitions argument would become:
"QT_MESSAGE_PATTERN=\"%{time dd:MM:yyyy-h:mm:ss:zzz} %{type} \
%{pid}\t%{message}\""
See here for further explanations.
A small CMake test project looks like this:
cmake_minimum_required(VERSION 3.0)
project(quoteTest)
add_executable(quoteTest main.cpp)
target_compile_definitions(${PROJECT_NAME} PUBLIC
"QT_MESSAGE_PATTERN=\"%{time dd:MM:yyyy-h:mm:ss:zzz} %{type} \
%{pid}\t%{message}\""
)

Related

generator expression in add_custom_target

I'm trying to create a cmake (3.22) function that creates a target called cppclean for the target that I provide in the arguments
function (cppclean target)
if(${STATIC_CODE_ANALYSIS})
find_program(CPP_CLEAN cppclean)
if(CPP_CLEAN)
add_custom_target(cppclean
COMMAND ${CPP_CLEAN} "--include-path $<JOIN:$<TARGET_PROPERTY:${target},INCLUDE_DIRECTORIES>, --include-path >" $<TARGET_PROPERTY:${target},SOURCE_DIR>
VERBATIM
COMMAND_EXPAND_LISTS
)
else()
message("Cannot find cppclean")
endif()
endif()
endfunction()
However I doesn't work with the error:
No such file or directory: '--include-path ... --include-path ...
--include-path ...'
When I look at the make file that is created I indeed see the quotes around the expanded generator expression which is probably wrong.
If I remove the quotes around the generator expression it gives a different error:
cannot create /home/foo/src: Is a directory
And the make file shows that the JOIN expression is not expanded.
How to fix this?

What does a string between percent signs, like `SET(%MY_VAR% ON)` mean in cmake?

Stumbled upon something like this in a cmake file and couldn't find the syntax explanation neither in cmake documentation, nor on the Internet.
SET(%MY_LIB_TYPE% ON)
The same line is defined in a .cmake and in a similarly named .cmake.in files, and MY_LIB_NAME does not appear anywhere else.
What does %string% syntax do?
In CMake, nothing. It looks like a template placeholder for something that's generating CMake files. I believe this is the most likely option.
Otherwise, % is technically an allowable variable name character in CMake, though you have to indirect through another variable to read it.
$ cat test.cmake
cmake_minimum_required(VERSION 3.20)
set(%FOO% bar)
set(var "%FOO%")
message("${${var}}")
$ cmake -P test.cmake
bar

CMake remove escape character from generator expresion

I have the generator expression GEN_EXPR_INCLUDE_PATHS that provides a list of the directories to include.
The goal is to pass this list directly as compiler option via add_custom_command:
add_custom_command(
OUTPUT ${CMAKE_BINARY_DIR}/${HEADER_FILE_NAME}.gch
DEPENDS ${HEADER_FILE} IMPLICIT_DEPENDS CXX ${HEADER_FILE}
COMMAND ${CMAKE_CXX_COMPILER}
${FLAGS}
${HEADER_INCLUDE_PATHS}
${gccGarbageCollectorOpts}
-c ${HEADER_FILE} -o
${CMAKE_BINARY_DIR}/${HEADER_FILE_NAME}.gch
)
Where HEADER_INCLUDE_PATHS is following generator expression:
$<1:-I$<JOIN:$<TARGET_PROPERTY:Some_Target,INTERFACE_INCLUDE_DIRECTORIES>, -I>>
Just because the INTERFACE_INCLUDE_DIRECTORIES of Some_Target is received as generator expression.
But cmake adds escape chars before spaces, and gcc fails due to these extra chars.
Is it possible to do something with it?
I'll be appriciate for any support.
add_custom_command accepts COMMAND parameters as a list. In CMake a list is a string which elements are separated by semicolon, so it is semicolon which should be used for joining, not a space.
Also, for correctly split semicolon-containing strings, add_custom_command needs COMMAND_EXPAND_LISTS keyword.
set(HEADER_INCLUDE_PATHS -I$<JOIN:$<TARGET_PROPERTY:mylib,INTERFACE_INCLUDE_DIRECTORIES>,;-I>)
add_custom_command(
...
COMMAND ${CMAKE_CXX_COMPILER}
...
"${HEADER_INCLUDE_PATHS}" # Double quotes are important!
...
COMMAND_EXPAND_LISTS # This option is important too
)
Actually, an example with a space-separated join of include directories
-I$<JOIN:$<TARGET_PROPERTY:INCLUDE_DIRECTORIES>, -I>
is provided in CMake documentation itself. Not sure about their intention for this example.

How to preserve single quotes in a CMake cached variable?

I have a variable
SET(CODE_COVERAGE_EXCLUSION_LIST
""
CACHE STRING "List of resources to exclude from code coverage analysis")
It must contain a list of expressions such as : 'tests/*' '/usr/*'
When trying to set the default value to the above expressions, the single quotes are removed.
How to preserve them ?
Moreover, when I try to pass the exclusion list like this
cmake -DCODE_COVERAGE_EXCLUSION_LIST="'tests/*' '/usr/*'" ..
The initial and final single quotes are lost. How to preserve them as well ?
Finally, the same question applies when using cmake-gui.
EDIT : I tried to use backslash to escape the quotes :
SET(CODE_COVERAGE_EXCLUSION_LIST
" \'tests/*\' \'/usr/*\'"
CACHE STRING "List of resources to exclude from code coverage analysis : ")
It gave me the following error :
Syntax error in cmake code at
xxx.cmake:106
when parsing string
\'tests/*\' \'/usr/*\'
Invalid escape sequence \'
EDIT2 : code of the add_custom_target (and not add_custom_command, my bad)
ADD_CUSTOM_TARGET(${_targetname}
# Cleanup lcov
${LCOV_PATH} --directory . --zerocounters
# Run tests
COMMAND ${_testrunner} ${ARGV3}
# Capturing lcov counters and generating report
COMMAND ${LCOV_PATH} --directory . --capture --output-file ${_outputname}.info
COMMAND ${LCOV_PATH} --remove ${_outputname}.info 'tests/*' '/usr/*' ${CODE_COVERAGE_EXCLUSION_LIST} --output-file ${_outputname}.info.cleaned
COMMAND ${GENHTML_PATH} -o ${_outputname} ${_outputname}.info.cleaned
COMMAND ${CMAKE_COMMAND} -E remove ${_outputname}.info ${_outputname}.info.cleaned
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
COMMENT "Resetting code coverage counters to zero.\nProcessing code coverage counters and generating report."
)
Turning my comments into an answer
First - taking the question why you need those quotes aside - I could reproduce your problem and found several possible solutions:
Adding spaces at the begin and end of your cached variable
cmake -DCODE_COVERAGE_EXCLUSION_LIST=" 'tests/*' '/usr/*' " ..
Using "escaped" double quotes instead of single quotes
cmake -DCODE_COVERAGE_EXCLUSION_LIST:STRING="\"tests/*\" \"/usr/\"" ..
Using your set(... CACHE ...) example by setting policy CMP0053 switch introduced with CMake 3.1:
cmake_policy(SET CMP0053 NEW)
set(CODE_COVERAGE_EXCLUSION_LIST
"\'tests/*\' \'/usr/*\'"
CACHE STRING "List of resources to exclude from code coverage analysis : ")
But when setting this in the code I could also just do
set(CODE_COVERAGE_EXCLUSION_LIST
"'tests/*' '/usr/*'"
CACHE STRING "List of resources to exclude from code coverage analysis : ")
The quoting issue seems only to be a problem when called from command line
Then - if I do assume you may not need the quotes - you could pass the paths as a list:
A semicolon separated CMake list is expanded to parameters again (with spaces as delimiter) when used in a COMMAND
cmake -DCODE_COVERAGE_EXCLUSION_LIST:STRING="tests/*;/usr/*" ..
with
add_custom_target(
...
COMMAND ${LCOV_PATH} --remove ${_outputname}.info ${CODE_COVERAGE_EXCLUSION_LIST} --output-file ${_outputname}.info.cleaned
)
would give something like
.../lcov --remove output.info tests/* /usr/* --output-file output.info.cleaned
I also tried to add the VERBATIM option, because "all arguments to the commands will be escaped properly for the build tool so that the invoked command receives each argument unchanged". But in this case, it didn't change anything.
References
add_custom_target()
CMake Language: Escape Sequences
0015200: Odd quoting issue when mixing single, double and escaped quotes to COMMAND

CMake error with string sub-command STRIP "requires two arguments"

I am trying to compile a library with CMake. This library uses CMake with the pods build system.
During configuring I get the following error:
CMake Error at cmake/pods.cmake:257 (string):
string sub-command STRIP requires two arguments.
In the specific file pods.cmake the command looks like this:
execute_process(COMMAND
${PKG_CONFIG_EXECUTABLE} --cflags-only-I ${ARGN}
OUTPUT_VARIABLE _pods_pkg_include_flags)
string(STRIP ${_pods_pkg_include_flags} _pods_pkg_include_flags)
which looks fine to me. Any ideas why this error occurs? I don't understand why cmake complains that it needs two arguments for the STRIP command when it clearly has two.
Note: I use cmake 2.8.12.2, but according to the documentation this should be valid.
While your CMake file does syntactically contain two arguments, ${_pods_pkg_include_flags} can be empty. If so, it is not an argument semantically and never reaches string(), which then sees just one. If it's possible for a string to be empty (and you want to treat it as an empty string in such case instead of skipping it), quote it:
string(STRIP "${_pods_pkg_include_flags}" _pods_pkg_include_flags)