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

Brad King brad.king at kitware.com
Mon Apr 9 13:41:16 EDT 2012


On 4/5/2012 10:30 PM, Christoph Anton Mitterer wrote:
>> 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.
>
> And you think this is not feasible?

I'm not commenting either way.  I'm just saying that is what may
need to be done to address your concerns.

> Ok but this alone is just helpful to get the "right" library, right?
> And has nothing to do on whether I can selectively specify how it is linked?

How it is linked depends on the file type at the given full path.
If it is an archive it will be linked statically and if it is a
shared library it will be linked dynamically.  Options like -Bstatic
only tell the linker to prefer "libX.a" when searching for "-lX".
If the full path is already known it is meaningless.

> So basically link_directories() == deprecated...

I wouldn't say "deprecated" because it is still useful to some people.
There are just better ways to do things most of the time.

>> 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.
>
> Is this a general thing? Or just working when link_directories() was used?
> I mean that depending on the filename, It automatically chooses per-library
> static or dynamic linking.

The latter.  As discussed below this entire concept is not portable.

> Nevertheless, if I have to specify the full name, e.g. libXXX.a, then I'm
> already leaving portability, right?

On Windows there is no way to tell if a library is static or shared
from just the file name.  Linkers do not use "foo.dll".  They use a
corresponding "import library" called "foo.lib".  It is possible for
"foo.lib" to be either an import library for foo.dll *or* its own
static library.  There is no way to tell without parsing the binary
format.  Also Windows toolchains have no equivalent to -Bstatic so
it does not make sense to "request" static or dynamic linking.  One
must always specify the full path to a given library file to get it.

> So far I always tried to avoid find_library (for no real special reason)... see my other reply on the cmake user list, where I ask for how things are done right (e.g. the pkg.config thingy)... so what's "THE" way?
> Did I get this right, find_library, gives me the full path, e.g. /path/to/libXXX.so ... including the platform specific lib and .so, while I just specify XXX on the search command

Use find_library to locate a library file.  Then pass the result to
target_link_libraries.  Since find_library stores the result in a
user-editable persistent cache users can always specify an exact
library file to use as the result of find_library.  The user can
choose a .a or .so to get the linking type desired.

>> (3) Use find_package to locate a package configuration file of a
>> CMake-aware project. It should make its libraries available as
    ^^^^^^^^^^^^^^^^^^^
> You mean this one? http://www.cmake.org/Wiki/CMake/Tutorials/Exporting_and_Importing_Targets

Yes, and if XXX is a CMake-aware project then there is no need for
a FindXXX.cmake module if it provides a XXXConfig.cmake in its
installation.  Option (3) won't work for libraries provided by
projects that are not CMake-aware.  It works very well otherwise.

> Also, I'm not sure whether I fully understand the ideas here...
> for me a target is something that I build in my project...
> but I never build the external libarary...

That's why they're called "imported" targets.  They are imported
from an outside source so they can be referenced as if they had
been built inside (from say target_link_libraries).

>> CMake will link imported libraries using the full path to the file
>> on disk just as it does for libraries built within the project.
>
> How does it know against which targets it should link the imported targets.

Imported targets are not themselves linked to form new files.  Their
existing files loaded from outside the project can be linked into other
targets that are built inside the project.  Transitive dependencies and
such are specified in target IMPORTED_* properties.

>> 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.
>
> Uhm how/why do you mix up approaches 2 and 3 now?

If an external library did not come with any CMake package configuration
file that define it as an imported library then the only option is to
use find_library to locate it.  After that an application can create its
own imported target and specify the find_library result as the location.
If it passes the imported target name to target_link_libraries then CMake
will use that to get the location and always link by full path instead
of doing the -L -l split.

>> In all cases it is better to specify the library by full path to
>> its file.
> So the compiler, at least gcc as far as I can see, doesn't behave differently (with respect to the generated code) between full path or -lXXX -L/path, right?

There is no difference in the resulting binary.  The main difference is
in how the library file is located.  Full path is very reliable.

> Well I still don't see how I can do this fully portable

As explained above Windows (MS-style tools) do not distinguish static
v. shared using the library file name in any way.  One *must* choose
the desired library file and specify it by full path.  IOW the entire
concept of asking a tool to "search for a shared lib" or "search for
a static lib" is not portable.  Instead CMake projects should just use
find_library so that a user can specify the desired library file if
the one found automatically is not preferred.

>> What is missing is the specification for base (language runtime) libs.
> You mean that find_library understands the architecture specific part for implict libs?

No.  We don't use find_library at all for the base libs.  The link lines
CMake generates drive the linker through the compiler front-end.  That
frond-end handles passing of base libs to the linker.

-Brad


More information about the cmake-developers mailing list