CMake: how to normalize paths? [duplicate] - cmake

This question already has answers here:
cmake generate error on windows as it uses \ as escape seq
(3 answers)
Closed 5 years ago.
The community reviewed whether to reopen this question 4 months ago and left it closed:
Original close reason(s) were not resolved
Is there a robust way to normalize paths in CMake?
Example:
# Let's assume that an environment variable MY_ROOT_DIR is set
# that points to some directory.
set(MYFILE "$ENV{MY_ROOT_DIR}/somefile.txt")
message(${MYFILE})
# This will result for example in
# Win: C:\path\to\my\root\dir/somefile.txt
# Unix based: /path/to/my/root/dir/somefile.txt
In this example, it would be required to normalize MY_ROOT_DIR (that is to replace backslashes with slashes) prior to using it as path component. How would you do this in CMake?
CMake (or the tools further down the toolchain) may handle paths with mixed separators (/ or \), or may not. CMake uses / as the standard separator. A typical warning generated by CMake for paths with the wrong path separator \ may look similar to this:
CMake Warning (dev) at cmake_install.cmake:5 (set):
Syntax error in cmake code at
C:/path/to/my/root/build/cmake_install.cmake:5
when parsing string
C:\path\to\my\root/somefile.txt
Invalid escape sequence \p
Policy CMP0010 is not set: Bad variable reference syntax is an error. Run
"cmake --help-policy CMP0010" for policy details. Use the cmake_policy
command to set the policy and suppress this warning.
Thanks for any hints on this!

You can use the file(TO_CMAKE_PATH) command for this.
The TO_CMAKE_PATH mode converts a native <path> into a cmake-style path with forward-slashes (/). The input can be a single path or a system search path like $ENV{PATH}. A search path will be converted to a cmake-style list separated by ; characters.
Here is an example:
file(TO_CMAKE_PATH "$ENV{MY_DIR_VAR}" ENV_MY_DIR_VAR)

Related

Expand variable name containing a generator expression in cmake

In the build process, I set directories where I gather the build output of different sub-projects. The directories are set as :
set( CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG "${CMAKE_CURRENT_LIST_DIR}/../build/bin/debug" )
set( CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE "${CMAKE_CURRENT_LIST_DIR}/../build/bin/release" )
Now, I'd like to copy some files (a directory of qt plugins) to that directory dependent on the configuration which it is built for.
I tried:
# copy qt plugins
add_custom_command( TARGET mytarget POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_directory
"${QT_DIR}/../../../plugins"
"${$<UPPER_CASE:CMAKE_RUNTIME_OUTPUT_DIRECTORY_$<CONFIG> >}/plugins"
COMMAND_EXPAND_LISTS)
thus, I try to build a string that equals the variable name and then try to expand that as described here: CMake interpret string as variable. In other words: I would like to have a generator expression that evaluates to the content of CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG or CMAKE_RUNTIME_OUTPUT_DIRECTOR_RELEASE dependent on the current build configuration.
However running cmake with the statement above results in an error:
"CMakeLists.txt:112: error: Syntax error in cmake code at [..] when parsing string ${$<UPPER_CASE:CMAKE_RUNTIME_OUTPUT_DIRECTORY_$<CONFIG> >}/plugins Invalid character ('<') in a variable name: '$'
So my question is, how can I use a generator-expression to access the corresponding variable? (Bonus question: is there another/better way to achieve the same goal?)
So my question is, how can I use a generator-expression to access the corresponding variable?
You cannot. There is currently (CMake <=3.23) no way to expand a variable whose name is determined by the value of a generator expression.
Bonus question: is there another/better way to achieve the same goal?
Yes, and you are almost there! You can use $<TARGET_FILE_DIR:...>:
add_custom_command(
TARGET mytarget POST_BUILD
COMMAND
${CMAKE_COMMAND} -E copy_directory
"${QT_DIR}/../../../plugins"
"$<TARGET_FILE_DIR:mytarget>/plugins"
VERBATIM
)
This works because TARGET_FILE_DIR evaluates to the actual directory containing the executable or library file for mytarget, no matter the active configuration, property values, etc.
Docs: https://cmake.org/cmake/help/latest/manual/cmake-generator-expressions.7.html#genex:TARGET_FILE_DIR
CMAKE_RUNTIME_OUTPUT_DIRECTORY_<CONFIG> is already relative to the binary directory so you should not try to compute the binary directory in its definition. Also, it supports generator expressions. Thus, the following will be much more robust:
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "bin/$<LOWER_CASE:$<CONFIG>>"
CACHE STRING "Common output directory for runtime artifacts")
This has a bunch of concrete benefits:
No need to set CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG or CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE
This will work for MinSizeRel and RelWithDebInfo, plus any custom configurations one might add down the line.
Since it's defined as a cache variable, it can be overridden for debugging / working around name clashes, etc.
A bit more context for (3): most CMAKE_* variables are intended to be either read-only or user-configurable (i.e. at the command line, from the GUI, etc.). Overriding their defaults via set(CACHE) is a polite compromise. A notable exception to this rule is the collection of Qt codegen flags (CMAKE_AUTO{MOC,RCC,UIC}). These must typically be set for the build to produce usable binaries.

How to use Set directory properties [duplicate]

This question already has answers here:
How do I add a linker or compile flag in a CMake file?
(7 answers)
Closed last year.
I used Set_directory_properties(PROPERTIES COMPILE_DEFINITIONS "--saferc=none") to mask misra check in directory, but I got Warning:
Ccv850:Warning:option "-D--saferc=none" ignored due to invalid argument. Expected name or name=string.
You should basically never use directory properties, ever.
For whichever targets cannot compile without the flag, you can add it like so:
target_compile_options(
my_target
PRIVATE
"$<$<CXX_COMPILER_ID:GHS>:--saferc=none>"
"$<$<C_COMPILER_ID:GHS>:--saferc=none>"
)
My understanding is that --saferc=none is a Green Hills flag, hence the check for $<CXX_COMPILER_ID:GHS>. If you are only using one of C or C++, you can delete the flag for the other language.

cmake replace string in custom target [duplicate]

This question already has an answer here:
How to call a CMake function from add_custom_target/command?
(1 answer)
Closed 5 years ago.
I want to have a cmake target that updates a specific file.
I tried following but it seems that I cannot put all what I want into a custom target.
ADD_CUSTOM_TARGET(update
file(READ "file.h" myFile)
string(REPLACE "originalString" "newString" myFile"${myFile}"))
)
I'm quite new to cmake so I may be missing something basic. How could I update the file on request ?
What I personally use for this type of problem is use configure_file. Essentially, you can make what you consider a template file and wrap variable names in the files.
Example.h.template
Here is my #VAR#
Then if you have VAR defined in your CMake project, it will replace VAR in your destination.
configure_file(<input> <output> NEWLINE_STYLE WIN32)
If input (your template) is modified, CMake will be re-run to keep your file up to date. So in your cmake you can
set(VAR "program")
configure_file("Path/To/Example.h.template" "Path/To/File.h" NEWLINE_STYLE [UNIX|DOS|WIN32|LF|CRLF])
The result should be:
File.h
Here is my program

CMake - set_property could not find CACHE variable

Disclaimer: I'm aware of this question. However, The OP's needs are different to mine: what he actually wants is to port an app to Linux and therefore the answers go in that line, not answering what I want to know: the reasons of the error.
I'm trying to create a dropdown list in CMake GUI following the instructions in here and here
So I have this very simple CMakeLists.txt:
cmake_minimum_required(VERSION 3.6)
project(datasetprograms)
set(CMAKE_CXX_STANDARD 11)
#LINES TO MAKE THE GUI DROP-DOWN:
set(TARGET_ARCHITECTURE “arm” CACHE STRING “Architecture to compile to”)
set_property(CACHE TARGET_ARCHITECTURE PROPERTY STRINGS arm x86)
#Add subdirectories for each project
add_subdirectory(helloworld)
Basically I just copied and pasted, following the instructions. However, instead of having a nice drop-down in the CMake GUI, I got the following error:
CMake Error at CMakeLists.txt:9 (set_property): set_property could
not find CACHE variable TARGET_ARCHITECTURE. Perhaps it has not yet
been created
Question: What I'm doing wrong?
You may check value of variable TARGET_ARCHITECTURE using message() and you will found CACHE is a part of that value.
This is because you use in set() command double quotes which are not common ones (") but language-specific (“). So CMake treats set() command as not CACHE'd one. That is a reason of the error message.

How to put several paths in CMAKE_PREFIX_PATH? [duplicate]

This question already has an answer here:
Multiple Cmake_Prefix_Paths
(1 answer)
Closed 6 years ago.
How can I have several paths for cmake to look for needed libraries. I installed zlib and libpng under /usr/local/zlib and /usr/local/libpng however, what I'm currently doing is first cmake -DCMAKE_PREFIX_PATH=/usr/local/zlib, then issuing a second command `cmake -DCMAKE_PREFIX_PATH=/usr/local/libpng" in order for cmake to recognize both.
Is there a way to have both paths in the same variable?
I tried -DCMAKE_PREFIX_PATH=/usr/local/zlib:/usr/local/libpng but it didn't work.
You need to use ; character instead of : to define lists.