如何用多个static lib 生成到一个static lib
背景
先前利用cmake 生成的文件太多,在最后生成可执行文件的时候,要配置多个lib的link,不方便。
想要简单的将多个static lib 打包到一个 static lib中,方便使用。
从网上查阅信息后,发现很多人都说这不是一个常规的需求,而且做不到跨平台。本文旨在记录调研过程中的一些收获。
target_link_libraries的一些说明
What does ‘target_link_libraries’ do when the target is a static library and the target link is a static library too?
In short
When target_link_libraries
is applied to the static library, it won’t affect on the resulted library file. But it affects on the target in the similar way, as it would affect on the target of the shared library.
So, you can use target_link_libraries
both for static and shared libraries in the same manner.
In details
When applied to the static library, target_link_libraries
doesn’t have immediate effect on the creation of this library. That is, when static library will be created (as file), it won’t store that linkage:
add_library(MyStaticLib STATIC ${SOURCES} )
target_link_libraries(MyStaticLib PUBLIC "${OPENCV_LIBS}/opencv_world410.lib")
# When file 'MyStaticLib.lib' will be created,
# it will NOT be linked with 'opencv_world410.lib'.
(As you probably know, a static library doesn’t store any information about the linkage, a static library is just a collection of object files.)
But while the file with the static library doesn’t store linkage information, the CMake target, which represents that static library, will be “aware of linkage”. This can be useful in many cases:
-
If in the same project you create an executable or a shared library, and link it with the static library (using
target_link_libraries
), that executable will actually linked with the dependent library:add_executable(myExe ...) target_link_libraries(myExe PRIVATE MyStaticLib) # When file 'myExe.exe' will be created, it WILL be linked with 'opencv_world410.lib'
-
If in the same project you create another static library, and link it with the static one, the another static library will be “aware of linkage” both with the initial static library and its dependency.
add_library(MyStaticLibAnother STATIC ..) target_link_libraries(MyStaticLibAnother PUBLIC MyStaticLib) # "As if" following line is executed # target_link_libraries(MyStaticLibAnother PUBLIC "${OPENCV_LIBS}/opencv_world410.lib")
-
If you install your library target and export it using command
install(TARGETS ... EXPORT ...)
, then the library can be found withfind_package
. And thatfind_package
will create a static library target, which will be aware of linkage with all its dependencies:# [In main project] install(TARGETS MyStaticLib EXPORT MyProject) install(EXPORT MyProject NAMESPACE MyProject::)
# [In another project] find_package(MyProject REQUIRED) # It creates the target MyProject::MyStaticLib which is # "aware of linkage" with 'opencv_world410.lib'.
Additionally, if you link a static library with a target (not with a plain file), and that target contains compile definitions or other information, applicable to the compile stage, the static library will be compiled using that compile information.
总结
简单说就是 target_link_libraries 对于static lib来说对生成件没有影响,但是static lib会记住这个link信息。 这样其他使用static lib的地方就不用记这个static lib的link信息了。所以static lib虽然不真的执行link,link信息也建议像exe/shared lib 一样带上。
Some clarification regarding STATIC and OBJECT library targets and how they interact with each other using `target_link_libraries
Some clarification regarding STATIC and OBJECT library targets and how
they interact with each other using target_link_libraries
:
A STATIC library target A can be linked (via target_link_libraries
) to
another STATIC library target B.
target_link_libraries(A STATIC PUBLIC B)
However, the resulting library file libB does not contain the
information (aka object-files) of libA.
Instead, CMake makes sure to link both static library files libB and
libA when e.g. creating an executable exeC1 using target C1 which just
links (via target_link_libraries
) to target B.
target_link_libraries(C1 EXECUTABLE PUBLIC B)
(Instead of an executable exeC1 you could have created a shared library
libC1 instead. The behavior is the same.)
If you instead want to create a combined, single STATIC library libC2,
which contains the object-files archived in both static library files
libA and libB created from targets A and B, then you somehow need to
extract the archived object-files from libA and libB. I am not sure if
CMake provides a (simple) way to do this.
For OBJECT libraries the behavior is like this:
An OBJECT library target X can be linked (via target_link_libraries
)
to another OBJECT library target Y.
target_link_libraries(Y OBJECT PUBLIC X)
This, however, only transports the usage-requirements
(preprocessor-defines, include-paths etc.) from X to Y. The object-files
of X are in no way referenced by Y.
So, if you then create a STATIC target Z1 that links (via
target_link_libraries
) to Y,…
target_link_libraries(Z1 STATIC PUBLIC Y)
… Z1 will reference/contain the usage-requirements of X and Y and the
object-files of Y, but not the object-files of X. (The static library
file libZ1 resulting from Z1 will contain the object-libraries of Y but
not of X.)
What you should do instead is not to link the OBJECT targets X and Y
together but instead only link them (explicitly) to the STATIC target Z2:
target_link_libraries(Z2 STATIC PUBLIC Y X)
Z2 then references the usage-requirements as-well-as object-files of
both OBJECT targets X and Y and the resulting static library file libZ2
will then contain the object-files of both library targets, X and Y.
如果真的想把多个static lib 合并成 1个static lib要怎么做
首先要说明的是,
- 这并不是一个常见的操作
- 有些人说目前还没有跨平台的做法。 linux 可以借助 ar,mac 可以借助libtool,windows 可以借助lib.exe
- 也有人说通过
CMAKE_CXX_ARCHIVE_CREATE
或者CMAKE_AR
可以实现跨平台 - 我最后是放弃了这个做法,直接用源文件生成1个static lib
详细信息可以参考:
Using cmake to build a static library of static libraries
Bundling together static libraries with CMake
CMake: include library dependencies in a static library
add_library(lib1 STATIC lib1.c)
add_library(lib2 STATIC lib2.c)
target_link_libraries(lib2 INTERFACE lib1)