如何在scons中添加--whole-archive链接器选项?

时间:2014-03-02 00:50:47

标签: c++ linker scons

我有一个只在静态范围内与应用程序交互的库。这需要我将库与--whole-archive选项链接起来,以避免链接器“优化”库(这样做是因为链接器实际上从未看到我的库被使用)。

问题是我还没有找到为scons中的特定库添加此链接器选项的方法。

env.Append(LIBS=['mylib']) #I don't have the linker option
env.Append(LINKFLAGS=['-Wl,--whole-archive','-lmylib']) #I don't add myself to the scons dependency tree, I also get added to the link line before the LIBPATH variable.

如何在scons中优雅地支持链接器标志?

3 个答案:

答案 0 :(得分:2)

重新提问:

如何使用scons将静态库链接到带有-sole-archive链接标志的共享库,同时保持依赖关系。

我正在重述你的问题只是为了确保我们都清楚地了解你想要完成的事情。如果我没有正确捕捉你的问题的意图,请发表评论。

为什么它不适合你:

您无法在LIBS中包含该库,因为您希望使用--whole-archive标记来包围库。如果您将此条目放在LINKFLAGS中,它可以正常工作,但您将失去依赖关系跟踪。

答案:

当您将库从LIBS中的条目移动到LINKFLAGS中的条目时,您将失去隐式依赖项,但这很好,只需设置显式Depends的依赖关系。

工作示例:

文件布局

.
├── A.cpp
├── A.h
├── B.cpp
├── B.h
├── main.cpp
└── SConstruct

文件

A.cpp

#include "A.h"

int foo2(void) {
    return 2;
}

A.H

#ifndef __A__
#define __A__
int foo2(void);
#endif

B.cpp

#include "B.h"
#include "A.h"

int bar(void) {
    return 2 * foo2();
}

B.h

#ifndef __B__
#define __B__
int bar(void);
#endif

的main.cpp

#include <iostream>
#include "B.h"

using namespace std;

int main() {

    cout << "Sum of foo and bar = " << bar() << endl;
    return 0;
}

SConstruct

import os

# Top level Build Environment
env = Environment()

# Library A
envA = env.Clone()
libA = envA.StaticLibrary('A.cpp')

# Library B
envB = env.Clone()
envB.Append(LINKFLAGS=['-Wl,--whole-archive,./libA.a,--no-whole-archive'])
libB = envB.SharedLibrary('B.cpp')
Depends(libB, libA)

# Test Program
envE = env.Clone()
envE.Append(LIBS=['B'],
            LIBPATH=['.'],
            RPATH=[os.path.abspath(os.curdir)])
envE.Program('example', 'main.cpp')

运行:

将所有文件复制到同一目录,并在该目录中键入scons。如果你构建并要求依赖树,这是你应该在linux上看到的输出。 (我正在使用Fedora 21)

>> scons --version
SCons by Steven Knight et al.:
    script: v2.3.4, 2014/09/27 12:51:43, by garyo on lubuntu
    engine: v2.3.4, 2014/09/27 12:51:43, by garyo on lubuntu
    engine path: ['/usr/lib/scons/SCons']
Copyright (c) 2001 - 2014 The SCons Foundation

>> scons --tree=prune
scons: Reading SConscript files ...
scons: done reading SConscript files.
scons: Building targets ...
g++ -o A.o -c A.cpp
g++ -o B.os -c -fPIC B.cpp
g++ -o main.o -c main.cpp
ar rc libA.a A.o
ranlib libA.a
g++ -o libB.so -Wl,--whole-archive,./libA.a,--no-whole-archive -shared B.os
g++ -o example -Wl,-rpath=/full/path/to/build/directory main.o -L. -lB
+-.
  +-A.cpp
  +-A.h
  +-A.o
  | +-A.cpp
  | +-A.h
  | +-/bin/g++
  +-B.cpp
  +-B.h
  +-B.os
  | +-B.cpp
  | +-A.h
  | +-B.h
  | +-/bin/g++
  +-SConstruct
  +-example
  | +-main.o
  | | +-main.cpp
  | | +-B.h
  | | +-/bin/g++
  | +-/bin/g++
  | +-libB.so
  |   +-[B.os]
  |   +-libA.a
  |     +-[A.o]
  |     +-/bin/ar
  |     +-/bin/ranlib
  +-[libA.a]
  +-[libB.so]
  +-main.cpp
  +-[main.o]
scons: done building targets.

>> ./example
Sum of foo and bar = 4

示例的作用:

  • 构建静态库A.
  • 使用库A上的--whole-archive链接标志构建动态库B.
  • 构建一个链接在库B中的可执行文件,并执行库B中使用库A中的函数的函数。
  • 正确跟踪目标之间的依赖关系。

结论:

您可以从上面的依赖关系图中看到,库A被正确列为库B的依赖关系。

享受!

答案 1 :(得分:1)

Scons 仍然不支持-Wl,--whole-archive等链接标记。使用Kenneth E. Bellock提供的解决方案多年来一直运作良好。缺点是这容易出错。您必须小心管理手动依赖列表。

还有一种替代解决方法。将以下内容添加到SConstruct文件中:

whole_archive = env.Command('-Wl,--whole-archive', [], '')
no_whole_archive = env.Command('-Wl,--no-whole-archive', [], '')

现在,您可以使用整个归档/非整个归档以任意组合包装必要的库。例如:

so_libs = env.SharedLibrary('myso', whole_archive+['libfoo1.a']+no_whole_archive+['libbar.a']+whole_archive+['libfoo2.a']+no_whole_archive)

答案 2 :(得分:0)

您可以将LIBS和LINKFLAGS添加到链接器语句中。

env.SharedLibrary('target',sources,LIBS=['mylib'],LINKFLAGS=env['LINKFLAGS']+['-Wl,--whole-archive','-lmylib'])

例如。