提问者:小点点

Cmake:如何从子项目的所有静态库创建单个共享库?


我有以下布局:

top_project
    + subproject1
    + subproject2

subproject ect1subproject ect2中的每一个都创建一个静态库。我想在top_project级别将这些静态库链接到一个共享库中。

到目前为止,我收集到的信息是:

  • 使用-fPic编译(在除Windows之外的所有东西上都需要)以创建与位置无关的代码,这将允许将静态库链接到单个共享库中,或者解压缩所有静态库(例如使用ar)并将它们重新链接到共享库中(我认为这是不优雅的

有什么想法吗?


共3个答案

匿名用户

好吧,我明白了:这比它应该的要痛苦得多。直到最近,Kitware的人还不明白为什么会有人想从静态库创建一个DLL。他们的论点是,在main(例如top_project在我的例子中)目录中应该总是有源文件,因为它实际上是一个自己的项目。我的看法不同

subproject ect1subproject ect2的CMakeList. txt中,您应该使用OBJECT库功能(在Cmake 2.8.8中引入)创建目标:

add_library(${PROJECT_NAME} OBJECT ${SRC})

其中SRC指定源文件列表(请注意,这些文件应在CMakeList. txt文件中显式设置,因为它允许make在检测到CMakeList.txt的修改时重新启动Cmake,例如在添加或删除文件时)

top_project中,使用以下方法添加子项目:

add_subdirectory(subproject1)
add_subdirectory(subproject2)

为了查看静态库中的符号,请使用:

set(CMAKE_SHARED_LINKER_FLAGS "-Wl,--export-all-symbols")

然后,您可以使用以下方式创建共享库:

add_library(${PROJECT_NAME} SHARED $<TARGET_OBJECTS:subproject1>
                                   $<TARGET_OBJECTS:subproject2>)

我发现任何普通库(即不是对象)都需要添加到单独的add_library命令中,否则它会被忽略。

对于可执行文件,您可以使用:

add_executable(name_of_executable $<TARGET_OBJECTS:subproject1>
                  $<TARGET_OBJECTS:subproject2>)
set(LINK_FLAGS ${LINK_FLAGS} "-Wl,-whole-archive")
target_link_libraries(name_of_executable ${PROJECT_NAME}

我重复一遍,这仅适用于Cmake的2.8.8版。同样,Cmake非常好地管理了依赖项

匿名用户

我的解决方案是简单地添加/WHOLEARCHIVE-all_load,或--whol-Archive到链接器标志,这样当您的主库链接时,所有的子库都包含在内,包括它们的所有符号(默认行为是只包含主库使用的子库的符号。例如:

$ echo "void Func1() { }" > source1.cpp
$ echo "void Func2() { }" > source2.cpp
$ echo "void Func3() { }" > source3.cpp
$ echo "void Func4() { }" > source4.cpp
cmake_minimum_required(VERSION 3.7)

# The 'sub' libraries, e.g. from an `add_subdirectory()` call.
add_library(sublib_a STATIC source1.cpp source2.cpp)
add_library(sublib_b STATIC source3.cpp source4.cpp)

# The main library that contains all of the sub libraries.
add_library(mainlib SHARED)

target_link_libraries(mainlib sublib_a sublib_b)

运行它(在OSX上):

$ make VERBOSE=1
...
[100%] Linking CXX shared library libmainlib.dylib
/usr/local/Cellar/cmake/3.7.1/bin/cmake -E cmake_link_script CMakeFiles/mainlib.dir/link.txt --verbose=1
/Library/Developer/CommandLineTools/usr/bin/c++   -dynamiclib -Wl,-headerpad_max_install_names  -o libmainlib.dylib -install_name @rpath/libmainlib.dylib  libsublib_a.a libsublib_b.a 
[100%] Built target mainlib

$ nm libmainlib.dylib | grep Func
$

附加这个:

# By default, symbols provided by the sublibs that are not used by mainlib (which is all of them in this case)
# are not used. This changes that.
if (WIN32)
    set_target_properties(mainlib PROPERTIES
        LINK_FLAGS "/WHOLEARCHIVE"
    )
elseif (APPLE)
    set_target_properties(mainlib PROPERTIES
        LINK_FLAGS "-Wl,-all_load"
    )
else ()
    set_target_properties(mainlib PROPERTIES
        LINK_FLAGS "-Wl,--whole-archive"
    )
endif ()

运行它(注意额外的-all_load):

$ make VERBOSE=1
[100%] Linking CXX shared library libmainlib.dylib
/usr/local/Cellar/cmake/3.7.1/bin/cmake -E cmake_link_script CMakeFiles/mainlib.dir/link.txt --verbose=1
/Library/Developer/CommandLineTools/usr/bin/c++   -dynamiclib -Wl,-headerpad_max_install_names -Wl,-all_load -o libmainlib.dylib -install_name @rpath/libmainlib.dylib  libsublib_a.a libsublib_b.a 
[100%] Built target mainlib

$ nm libmainlib.dylib | grep Func
0000000000001da0 T __Z5Func1v
0000000000001db0 T __Z5Func2v
0000000000001dc0 T __Z5Func3v
0000000000001dd0 T __Z5Func4v

请注意,到目前为止,我只实际测试了-all_load/WHOLEARCHIVE是MSVC 2015选项。

匿名用户

另一种方法。

这种方式似乎更简单,但我不确定它有多完美:

https://stackoverflow.com/a/14347487/602340