【问题标题】:How do I add --whole-archive linker option in scons?如何在 scons 中添加 --whole-archive 链接器选项?
【发布时间】:2014-03-02 00:50:46
【问题描述】:

我有一个仅在静态范围内与应用程序交互的库。这需要我使用 --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 中优雅地支持链接器标志?

【问题讨论】:

  • 2006 年有一个关于dev list 的讨论,谷歌帮我找到了。这表明也许这个问题已经解决了,但我仍然找不到合适的答案。
  • @cape1232 对不起,赏金将在 6 分钟后结束,您还没有将其授予任何人
  • @NabeelOmer 没有一个答案可以解决问题。我让赏金到期。
  • 我已经从这个问题中删除了一段时间,但我从未找到一个好的解决方案。供参考,但这就是让我完全停止使用 scons 的原因。

标签: c++ linker scons


【解决方案1】:

改写的问题:

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

我重申您的问题只是为了确保我们都清楚地了解您要完成的工作。如果我没有正确理解您的问题的意图,请发表评论。

为什么它不适合你:

您不能在LIBS 中包含该库,因为您想用--whole-archive 标志包围该库。如果您将此条目放在LINKFLAGS 中,它可以工作,但您会丢失依赖跟踪。

答案:

当您将库从 LIBS 中的条目移动到 LINKFLAGS 中的条目时,您将失去 implicit 依赖项,但这没关系,只需设置一个 explicitDepends 的依赖关系。

工作示例:

文件布局

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

文件

A.cpp

#include "A.h"

int foo2(void) {
    return 2;
}

啊.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;
}

S构造

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 的依赖。

享受吧!

【讨论】:

    【解决方案2】:

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

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

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

    现在,您可以使用 Whole-archive/no-whole-archive 以任意组合包装必要的库。示例:

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

    【讨论】:

      【解决方案3】:

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

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

      例如。

      【讨论】:

      • 这与亚历克斯的第二个选项有何不同?添加到 LINKFLAGS 的问题在于 LINKFLAGS 位于 LIBS 之前,但您可能不希望先链接 -lmylib。链接的顺序很重要。
      • 顺序对于链接静态库很重要,但对于共享库来说并不重要(或者至少不是以相同的方式)。他可能真正想要的是 LIBS=[WHOLELIB('mylib'),'otherlib'] 之类的东西,但目前 SCons 中还没有对此的直接支持。可以通过使用字符串替换逻辑的一些更高级的用法重新定义 _LIBFLAGS 来做到这一点。
      • 我对静态库有这个问题,像 LIBS=[WHOLELIB(mylib), ...] 这样的东西会很完美。叹息。
      猜你喜欢
      • 1970-01-01
      • 2010-10-22
      • 2015-08-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-04-21
      相关资源
      最近更新 更多