I would like to compile a library as shared or static based on other variable eg:
add_library(MyLibrary $<$<IF:${BUILD_SHARED_LIBS},SHARED,STATIC> ${SOURCES})
For clarity I expect this to be equivalent with the following:
if(BUILD_SHARED_LIBS)
add_library(MyLibrary SHARED ${SOURCES})
elseif()
add_library(MyLibrary STATIC ${SOURCES})
endif()
AFAIK, you cannot do that with generator expressions (no way to query that aspect according to doc), since BUILD_SHARED_LIBS is there for exactly that reason; to allow you to select its value during configuration (using the -D command line option). This will work only if you do not set the library type explicitly as in your code, but like this
add_library(MyLibrary ${SOURCES})
Actually, that is the recommended practice. If you need to influence its value in association with some other condition, you can override it with the usual if()/else() logic, making sure that you print at least an informative message() for the user.
However, an even better approach would be to push those decisions to the user (via options) and check for the illegal combinations, issuing a message(FATAL_ERROR). Even if that condition is determined automatically, this is still a tactic that has merit.
Related
I understand the purpose of object libraries, but why does linking it to a target need to involve a generator expression?
add_library(myObjects OBJECT a.cpp b.cpp)
add_library(mainLib ${other_srcs} $<TARGET_OBJECTS:myObjects>) # Why not "PRIVATE myObjects" just like other files and targets?
From my understanding, generator expressions are useful for evaluating things available only during generation phase. Why would it be the case that object libraries, which are simply collection of object files, and their location not be known during the configuration phase?
In addition to what #Alex Reinking has already said, the location of the object file may itself depend on the configuration, e.g. with the "Ninja Multi-Config" generator the object files of a target t are located in <build-dir>/t/CMakeFiles/t.dir/<config>/<path-of-source-file-relative-to-dir-in-which-target-is-defined>/<src-file-name>.o
So you're exactly in the situation that you only know the location at generation time, hence the need for a generator expression.
add_library(mainLib ${other_srcs} $<TARGET_OBJECTS:myObjects>) # Why not "myObjects" just like other files and targets?
So:
add_library(mainLib ${other_srcs} myObjects)
Because that would try to find a file named myObjects and compile it. The file has no extensions, so cmake will exit because the file does not exists and he doesn't know how to compile it anyway.
If you meant:
add_library(mainLib ${other_srcs})
target_link_libraries(mainLib PUBLIC myObjects)
The link_libraries dependency on object libraries did not work in older cmake when OBJECT libraries were introduced.
The documentation on object libraries explicitly mentions the form add_library(... $<TARGET_OBJECTS:...) and notes that since cmkae 3.12 target_link_libraries may be used with object libraries.
Why would it be the case that object libraries, which are simply collection of object files, and their location not be known during the configuration phase?
Simple: the target_sources command may be used to add sources (and therefore objects) to a target at any point. If a variable were expanded immediately, one would miss objects that were added later.
In multi-config builds, it is also unknown at configuration time whether you refer to the Debug or Release objects.
Imagine that add_library(target a.cpp b.cpp) created a variable named target_OBJECTS containing /path/to/a.o;/path/to/b.o. Then the following sequence demonstrates the problem:
add_library(target a.cpp b.cpp)
add_executable(main main.cpp ${target_OBJECTS}) # (1)
# ... later ...
target_sources(target PRIVATE c.cpp)
# ... later ...
add_executable(utility util.cpp ${target_OBJECTS}) # (2)
Now how would (2) know about /path/to/c.o? You could have target_sources update that variable, but now a single object library has dependents that see different subsets of it. That's horribly confusing. Moreover, (1) wouldn't see c.o, which is maybe what's desired in this example, but that's not always true. Maybe your code is just organized to define custom commands to create generated sources later.
Making this imperative, rather than declarative like $<TARGET_OBJECTS:target>, imposes structure on CMake code akin to requiring targets in a Makefile to be topologically sorted. It also changes the meaning from "the object files for this target" to "the object files for this target at this point in CMake execution time", which is strictly more complicated to reason about while not offering any expressive advantage.
If you replace this code with the CMake 3.12+ object library linking support, it looks even more vexing:
add_library(target a.cpp b.cpp)
add_executable(main main.cpp)
target_link_libraries(main PRIVATE target) # (1)
# ... later ...
target_sources(target PRIVATE c.cpp)
# ... later ...
add_executable(utility util.cpp)
target_link_libraries(utility PRIVATE target) # (2)
Now, looking at either call to target_link_libraries(... target), one would reasonably expect the same objects to be added.
My current attempt at this includes the following:
CHECK_CXX_COMPILER_FLAG("-pedantic" SUPPORTS_PEDANTIC)
if (SUPPORTS_PEDANTIC)
target_compile_options ( some_target PRIVATE -pedantic )
endif()
Is there a function with equivalent functionality, like this?
target_compile_options_if_supported ( some_target PRIVATE -pedantic )
I am wondering if there is already a standard way to do this, other than writing my own function.
As of today with cmake 3.24, nothing in the docs for the CheckCXXCompilerFlag module or the CheckCCompileFlag module docs document that such a function exists. Just write your own. It's simple and short. (Opinion) I don't personally think there's tons of merit for CMake to provide such functions since they'd have to make one for each kind of possible thing you might want to do with the result of the check.
In CMake, assuming one is just setting one property, is there any difference between
set_target_properties(target PROPERTIES prop value)
and
set_property(TARGET target PROPERTY prop value)
?
Cf.
https://cmake.org/cmake/help/v3.0/command/set_property.html
https://cmake.org/cmake/help/v3.0/command/set_target_properties.html
which imply there is no difference but aren't that clear.
Consider set_target_properties() as a specialized form of set_property().
Advantages of ...
set_target_properties(...) is a convenience function because it allows to set multiple properties of multiple targets.
For example:
add_executable(a ...)
add_executable(b ...)
set_target_properties(
a
b
PROPERTIES
LINKER_LANGUAGE CXX
FOLDER "Executable"
)
set_property(TARGET ...) can APPEND to a list- or APPEND_STRING to a string-based property of targets.
For example:
add_executable(a ...)
set_property(
TARGET a
APPEND PROPERTY
INCLUDE_DIRECTORIES "${CMAKE_CURRENT_SOURCE_DIR}"
)
References
How to change the name of the output binary to not be a.out with CMake?
target_include_directories prior to 2.8.12?
Appending compiler flags to a file with CMake
The difference is that with set_property, you get to define the scope. You actually have more options with the set_property other than just specifying a target, such as specifying source files in a list to have a certain property.
For example:
set_property(SOURCE src1.cpp src2.cpp PROPERTY SKIP_AUTOMOC ...)
This will add the SKIP_AUTOMOC property to source files listed. (This is for Qt, where Moc'ing of objects occurs automatically and sometimes you don't want that).
Contrast with set_target_properties where you must specify a Target and the property and it's value.
set_target_properties(target PROPERTIES CXX_STANDARD 11 ...)
Hopefully this helps!
Note that you also have respective set_*_properties functions for some of the other types of properties: set_source_files_properties, set_directory_properties and set_tests_properties. Notably absent are setters for install and global properties.
The reason for that is that these functions predate the general set_property call, which was only introduced with CMake 2.6, together with a general overhaul of the property system to what it is today.
These days, people tend to prefer the generic set_property, as it is the more modern function and provides a few additional features. It also offers a more consistent syntax than the old functions (eg. set_directory_properties not allowing to specify the directory as a parameter, set_source_files vs set_directory, etc.).
There is not a strong technical reason for preferring set_property, but I would consider it slightly better style than using the old, specific functions.
I'm using a cmake find_package script (the exact one probably isn't terribly important, but it's https://raw.githubusercontent.com/snikulov/cmake-modules/master/FindFFmpeg.cmake) that uses a variable:
if (NOT FFmpeg_FIND_COMPONENTS)
set(FFmpeg_FIND_COMPONENTS AVCODEC AVFORMAT AVUTIL)
endif ()
Obviously the intent is that the caller be able to override the list of components to look for, based on the project's requirements.
So I do that from my CMakeLists.txt:
set(FFmpeg_FIND_COMPONENTS AVCODEC AVFORMAT AVUTIL SWRESAMPLE SWSCALE)
find_package(FFmpeg)
But the new value is ignored, and the script behaves as if FFmpeg_FIND_COMPONENTS wasn't customized.
How do I make this work?
Variable <package>_FIND_COMPONENTS is filled with the value of COMPONENTS option of the find_package:
find_package(FFmpeg COMPONENTS AVCODEC AVFORMAT AVUTIL SWRESAMPLE SWSCALE)
See find_package documentation for more details.
I have a CMake setup where the accessibilty of one variable will depend whether another one is set or not. Small snippet:
option(build-compiler "Build the Nap Compiler" ON)
set(include_interrupt_dirs CACHE INTERNAL "interrupts/intr_4" FORCE)
if(build-compiler)
option(enable-runtime-compilation
"Build in the runtime code compilation link in intr_2 & intr_3)" ON)
if(enable-runtime-compilation)
list(APPEND include_interrupt_dirs "interrupts/intr_2" "interrupts/intr_3" )
endif()
endif()
I use cmake-gui for configuring the project, and what I would like to achieve is:
if the user selects the build-compiler the enable-runtime-compilation should also be presented. This part is done.
if the user deselects the build-compiler the enable-runtime-compilation should be hidden from the GUI. This is not working.
Do you have any idea how to make it work?
Using unset(var [CACHE]) is subtly tricky. If you just unset the variable, it will remain in the cache (although it will not be visible to the script, it will still be visible to the user). If you also delete it from the cache, then you lose the value that was there.
In my use case, I wanted to hide variables based on some condition. I found it that deleting the variables from the cache might get confusing as when reinstated, they would return to their default state rather than to what the user might have set before.
I prefer to hide the variables using mark_as_advanced(FORCE var) and unhide using mark_as_advanced(CLEAR var). It does exactly what you need-it hides the variable from the GUI but it still exists in the cache. You might use this together with the "soft" unset (the one without CACHE) to make sure that the hidden variable is not still being used in the configuration.
Additionally, there is CMakeDependentOption which is intended specifically for this use case (an option that is only available if some set of condition evaluates as true). This is apparently available since CMake 3.0.2.
You can use unset(var CACHE) to remove the variable from the cache:
if(build-compiler)
option(enable-runtime-compilation
"Build in the runtime code compilation link in intr_2 & intr_3)" ON)
if(enable-runtime-compilation)
list(APPEND include_interrupt_dirs "interrupts/intr_2" "interrupts/intr_3" )
endif()
else()
unset(enable-runtime-compilation CACHE)
endif()