【发布时间】:2015-04-23 12:12:54
【问题描述】:
如果我在一个链接中将所有目标文件链接在一起,我可以让 GNU __attribute__((constructor)) 工作(对于 C++ 程序),但如果我将包含构造函数的目标文件存储在库中,它就不再工作了然后链接库而不是目标文件。我做错了什么?
Makefile.am:
SUBDIRS = src
src/Makefile.am:
bin_PROGRAMS = hello
hello_SOURCES = hello.cc register.cc register.hh myfunc.cc
src/hello.cc:
#include <iostream> // for cout
#include <map>
#include "register.hh"
int main(int argc, char* argv[])
{
std::cout << "Hello, World!" << std::endl;
std::cout << "Have " << functions.size() << " functions registered."
<< std::endl;
for (Function_map::iterator it = functions.begin(); it != functions.end(); ++it) {
std::cout << "Registered " << (*it).first << std::endl;
(*it).second();
}
return 0;
}
src/register.cc:
#include <map>
#include <string>
#include "register.hh"
Function_map functions;
void register_function(const std::string& name, Function f)
{
functions[name] = f;
}
src/register.hh:
#ifndef REGISTER_H_
#define REGISTER_H_
#include <map>
#include <string>
typedef void (*Function)();
typedef std::map<const std::string, Function> Function_map;
extern Function_map functions;
void register_function(const std::string& name, Function f);
#endif
src/myfunc.cc:
#include "register.hh"
#include <iostream>
void myfunc()
{
std::cout << "This is myfunc!" << std::endl;
}
__attribute__((constructor))
void register_myfunc()
{
register_function("MYFUNC", myfunc);
}
配置.ac:
AC_PREREQ([2.69])
AC_INIT([hello], [1.4], [bugs@my.domain])
AC_CONFIG_SRCDIR([src/hello.cc])
AC_CONFIG_HEADERS([config.h])
AC_CONFIG_AUX_DIR([auxiliary])
AM_INIT_AUTOMAKE([-Wall -Werror])
AC_PROG_CXX
AM_PROG_AR
AC_CONFIG_FILES([Makefile
src/Makefile])
AC_OUTPUT
所以所有 C++ 文件都被编译成目标文件,这些目标文件被链接到“hello”可执行文件中。
生成的“hello”程序的输出是:
Hello, World!
Have 1 functions registered.
Registered MYFUNC
This is myfunc!
如果我将 src/Makefile.am 更改为
bin_PROGRAMS = hello
hello_SOURCES = hello.cc register.cc register.hh
hello_LDADD = liblibrary.a
noinst_LIBRARIES = liblibrary.a
liblibrary_a_SOURCES = myfunc.cc
(即 myfunc.cc 编译成 myfunc.o 存储在 liblibrary.a 中,它与其他目标文件链接到 'hello'),然后 'hello' 的输出是
Hello, World!
Have 0 functions registered.
所以现在'register_myfunc'函数没有被执行。为什么不呢?
EDITED 2015-02-22(回应 Basile Starynkevitch 的回答):我使用的是 GNU/Linux (Fedora 20) 系统。我尝试使用 libtools 构建共享库,但没有成功。我调整了 src/Makefile.am 如下:
bin_PROGRAMS = hello
hello_SOURCES = hello.cc register.cc register.hh
hello_LDADD = liblibrary.la
noinst_LTLIBRARIES = liblibrary.la
liblibrary_la_SOURCES = myfunc.cc
liblibrary_la_LDFLAGS = -shared -fPIC
(首先是-shared,后来也是-fPIC)并将LT_INIT 添加到configure.ac,但这并没有改变结果。我将尝试您为 C++ 提到的“具有显式构造函数的静态数据”技巧,但我仍然想知道如何让我的示例与 __attribute__((constructor)) 一起使用。
EDITED 2015-02-23 我尝试了“带有显式构造函数的静态数据”技巧,但得到的结果与以前相同:如果所有对象文件都显式链接到一个可执行文件中,它就可以工作,但是如果我想要自动构建的东西通过库链接到可执行文件中,则不会。
添加hello_LDFLAGS = -Wl,--whole-archive(David Grayson 建议)会导致许多“多重定义”错误。 Automake 将这些标志放置在链接命令的开头附近,因此它不仅适用于库。 Automake 建议不要在 hello_LDADD 中直接包含链接器标志,其中指定了要链接的库。可以使用显式 Make 规则覆盖 Automake 规则(我可以将链接器标志准确地放在我想要它们的位置),但是我可能会冒其他标准 Make 规则(由 Automake 提供)行为不端的风险。
我会看看我是否可以使用dlopen 让它工作。
【问题讨论】:
标签: c++ linux makefile gnu autotools