使用cmake构建静态库的静态库

Using cmake to build a static library of static libraries

我正在尝试创建静态库的静态库。这是我的 CMakeLists.txt

cmake_minimum_required(VERSION 2.8)

project(myRtspClient)

add_subdirectory(../third_party/Base64_live555 base64_live555)
add_subdirectory(../third_party/md5 md5)
add_subdirectory(../third_party/JRTPLIB jrtplib)

include_directories(include)
include_directories(../third_party/Base64_live555/include)
include_directories(../third_party/md5/include)
include_directories(jrtplib/src)
include_directories(../third_party/JRTPLIB/src)

file(GLOB SOURCES "*.cpp")

add_library(myRtspClient STATIC ${SOURCES})

add_library(libmd5 STATIC IMPORTED)
SET_PROPERTY(TARGET libmd5 PROPERTY IMPORTED_LOCATION ./md5/libmd5.a)

add_library(libbase64_live555 STATIC IMPORTED)
SET_PROPERTY(TARGET libbase64_live555 PROPERTY IMPORTED_LOCATION ./base64_live555/libbase64_live555.a)

add_library(libjrtp STATIC IMPORTED)
SET_PROPERTY(TARGET libjrtp PROPERTY IMPORTED_LOCATION ./jrtplib/src/librtp.a)

target_link_libraries(myRtspClient libmd5 libbase64_live555 libjrtp)
#install(TARGETS myRtspClient DESTINATION /usr/lib)

如果想看全图:https://github.com/lucaszanella/myRtspClient/blob/8658dbcb8ed071b8d2649a471455f57f268932f4/myRtspClient/CMakeLists.txt

如您所见,我正在尝试通过 link 使用 libmd5 libbase64_live555 libjrtp 来创建目标 myRtspClient。因为 cmake 没有错误,即使我这样做

target_link_libraries(myRtspClient eewgg dsgsg dgsgsdgsg)

我不确定是什么错误。图书馆在我指出的位置。但是,我不知道它们是否在第一个编译中。虽然我试过第二次,但谁知道呢...

所以,继续...我尝试了很多 SET_PROPERTY,例如:

SET_PROPERTY(TARGET libbase64_live555 PROPERTY IMPORTED_LOCATION ./base64_live555/libbase64_live555.a)

SET_PROPERTY(TARGET libbase64_live555 PROPERTY IMPORTED_LOCATION ./base64_live555)

SET_PROPERTY(TARGET libbase64_live555 PROPERTY IMPORTED_LOCATION base64_live555/libbase64_live555.a)

当我转到 examples 并尝试构建 common_example.cpp(如有必要,请参阅上面 link 中的源代码树)我会:

g++ common_example.cpp -I ../myRtspClient/include ../myRtspClient/libmyRtspClient.a

但是我得到 linking 像这样的错误:

utils.cpp:(.text+0x2f4): undefined reference to `MD5Init(MD5_CTX*)'
utils.cpp:(.text+0x316): undefined reference to `MD5Update(MD5_CTX*, unsigned char*, unsigned int)'
utils.cpp:(.text+0x32c): undefined reference to `MD5Final(MD5_CTX*, unsigned char*)'
../myRtspClient/libmyRtspClient.a(MediaSession.cpp.o): In function `MyRTPSession::MyRTPSession()':
MediaSession.cpp:(.text._ZN12MyRTPSessionC2Ev[_ZN12MyRTPSessionC5Ev]+0x1e): undefined reference to `jrtplib::RTPSession::RTPSession(jrtplib::RTPRandom*, jrtplib::RTPMemoryManager*)'
../myRtspClient/libmyRtspClient.a(myRtpSession.cpp.o): In function `MyRTPSession::IsError(int)':
myRtpSession.cpp:(.text+0x48): undefined reference to `jrtplib::RTPGetErrorString[abi:cxx11](int)'
../myRtspClient/libmyRtspClient.a(myRtpSession.cpp.o): In function `MyRTPSession::MyRTP_SetUp(MediaSession*)':
myRtpSession.cpp:(.text+0x1b5): undefined reference to `jrtplib::RTPSessionParams::RTPSessionParams()'
myRtpSession.cpp:(.text+0x25c): undefined reference to `jrtplib::RTPSession::Create(jrtplib::RTPSessionParams const&, jrtplib::RTPTransmissionParams const*, jrtplib::RTPTransmitter::TransmissionProtocol)'

我在 linking 过程中做错了什么? libMyRtspClient 应该有所有这些库 linked 到它。

更新:

似乎我无法 link 将静态库放在一起,既不能从静态库创建共享库。我应该如何将所有代码打包到一个共享库和一个静态库中?

首先要知道的是:没有 link 静态库 - 使用归档器(Linux 上的 ar),它只是将所有目标文件放入一个归档 - libXXX.a

从其他静态库构建静态库不是很常见,但并非不可能(虽然我不知道如何用 cmake 做,但如果其他一切都失败了 - 你仍然有 add_custom_command).

假设您有两个静态库 libA.alibB.a 并且想将它们合并到一个组合库 libALL.a 中。最直接的方法是解压两个档案(记住静态库毕竟只是档案),并将所有解压的目标文件打包到一个新的 archive/static 库 libALL.a (请参考 man pages of ar 了解有关已用选项的更多信息):

ar -x libA.a
ar -x libB.a
ar -crs libALL.a *.o

另一种可能性是对 ar 使用 mri-script,使用它我们可以避免所有解压缩的目标文件(并且它更健壮,因为并非所有目标文件都有 *.o-扩展名):

ar -M <<EOM
    CREATE libALL.a
    ADDLIB libA.a
    ADDLIB libB.a
    SAVE
    END
EOM

还有人运行另外

ar -s libALL.a 

或同等水平

ranlib libALL.a 

确保创建存档索引(这是静态库与简单存档的唯一区别),但存档索引无论如何都是默认构建的(至少 [=15 是这样的) =]-到目前为止我使用的版本)。

再补充一点:直观(更类似于VisualStudio命令lib.exe /OUT:libALL.lib libA.lib libB.lib

ar -crs libALL.a libA.a libB.a

不生成可供 linker 使用的存档 - ar 需要目标文件并且不够聪明,无法查看子存档以找到它们。


共享库已 linked。此外,共享库需要位置独立代码,这意味着所有目标文件都必须使用选项 -fPIC.

进行编译

通常一个库提供两个版本:

  1. 静态,编译时没有 -fPIC
  2. 共享,用-fPIC
  3. 编译

在没有 -fPIC 的情况下进行编译,静态版本的效率稍微高一些。它还确保静态库不被用作共享库中的依赖项,这可能导致违反 One Definition Rule.

根据经验,共享库应该依赖于其他共享库而不是静态库。

显然,您可以将所有带有 -fPIC 和 link 的静态库一起重新编译为一个共享库 - 但我不推荐这样做。