I have the same problem as in Cmake adds nonexisting lib into linklibs.rsp (no answer there) (EDIT: apologies for the confusion; I mean the same problem in principle as the title of the question, in that I perceive cmake
to "add" libraries that I did not expect, albeit existing ones)
I have seen stop cmake target_link_libraries linking both object files of static lib in addtion to the static lib itself , where it is claimed:
This is the effect of target_sources command: with PUBLIC keyword it adds sources both for the library (static) and for anyone who links that library.
... with which I disagree, considering the example below.
Also, CMake: Link a library to library has an interesting quote:
I think it's CMake's default behavior to not link project2 to the external library, but to link both libraries to the executable. From the book "Mastering CMake".
Since static libraries do not link to the libraries on which they depend, it is important for CMake to keep track of the libraries so they can be specified on the link line of the executable being created.
This I think is also confirmed by the example in CMake: include library dependencies in a static library , where two static libraries are "merged"/"combined" by using ar
.
Anyways, here is a minimal example:
cd /tmp
mkdir cmake_lib_test
cd cmake_lib_test
nano genfiles.sh
As genfiles.sh
enter the following:
echo "char lib_a_func(void);" > lib_a.h
echo "#include \"lib_a.h\"
char lib_a_func(void) { return 'a'; }
" > lib_a.c
echo "char lib_b_func(void);" > lib_b.h
echo "#include \"lib_a.h\"
#include \"lib_b.h\"
char lib_b_func(void) { lib_a_func(); return 'b'; }
" > lib_b.c
echo "#include \"lib_a.h\"
#include \"lib_b.h\"
#include \"stdio.h\"
int main(void) {
printf(\"a: '%c', b: '%c'\\n\", lib_a_func(), lib_b_func());
return 0;
}
" > main.c
Then run this script to generate source files:
bash genfiles.sh
tree .
#.
#├── genfiles.sh
#├── lib_a.c
#├── lib_a.h
#├── lib_b.c
#├── lib_b.h
#└── main.c
Finally create a CMakeLists.txt
at the same location, with the contents:
project(main C)
cmake_minimum_required(VERSION 3.0)
cmake_policy(SET CMP0005 NEW)
set(BUILD_SHARED_LIBS OFF)
set(libA_LIB_SRCS lib_a.c)
add_library(libA STATIC ${libA_LIB_SRCS})
set_target_properties(libA PROPERTIES VERSION 1.0.0) #SOVERSION 1
target_link_libraries(libA PRIVATE ${M_LIBRARIES} ${ZLIB_LIBRARIES})
set(libB_LIB_SRCS lib_b.c)
add_library(libB STATIC ${libB_LIB_SRCS})
set_target_properties(libB PROPERTIES VERSION 1.0.0) # SOVERSION 1
target_link_libraries(libB libA)
set(main_SRCS main.c)
add_executable(main ${main_SRCS})
target_include_directories(main PRIVATE "/usr/include")
target_compile_options(main PRIVATE "-Wall")
target_link_libraries(main PRIVATE libA libB ${MAIN_LIBRARIES})
Then create a build folder, go there, and run cmake
with these options:
mkdir build
cd build
cmake --version
# cmake version 3.14.3
CC=gcc cmake \
-DM_LIBRARIES=/usr/lib/libm.a -DZLIB_LIBRARIES=/usr/lib/libz.a \
-DMAIN_LIBRARIES="/usr/lib/libintl.a;/usr/lib/libiconv.a" \
../ -DCMAKE_BUILD_TYPE=Debug -G "Unix Makefiles"
Once cmake
completes, I can immediately see the linker flags for the main executable/application:
$ cat CMakeFiles/main.dir/linklibs.rsp
liblibA.a liblibB.a /usr/lib/libintl.a /usr/lib/libiconv.a liblibA.a /usr/lib/libm.a /usr/lib/libz.a
And here is my problem:
- To begin with,
liblibA.a
andliblibB.a
got an extra prefix in the final output filename - how can I explicitly set the static library name? - More importantly: the CMakeLists.txt specified
target_link_libraries(main PRIVATE libA libB ${MAIN_LIBRARIES})
, and I specify-DMAIN_LIBRARIES="/usr/lib/libintl.a;/usr/lib/libiconv.a"
on the command line - so, I implicitly expect that the order of the libraries will be:
liblibA.a liblibB.a /usr/lib/libintl.a /usr/lib/libiconv.a
... but instead, I get the construction given above, where liblibA.a
is repeated, and after that the dependencies of (lib)libA.a
are appended.
And that means, I cannot "add" static libraries at the very end of the linker line, and thereby satisfy dependencies, by specifying MAIN_LIBRARIES
on the command line - which is what I want to achieve. (The simple example here actually compiled for me, but in my actual project the duplication and inability to order the static libraries causes linker errors).
So, my question would be:
- Can I somehow write a CMakeLists.txt file similar to the one given, such that the additional appending of
(lib)libA.a
and its dependencies, is disabled?- (though ... this would imply that
libA
would also contain the symbols of its dependencies, and that can be achieved only by "merging" with AR, so this is likely not possible). - At the very least, how can I avoid a duplicated
(lib)libA.a
on the linker line?
- (though ... this would imply that
- Alternatively, can I somehow rewrite the CMakeLists.txt file, so that when
MAIN_LIBRARIES
is specified on the command line, they will end up as the very last on the linker line - after the specified libraries, and all their dependencies, have been output?