I am a bit late in the game of "modern cmake" and trying to catch up. One question after reading target centric paradigm is how to share properties (include, compile options, definitions etc) across multiple targets?
More specifically, my project simply involves a few libraries and multiple executables as targets. They pretty much share the same includes, language features etc. Do I need to repeat it for every target? or just one target is enough for the rest? or any other alternative ways? TIA.
If there are dependencies between targets, then target_include_libraries and other target_ commands will take care of propagating the properties if you use the PUBLIC visibility:
add_library(foo ...)
target_include_directories(foo PUBLIC foo_includes)
add_executable(bar ...)
# foo_includes propagate to bar.
target_link_libraries(bar foo)
If there is no dependency relationship between the targets you can share option via CMake variables:
set(my_includes ...)
add_library(foo ...)
target_include_directories(foo PUBLIC ${my_includes})
add_library(bar ...)
target_include_directories(bar PUBLIC ${my_includes})
Related
I am trying to link foo-lib library into another target bar-lib however doing the following results in an error.
(add_executable):
Cannot find source file: foo-lib
How can I create an executable out of a library and the same library can be linked into another target?
add_library(foo-lib STATIC src/foo.cpp)
add_executable(foo-ut foo-lib)
target_include_directories(foo-ut PRIVATE include)
target_link_libraries(foo-ut PUBLIC lib1 lib2)
# second library that links foo-lib
add_library(bar-lib STATIC src/bar.cpp)
add_executable(bar-ut bar-lib)
target_include_directories(bar-ut PRIVATE include)
target_link_libraries(bar-ut PUBLIC foo-lib)
This worked the way I wanted but I am not sure if I should be adding foo.cpp for the bar-ut target
add_executable(bar-ut src/foo.cpp src/bar.cpp)
I'm not going to question the design choices and what you need it for and if it is a good idea in any way. I will just provide you with a "scalable" way of doing this.
As the others pointed out add_executable() requires source files.
Now assuming that the source files that you use to create a static library contain a main() function. Then you can create (out of the same source files) an executable, by passing to the add_executable the same source files as you would to add_library.
As the program grows these would get lengthy, so what you should do is something that is no longer recommended by "CMake best practices" and that is to introduce a SOURCES variable. I.e.:
set(PROJECT_SOURCES source1.cpp source2.cpp source3.cpp)
set(PROJECT_HEADERS header1.h header2.h header3.h)
add_library(foo-lib STATIC ${PROJECT_SOURCES} ${PROJECT_HEADERS})
add_executable(foo-ut ${PROJECT_SOURCES} ${PROJECT_HEADERS}
As your program grows you would just add the respective files into the designated variables. Now as to possible improvements:
fabian mentioned a very good thing which is OBJECT libraries, since you are rebuilding the same files for both the executable and library you could just create an object library and link it. This would make it twice as fast (you only need to compile once).
Since these SOURCES are already once passed to some target, you could just get them from the target's properties via get_target_properties(MY_SOURCES foo-lib SOURCES) this would give you a variable MY_SOURCES that contains sources which are used by the target library.
So I'm building a library, it's basically same code base, but I need to build it twice, the only difference is the second show compile with a -D option, and they need to produce two different artifact. Currently I have this:
add_library(foo STATIC sources...)
add_library(foo.ex STATIC sources...)
target_compile_definitions(foo.ex PUBLIC FOO)
Is this the best way? Is there any other better ways to do?
Is this the best way? Is there any other better ways to do?
Yes, I think this is the best way. I would only refactor and places sources in a common variable so they are not repeated:
set(sources sources...)
add_library(foo STATIC ${sources})
add_library(foo.ex STATIC ${sources})
target_compile_definitions(foo.ex PUBLIC FOO)
I am bit confused about linking libraries when our target is a static library.
For instance, for an executable it will help linker resolve undefined symbols. But, incase of a static libraries, why would it link at this stage?
Won't linking be done when I will link some executable against libstatic?
Thanks.
In CMake,
target_link_libraries(targetName PUBLIC lib1 lib2)
affects to the linker's argument in two scenarios:
PRIVATE: when the linker is called for the for the executable/library, corresponded to the target targetName.
INTERFACE: when the linker is called for the other executable/library otherTargetName, which is linked with targetName via
target_link_libraries(otherTargetName PUBLIC targetName)
This is known as transitive property of the linking libraries.
You are right that the linker is not called for the static libraries, so in that case the first scenario is eliminated.
But the second scenario remains: When you create the executable (or other shared library) and call
target_link_libraries(otherTargetName PUBLIC libStatic)
then CMake automatically links that executable(or shared library) with everything, to which libStatic is "linked" with target_link_libraries.
Such automation helps in structuring the project:
By calling
target_link_libraries(libStatic PUBLIC lib1 lib2)
you state, that libStatic uses functions defined in lib1 and lib2
By calling
target_link_libraries(otherTargetName PUBLIC libStatic)
you state, that executable/library otherTargetName uses functions from libStatic.
At this stage you don't care about internals of libStatic, whether it is self-contained or depends from some other libraries: CMake will care about this for you.
Note on using PUBLIC keyword in target_link_libraries: while in some cases this is equivalent to omitting the keyword, a modern CMake way is to specify keywords explicitly. See also policy CMP0023.
Other possible keywords are PRIVATE and INTERFACE, each of them selects only a single scenario described above.
Note that transitive linking property is a pure CMake feature and works only when linking to a target. The library file (.a or .lib) itself doesn't contain information about dependent libraries, so linking with a file doesn't trigger transitive linking.
A somewhat similar question was asked here, Transitive target_include_directories on OBJECT libraries, but there was no real solution.
If I have a project b that depends on a project a I can build them as follows
add_library(a OBJECT ${a_srcs})
add_library(b OBJECT ${b_srcs})
When I want to build an excutable using I them I can write
add_executable(p ${p_srcs} $<TARGET_OBJECTS:b> $<TARGET_OBJECTS:a>)
Is there any way to not have to specify $<TARGET_OBJECTS:a>? I assume this means telling CMake in some way that there is a dependency. If I was building SHARED libraries rather than OBJECT ones the b project would contain
target_link_libraries(b a)
which creates this dependency, but I can't find some equivalent way for OBJECT libraries.
Insofar as I understand it, in the current setup, no. The add_executable for target p can either
Link against some library (shared or static), or
Merge object sources into itself.
You have chosen (2). The only other option I see here is create a third library c that merges in a and b into a full-blown library (see Usage section at the bottom, which is likely where you were already looking).
When you do that, you could then target_link_libraries(c). The compiled OBJECTs cannot be linked against on their own. You have to merge the sources into either an executable or a library for them to be used.
Your add_executable call could be thought of basically doing add_executable(p ${p_srcs} ${a_srcs} ${b_srcs}), only instead of compiling a_srcs and b_srcs (which has been done previously), just copy in the compiled objects instead of redoing the work. That's a really simple / bad explanation, but that's the general idea.
The best way I have found to do this is to wrap the OBJECT library in an INTERFACE library.
add_library(a-objects OBJECT ${a_srcs})
add_library(b-objects OBJECT ${b_srcs})
add_library(a INTERFACE)
add_library(b INTERFACE)
target_link_libraries(a INTERFACE a-objects)
target_link_libraries(b INTERFACE b-objects)
target_sources(a INTERFACE $<TARGET_OBJECTS:a-objects>)
target_sources(b INTERFACE $<TARGET_OBJECTS:b-objects>)
My rule is to use the OBJECT library to set requirements, but only ever link against the INTERFACE library.
target_link_libraries(b-objects INTERFACE a)
Setting it up this way should allow you to link against both libraries like this:
add_executable(p ${p_srcs})
target_link_libraries(p PRIVATE b)
There are multiple mechanisms offered by CMake for getting flags to the compiler:
CMAKE_<LANG>_FLAGS_<CONFIG> variables
add_compile_options command
set_target_properties command
Is there one method that is preferred over the other in modern use? If so why? Also, how can this method be used with multiple configuration systems such as MSVC?
For modern CMake (versions 2.8.12 and up) you should use target_compile_options, which uses target properties internally.
CMAKE_<LANG>_FLAGS is a global variable and the most error-prone to use. It also does not support generator expressions, which can come in very handy.
add_compile_options is based on directory properties, which is fine in some situations, but usually not the most natural way to specify options.
target_compile_options works on a per-target basis (through setting the COMPILE_OPTIONS and INTERFACE_COMPILE_OPTIONS target properties), which usually results in the cleanest CMake code, as the compile options for a source file are determined by which project the file belongs to (rather than which directory it is placed in on the hard disk). This has the additional advantage that it automatically takes care of passing options on to dependent targets if requested.
Even though they are little bit more verbose, the per-target commands allow a reasonably fine-grained control over the different build options and (in my personal experience) are the least likely to cause headaches in the long run.
In theory, you could also set the respective properties directly using set_target_properties, but target_compile_options is usually more readable.
For example, to set the compile options of a target foo based on the configuration using generator expressions you could write:
target_compile_options(foo PUBLIC "$<$<CONFIG:DEBUG>:${MY_DEBUG_OPTIONS}>")
target_compile_options(foo PUBLIC "$<$<CONFIG:RELEASE>:${MY_RELEASE_OPTIONS}>")
The PUBLIC, PRIVATE, and INTERFACE keywords define the scope of the options. E.g., if we link foo into bar with target_link_libraries(bar foo):
PRIVATE options will only be applied to the target itself (foo) and not to other libraries (consumers) linking against it.
INTERFACE options will only be applied to the consuming target bar
PUBLIC options will be applied to both, the original target foo and the consuming target bar