Build twice same library - cmake

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)

Related

Creating a executable out of a library in CMake, and linking the library in another library

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.

Include one target's include directories in another target

How can I include target1's include directories (made by target_include_directories(target1 t1/include)) into target2?
I know only one way, which is to create a variable and set() include directories in it, and then reuse the variable for another target. But this looks too non-flexible, and I think CMake must have an much easier way.
My targets are shared libraries.
"$<TARGET_PROPERTY:TargetName,INTERFACE_INCLUDE_DIRECTORIES>"
is what I looked for
using like that:
target_include_directories(MyTarget
PRIVATE
"$<TARGET_PROPERTY:OtherTarget,INTERFACE_INCLUDE_DIRECTORIES>"
)
it allows me to include PUBLIC and INTERFACE include directories of target OtherTarget into MyTarget

What is a way to simplify linking multiple libraries in CMake?

I'm new to CMake and trying to learn to use it for a simple project. If I have a CMakeLists.txt file that looks like this:
add_executable(alpha alpha.cpp)
add_executable(beta beta.cpp)
add_library(one STATIC one.cpp)
add_library(two STATIC two.cpp)
target_link_libraries(alpha one)
target_link_libraries(alpha two)
target_link_libraries(beta one)
target_link_libraries(beta two)
Is there a way to simplify this sort of pattern? What I would like is to define something like all_libraries that contains both one and two, and then only have to do one linking per binary. Is there a way to do it?
You can use interface libraries:
add_library(all_libraries INTERFACE)
target_link_libraries(all_libraries
INTERFACE
one
two
)
... then later ...
target_link_libaries(alpha PUBLIC all_libraries)
You can use variable:
set(all_libraries one two)
.. then later ..
target_link_libraries(alpha PUBLIC ${all_libraries})
Notes:
I would advise to always explicit specify the the PUBLIC, PRIVATE and INTERFACE keywords.
I would go with interface libraries. It's nice to have a big project, expose different mix of libraries as a single interface library, than you only link another big project against that interface. Gives nice control and look of it.

How to share properties across multiple targets in CMake?

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})

"Linking" my static lib with a third-party static lib

I'm writing a CMake script that makes a static library MyLib. I'd like to concatenate it with a 3rd party static library AnotherLib. I try to accomplish this as follows:
"Deconstruct" AnotherLib to object files by invoking ar as a part of ADD_CUSTOM_COMMAND.
Prepare an intermediate MyLibObj using ADD_LIBRARY(MyLibObj OBJECT ${MYLIB_SOURCES})
Make the final MyLib using (1) and (2) -- here is the problem. How to do this? Is it possible to make CMake treat the object files made in (1) as OBJECT library?
This CMake script merges several static libraries - but in a straightforward way, without the new OBJECT feature. It's a part of MERGE_STATIC_LIBS macro referenced in this answer.