【问题标题】:Using --whole-archive in CMake on a library you build在您构建的库上使用 CMake 中的 --whole-archive
【发布时间】:2017-09-12 05:47:50
【问题描述】:

我有一个 CMake 项目,同时构建一个静态库并将其与其他代码链接到一个可执行文件中。由于我不会详细介绍的原因,我希望使用 --whole-archive 链接器标志进行此链接。

现在,这个标志很棘手,因为你不能在任何地方添加它 - 你必须切换它,然后列出你想要它应用的库,然后取消它。

我在某处读到(URL 忽略了我),如果您有一个预先存在的库,您可以通过执行以下操作有效地添加此链接器标志:

# Just an example, find_library calls should really be isolated to separate find modules
find_library(FOO_LIBRARY foo)
set(FOO_LIBRARY "-Wl,--whole-archive ${FOO_LIBRARY} -Wl,--no-whole-archive")

add_executable(hello main.c)
target_link_libraries(hello ${FOO_LIBRARY})

这很好。但是,如果 正在构建一个静态库,而您没有预先存在的变量(即,您有一个 add_library() CMake 命令的东西)怎么办?您是否必须手动指示其路径而不是 ${FOO_LIBRARY}?或者您是否可以使用其他一些技巧来获取 CMake 为其在命令行上放置的路径?

另外,如果我要使用某种${FOO_LIBRARY}-like 字符串而不是我的静态库目标标识符 - 我相信 CMake 可能会丢失依赖项,即它可能不会重新链接到修改后的库(甚至构建它)因为 target_link_libraries 命令会看到一个奇怪的字符串而不是另一个目标的标识符。

【问题讨论】:

    标签: build cmake ld build-dependencies


    【解决方案1】:

    这可以使用:

    add_dependencies(the_exe the_static_lib)
    set_target_properties(the_exe LINK_FLAGS
        "-L/path/to/the_static_lib -Wl,--whole-archive,-lthe_static_lib,--no-whole-archive")
    

    -L/path/to/the_static_lib 的值透明地遵循您指定的输出目录 要成为的目标,或者目标的默认输出目录(如果不这样做)。例如。如果the_static_lib 是 只需在构建目录中输出,然后-L/path/to/the_static_lib 将是-L.

    这是一个以合理一般的方式说明的项目,我们在其中 具有用于源和标题的结构化子目录以及不同的常规 输出目录,binlib

    $ ls -R
    .:
    app  build  CMakeLists.txt  foobar  inc
    
    ./app:
    main.c
    
    ./build:
    
    ./foobar:
    bar.c  foo.c
    
    ./inc:
    foobar.h
    

    有文件:

    app/main.c

    #include <foobar.h>
    
    int main(void)
    {
        foo();
        bar();
        return 0;
    }
    

    foobar/foo.c

    #include <foobar.h>
    #include <stdio.h>
    
    void foo(void)
    {
        puts(__func__);
    }
    

    foobar/bar.c

    #include <foobar.h>
    #include <stdio.h>
    
    void bar(void)
    {
        puts(__func__);
    }
    

    inc/foobar.h

    #ifndef FOOBAR_H
    #define FOOBAR_H
    
    void foo(void);
    void bar(void);
    
    #endif
    

    CMakeLists.txt (1)

    cmake_minimum_required(VERSION 3.0)
    project(app)
    include_directories(inc)
    add_library(foobar STATIC foobar/foo.c foobar/bar.c)
    set_target_properties(foobar
        PROPERTIES ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib")
    add_executable(app app/main.c)
    add_dependencies(app foobar)
    set_target_properties(app PROPERTIES
        RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin"
        LINK_FLAGS "-Llib -Wl,--whole-archive,-lfoobar,--no-whole-archive")
    

    我们想从./foobar/foo.c./foobar/bar.c 生成./build/lib/libfoobar.a。 我们想从./app/main.c制作./build/bin/app,链接整个档案./build/lib/libfoobar.a

    生成、构建和运行:

    $ cd build; cmake ..; make; ./bin/app
    -- The C compiler identification is GNU 8.2.0
    -- The CXX compiler identification is GNU 8.2.0
    -- Check for working C compiler: /usr/bin/cc
    -- Check for working C compiler: /usr/bin/cc -- works
    -- Detecting C compiler ABI info
    -- Detecting C compiler ABI info - done
    -- Detecting C compile features
    -- Detecting C compile features - done
    -- Check for working CXX compiler: /usr/bin/c++
    -- Check for working CXX compiler: /usr/bin/c++ -- works
    -- Detecting CXX compiler ABI info
    -- Detecting CXX compiler ABI info - done
    -- Detecting CXX compile features
    -- Detecting CXX compile features - done
    -- Configuring done
    -- Generating done
    -- Build files have been written to: /home/imk/develop/so/cmake_prob/build
    Scanning dependencies of target foobar
    [ 20%] Building C object CMakeFiles/foobar.dir/foobar/foo.c.o
    [ 40%] Building C object CMakeFiles/foobar.dir/foobar/bar.c.o
    [ 60%] Linking C static library lib/libfoobar.a
    [ 60%] Built target foobar
    Scanning dependencies of target app
    [ 80%] Building C object CMakeFiles/app.dir/app/main.c.o
    [100%] Linking C executable bin/app
    [100%] Built target app
    foo
    bar
    

    类似地,例如而不是 CMakeLists.txt 我们有:

    CMakeLists.txt (2)

    cmake_minimum_required(VERSION 3.0)
    project(app)
    include_directories(inc)
    add_subdirectory(foobar)
    add_executable(app app/main.c)
    add_dependencies(app foobar)
    set_target_properties(app PROPERTIES
        RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin"
        LINK_FLAGS "-Llib -Wl,--whole-archive,-lfoobar,--no-whole-archive")
    

    和分开:

    foobar/CMakeLists.txt (1)

    add_library(foobar STATIC foo.c bar.c)
    set_target_properties(foobar
        PROPERTIES ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib")
    

    使用相同的分隔,但默认输出目录,我们将拥有:

    CMakeLists.txt (3)

    cmake_minimum_required(VERSION 3.0)
    project(app)
    include_directories(inc)
    add_subdirectory(foobar)
    add_executable(app app/main.c)
    add_dependencies(app foobar)
    set_target_properties(app PROPERTIES
        LINK_FLAGS "-Lfoobar -Wl,--whole-archive,-lfoobar,--no-whole-archive")
    

    foobar/CMakeLists.txt (2)

    add_library(foobar STATIC foo.c bar.c)
    

    会是这样的:

    $ cd build; cmake ..; make; ./app
    -- The C compiler identification is GNU 8.2.0
    -- The CXX compiler identification is GNU 8.2.0
    -- Check for working C compiler: /usr/bin/cc
    -- Check for working C compiler: /usr/bin/cc -- works
    -- Detecting C compiler ABI info
    -- Detecting C compiler ABI info - done
    -- Detecting C compile features
    -- Detecting C compile features - done
    -- Check for working CXX compiler: /usr/bin/c++
    -- Check for working CXX compiler: /usr/bin/c++ -- works
    -- Detecting CXX compiler ABI info
    -- Detecting CXX compiler ABI info - done
    -- Detecting CXX compile features
    -- Detecting CXX compile features - done
    -- Configuring done
    -- Generating done
    -- Build files have been written to: /home/imk/develop/so/cmake_prob/build
    Scanning dependencies of target foobar
    [ 20%] Building C object foobar/CMakeFiles/foobar.dir/foo.c.o
    [ 40%] Building C object foobar/CMakeFiles/foobar.dir/bar.c.o
    [ 60%] Linking C static library libfoobar.a
    [ 60%] Built target foobar
    Scanning dependencies of target app
    [ 80%] Building C object CMakeFiles/app.dir/app/main.c.o
    [100%] Linking C executable app
    [100%] Built target app
    foo
    bar
    

    【讨论】:

    • 这有点骇人听闻,但是,好吧,它似乎有效。
    • 这不起作用 100% add_dependencies(app foobar) 说,在 foobar 之后构建 app。但不是:如果foobar 需要重建,app 也需要重建!见documentation。最好也添加target_link_libraries(app foobar),即使这个链接没有或只有部分。
    猜你喜欢
    • 2015-08-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-04-07
    相关资源
    最近更新 更多