Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using cmake to build a static library of static libraries

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?

like image 911
PPP Avatar asked Apr 25 '18 12:04

PPP


People also ask

How do I add multiple libraries to CMake?

To add a library in CMake, use the add_library() command and specify which source files should make up the library. Rather than placing all of the source files in one directory, we can organize our project with one or more subdirectories. In this case, we will create a subdirectory specifically for our library.

How do I create a shared library in CMake?

To build everything, just place yourself into the build directory and run: /tmp/example/library/build $ cmake .. That's it, you should find mymath. h under /usr/local/include as well as libmymath.so under /usr/local/lib .

Is CMake better than make?

So, what is the real difference? CMake is much more high-level. It's tailored to compile C++, for which you write much less build code, but can be also used for general purpose build. make has some built-in C/C++ rules as well, but they are useless at best.

What does Add_subdirectory do in CMake?

Add a subdirectory to the build. Adds a subdirectory to the build. The source_dir specifies the directory in which the source CMakeLists.


1 Answers

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.

like image 155
ead Avatar answered Sep 20 '22 15:09

ead