[cmake-developers] portable way for linking (single) libraries statically or dynamically

Brad King brad.king at kitware.com
Wed Apr 4 09:10:00 EDT 2012


On 4/3/2012 9:41 PM, Christoph Anton Mitterer wrote:
> I'd like if CMake was more abstract and frees me from fiddling around
> with compiler/platform specific stuff in many cases.

CMake does this for several things but as you mentioned there are many
abstractions, or "feature to flag maps", that are not available.

> One (and which I consider very basic) for which this is missing is the
> selection whether single libraries (including the basic ones, libc,
> libstd++, the loader) are linked statically or dynamically.

This would need to be done in two pieces.  The first piece is the
language runtime libraries.  CMake uses the compiler front-end to
invoke the linker so language runtime libraries are implicitly linked.
Special flags to tell the compiler which runtime library to use would
need to be mapped for each toolchain.

The second piece is user-specified libraries:

> A syntactical way to do (at least for the non base libs) this was
> perhaps something like:
> target_link_library(target<[STATIC|DYNAMIC] lib+>* )
> If STATIC DYNAMIC is omitted, the compiler default (typically dynamical)
> or another global CMake default is used.

Keyword options should not be necessary.  The current optimized/debug
keywords (lower-case for ancient historical reasons) are not even
necessary anymore if one uses imported targets.  See below.

For libraries built in the current project CMake always links using
the full path to the library file on disk.  This ensures that the
desired library will be used.  Libraries outside the project can be
brought in in three ways:

(1) Specify link_directories() and pass to target_link_libraries just
name the library "x".  CMake will generate a link line with "-lx" (or
the equivalent to -l for the toolchain in use) and let the linker
search for the library.  This is discouraged as it is difficult to
control which library will be found.  One may also specify a library
file name like "libx.a" and CMake will recognize that it looks like
a static library and generate "-Wl,-Bstatic -lx" (or the equivalent
for the toolchain) to tell the linker to look for a static library.

(2) Use find_library() to locate the full path to a desired library.
This will report the location in a variable which can be referenced
in the target_link_libraries call.  If the library is NOT in an
implicit link directory (like /usr/lib) then CMake will use the full
path to the library file on the link line to guarantee it is used.

Unfortunately we currently convert libraries in implicit directories
(like /usr/lib) to the "-lx" form because some toolchains substitute
per-architecture alternatives under the hood so "/usr/lib/libx.a"
actually needs to be "/usr/lib/$arch/libx.a".  However, find_library
does not know to prefer the latter because it can't parse the binary
format on every platform to detect libraries of proper architecture.
Since that was implemented CMake has been enhanced to detect the
implicit link directories for the toolchain/arch but find_library
has not been taught to use the results.

(3) Use find_package to locate a package configuration file of a
CMake-aware project.  It should make its libraries available as
IMPORTED targets whose library types and full paths are known:

  http://www.cmake.org/Wiki/CMake/Tutorials#CMake_Packages

CMake will link imported libraries using the full path to the file
on disk just as it does for libraries built within the project.

A project using approach #2 can tell CMake to link a library using
the full path even if it is in an implicit link directory by using
the library through an imported target.  This allows one to force
use of a specific library file.

In all cases it is better to specify the library by full path to
its file.  This is particularly important on platforms where the
library file name cannot be used to distinguish shared from static
and the toolchain has no equivalent to -Bstatic/-Bdynamic.

The conclusion is that target_link_libraries can already be used
to force linking to a specific library as shared or static.  What
is missing is the specification for base (language runtime) libs.

-Brad



More information about the cmake-developers mailing list