__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);
}
configure.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' 函数为什么没有被执行?
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
,并在configure.ac中添加了LT_INIT
,但结果没有改变。我将尝试你提到的用于C++的“具有显式构造函数的静态数据”技巧,但我仍然想知道如何使用__attribute__((constructor))
使我的示例工作。
编辑 2015-02-23 我尝试了“具有显式构造函数的静态数据”技巧,但得到了与之前相同的结果:如果所有对象文件都明确链接到可执行文件中,它将起作用,但如果要自动链接到库中的可执行文件,则不起作用。
添加hello_LDFLAGS = -Wl,--whole-archive
(由David Grayson建议)会导致许多“多重定义”错误。 Automake将这些标志放置在链接命令的开头附近,因此它不仅适用于库。 Automake不建议直接在指定要链接的库的hello_LDADD
中包含链接器标志。可以使用显式Make规则覆盖Automake规则(在其中可以将链接器标志放在我想要它们的任何位置),但是那么我可能会冒着其他标准Make规则(由Automake提供)无法正常工作的风险。
我会尝试使用dlopen
来使其工作。