CMake 2.6 Notes: Difference between revisions

From KitwarePublic
Jump to navigationJump to search
Line 29: Line 29:
   ... /path/to/libfoo.a ...
   ... /path/to/libfoo.a ...


This guarantees that the correct library is chosen.
This guarantees that the correct library is chosen.  However there are some side-effects.


There is a side-effect of this fix.  Projects used to be able to write  
==Missing Linker Search Directories==
this (wrong) code and it would work by accident:
 
Projects used to be able to write this (wrong) code and it would work by accident:


   add_executable(myexe myexe.c)
   add_executable(myexe myexe.c)
Line 65: Line 66:


in the top of the build tree.
in the top of the build tree.
==Linking to System Libraries==
System libraries on UNIX-like systems are typically provided in <code>/usr/lib</code> or <code>/lib</code>.  These directories are considered implicit linker search paths because linkers automatically search these locations even without a flag like <code>-L/usr/lib</code>.  Consider the code
  find_library(M_LIB m)
  target_link_libraries(myexe ${M_LIB})
Typically the <code>find_library</code> command would find the math library
  /usr/lib/libm.so
In CMake 2.4 and lower this value would be assigned directly to <code>M_LIB</code>.  Then the link line generation would split off the link directory <code>/usr/lib</code> and the library <code>libm.so</code> and produce the
  ... -lm ...
Note that the <code>-L/usr/lib</code> option is left out because it is an implicit linker search path.  The linker would see <code>-lm</code> 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 <code>-lm</code> it in fact searches the system path corresponding to the current architecture.  Internally it might use <code>-L/usr/lib/sparcv9</code> instead of <code>-L/usr/lib</code>.
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 <code>/usr/lib/libm.so</code> does not match the architecture it wants.  This is not a problem with the link line computation.  CMake is linking <code>myexe</code> to the library to which it was told to link.
The problem is created because <code>find_library</code> may not know about all the architecture-specific system search paths used by the linker.  In fact when it finds <code>/usr/lib/libm.so</code> 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 <code>find_library</code> command will set <code>M_LIB</code> to contain just "<code>libm.so</code>" when it finds <code>/usr/lib/libm.so</code>.  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 <code>find_library</code> 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 <code>M_LIB</code> to a full path.  In both cases the full path given to target_link_libraries will be preserved on the final link line.

Revision as of 14:47, 28 January 2008

Exporting and Importing Targets

Linking

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.