CMake 2.6 Notes
This page documents some of the changes and new features available in CMake 2.6.
Exporting and Importing Targets
To be written...
Preprocessor Definitions
Preprocessor definitions may now be added to builds with much finer granularity than in previous versions of CMake. There is a new property called COMPILE_DEFINITIONS
that is defined directories, targets, and source files. For example, the code
add_library(mylib src1.c src2.c) add_executable(myexe main1.c)
set_property( DIRECTORY PROPERTY COMPILE_DEFINITIONS A AV=1 ) set_property( TARGET mylib PROPERTY COMPILE_DEFINITIONS B BV=2 ) set_property( SOURCE src1.c PROPERTY COMPILE_DEFINITIONS C CV=3 )
will build the source files with these definitions:
src1.c: -DA -DAV=1 -DB -DBV=2 -DC -DCV=3 src2.c: -DA -DAV=1 -DB -DBV=2 main2.c: -DA -DAV=1
When the add_definitions
command is called with flags like "-DX
" the definitions are extracted and added to the current directory's COMPILE_DEFINITIONS
property. When a new subdirectory is created with add_subdirectory
the current state of the directory-level property is used to initialize the same property in the subdirectory.
Note in the above example that the set_property
command will actually set the property and replace any existing value. The command provides the APPEND
option to help add more definitions without removing existing ones. For example, the code
set_property( SOURCE src1.c APPEND PROPERTY COMPILE_DEFINITIONS D DV=4 )
will add the definitions "-DD -DDV=4
" when building src1.c
.
Definitions may also be added on a per-configuration basis using the COMPILE_DEFINITIONS_<CONFIG>
property. For example, the code
set_property( TARGET mylib PROPERTY COMPILE_DEFINITIONS_DEBUG MYLIB_DEBUG_MODE )
will build sources in mylib with -DMYLIB_DEBUG_MODE
only when compiling in a Debug
configuration.
Link Line Generation
CMake 2.6 implements a new approach to generating link lines for targets.
Consider these libraries:
/path/to/libfoo.a /path/to/libfoo.so
Previously if someone wrote
target_link_libraries(myexe /path/to/libfoo.a)
CMake would generate this code to link it:
... -L/path/to -Wl,-Bstatic -lfoo -Wl,-Bdynamic ...
This worked most of the time, but some platforms (such as OS X) do not
support the -Bstatic
or equivalent flag. This made it impossible to
link to the static version of a library without creating a symlink in
another directory and using that one instead.
Now CMake will generate this code:
... /path/to/libfoo.a ...
This guarantees that the correct library is chosen. However there are some side-effects.
Missing Linker Search Directories
Projects used to be able to write this (wrong) code and it would work by accident:
add_executable(myexe myexe.c) target_link_libraries(myexe /path/to/libA.so B)
where "B
" is meant to link "/path/to/libB.so
". This code is incorrect
because it asks CMake to link to B
but does not provide the proper
linker search path for it. It used to work by accident because the
-L/path/to
would get added as part of the implementation of linking to
A. The correct code would be
link_directories(/path/to) add_executable(myexe myexe.c) target_link_libraries(myexe /path/to/libA.so B)
or even better
add_executable(myexe myexe.c) target_link_libraries(myexe /path/to/libA.so /path/to/libB.so)
In order to support projects that have this bug, we've added a
compatibility feature that adds the "-L/path/to
" paths for all libraries
linked with full paths even though the linker will not need those paths
to find the main libraries. The compatibility mode is enabled when a
link line contains a non-full-path library (like B
) and either
CMAKE_BACKWARDS_COMPATIBILITY
is set to 2.4 or lower or
CMAKE_LINK_OLD_PATHS
is set to true.
If you are trying to build a project and run into this problem, a quick-fix is to run
cmake -DCMAKE_LINK_OLD_PATHS:BOOL=ON .
in the top of the build tree.
Linking to System Libraries
System libraries on UNIX-like systems are typically provided in /usr/lib
or /lib
. These directories are considered implicit linker search paths because linkers automatically search these locations even without a flag like -L/usr/lib
. Consider the code
find_library(M_LIB m) target_link_libraries(myexe ${M_LIB})
Typically the find_library
command would find the math library
/usr/lib/libm.so
In CMake 2.4 and lower this value would be assigned directly to M_LIB
. Then the link line generation would split off the link directory /usr/lib
and the library libm.so
and produce the
... -lm ...
Note that the -L/usr/lib
option is left out because it is an implicit linker search path. The linker would see -lm
and search for the math library. Typically the linker would find /usr/lib/libm.so too. However some platforms provide multiple versions of libraries correesponding to different architectures. For example, on an IRIX machine one might find the libraries
/usr/lib/libm.so (ELF o32) /usr/lib32/libm.so (ELF n32) /usr/lib64/libm.so (ELF 64)
On a Solaris machine one might find
/usr/lib/libm.so (sparcv8 architecture) /usr/lib/sparcv9/libm.so (sparcv9 architecture)
When the linker sees -lm
it in fact searches the system path corresponding to the current architecture. Internally it might use -L/usr/lib/sparcv9
instead of -L/usr/lib
.
In CMake 2.6 the code
target_link_libraries(myexe /usr/lib/libm.so)
would generate the link line
... /usr/lib/libm.so ...
no matter what architecture is getting linked. This might cause the linker to complain if /usr/lib/libm.so
does not match the architecture it wants. This is not a problem with the link line computation. CMake is linking myexe
to the library to which it was told to link.
The problem is created because find_library
may not know about all the architecture-specific system search paths used by the linker. In fact when it finds /usr/lib/libm.so
it may be finding a library of incorrect architecture. The solution is for the command to recognize that when it finds a library in a system search path that it should ask the linker to find the correct version of the library at link time. Consider the original example:
find_library(M_LIB m) target_link_libraries(myexe ${M_LIB})
In CMake 2.6 the find_library
command will set M_LIB
to contain just "libm.so
" when it finds /usr/lib/libm.so
. The link command will then be
target_link_libraries(myexe libm.so)
which will be converted to the link command line
... -lm ...
and the linker will locate the correct version of the library. If find_library
does not find the library in an implicit link directory it will report the full path as usual. The user might also edit the cache to set M_LIB
to a full path. In both cases the full path given to target_link_libraries will be preserved on the final link line.