I have a project with a core library (LibA
in the example below), an executable, and a second library (LibB
) that depends on the first library. The second library (LibB
) is always built in shared (dynamic library) form.
Is there any way that I can force LibB
to always link against the shared version of LibA
?
Here is a small CMakeLists.txt
file illustrating the problem:
cmake_minimum_required(VERSION 3.16)
project(my_project LANGUAGES CXX)
# LibA should be buildable in either static or shared form.
add_library(LibA A.cpp)
# In the real case, there are many customizations to `LibA`:
# compile flags, include dirs, target properties, etc.
add_executable(ExecutableA main.cpp)
target_link_libraries(ExecutableA LibA)
# I want library myB to *always* link against the dynamic library libLibA.so.
add_library(LibB SHARED B.cpp)
target_link_libraries(LibB PUBLIC LibA m pthread)
It can be built with the following commands:
echo 'int main() {}' > main.cpp
touch A.cpp B.cpp
mkdir -p build
cmake -B build/ -S .
cmake --build build/
I know that I can force LibA
to be always shared with add_library(LibA SHARED A.cpp)
, but I want to be able to build LibA
as a static library.
The real context for this is that I have a core library (LibA
), and want to link against it statically when creating executables, but link against it dynamically (as LibA.so
) when creating a Python extension module (LibB.so
).
This is not possible, libA
can only be either static or dynamic, not both.
You need to have two versions of libA
, one dynamic, one static:
cmake_minimum_required(VERSION 3.16)
project(my_project LANGUAGES CXX)
function( addLibA suffix type )
set( libname LibA${suffix} )
add_library(${libname} ${type} A.cpp)
# specify library properties here
endfunction()
# LibA should be buildable in either static or shared form.
addLibA("s" STATIC)
addLibA("" SHARED)
# In the real case, there are many customizations to `LibA`:
# compile flags, include dirs, target properties, etc.
add_executable(ExecutableA main.cpp)
target_link_libraries(ExecutableA LibAs)
# I want library myB to *always* link against the dynamic library libLibA.so.
add_library(LibB SHARED B.cpp)
target_link_libraries(LibB PUBLIC LibA m pthread)
What you are specifically asking for will require multiple targets, as has been mentioned in comments / jpo38's answer
However you might be interested in using CMake's Object Libraries instead to share the objects between a library target and an executable target. For example:
cmake_minimum_required(VERSION 3.16)
project(my_project LANGUAGES CXX)
# Objects get built exactly once
add_library(LibA.objects OBJECTS
A.cpp
)
target_compile_commands( ... )
target_include_directories( ... )
# Shared library for libA
add_library(LibA SHARED
$<OBJECTS:LibA.objects>
)
# LibB -- always shared, always linked against dynamic LibA
add_library(LibB SHARED
B.cpp
)
target_link_libraries(LibB PUBLIC LibA)
# ExecutableA, built using LibA's objects
# (effectively the same linking a static LibA.a)
add_executable(ExecutableA
main.cpp
$<OBJECTS:LibA.objects>
)
Using an object library, your objects get built once, but are shared between multiple targets. Using multiple library targets, on the other hand, will force a rebuild of each object, since each target may use different compile commands.
This allows ExecutableA
to have LibA
's objects built into it, so it behaves effectively as though you had statically linked in a LibA.a
.
In this case, LibA
is now built as a SHARED
library explicitly, since this is desired for LibB
to dynamically link against.
If you're using newer versions of CMake, you can also avoid the $<OBJECTS:...>
generator expression, and just link against the object library directly with target_link_libraries
-- e.g.:
target_link_libraries(libA PRIVATE LibA.objects)
...
target_link_libraries(ExecutableA PRIVATE LibA.objects)
This approach will also allow properties to be applied once to their respective targets. Any properties regarding the sourcefiles themselves just needs to apply directly to the Object library. Any properties regarding the library setup/layout (e.g. output location, suffixes, etc) applies strictly to the library targets.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With