在您建立的库中的CMake中使用--whole-archive [英] Using --whole-archive in CMake on a library you build

查看:395
本文介绍了在您建立的库中的CMake中使用--whole-archive的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在构建静态库并将其与其他代码链接到可执行文件时,我有一个CMake项目.由于我不愿讨论的原因,我希望使用--whole-archive链接器标志进行此链接.

I have a CMake project while builds a static library and links it with other code into an executable. For reasons I won't go into, I want this linking to happen with the --whole-archive linker flag.

现在,此标志非常棘手,因为您不能仅将其添加到任何地方-您必须对其进行切换,然后列出要对其应用的库,然后取消对其进行切换.

Now, this flag is tricky, since you can't just add it anywhere - you have to toggle it, then list the libraries for which you want it to apply, then untoggle it.

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

I've read somewhere (the URL escapes me) that if you have a pre-existing library, you can effectively add this linker flags by doing the following:

# 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在命令行中放置的路径?

and that's fine. But what if it's a static library that you are building for which you don't have a pre-existing variable (i.e. something for which you have an add_library() CMake command)? Do you have to manually indicate its path instead of ${FOO_LIBRARY}? Or is there some other trick you can use to obtain the path CMake would put on the command-line for it?

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

Also, if I were to use some kind of ${FOO_LIBRARY}-like string instead of my static library target identifier - I believe CMake might miss the dependency, i.e. it might not re-link with the modified library (or not even build it) because the target_link_libraries command will see a strange string rather than the identifier of another target.

推荐答案

这可以使用:

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.

The value of -L/path/to/the_static_lib follows transparently from what you specify the output directory of the target to be, or the default output directory of the target if you don't. E.g. if the_static_lib is just output in the build directory, then -L/path/to/the_static_lib would be -L.

这是一个以合理的一般方式说明的项目, 具有用于源和标头的结构化子目录,以及常规的 输出目录binlib

Here is a project to illustrate in a reasonably general way, where we have structured subdirectories for sources and headers and distinct conventional output directories, bin, lib

$ 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

We want to make ./build/lib/libfoobar.a from ./foobar/foo.c and ./foobar/bar.c. And we want to make ./build/bin/app from ./app/main.c, linking the whole archive ./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,我们有:

Similarly if, e.g. instead of that CMakeLists.txt we have:

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")

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

And with the same separation, but default output directories, we'd have:

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

这篇关于在您建立的库中的CMake中使用--whole-archive的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆