Reputation: 1527
Please bear with this question, it is rather long.
TLDR: A CMake project with a subdirectory library links successfully, but creates a dynamic executable.
Code Available at: https://github.com/georcon/cmake-issue
Also Note: I have read all related questions/answers, and none answer this question.
I have created the following minimal example:
(Git Tag: SimpleExecutable)
main.c
#include <uuid/uuid.h>
#include <stdio.h>
int main(){
uuid_t some_uuid;
char uuid_str[40];
uuid_generate(some_uuid);
uuid_unparse(some_uuid, uuid_str);
printf("UUID: %s\n", uuid_str);
return 0;
}
CMakeLists.txt
project(cmake-issue VERSION 1.0 DESCRIPTION "Static target issue" LANGUAGES C)
add_executable(main-dynamic main.c)
target_link_libraries(main-dynamic uuid)
add_executable(main-static main.c)
target_link_libraries(main-static uuid -static)
Result
ldd main-dynamic
linux-vdso.so.1 (0x00007ffc406bb000)
libuuid.so.1 => /lib/x86_64-linux-gnu/libuuid.so.1 (0x00007f76781cd000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f7677fdb000)
/lib64/ld-linux-x86-64.so.2 (0x00007f76781eb000)
ldd main-static
not a dynamic executable
(Git Tag: ExecutableWithLibrary)
lib/lib.h
#ifndef LIB_H
#define LIB_H
void PrintUUID();
#endif //LIB_H
lib/lib.c
#include <uuid/uuid.h>
#include <stdio.h>
void PrintUUID(){
uuid_t some_uuid;
char uuid_str[40];
uuid_generate(some_uuid);
uuid_unparse(some_uuid, uuid_str);
printf("UUID: %s\n", uuid_str);
}
lib/CMakeLists.txt
cmake_minimum_required(VERSION 3.13)
project(testlibrary VERSION 1.0 DESCRIPTION "Static target issue - Library" LANGUAGES C)
add_library(testlib lib.c)
target_link_libraries(testlib uuid)
main.c
#include "lib/lib.h"
int main(){
PrintUUID();
return 0;
}
CMakeLists.txt
cmake_minimum_required(VERSION 3.13)
project(cmake-issue VERSION 1.0 DESCRIPTION "Static target issue" LANGUAGES C)
add_subdirectory(lib ./bin)
link_directories(./lib/ ./bin)
add_executable(main-dynamic main.c)
add_dependencies(main-dynamic testlib)
target_link_libraries(main-dynamic libtestlib.a uuid -static)
link_libraries("-static")
add_executable(main-static main.c)
target_link_libraries(main-static PUBLIC "-static" libtestlib.a uuid)
add_dependencies(main-static testlib)
#target_link_libraries(main-static libtestlib.a uuid -static)
Result
ldd main-static
linux-vdso.so.1 (0x00007ffe6b485000)
libuuid.so.1 => /lib/x86_64-linux-gnu/libuuid.so.1 (0x00007fc67edd3000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fc67ebe1000)
/lib/ld64.so.1 => /lib64/ld-linux-x86-64.so.2 (0x00007fc67edec000)
Looking at the linker command:
~/cmake_issue$ cat CMakeFiles/main-static.dir/link.txt /usr/bin/cc
CMakeFiles/main-static.dir/main.c.o -o main-static
-L/home/georcon/cmake_issue/./lib -L/home/georcon/cmake_issue/./bin -Wl,-rpath,/home/georcon/cmake_issue/./lib:/home/georcon/cmake_issue/./bin -static -static -Wl,-Bstatic -ltestlib -Wl,-Bdynamic -luuid
Why does CMake not generate a statically-linked executable in this case?
Upvotes: 3
Views: 3818
Reputation: 65928
Long story short: You need to tell CMake that you prefer static linking with the libraries.
This is done by setting property LINK_SEARCH_START_STATIC
. Also you need to tell CMake to not reset static linkage at the end of the libraries list.
This is done by setting property LINK_SEARCH_END_STATIC
:
set_target_properties(main-static PROPERTIES
LINK_SEARCH_START_STATIC ON
LINK_SEARCH_END_STATIC ON
)
See also that question: CMake and Static Linking.
Actually, the linker option -static
not only disables PIE, but also affects on further libraries listed in the command... unless -dynamic
is specified.
CMake has a notion about "default linking type", which is applied for every library (uuid
in your case) for which CMake cannot deduce its type. Moreover, CMake maintains that default linking type after each library it adds into the linker's command line. And CMake expects the same behavior from the user, who manually adds linker flags.
Your first example is wrong, but suddenly works:
You add -static
which turns current linkage type to static. And thus you break CMake expectations about current linkage type.
When produce the linker option for link with uuid, CMake expects that current linkage is dynamic. So, CMake doesn't add -dynamic
linker switch.
That time CMake expectations doesn't correspond to the reality, which in turn corresponds to your expectations: uuid
is linked statically.
But the second example reveals the problem:
When linking with libtestlib.a
library, CMake is perfectly aware that this is a static library, and thus adds Wl,-Bstatic
option before that library. But CMake need to maintain default linkage after every option, so it adds -Wl,-Bdynamic
after the library:
-Wl,-Bstatic -ltestlib -Wl,-Bdynamic
With such options CMake expectations about default dynamic linking corresponds to the reality: uuid
is linked dynamically. But now that reality doesn't correspond to yours expectations.
Upvotes: 2