Issue
Let's consider Debian or Ubuntu distro where one can install some library package, say libfoobar
, and a corresponding libfoobar-dev
. The first one contains shared library object. The later usually contains headers, static library variant and cmake exported targets (say, FoobarTargets.cmake
) which allow CMake stuff like find_package
to work flawlessly. To do so FoobarTargets.cmake
have to contain both targets: for static and for shared variant.
From the other side, I've read many articles stating that I (as a libfoobar's author) should refrain from declaring add_library(foobar SHARED ....)
and add_library(foobar_static STATIC ...)
in CMakeLists.txt
in favour of building and installing library using BUILD_SHARED_LIBS=ON
and BUILD_SHARED_LIBS=OFF
. But this approach will export only one variant of the library into FoobarTargets.cmake
because the later build will overwrite the first one.
So, the question is: how to do it the right way? So that package maintainer would not need to patch library's CMakeLists.txt
to properly export both variants from the one side. And to adhere CMake's sense of a true way, removing duplicating targets which differ only by static/shared from the other side?
Solution
I wrote an entire blog post about this. A working example is available on GitHub.
The basic idea is that you need to write your FoobarConfig.cmake
file in such a way that it loads one of FoobarSharedTargets.cmake
or FoobarStaticTargets.cmake
in a principled, user-controllable way, that's also tolerant to only one or the other being present. I advocate for the following strategy:
- If the
find_package
call lists exactly one ofstatic
orshared
among the required components, then load the corresponding set of targets. - If the variable
Foobar_SHARED_LIBS
is defined, then load the corresponding set of targets. - Otherwise, honor the setting of
BUILD_SHARED_LIBS
for consistency with FetchContent users.
In all cases, your users will link to Foobar::Foobar
.
Ultimately, you cannot have both static and shared imported in the same subdirectory while also providing a consistent build-tree (FetchContent) and install-tree (find-package) interface. But this is not a big deal since usually consumers want only one or the other, and it's totally illegal to link both to a single target.
Answered By - Alex Reinking Answer Checked By - Dawn Plyler (WPSolving Volunteer)