How do I add --whole-archive linker option in scons?

谁都会走 提交于 2019-12-24 03:30:28

问题


I have a library that only interacts in static scope with an application. This requires me to link the library with the --whole-archive option to avoid the linker from "optimizing" out the library (this is done because the linker never actually sees my library being used).

The issue is that I haven't found a way to add this linker option for a specific library in 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.

How do I support linker flags elegantly in scons?


回答1:


Reworded Question:

How do I link a static library into a shared library with the --whole-archive link flag, with scons, while maintaining dependencies.

I am restating your question just to make sure we both have a clear understanding of what you are trying to accomplish. Please comment if I am not properly capturing the intent of your question.

Why it is not working for you:

You cannot include the library in LIBS, because you want to surround the library with the --whole-archive flags. If you place this entry in the LINKFLAGS it could work, but you lose your dependency tracking.

Answer:

When you move the library from an entry in LIBS to an entry in LINKFLAGS you lose the implicit dependency, but that's fine, just set an explicit dependency with Depends.

Working Example:

File Layout

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

Files

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

To Run:

Copy all the files to the same directory, and type scons in that directory. This is the output you should see on linux if you build and ask for the dependency tree. (I'm using 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

What The Example Does:

  • Builds a static library A.
  • Builds a dynamic library B with the --whole-archive link flag on library A.
  • Builds an executable that links in library B and executes a function from library B that utilizes a function in library A.
  • Properly tracks dependencies between targets.

Conclusion:

You can see from the dependency graph above that library A is correctly listed as a dependency of library B.

Enjoy!




回答2:


Scons still doesn't support link flags such as -Wl,--whole-archive. Using the solution provided by Kenneth E. Bellock is has been working well for many years. The downside is that this is error prone. You have to be careful to manage your manual dependency list.

There is an alternate workaround. Add the following to your SConstruct file:

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

Now you can wrap the necessary libraries with whole-archive/no-whole-archive in any combination. Example:

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



回答3:


You can add LIBS and LINKFLAGS to your linker statement.

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

For example.



来源:https://stackoverflow.com/questions/22122498/how-do-i-add-whole-archive-linker-option-in-scons

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!