View Issue Details Jump to Notes ] Print ]
IDProjectCategoryView StatusDate SubmittedLast Update
0015034CMakeCMakepublic2014-07-23 04:562015-01-05 08:39
ReporterGlenn Coombs 
Assigned ToBrad King 
PrioritynormalSeverityminorReproducibilityalways
StatusclosedResolutionfixed 
PlatformIntel x86_64OSCentOSOS Version5.10
Product VersionCMake 3.0 
Target VersionCMake 3.1Fixed in VersionCMake 3.1 
Summary0015034: target_link_libraries: clarify documented treatment of link flags
DescriptionThe target_link_libraries command fails to add the specified linker option under some conditions.
Steps To ReproduceSave the example CMakeLists.txt file attached to this ticket and then run these commands:

mkdir build
cd build
cmake ..
make VERBOSE=yes

The link command generated for my_lib_shared is as follows:

gcc -fPIC -shared -Wl,-soname,libmy_lib_shared.so
-o libmy_lib_shared.so CMakeFiles/my_lib_shared.dir/my_lib_shared.c.o
libsome_lib_1.a
-Wl,-whole-archive libsome_lib_3.a -Wl,-no-whole-archive
libsome_lib_2.a
-Wl,-whole-archive libsome_lib_4.a
libsome_lib_5.a

which is incorrect. The lib4 line should include a -no-whole-archive option on the end. If you comment line 25 and uncomment line 26 in the CMakeLists.txt then the correct output is generated:

gcc -fPIC -shared -Wl,-soname,libmy_lib_shared.so -o
libmy_lib_shared.so CMakeFiles/my_lib_shared.dir/my_lib_shared.c.o
libsome_lib_1.a
-Wl,-whole-archive libsome_lib_3.a -Wl,-no-whole-archive
libsome_lib_2.a
-Wl,-whole-archive libsome_lib_4.a -Wl,-Qy,-no-whole-archive
libsome_lib_5.a

For some reason the -no-whole-archive is omitted unless another option precedes it.
TagsNo tags attached.
Attached Filestxt file icon CMakeLists.txt [^] (833 bytes) 2014-07-23 04:56 [Show Content]

 Relationships

  Notes
(0036435)
Brad King (manager)
2014-07-23 08:33

CMake assumes that items given to target_link_libraries are libraries or flags that act like libraries (e.g. -lfoo). The link rule for a specific target starts with the explicit target_link_libraries calls with that target as the first argument, and then adds dependencies. Flags like -Wl,-whole-archive are not safe to use in transitive contexts but can work in private/direct linking cases.

Instead of depending on platform-specific behavior like the linker -whole-archive flag, consider using OBJECT libraries.
(0036448)
Glenn Coombs (reporter)
2014-07-24 04:19

I'm not sure that using OBJECT libraries is a good way to solve my problem.

Have a look here:

http://cmake.3232098.n2.nabble.com/How-to-get-a-list-of-all-the-static-libraries-that-a-target-will-link-against-tt7587795.html [^]

to see the background to this issue. Essentially, I need to create an executable and a shared library from the same set of sources (the shared library actually uses a subset of the sources). The shared library depends on a library called mtx_wrapper, which in turn may depend on 5 further libraries depending on how the mtx_wrapper library is configured to build. Currently the top level CMakeLists.txt file uses target_link_libraries to specify that the shared library has a dependency on the mtx_wrapper library. And separately in the mtx_wrapper CMakeLists.file the target_link_libraries command is used to specify that the mtx_wrapper library has a dependency on the 5 other libraries.

If I were to use OBJECT libraries then the CMakeLists.txt that creates the shared library would need to know how the mtx_wrapper was built so that it could include its dependencies. And if the 5 other libraries also had dependencies it would need to know about those as well. The same would be true of all libraries that I currently build and link into the executable and shared library. It seems like this would completely break the encapsulation where each library has its own directory with its own CMakeLists.txt that has all the details of how it needs to be built. Instead of the top level CMakeLists.txt specifying the immediate dependencies it would end up needing to specify the dependencies of those immediate dependencies, and their dependencies etc. recursively.

That doesn't seem like a good solution to the problem. Additionally, the 5 libraries that the mtx_wrapper library depends on are from a separate group and are built as an external project. I only have access to the libraries as IMPORT libraries from the external build tree so I'm not sure if that would even work with an OBJECT library.

There must be a cleaner way to solve this problem. Can I read the INTERFACE_LINK_LIBRARIES property of the shared library to see the dependencies ? And then recursively look at the INTERFACE_LINK_LIBRARIES property of each of them to build up a list of all dependencies ? I could then add the -whole-archive/-no-whole-archive options to the list in the appropriate place and replace the INTERFACE_LINK_LIBRARIES property with my list. Would that work ?
(0036449)
Brad King (manager)
2014-07-24 08:51

OBJECT libraries were created exactly for the purpose of compiling separate groups of source files with their own requirements and then linking them all together into a larger library. This works, but we have not yet defined any way to specify usage requirements for object libraries that get propagated into the targets that link their objects. See also discussion at 0014970:0036178. Still, you could record information in the object libraries in your own custom properties to be read later and propagated to the real interface of the real shared library.

If your goal is to collect a list of static libraries to put in a whole-archive group, then don't depend on target_link_libraries to do it. Just set your own property on each static library to record its dependencies. Then when linking the final shared library, compute your own transitive closure from that staging property and do a single target_link_libraries call for the shared lib:

  add_library(finallib SHARED ...)
  target_link_libraries(finallib PRIVATE -Wl,-whole-archive ${list_of_static_libs} -Wl,-no-whole-archive)

Of course this will only work with binutils that support whole-archive flags. MS tools do not.
(0036463)
Glenn Coombs (reporter)
2014-07-25 07:05

Yes, my goal is to collect a list of static libraries to put into a whole-archive group. The problem doesn't exist on the Windows build because the MSVC linker seems to include all the object files by default anyway.

I am puzzled why you suggest not to use target_link_libraries to do this. I already use target_link_libraries on all my libraries to specify their dependencies so that I can link the executable correctly. Why would I want to implement a parallel system that does exactly the same as that ?

I have written a cmake function called get_deps(target) that I can call for any target. It looks at the INTERFACE_LINK_LIBRARIES value for the given target to get the list of immediate dependencies (as set by the target_link_libraries command). It then recursively calls itself on each of them to build up a list of ALL the dependencies, which it then puts onto a property on the target called ALL_DEPS.

If I call get_deps on my shared library target then it correctly gets me the list of all the dependencies. After adding the -whole-archive and -no-whole-archive options in the appropriate places I then write that list to the LINK_LIBRARIES property of my shared library.

This produces the correct link line for the shared library and is working fine for me at the moment. Is there anything wrong with doing it like this ? Is it reliant on internal cmake behaviour that is liable to change in a future version ?
(0036467)
Brad King (manager)
2014-07-28 09:09

Re 0015034:0036463: That should be okay as long as it works when policy CMP0022 is set to NEW (activating CMake's interpretation of INTERFACE_LINK_LIBRARIES).

The MSVC linker does not bring in all objects. What it may do is repeatedly search for symbols in objects from static libraries already searched earlier. If that works for you then it sounds like you do not actually need whole-archive, but instead have a case of circular dependencies among the static libraries. Is that the case?
(0036471)
Glenn Coombs (reporter)
2014-07-28 11:17

I have just checked more carefully and I think you're right. It appears that my shared library will link correctly with just -Bsymbolic if I alter the order of some of the libraries on the link line (looks like the 5 imported libraries need to specify their internal dependencies on each other).

I also discovered the --no-undefined option to the GNU linker. With that it now generates an error at link time if the order is incorrect rather than waiting until the library is dlopen'd. That is a much simpler solution than using -whole-archive and my get_deps() function.

I'm not sure where that leaves this bug report. On the one hand I have a working solution (two in fact) for my problem. On the other hand I still feel that the behaviour of target_link_libraries is a little bit unexpected. Maybe it isn't a code bug, but the documentation could perhaps do with some clarification ? In particular, the section on target_link_libraries says:

Item names starting with -, but not -l or -framework, are treated as linker flags.

It doesn't say that they are not safe to use in transitive contexts or that cmake will sometimes omit them in such cases.
(0036475)
Brad King (manager)
2014-07-28 12:45

Re 0015034:0036471: Great, I'm glad you have a solution. I've extended the documentation:

 Help: Clarify target_link_libraries treatment of flags
 http://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=8c03f157 [^]
(0037604)
Robert Maynard (manager)
2015-01-05 08:39

Closing resolved issues that have not been updated in more than 4 months

 Issue History
Date Modified Username Field Change
2014-07-23 04:56 Glenn Coombs New Issue
2014-07-23 04:56 Glenn Coombs File Added: CMakeLists.txt
2014-07-23 08:33 Brad King Note Added: 0036435
2014-07-24 04:19 Glenn Coombs Note Added: 0036448
2014-07-24 08:51 Brad King Note Added: 0036449
2014-07-25 07:05 Glenn Coombs Note Added: 0036463
2014-07-28 09:09 Brad King Note Added: 0036467
2014-07-28 11:17 Glenn Coombs Note Added: 0036471
2014-07-28 12:44 Brad King Summary target_link_libraries omits some dependencies => target_link_libraries: clarify documented treatment of link flags
2014-07-28 12:45 Brad King Note Added: 0036475
2014-07-28 12:46 Brad King Assigned To => Brad King
2014-07-28 12:46 Brad King Status new => assigned
2014-07-28 12:46 Brad King Target Version => CMake 3.1
2014-07-31 14:46 Brad King Status assigned => resolved
2014-07-31 14:46 Brad King Resolution open => fixed
2014-07-31 14:46 Brad King Fixed in Version => CMake 3.1
2015-01-05 08:39 Robert Maynard Note Added: 0037604
2015-01-05 08:39 Robert Maynard Status resolved => closed


Copyright © 2000 - 2018 MantisBT Team