5

I'm trying to create a static library of static libraries. Here's my 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)

If you want to see the whole picture: https://github.com/lucaszanella/myRtspClient/blob/8658dbcb8ed071b8d2649a471455f57f268932f4/myRtspClient/CMakeLists.txt

As you see, I'm trying to create the target myRtspClient by linking it with libmd5 libbase64_live555 libjrtp. Since cmake gives no errors, even if I do

target_link_libraries(myRtspClient eewgg dsgsg dgsgsdgsg)

I can't be sure what is the error. The libraries are in the location I pointed. However, I don't know if they are in the first compilation. I tried on the second though, but who knows...

So, continuing... I tried lots of SET_PROPERTY like these:

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)

When I go to examples and try to build common_example.cpp (see my source tree in the link above if necessary) I do:

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

But I get linking errors like these:

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

What am I doing wrong in the linking process? libMyRtspClient should have all these libs linked to it.

UPDATE:

Seems like I cannot link static libraries together neither create a shared one from static ones. How should I pack all my code into one single shared and one static library?

Lucas Zanella
  • 223
  • 9
  • 35
  • static libs don't link to other static libs. – tkausl Apr 25 '18 at 12:27
  • @tkausl ok, I changed to `add_library(myRtspClient SHARED ${SOURCES})`, not I get `/usr/bin/ld: md5/libmd5.a(md5.cpp.o): relocation R_X86_64_PC32 against symbol `_Z12MD5TransformPjPh' can not be used when making a shared object; recompile with -fPIC`. Seems like I cannot use static libraries to make a shared one? What would be the solution here? – Lucas Zanella Apr 25 '18 at 12:44
  • `Seems like I cannot use static libraries to make a shared one?` - You can. Simply follow the error message: recompile static library with -fPIC or compile shared library without it. – Tsyvarev Apr 25 '18 at 12:46
  • This might help: [Answer to "CMake: include library dependencies in a static library"](https://stackoverflow.com/a/32888999/1945549). – Roland Sarrazin Jul 05 '19 at 07:11

1 Answers1

8

The first thing to know: one doesn't link a static library - one uses an archiver (ar on Linux), which just puts all object files into one archive - libXXX.a

It's not very usual to construct a static library from other static libraries, but not impossible (though I don't know exactly how to do it with cmake, but if everything else fails - you still have add_custom_command).

Let's assume you have two static libs libA.a and libB.a and would like to merge them into a combined library libALL.a. The most straight forward way would be to unpack both archives (remember static libraries are just archives after all), and pack all unpacked object-files into a new archive/static library libALL.a (please refer to man pages of ar for more information about used options):

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

Another possibility would be to use a mri-script for ar, using it we would avoid all unpacked object files laying around (and it is more robust, because not all object-files have *.o-extension):

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

Some people ran in addition

ar -s libALL.a 

or the equivalent

ranlib libALL.a 

to ensure that an archive index is created (this is the only thing that differentiate a static library from a simple archive), but the archive index is built per default anyways (it was at least the case for ar-versions I have used so far).

One more note: The intuitive (and more similar to the VisualS tudio command lib.exe /OUT:libALL.lib libA.lib libB.lib)

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

does not produces an archive which can be used by the linker - ar expects object-files and is not smart enough to look into the sub-archives to find them.


Shared libraries are linked. Furthermore, shared libraries need Position Independent Code, that means all object files must have been compiled with options -fPIC.

Often a library provides two versions:

  1. static, compiled without -fPIC
  2. shared, compiled with -fPIC

Being compiled without -fPIC, the static version is slightly more efficient. It also assures that a static library isn't used as dependency in a shared library, which could lead to violations of One Definition Rule.

As a rule of thumb, shared libraries should depend on other shared libraries and not static libraries.

Clearly, you could recompile all your static libraries with -fPIC and link them together to a single shared library - but I would not recommend it.

ead
  • 27,136
  • 4
  • 67
  • 108