在实际的项目开发过程中,可能会用到很多的静态库,有时会想把几个静态库打包成一个静态库,链接起来更方便。本文将要学习如果将静态库合并。
前期准备
准备一个静态库liba.a,后续将这个静态库与其他静态库合并。
头文件a.h
#pragma once
class a
{
public:
a() {}
~a() {}
void test_a();
};
cpp文件a.cpp
#include "a.h"
#include <iostream>
void a::test_a()
{
std::cout << "this is test_a" << std::endl;
}
CMakeLists.txt
CMAKE_MINIMUM_REQUIRED(VERSION 3.10)
PROJECT(a)
SET(CMAKE_CXX_FLAGS "-fPIC -g ")
# 指定源代码目录
AUX_SOURCE_DIRECTORY(${PROJECT_SOURCE_DIR} LIBSRC)
# 指定静态库生成的目录
SET(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/lib)
# 生成静态库
ADD_LIBRARY(a STATIC ${LIBSRC})
使用以上代码,能够make出来一个静态库,名为liba.a。
合并静态库
接下来,我们将生成另一个静态库libb.a,这个库使用了liba.a的函数,然后把liba.a和libb.a合并成一个新的静态库libmerge.a。
头文件b.h
#pragma once
class b
{
public:
b() {}
~b() {}
void test_b();
};
cpp文件b.cpp
#include <iostream>
#include "b.h"
#include "../liba/a.h"
void b::test_b()
{
std::cout << "this is test_b" << std::endl;
a tmp_a{}; // 使用了liba.a的类
tmp_a.test_a();
}
CMakeLists.txt
CMAKE_MINIMUM_REQUIRED(VERSION 3.10)
PROJECT(b)
SET(CMAKE_CXX_FLAGS "-fPIC -g ")
SET(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/lib)
ADD_LIBRARY(a STATIC IMPORTED)
SET_TARGET_PROPERTIES(a PROPERTIES IMPORTED_LOCATION ${PROJECT_SOURCE_DIR}/../liba/lib/liba.a)
# 指定源代码目录
AUX_SOURCE_DIRECTORY(${PROJECT_SOURCE_DIR} LIBSRC)
# 生成静态库
ADD_LIBRARY(b_static STATIC ${LIBSRC})
# 对b_static的重名为b
SET_TARGET_PROPERTIES(b_static PROPERTIES OUTPUT_NAME "b")
# cmake 在构建一个新的target时,清理掉其他使用这个名字的库
SET_TARGET_PROPERTIES(b_static PROPERTIES CLEAN_DIRECT_OUTPUT 1)
# 将liba.a和libb.a合并成一个新的静态库libmerge.a
ADD_CUSTOM_COMMAND(OUTPUT libmerge.a
COMMAND ar rcsT ../lib/libmerge.a $<TARGET_FILE:b_static> $<TARGET_FILE:a>
DEPENDS a b_static
)
# 创建target,用于生成libmerge.a,不创建则不会生成libmerge.a
ADD_CUSTOM_TARGET(_merge ALL DEPENDS libmerge.a)
在CMakeLists.txt中的ADD_CUSTOM_COMMAND是执行一个命令,命令的功能是使用ar将libb.a和liba.a打包合并成libmerge.a
使用命令nm libmerge.a查看符号,能够看到两个库的符号都包含在内。
[root@VM-8-2-centos lib]# nm libmerge.a
b.cpp.o:
U __cxa_atexit
U __dso_handle
0000000000000000 V DW.ref.__gxx_personality_v0
U _GLOBAL_OFFSET_TABLE_
00000000000000c8 t _GLOBAL__sub_I_b.cpp
U __gxx_personality_v0
U _Unwind_Resume
000000000000007f t _Z41__static_initialization_and_destruction_0ii
U _ZN1a6test_aEv
0000000000000000 W _ZN1aC1Ev
0000000000000000 W _ZN1aC2Ev
0000000000000000 n _ZN1aC5Ev
0000000000000000 W _ZN1aD1Ev
0000000000000000 W _ZN1aD2Ev
0000000000000000 n _ZN1aD5Ev
0000000000000000 T _ZN1b6test_bEv
U _ZNSolsEPFRSoS_E
U _ZNSt8ios_base4InitC1Ev
U _ZNSt8ios_base4InitD1Ev
U _ZSt4cout
U _ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_
0000000000000000 r _ZStL19piecewise_construct
0000000000000000 b _ZStL8__ioinit
U _ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc
a.cpp.o:
U __cxa_atexit
U __dso_handle
U _GLOBAL_OFFSET_TABLE_
0000000000000083 t _GLOBAL__sub_I_a.cpp
000000000000003a t _Z41__static_initialization_and_destruction_0ii
0000000000000000 T _ZN1a6test_aEv
U _ZNSolsEPFRSoS_E
U _ZNSt8ios_base4InitC1Ev
U _ZNSt8ios_base4InitD1Ev
U _ZSt4cout
U _ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_
0000000000000000 r _ZStL19piecewise_construct
0000000000000000 b _ZStL8__ioinit
U _ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc
实验验证
写一个小程序,引用libmerge.a并调用class b的成员函数test_b。
#include <iostream>
#include "b.h"
int main()
{
b tmp_b{};
tmp_b.test_b();
return 0;
}
CMakeLists.txt
CMAKE_MINIMUM_REQUIRED(VERSION 3.10)
PROJECT(test)
# 指定源代码目录
AUX_SOURCE_DIRECTORY(${PROJECT_SOURCE_DIR} LIBSRC)
INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/../libb)
LINK_DIRECTORIES(${PROJECT_SOURCE_DIR}/../libb/lib)
ADD_EXECUTABLE(test ${LIBSRC})
TARGET_LINK_LIBRARIES(test merge)
编译代码
[root@VM-8-2-centos build]# cmake ../
-- The C compiler identification is GNU 8.5.0
-- The CXX compiler identification is GNU 8.5.0
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: /usr/bin/cc - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
m-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: /usr/bin/c++ - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done (0.4s)
-- Generating done (0.0s)
-- Build files have been written to: /root/work_dir/test_programs/lib_merge/test/build
[root@VM-8-2-centos build]# make
[ 50%] Building CXX object CMakeFiles/test.dir/test.cpp.o
[100%] Linking CXX executable test
[100%] Built target test
运行代码
[root@VM-8-2-centos build]# ./test
this is test_b
this is test_a
运行成功!
结束语
本文学习了如果将多个静态库合并成一个,链接起来更方便,对于库的使用者更加友好。