3

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:

Create a statically-linked executable (Works correctly)

(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

Create a static executable with library

(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?

1
  • The library that is being built is a shared library by default, unless you specify otherwise. Try adding STATIC like this: add_library(testlib STATIC lib.c), and have a look at the CMake documentation of add_library(): cmake.org/cmake/help/v3.21/command/add_library.html Commented Jul 12, 2021 at 16:11

1 Answer 1

2

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.

What is going on

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.

Sign up to request clarification or add additional context in comments.

2 Comments

Looks like this was the solution - I still needed to keep -static at the start of the target_link_libraries. Is this best practice?
Additionally, the question quoted in this answer directly sets the CMAKE_EXE_LINKER_FLAGS - which from reading concluded this is discouraged. Is this correct?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.