target_link_libraries and add_dependencies - cmake

Is there any use case in which
target_link_libraries(my-lib x y z)
add_dependencies(my-lib x) # this is not just a waste of bytes?
If so, can someone explain what it would be?

In current CMake releases:
After some error checking add_dependencies results in a call to Target->AddUtility(). x is added to the list of utilities for my-lib.
target_link_libraries does not result in a call to AddUtility, but it does add the arguments to the LINK_LIBRARIES target property.
Later, both the content of the LINK_LIBRARIES target property and the list of utilities are used to compute the dependencies of the target in cmComputeTargetDepends.
The list of utilities in a target can not be queried at configure time, and is only used at generate time, so the use of add_dependencies with arguments which are libraries already added with target_link_libraries is redundant.

I don't know what you're particularly interested in...
From a conceptual point of view -- I think you're right. It is a waste of bytes.
From a CMake documentation point of view -- You should prefer make so to guarantee the correct build order.
According to the documentation target_link_libraries, add_dependencies concepts was ideologically split.
Such an idea of split dependencies, and linker options is also persisted in the Makefile format in the GNU make tool.
target_link_libraries
..Specify libraries or flags to use when linking a given target..
add_dependencies
...Make a top-level <target> depend on other top-level targets to ensure
that they build before <target> does...
In modern CMake from 3.* you can omit add_dependencies if you will perform linking with an aliased target:
add_library(fooLib 1.cpp 2.cpp)
add_library(my::fooLib ALIAS fooLib)
...
target_link_libraries(fooBin my::fooLib)

It's used in cases where top-level targets depend on each other. That is, if x is a something that you add to your project (at top-level) with
add_library( x x.c y.c z.c )
you shall tell CMake about it. And you do that with add_dependencies.

Related

How to include target include directories transitive through multiple linked libraries

we are working on an embedded project in C/C++ and currently some special needs appeared. Background is there are two compiled libraries which define the same symbols. The compiler allows to create relocatable output modules (with partial linking) and to hide symbols for other compilation units when linking. This also means the output module does not need to have all the symbols defined, this will be done in the final linking. Compiler used is TI LTS1.3.0. I will link directly to the relocatable-section of the manual: https://software-dl.ti.com/codegen/docs/tiarmclang/rel1_3_0_LTS/compiler_manual/linker_description/04_linker_options/linker-output-options.html#stdz0756429
The other part of the project is hardly built on CMake with static libraries which are linked against each other via target_link_libraries.
To get this working I created an "add_executable"-target for each of those both output modules with the same symbols. To those I pass the static-libraries by CMake and get the linked with target_link_libraries.
But now I have a problem. All contents of the static libraries are compiled in each of those output modules. This is unwanted behaviour since as said the final linking does the job of linking the missing stuff - so the static-libraries - to it. This should be done with another add_executable command via CMake as well.
using the target include directories property is not suitable since it only adds the include directories of the given target itself but not of the target the target will include and link against.
So e.g. if you have (pseudo code):
#library A
function( create_libA )
add_library( libA src/A.c )
target_include_directories( libA PUBLIC /inc ) #contains A.h
endfunction()
#library B. different location
function( create_libB LIBA )
add_library( libB src/B.c )
target_link_libraries( libB PUBLIC ${LIBA} )
target_include_directories( libB PUBLIC /inc ) #contains B.h
endfunction()
#target output module with partial linking. Only should link and compile LIBTOBELINKEDIN, not libB. different location.
function( build_part_module LIBB LIBTOBELINKEDIN )
add_executable( outputModuleA src/func.c ) #func.c does include A.h
#following would cause libA and libB also to be compiled and linked in the output due to transitive stuff as I understood, which is unwanted.
target_link_libraries( outputModuleA PUBLIC ${LIBB} ${LIBTOBELINKEDIN} )
#trying this
get_target_property(libBInc ${LIBB} INTERFACE_INCLUDE_DIRECTORIES)
#will only include B.h but not A.h. compilation will fail.
target_include_directories(outputModuleA /inc ${libBInc})
I did not find any solution in Cmake itself to solve this problem. It's confusing me since all the include-directories must be known when the libraries are passed transitive, which is stated in the documentation. But I understand that getting the target include directories of just the passed lib does not include the other ones.
Since target_link_libraries does also not work this way I can only think of a maybe recursive solution? But for that my knowledge is just non-existent.
target_link_libraries with something like HEADERS_ONLY would be helpfull for this job.
Also one can say: if the output module contains all the definitions it won't be a problem, since the linker then knows them and will do its magic.
But this is also unwanted, since we use the generated static-libraries to place them into sections in different regions of the RAM directly. This would then mean to create another linker-script for partial linking which defines sections which then can be again moved. But the more we go this direction, the less we need CMake for it.
Instead of get_target_property use $<TARGET_PROPERTY> generator expression: the property's value, extracted by that expression, already includes transitive propagation:
target_include_directories(outputModuleA PRIVATE
$<TARGET_PROPERTY:libB,INTERFACE_INCLUDE_DIRECTORIES>
)
Note, that generator expressions has limited usage: not all functions expects them. Documentation for target_include_directories clearly states that the command supports generator expressions.

How can I understand when something is a variable or a value?

Not sure how to perfectly word this from the title, but I am new to CMake and slowly progressing through the online tutorial.
I am up to Step 4 and sometimes find it confusing when mixing passed values that in my eyes are strings, and thus in all programming languages I expect them to have quotation marks or some sort around them. However sometimes I create new targets with the same names. I will elaborate with an example. I reworded some things from the tutorial to make it a bit more clear for me to see what they actually do.
In the root CMakeLists.txt I have this file,
cmake_minimum_required(VERSION 3.10)
project(My_Project VERSION 1.0)
add_library(tutorial_compiler_flags INTERFACE)
target_compile_features(tutorial_compiler_flags INTERFACE cxx_std_11)
option(USE_MYMATH "Use tutorial provided math implementation" TRUE)
configure_file(src/sqrt.h.in src/sqrt.h)
if(USE_MYMATH)
add_subdirectory(MathFunctions)
list(APPEND EXTRA_LIBS MathFunctions)
endif()
add_executable(compute_square_root src/sqrt.cxx)
target_link_libraries(compute_square_root PUBLIC ${EXTRA_LIBS} tutorial_compiler_flags)
target_include_directories(compute_square_root PUBLIC "${PROJECT_BINARY_DIR}/src")
Inside of MathFunctions I have
add_library(MathFunctions mysqrt.cxx)
target_include_directories(MathFunctions INTERFACE ${CMAKE_CURRENT_SOURCE_DIR})
Here is where the confusion can come from. Notice that in
add_subdirectory(MathFunctions)
MathFunctions is kind of treated as a string in my eyes, because it is now looking for the directory current_location/MathFunctions. However inside of of the MathFunctions CMakeLists.txt it now creates a target with the exact same spelling from the line "add_library(MathFunctions mysqrt.cxx)", this is then immediately referenced afterwards from the "target_include_directories(MathFunctions, ...".
Here, target_include_directories is referring to the target MathFunctions we just created. Now, when we leave that CMakeLists.txt we now have another line "list(APPEND EXTRA_LIBS MathFunctions)". Now I some confusion, like, is this MathFunctions referring to the target we just made? Is it a string called "MathFunctions"? In the documentation for target_link_libraries it says that it has to be a target created by add_library so I assume it is referring to the previous add_library(MathFunctions ...) call. I find the scoping weird here too, since we are referring to something that was made from a child, inside a different call.
Do we have certain rules in CMake for this kind of behaviour? THanks
All command parameters are treated as strings in cmake. Parameters are separated by whitespace unless quoted. The exact effect of a parameter depends on the command.
The following commands have the same effect:
add_subdirectory(MathFunctions)
add_subdirectory("MathFunctions")
In the case of add_library the first parameter is treated as the target name. CMake internally keeps track of targets and stores several pieces of information for them. The target name MathFunctions is entirely unrelated to the name of the subdirectory added via add_subdirectory; you could rename the directory to FooBar and use add_subdirectory(FooBar) and nothing would change.
There are several commands you pass the target name to to modify the properties of the cmake target as well as commands that treat the name of cmake targets specially e.g.:
target_include_directories: the target to modify the [INTERFACE_]INCLUDE_DIRECTORIES property for is passed
target_link_directories: the target to modify the [INTERFACE_]LINK_DIRECTORIES property for is passed
set_target_properties: One or more targets to set properties for are passed
target_link_libraries: The cmake target linked to is passed. Furthermore cmake library targets may be specified as libraries to be linked to the target.
add_test: If you use the name of a cmake target in the COMMAND part, the test logic uses the path to the target instead.
...
As for scope:
Variable values you write are actually set for the current scope only, but reading variables cmake looks into ancestor scopes, unless a variable is found in the current scope. CMake targets are visible in the whole cmake project though from the point of the parsing of the command creating the target(add_library, add_executable, add_custom_target): cmake targets are "global objects". (Exceptions exist for imported libs and alias targets, but that's probably nothing relevant to you right now.)

Remove library added with link_libraries()

How do I remove libraries added with link_libraries()?
Yes, I know I should use target_link_libraries(). I can`t because I must link a library to every future target. See this. The library is CMake built.
This should be invisible to the C++/CMake developer. He should not have to worry about this lib.
Example:
add_library(link-to-all a.cpp)
link_libraries(link-to-all)
add_executable(e1 e1.cpp) # with link-to-all
add_executable(e2 e2.cpp) # with link-to-all
unlink_libraries(link-to-all) #does not exist!
add_executable(e3 e3.cpp) # without link-to-all
# all further targets link without link-to-all!
In my case link-to-all is a library with implementation for coverage checking functions. It is enabled depending on a configuration option and should be implicitly used for all coming targets. Coverage analysis may be disabled for specific targets, so I want to be able to disable it.
The coverage is enabled by prepending CMAKE_<LANG>_COMPILE_OBJECT and disabled by removing the prefix. Afaik this cannot be done target specific, only global for coming targets. So unlink_libraries() would be a function that i can call symmetrically.
function(enable_coverage)
prepend_compiler();
link_libraries(cov);
# alternative with loosing target information/dependency
# prepend_system_libs(<path>/libcov.a)
endfunction()
function(disable_coverage)
reset_compiler();
unlink_libraries(cov);
# reset_system_libs()
endfunction()
I could use CMAKE_<LANG>_STANDARD_LIBRARIES, (and also remove it there) but I would need the LOCATION of the library (generator expression: TARGET) in there. But I would also lose the interfaces of link-to-all. Also, that would probably remove the build dependencies.
While I agree with #Guillaume, I'll combine the suggestions into an answer, as the linked answer is not very clear. As #Tsyvarev confirmed in the CMake source, the link_libraries() call sets the LINK_LIBRARIES target property; the target_link_libraries() call does the same. While your executable e3 will initially be set to link with all libraries, you can remove one (or multiple) libraries from the list using a combination of get_target_property() and set_property(). Here is an example to demonstrate how:
# Library to be linked to all targets.
add_library(link-to-all a.cpp)
# Library to be linked to (almost) all targets.
add_library(link-to-almost-all b.cpp)
link_libraries(link-to-all link-to-almost-all)
# Gets our link-everywhere libraries. Oops!
add_executable(e3 test.cpp)
# Get the LINK_LIBRARIES property for this target.
get_target_property(E3_LINKED_LIBS e3 LINK_LIBRARIES)
message("Libraries linked to e3: ${E3_LINKED_LIBS}")
# Remove one item from the list, and overwrite the previous LINK_LIBRARIES property for e3.
list(REMOVE_ITEM E3_LINKED_LIBS link-to-almost-all)
set_property(TARGET e3 PROPERTY LINK_LIBRARIES ${E3_LINKED_LIBS})
# Verify only one library is now linked.
get_target_property(E3_LINKED_LIBS_NEW e3 LINK_LIBRARIES)
message("Libraries linked to e3: ${E3_LINKED_LIBS_NEW}")
The messages printed here confirm the library was removed from the LINK_LIBRARIES target property for e3:
Libraries linked to e3: link-to-all;link-to-almost-all
Libraries linked to e3: link-to-all
As an additonal answer I repeat what I commented on squarekittles answer (for future reference):
You should use the target property <LANG>_COMPILER_LAUNCHER instead of CMAKE_<LANG>_COMPILE_OBJECT. It can be set on target base.

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