其他分享
首页 > 其他分享> > c – 如何让GNU __attribute __((构造函数))在库中工作?

c – 如何让GNU __attribute __((构造函数))在库中工作?

作者:互联网

如果我将所有目标文件链接在一个链接中,我可以使GNU __attribute __((构造函数))工作(对于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)并将LT_INIT添加到configure.ac,但这并没有改变结果.我将尝试为C提及的“使用显式构造函数的静态数据”技巧,但我仍然有兴趣知道如何使用__attribute __((构造函数))来使用我的示例.

编辑2015-02-23我尝试了“带有显式构造函数的静态数据”技巧但获得了与之前相同的结果:如果所有对象文件显式链接到可执行文件中,它可以工作,但如果我想要自动构建的东西是通过库链接到可执行文件.

添加hello_LDFLAGS = -Wl, – 整个存档(由David Grayson建议)会导致许多“多重定义”错误. Automake将这些标志放在link命令的开头附近,因此它不仅适用于库. Automake建议不要直接在hello_LDADD中包含链接器标志,其中指定了要链接的库.可以使用显式的Make规则覆盖Automake规则(我可以将链接器标记准确地放在我想要的位置),但是我可能会冒其他标准Make规则(由Automake提供)行为不端的风险.

我会看看我是否可以使用dlopen来使用它.

解决方法:

我想你有一个Linux系统.然后确保将库构建为共享库(请参阅here),而不是静态库.

加载该共享库时将调用具有__attribute __(构造函数)的函数,例如在ld.so时间,或者在dlopen时,如果库是一个加载的插件.

BTW __attribute __(构造函数)在C中比在C中更有用.在C中你并不真正需要它,因为你可以在其类中使用静态数据和一些显式定义的构造函数来实现相同的结果.

有关详细信息,请阅读Drepper’s paper: How to Write a Shared Library.

标签:c,linux,gnu,makefile,autotools
来源: https://codeday.me/bug/20190830/1765591.html