CMake depedency

Some tips about cmake depedency.

Within the same project

We may start with the default option to link two libraries, however, the depedency between two library in the same projects can be classified as PRIVATE PUBLIC INTERFACE.

Let’s start with a simple example to show how these things are differnet in cmake.

Assuming there is a main function call the hello, and the hello function calls the helloinner.

Before adding the constraints for the depedency, lets look at the static and daynamic link firstly.

There are four cases, we take down the main operations of make by using make VERBOSE=1

Case 1
Both helloinner and hello are static libraries

#1 create the object file for helloinner
/usr/bin/c++ -I/home/zw/cworkspace/src/5MCST/cmake_example/Depedency -MD -MT hello/helloinner/CMakeFiles/helloinner.dir/helloinner.cpp.o -MF CMakeFiles/helloinner.dir/helloinner.cpp.o.d -o CMakeFiles/helloinner.dir/helloinner.cpp.o -c /home/zw/cworkspace/src/5MCST/cmake_example/Depedency/hello/helloinner/helloinner.cpp

#2 build the object file into the static library
/usr/bin/ar qc libhelloinner.a CMakeFiles/helloinner.dir/helloinner.cpp.o
/usr/bin/ranlib libhelloinner.a

#3 build object file for hello
/usr/bin/c++ -I/home/zw/cworkspace/src/5MCST/cmake_example/Depedency -MD -MT hello/CMakeFiles/hello.dir/hello.cpp.o -MF CMakeFiles/hello.dir/hello.cpp.o.d -o CMakeFiles/hello.dir/hello.cpp.o -c /home/zw/cworkspace/src/5MCST/cmake_example/Depedency/hello/hello.cpp

#4 create the static library for hello
/usr/bin/ar qc libhello.a CMakeFiles/hello.dir/hello.cpp.o
/usr/bin/ranlib libhello.a

#5 build the object file for main
/usr/bin/c++ -I/home/zw/cworkspace/src/5MCST/cmake_example/Depedency -MD -MT CMakeFiles/main.dir/main.cpp.o -MF CMakeFiles/main.dir/main.cpp.o.d -o CMakeFiles/main.dir/main.cpp.o -c /home/zw/cworkspace/src/5MCST/cmake_example/Depedency/main.cpp

#6 link the static libraris to main executable file
/usr/bin/c++ -rdynamic CMakeFiles/main.dir/main.cpp.o -o main hello/libhello.a hello/helloinner/libhelloinner.a

Case 2
helloinner is shared library and hello is static library

# 1 build the shared object for helloinner
# except the parameter used for shared library, it adds -Dhelloinner_EXPORTS as a preprocessor macro helloinner_EXPORTS

/usr/bin/c++ -Dhelloinner_EXPORTS -I/home/zw/cworkspace/src/5MCST/cmake_example/Depedency -fPIC -MD -MT hello/helloinner/CMakeFiles/helloinner.dir/helloinner.cpp.o -MF CMakeFiles/helloinner.dir/helloinner.cpp.o.d -o CMakeFiles/helloinner.dir/helloinner.cpp.o -c /home/zw/cworkspace/src/5MCST/cmake_example/Depedency/hello/helloinner/helloinner.cpp

# 2 create the shared library

/usr/bin/c++ -fPIC -shared -Wl,-soname,libhelloinner.so -o libhelloinner.so CMakeFiles/helloinner.dir/helloinner.cpp.o

# 3 build the object of hello, this is same with previous situation
/usr/bin/c++ -I/home/zw/cworkspace/src/5MCST/cmake_example/Depedency -MD -MT hello/CMakeFiles/hello.dir/hello.cpp.o -MF CMakeFiles/hello.dir/hello.cpp.o.d -o CMakeFiles/hello.dir/hello.cpp.o -c /home/zw/cworkspace/src/5MCST/cmake_example/Depedency/hello/hello.cpp

# 4 link to a static lib (same with prevoius situation)
/usr/bin/ar qc libhello.a CMakeFiles/hello.dir/hello.cpp.o
/usr/bin/ranlib libhello.a

# 5 build object for main (same with previous situation)
/usr/bin/c++ -I/home/zw/cworkspace/src/5MCST/cmake_example/Depedency -MD -MT CMakeFiles/main.dir/main.cpp.o -MF CMakeFiles/main.dir/main.cpp.o.d -o CMakeFiles/main.dir/main.cpp.o -c /home/zw/cworkspace/src/5MCST/cmake_example/Depedency/main.cpp

# 6 link the shared object (helloinner) and static library (hello) to the main (two libraries are linked here)
/usr/bin/c++ -rdynamic CMakeFiles/main.dir/main.cpp.o -o main -Wl,-rpath,/home/zw/cworkspace/src/5MCST/cmake_example/Depedency/build/hello/helloinner hello/libhello.a hello/helloinner/libhelloinner.so

Case 3
helloinner is static and hello is dynamic library

# 1 and 2 same with the case 1
# 3 build shared object for hello, there is also export macro

/usr/bin/c++ -Dhello_EXPORTS -I/home/zw/cworkspace/src/5MCST/cmake_example/Depedency -fPIC -MD -MT hello/CMakeFiles/hello.dir/hello.cpp.o -MF CMakeFiles/hello.dir/hello.cpp.o.d -o CMakeFiles/hello.dir/hello.cpp.o -c /home/zw/cworkspace/src/5MCST/cmake_example/Depedency/hello/hello.cpp

# 4 link the static library to the shared library
/usr/bin/c++ -fPIC -shared -Wl,-soname,libhello.so -o libhello.so CMakeFiles/hello.dir/hello.cpp.o helloinner/libhelloinner.a

# 5 build the object for main, same with the case 1

# 6 link the shared lib to the main (two libraries are linked here)
/usr/bin/c++ -rdynamic CMakeFiles/main.dir/main.cpp.o -o main -Wl,-rpath,/home/zw/cworkspace/src/5MCST/cmake_example/Depedency/build/hello hello/libhello.so hello/helloinner/libhelloinner.a

Case 4
Both helloinner and hello are dynamic libraries

# 1 build shared object for helloinner

/usr/bin/c++ -Dhelloinner_EXPORTS -I/home/zw/cworkspace/src/5MCST/cmake_example/Depedency -fPIC -MD -MT hello/helloinner/CMakeFiles/helloinner.dir/helloinner.cpp.o -MF CMakeFiles/helloinner.dir/helloinner.cpp.o.d -o CMakeFiles/helloinner.dir/helloinner.cpp.o -c /home/zw/cworkspace/src/5MCST/cmake_example/Depedency/hello/helloinner/helloinner.cpp

# 2 link the shared lib

/usr/bin/c++ -fPIC -shared -Wl,-soname,libhelloinner.so -o libhelloinner.so CMakeFiles/helloinner.dir/helloinner.cpp.o

# 3 build shared object for hello

/usr/bin/c++ -Dhello_EXPORTS -I/home/zw/cworkspace/src/5MCST/cmake_example/Depedency -fPIC -MD -MT hello/CMakeFiles/hello.dir/hello.cpp.o -MF CMakeFiles/hello.dir/hello.cpp.o.d -o CMakeFiles/hello.dir/hello.cpp.o -c /home/zw/cworkspace/src/5MCST/cmake_example/Depedency/hello/hello.cpp

# 4 link the shared lib for hello

/usr/bin/c++ -fPIC -shared -Wl,-soname,libhello.so -o libhello.so CMakeFiles/hello.dir/hello.cpp.o -Wl,-rpath,/home/zw/cworkspace/src/5MCST/cmake_example/Depedency/build/hello/helloinner helloinner/libhelloinner.so

# 5 build shared object for main

/usr/bin/c++ -I/home/zw/cworkspace/src/5MCST/cmake_example/Depedency -MD -MT CMakeFiles/main.dir/main.cpp.o -MF CMakeFiles/main.dir/main.cpp.o.d -o CMakeFiles/main.dir/main.cpp.o -c /home/zw/cworkspace/src/5MCST/cmake_example/Depedency/main.cpp

# 6 link the shared executable for main (there are two shared files)

/usr/bin/c++ -rdynamic CMakeFiles/main.dir/main.cpp.o -o main -Wl,-rpath,/home/zw/cworkspace/src/5MCST/cmake_example/Depedency/build/hello:/home/zw/cworkspace/src/5MCST/cmake_example/Depedency/build/hello/helloinner hello/libhello.so hello/helloinner/libhelloinner.so

There are some discussion about the meaning of PRIVATE keyward PUBLIC keyword when link to the target here

If the hello library in our situation is the static library, we does not need to care about the private and public keyword, the static library does not contains the information about the shared library, so the shared library is added to the link path of the main even if we use the private key word here.

The thing that matters is when both helloinner and hello are shared libraries. In this case, when we use the private keyword, at the link stage of the main, we get:

# 1, 2  and 3 are same with the case 4
# 4 link the hello.so libraray, the path of the helloinner is added into the rpath based on the comma format, which is different with the previous case 4

/usr/bin/c++ -fPIC -shared -Wl,-soname,libhello.so -o libhello.so CMakeFiles/hello.dir/hello.cpp.o -Wl,-rpath,/home/zw/cworkspace/src/5MCST/cmake_example/Depedency/build/hello/helloinner: helloinner/libhelloinner.so

#5 same with previous case for build object file

#6 Do not contain the helloinner.so in linked library, only put it into the -rpath-link, which is different with previous one

/usr/bin/c++ -rdynamic CMakeFiles/main.dir/main.cpp.o -o main -Wl,-rpath,/home/zw/cworkspace/src/5MCST/cmake_example/Depedency/build/hello:/home/zw/cworkspace/src/5MCST/cmake_example/Depedency/build/hello/helloinner hello/libhello.so -Wl,-rpath-link,/home/zw/cworkspace/src/5MCST/cmake_example/Depedency/build/hello/helloinner

Between different projeccts

export and install export

https://cmake.org/cmake/help/latest/command/export.html

https://stackoverflow.com/questions/47534442/cmake-how-to-export-a-library-with-private-dependencies

static vs dynamic linnk from speed perspective

https://stackoverflow.com/questions/4667882/is-a-statically-linked-executable-faster-than-a-dynamically-linked-executable

References

gcc depedency file

https://stackoverflow.com/questions/97338/gcc-dependency-generation-for-a-different-output-directory

(you may track what is changed and instead of building whole things from the scratch)
http://www.electronvector.com/blog/using-gcc-for-automatic-c-language-dependency-management-with-rake

推荐文章