Changing CMake compiler flags for multiple source files using asterisks - cmake

I'm trying to debug a problem related to compiler optimisation (no issue with -O2 or below, segfault with -O3) and I'd like to be able to switch the compiler flags for a chunk of my source so I can try to narrow down where the segfault is coming from.
I can do this setting the global optimisation level to -O2, and altering the PROPERTIES for single files like so:
SET_SOURCE_FILES_PROPERTIES(file1.f90 PROPERTIES COMPILE_FLAGS -O3)
However, when I try to do this for multiple files using *.f90 for example, it seems to not work:
SET_SOURCE_FILES_PROPERTIES(*.f90 PROPERTIES COMPILE_FLAGS -O3)
Is there any way to do this for multiple files without specifying every file by name?

You can glob for a list of files:
file(GLOB MyFiles *.f90)
set_property(SOURCE ${MyFiles} PROPERTY COMPILE_FLAGS -O3)
Alternatively, you could set the COMPILE_FLAGS target property of the respective target instead. Usually, it does not make much sense to compile certain source files with different compile flags than others within the same target. So unless you have good reason to do this on a per-file basis, you should always use the target properties instead.

Just adding to #ComicSansMS correct answer.
You could also use SET_SOURCE_FILES_PROPERTIES this way:
file(GLOB MyFiles *.f90)
SET_SOURCE_FILES_PROPERTIES(${MyFiles} PROPERTIES COMPILE_FLAGS -O3)
This code will have the same effect as
file(GLOB MyFiles *.f90)
set_property(SOURCE ${MyFiles} PROPERTY COMPILE_FLAGS -O3)

Related

CMake: How to specify a different link script for each target

I have multiple targets that are being made in a CMake project. Each target has a different linkscript (LD file). How do I write the CMakeLists.txt file to make this happen? This is for an embedded project with C/C++/ASM files.
This is what I have so far. The problem is that LINKER_SCRIPT is defined globally and not per-target.
# add alpha target
add_executable(alpha.elf ${SOURCES})
target_compile_definitions(alpha.elf PUBLIC -DALPHA_DEFINED)
set(LINKER_SCRIPT ${CMAKE_SOURCE_DIR}/Linker/alpha.ld)
# add beta target
add_executable(beta.elf ${SOURCES})
target_compile_definitions(beta.elf PUBLIC -DBETA_DEFINED)
set(LINKER_SCRIPT ${CMAKE_SOURCE_DIR}/Linker/beta.ld)
set(CMAKE_EXE_LINKER_FLAGS
"${CMAKE_EXE_LINKER_FLAGS} -T ${LINKER_SCRIPT}")
The problem is that LINKER_SCRIPT gets overwritten and the last definition is the one used. How can I make this work?
I have tried to define per-target variable using the following, however the output is not as expected. The file gets compiled, however things are not where they should be. For example, the generated HEX file does not start at 0x08000000 which is where it should be defined per the LD file.
set_target_properties(alpha.elf PROPERTIES
CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-Map=${PROJECT_BINARY_DIR}/alpha.elf.map -T ${CMAKE_SOURCE_DIR}/Linker/alpha.ld")
The variable LINKER_SCRIPT is just being over-ridden the second time you set it to a value. It doesn't have global scope but sub-directory / function scope. But like any variable it takes on its latest value.
CMAKE_EXE_LINKER_FLAGS is being used for both targets in this case. Splitting this into separate sub-directories may work but I've never tried it.
There are no per-target variables that I am aware of. set_target_properties is used to set properties. Some properties are known to CMake, but the property CMAKE_EXE_LINKER_FLAGS is not one of them. It should just be ignored when generating the build files.
Try using target_link_options to set per-target property LINK_OPTIONS which is known and the option will show up when linking the executable.
For example target_link_options(alpha.elf PRIVATE -T${CMAKE_SOURCE_DIR}/Linker/alpha.ld). I haven't used it with options that have a space in them so that might be a problem.
To re-link if the linker script changes then refer to this answer:
https://stackoverflow.com/a/42138375/1028434

Different linker options for each executable

I would like to create two separate executable from the same source files but with different linker parameters.
With the lines above, I can generate one executable without problem:
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} --specs=nano.specs -T libs.ld -T mem.ld -T sections.ld -L\"${CMAKE_CURRENT_SOURCE_DIR}/script\" -Wl,-Map,${MAP_NAME}")
add_executable(${ELF_NAME} ${PRJ1_SOURCE_FILES} ${PRJ1_HEADER_FILES})
target_link_libraries(${ELF_NAME} PRIVATE liba libb libc)
When I add the following two lines at the end of the code above, I can very well generate the second executable (with the same linker flags) besides the first one without problem:
add_executable(${ELF2_NAME} ${PRJ1_SOURCE_FILES} ${PRJ1_HEADER_FILES})
target_link_libraries(${ELF2_NAME} PRIVATE liba libb libc)
But my problem is that I have to generate the second executable (at the same time with the first one) with different linker parameters. I don't want to use conditional statements to generate one after another. My goal is to automate the process.
How can achieve this?
Use set_target_properties with LINK_FLAGS property. From set_target_properties manual:
set_target_properties(target1 target2 ...
PROPERTIES prop1 value1
prop2 value2 ...)
Set properties on a target.
...
See Properties on Targets for the list of properties known to CMake.
In the link properties on targets we can find LINK_FLAGS:
Additional flags to use when linking this target.
The LINK_FLAGS property can be used to add extra flags to the link step of a target. LINK_FLAGS_ will add to the configuration , for example, DEBUG, RELEASE, MINSIZEREL, RELWITHDEBINFO.
So use something similar to:
set_target_properties(${ELF_NAME} PROPERTIES LINK_FLAGS " --specs=rdimon.specs")
While Kamil answer is good for now, I believe question you're asking for is properly addressed in upcoming CMake v3.13.
target_link_options was introduced for that purpose,
"Specify link options to use when linking a given target. The named must have been created by a command such as add_executable() or add_library() and must not be an ALIAS target."
https://cmake.org/cmake/help/v3.13/command/target_link_options.html#command:target_link_options

target_compile_definitions for multiple CMake targets?

I've been told it's bad practice to do things like seting CFLAGS directly in CMake, and that, instead, I should use the target_compile_definitions() command.
Ok, but - what if I want to use similar/identical definitions for multiple (independent) targets? I don't want to repeat myself over and over again.
I see three possible ways:
The preferred one using target_compile_definitions(... INTERFACE/PUBLIC ...) which would self-propagate the compiler definitions to targets depending on it via target_link_libraries() command.
Using the set_property(TARGET target1 target2 ... APPEND PROPERTY COMPILE_DEFINITIONS ...) to set the same definitions to multiple targets.
You may still use the "old commands" of add_definitions() and remove_definitions() to modify COMPILE_DEFINITIONS directory property (which would pre-set all COMPILE_DEFINITIONS target properties in this directories scope).
References
Is Cmake set variable recursive?
CMake: Is there a difference between set_property(TARGET ...) and set_target_properties?
tl;dr: You can iterate the targets in a loop.
If you have a bunch of targets with some common/similar features, you may want to simply manipulate them all in a loop! Remember - CMake is not like GNU Make, it's a full-fledged scripting language (well, sort of). So you could write:
set(my_targets
foo
bar
baz)
foreach(TARGET ${my_targets})
add_executable(${TARGET} "${TARGET}.cu")
target_compile_options(${TARGET} PRIVATE "--some_option=some_value")
target_link_libraries(${TARGET} PRIVATE some_lib)
# and so on
set_target_properties(
${TARGET}
PROPERTIES
C_STANDARD 99
C_STANDARD_REQUIRED YES
C_EXTENSIONS NO )
endforeach(TARGET)
And you could also initialize an empty list of targets, then add to it here-and-there, and only finally apply your common options and settings to all of them, centrally.
Note: In this example I added PRIVATE compile options, but if you need some of them to propagate to targets using your targets, you can make them PUBLIC).
another neat solution is to define an interface library target (a fake target that does not produce any binaries) with all required properties and compiler definitions, then link the other existing targets against it
example:
add_library(myfakelib INTERFACE)
target_compile_definitions(myfakelib INTERFACE MY_NEEDED_DEFINITION)
add_executable(actualtarget1 main1.cpp)
add_executable(actualtarget2 main2.cpp)
set_property(
TARGET actualtarget1 actualtarget2
APPEND PROPERTY LINK_LIBRARIES myfakelib
)
refs:
https://cmake.org/cmake/help/latest/command/add_library.html#interface-libraries

CMake: show all modified variables

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, …)?

Difference between COMPILE_FLAGS and COMPILE_OPTIONS

What is the difference between
COMPILE_FLAGS: Additional flags to use when compiling this target's sources.
and
COMPILE_OPTIONS: List of options to pass to the compiler.
In terms of resulting VS2010 solution these commands produce the same result:
target_compile_options(target PRIVATE "/option=test1")
set_target_properties(target PROPERTIES COMPILE_FLAGS "/option=test1")
set_target_properties(target PROPERTIES COMPILE_OPTIONS "/option=test1")
COMPILE_OPTIONS is a list, but COMPILE_FLAGS is a string.
set_target_properties(target PROPERTIES
COMPILE_OPTIONS "/option=test1;/option2=test2")
set_target_properties(target PROPERTIES
COMPILE_FLAGS "/option=test1 /option2=test2")
You can more-easily append to a list than to a string.
Also, COMPILE_OPTIONS is properly escaped, whereas some characters in COMPILE_FLAGS may need to be escaped manually or cause problems.
Can be used to the same end, but flags are associated with some target enviroment. So you could use different sets of flags for different enviroments.