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

时间:2018-04-25 12:25:45

标签: c++ build cmake linker linker-errors

我试图创建静态库的静态库。这是我的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)

如果你想看到整个图片:enter image description here

如您所见,我尝试通过将其与myRtspClient相关联来创建目标libmd5 libbase64_live555 libjrtp。由于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时(如有必要,请参阅上面链接中的源代码树),我会这样做:

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

但我得到的链接错误如下:

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)'

在链接过程中我做错了什么? libMyRtspClient应该将所有这些lib链接到它。

更新

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

1 个答案:

答案 0 :(得分:5)

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

从其他静态库构建静态库并不常见,但并非不可能(虽然我不知道如何使用cmake完全实现它,但如果其他一切都失败了,你仍然有add_custom_command)。

假设您有两个静态库libA.alibB.a,并希望将它们合并到一个组合库libALL.a中。最直接的方法是解压缩两个存档(记住静态库毕竟只是存档),并将所有解压缩的对象文件打包到一个新的存档/静态库libALL.a中(请参阅man pages of ar有关使用选项的更多信息):

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

另一种可能性是对ar使用mri-script,使用它我们将避免所有解包的目标文件(并且它更健壮,因为并非所有对象文件都具有{{1} }} - 扩展):

*.o

有些人另外跑了

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

或等效的

ar -s libALL.a 

确保创建归档索引(这是区分静态库和简单归档的唯一方法),但它是默认构建的。

还有一点需要注意:直观(更类似于VisualS tudio命令ranlib libALL.a

lib.exe /OUT:libALL.lib libA.lib libB.lib

不会生成可供链接器使用的存档 - ar -crs libALL.a libA.a libB.a 需要对象文件,并且不够智能,无法查看存档以查找它们。

共享库已链接。此外,共享库需要位置独立代码,这意味着所有目标文件必须使用选项ar进行编译。

库通常提供两个版本:

  1. static,编译时没有-fPIC
  2. 分享,使用-fPIC
  3. 编译

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

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

    显然,您可以使用-fPIC重新编译所有静态库,并将它们链接到一个共享库中 - 但我不推荐它。