【问题标题】:Generate Static Executable with CMake使用 CMake 生成静态可执行文件
【发布时间】:2021-07-12 15:57:34
【问题描述】:

请耐心等待,这个问题比较长。

TLDR:带有子目录库的 CMake 项目链接成功,但创建了一个动态可执行文件。

代码在:https://github.com/georcon/cmake-issue

另外注意:我已阅读所有相关问题/答案,但没有人回答这个问题。

我创建了以下最小示例:

创建一个静态链接的可执行文件(正常工作)

(Git 标签:SimpleExecutable)

ma​​in.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)

结果

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 标签: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)

ma​​in.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)

结果

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)

查看链接器命令:

~/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/./斌 - 静态 - 静态 -Wl,-Bstatic -ltestlib -Wl,-Bdynamic -luuid

为什么在这种情况下 CMake 不生成静态链接的可执行文件?

【问题讨论】:

标签: c cmake static-libraries static-linking


【解决方案1】:

长话短说:您需要告诉 CMake 您更喜欢静态链接与库。 这是通过设置属性LINK_SEARCH_START_STATIC 来完成的。您还需要告诉 CMake 不要在库列表末尾重置静态链接。 这是通过设置属性LINK_SEARCH_END_STATIC来完成的:

set_target_properties(main-static PROPERTIES
  LINK_SEARCH_START_STATIC ON
  LINK_SEARCH_END_STATIC ON
)

另请参阅该问题:CMake and Static Linking

发生了什么

实际上,链接器选项 -static 不仅会禁用 PIE,还会影响命令中列出的其他库...除非指定了 -dynamic

CMake 有一个关于“默认链接类型”的概念,它适用于 CMake 无法推断其类型的每个库(在您的情况下为 uuid)。此外,CMake 在添加到链接器命令行的每个库之后维护默认链接类型。 CMake 期望用户有相同的行为,他们手动添加链接器标志。

您的第一个示例错误,但突然有效

您添加-static,它将当前链接类型变为静态。因此,您打破了 CMake 对当前链接类型的期望。

当使用 uuid 生成链接器选项时,CMake 期望当前链接是动态的。所以,CMake 没有添加-dynamic 链接器开关。

那时 CMake 的期望与现实不相符,而现实又与您的期望相符:uuid 是静态链接的。

但第二个例子揭示了问题:

当与libtestlib.a 库链接时,CMake 完全知道这是一个静态库,因此在该库之前添加了Wl,-Bstatic 选项。但是CMake需要在每个选项之后保持默认链接,所以它在库之后添加了-Wl,-Bdynamic

-Wl,-Bstatic -ltestlib -Wl,-Bdynamic

有了这样的选项,CMake expectations 关于默认动态链接对应于现实:uuid 是动态链接的。但现在现实与你的期望不符。

【讨论】:

  • 看起来这是解决方案 - 我仍然需要在 target_link_libraries 的开头保留 -static。这是最佳做法吗?
  • 此外,此答案中引用的问题直接设置了CMAKE_EXE_LINKER_FLAGS - 从阅读中得出的结论是不鼓励这样做。这是正确的吗?
猜你喜欢
  • 2014-08-30
  • 2017-03-29
  • 1970-01-01
  • 2015-10-24
  • 1970-01-01
  • 2015-04-16
  • 1970-01-01
  • 1970-01-01
  • 2020-10-02
相关资源
最近更新 更多