Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

specifying link flags for only one static lib while linking executable

Tags:

cmake

I have an executable built from several object files and linked with several static and shared libraries. I want to specify -Wl,-whole-archive linker option to one of linked libraries.

For example, from this command:

/usr/bin/c++ _objectFiles_ -o _myExec_  _someCommonOptions_  _myLibraries_ -Wl,-rpath _path to libs_

I want to get this command:

/usr/bin/c++ _objectFiles_ -o _myExec_  _someCommonOptions_  _allOtherLibs_ \
  -Wl,-whole-archive _one particular lib_ -Wl,-no_whole-archive -Wl,-rpath _path to libs_

Is it any way I can achieve this using cmake? As I understand when I add something like

set_target_properties(myExec PROPERTIES LINK_FLAGS "-Wl,-whole-archive")

then -whole-archive options is set for all linked libraries and this is definitely not what I want.

Thank you.

like image 496
beduin Avatar asked Apr 17 '11 12:04

beduin


People also ask

Can a exe link to DLL and static library at the same time?

Yes, the Core and Utils code will be duplicated. Instead of building them as static libs you can build them as dlls and use anywhere.

What happens when you link a static library?

Static Linking and Static Libraries is the result of the linker making copy of all used library functions to the executable file. Static Linking creates larger binary files, and need more space on disk and main memory.

Can you statically link a shared library?

You can't statically link a shared library (or dynamically link a static one). The flag -static will force the linker to use static libraries (. a) instead of shared (. so) ones.


3 Answers

This thread Linking static libraries into shared libs? has a method for that.

SET (MYLIB -Wl,--whole-archive my_particular_lib -Wl,--no-whole-archive)
....
TARGET_LINK_LIBRARIES(yourtarget ${normalstuff} ${MYLIB} ${othernormalstuff})

The CMake docs state:

If a library name matches that of another target in the project a dependency will automatically be added in the build system to make sure the library being linked is up-to-date before the target links. Item names starting with '-', but not '-l' or '-framework', are treated as linker flags.

So the -Wl options should not interfere/be touched by CMake.

like image 190
Mat Avatar answered Oct 17 '22 10:10

Mat


TARGET_LINK_LIBRARIES(myTarget -Wl,--whole-archive myLib -Wl,--no-whole-archive)

Simply replace myTarget and myLib

Oryginal post: https://stackoverflow.com/a/37564428/1052261

like image 29
Dawid Avatar answered Oct 17 '22 10:10

Dawid


As @RichvonLehe points out, the proposed solution may not work if you have multiple libraries. CMake treats -Wl,--whole-archive my_particular_lib -Wl,--no-whole-archive as 3 separate libraries, and makes no guarantees about ordering. In my particular case, I found that I ended up having a bunch of other archives being included between the -Wl,--whole-archive and -Wl,--no-whole-archive flags, resulting in duplicate symbol definitions.

Unfortunately, you also may not be able to wrap everything in quotes. If you do -Wl,--whole-archive,$<TARGET_FILE:my_particular_lib>,--no-whole-archive or similar you'll find that CMAKE stops treating my_particular_lib as a symbolic target and instead just treats the whole string as a link flag. If my_particular_lib happens to have other CMake side-effects, such as target_include_directories() or in my case, PUBLIC HEADERS, they will cease to be included.

Ultimately I had to resort to a layer of indirection. The trick is to use an INTERFACE library as the top level thing. Use one library (my_lib_part_1) to dangle all of the properties that I needed to be transitively inherited by other targets, such as PUBLIC HEADERS, and another library (my_lib_part_2) that emphatically does not have any properties that needed to be inherited and only vends the .a archive.

Even this is lacking. CMake makes it difficult to have empty STATIC libraries and does not allow you to put PUBLIC HEADERS on INTERFACE libraries (yet?).

add_library(my_lib INTERFACE)

add_library(my_lib_part_1 STATIC
  foo.cpp
  )

add_library(my_lib_part_2 STATIC
  bar.cpp
  )

target_link_libraries(my_lib
  INTERFACE
    my_lib_part_1
    # It is very important this is in quotes so CMake treats it as a single flag
    "-Wl,--whole-archive $<TARGET_FILE:my_lib_part_2> -Wl,--no-whole-archive"
   )

set_target_properties(my_lib_part_1 PROPERTIES
  PUBLIC_HEADER "my_public_header.hpp"
  )


set_target_properties(my_lib_part_2 PROPERTIES
  POSITION_INDEPENDENT_CODE ON
  )
like image 1
tgoodhart Avatar answered Oct 17 '22 12:10

tgoodhart