【问题标题】:How to build *.so module in Automake and a libtool-using project?如何在 Automake 和使用 libtool 的项目中构建 *.so 模块?
【发布时间】:2012-12-06 14:24:39
【问题描述】:

我和others有同样的问题:

  • 我有一个由 libtoolAutomake 项目中生成的 *.la 文件(例如 module.la),
  • 但我需要它的*.so才能将其用于dlopen()(例如module.so)。

但是:项目是用--disable-shared 配置和构建的,以确保创建的主二进制文件是一个大的静态链接程序,例如main.x(更易于部署和调试)。因此不会创建*.so 文件。

main.x 程序是一个巨大的类似框架的应用程序,它能够通过dlopen() 加载扩展(模块)——尽管它是静态链接的。

当我手动构建module.so 时,这很好用。但是在Makefile.am 中使用它对我来说似乎是不可能的。是的,我可以写lib_LTLIBRARIES,但使用我的标准--disable-shared,我没有得到*.so 文件。

lib_LTLIBRARIES = module.la
module_so_SOURCES = module.cpp

文件module.la 已创建,dlopen() 拒绝加载(当然)。

我尝试将规则放入 Makefile.am 手动构建它并且有效:

# Makefile.am (yes, .am)
all: mm_cpp_logger.so

SUFFIXES = .so

%.so: %.cpp
    $(CXX) $(CXXFLAGS) -fPIC -fpic -c -I $(top_srcdir)/include -o $@  $<

%.so: %.o
    $(CXX) $(LDFLAGS) -shared -fPIC -fpic -o $@  $<

但这只能是一种解决方法。我没有得到所有好的自动功能,比如依赖检查和安装。

如何在Makefile.am-way 中使用--disable-shared(或具有相同效果)构建主程序的同时构建module.so

  • 我可以使用特殊的自动生成规则将 *.la 文件后处理为 *.so 文件吗?
  • 无论如何我可以调整lib_LTLIBRARIES 进程来创建*.so 文件吗?

【问题讨论】:

    标签: shared-libraries automake libtool


    【解决方案1】:

    您要查找的内容称为 module。您可以通过将-all-static 添加到应用程序的LDFLAGS 来告诉Autotools 创建一个静态二进制文件(可执行文件)。我认为这是使用 --disable-shared 配置标志的首选方式(它实际上是针对库而不是可执行文件)

    这样的事情应该可以解决问题:

    AM_CPPFLAGS=-I$(top_srcdir)/include
    
    lib_LTLIBRARIES = module.la
    module_la_LDFLAGS = -module -avoid-version -shared
    module_la_SOURCES = mm_cpp_logger.cpp
    
    bin_PROGRAMS = application
    application_LDFLAGS = -all-static
    application_SOURCES = main.cpp
    

    .so 文件将(像往常一样)最终位于 .libs/ 子目录中(当然,除非您安装它)。

    您可以一次性构建您的应用程序和插件(即使使用一个Makefile.am),因此无需多次调用configure

    Autotools 应该会自动检测到 -fPIC(和朋友)的使用。


    更新:这里有一个小技巧可以让共享库在您期望的地方可用。由于所有 shlib 最终都位于 .libs/ 中,因此有时将它们放在非隐藏目录中会很好。

    以下 makefile sn-p 创建便利链接(在支持符号链接的平台上;否则它们被复制)。只需将 sn-p 添加到您的 makefile(我通常使用 -include convenience-link.mk)就足够了(您可能需要在 configure.ac 中添加 AC_PROG_LN_S

    .PHONY: convenience-link clean-convenience-link
    
    convenience-link: $(lib_LTLIBRARIES)
        @for soname in `echo | $(EGREP) "^dlname=" $^ | $(SED) -e "s|^dlname='\(.*\)'|\1|"`; do  \
            echo "$$soname: creating convenience link from $(abs_builddir)/.libs to $(top_builddir)"; \
            rm -f $(top_builddir)/$$soname ; \
            test -e $(abs_builddir)/.libs/$$soname && \
            cd $(top_builddir) && \
            $(LN_S) $(abs_builddir)/.libs/$$soname $$soname || true;\
        done 
    
    clean-convenience-link:
        @for soname in `echo | $(EGREP) "^dlname=" $(lib_LTLIBRARIES) | $(SED) -e "s|^dlname='\(.*\)'|\1|"`; do  \
            echo "$$soname: cleaning convenience links"; \
            test -L $(top_builddir)/$$soname && rm -f $(top_builddir)/$$soname || true; \
        done 
            
    all-local:: convenience-link
    
    clean-local:: clean-convenience-link
    

    【讨论】:

    • 伙计,由于 libtool 问题,我现在不得不跳槽。我在我的其他“便利”库(不是我们讨论的那个)中用-static-libtool-libs替换了“应用程序”中的-all-static——我必须这样做,因为dl_blahblah()-stuff 在我这样做时使程序崩溃了@ 987654338@(我很确定这是罪魁祸首)。无论如何:唉,我仍然得到.libs/mm_cpp_logger.so——在为模块编写测试时我觉得有点尴尬。从.libs/ 加载它似乎......错误。不管我做什么,它总是到达那里是正常的吗?
    • 我更新了我的答案,以获得在.libs之外获取可用库的可能解决方案@
    • @umläute:很好的解决方案!不幸的是,干净的部分不起作用,因为所有包含“dlname=(.*)”的文件都在该部分启动之前被删除(因此 grep 不返回任何内容)。我已将您的 sn-p 硬拷贝到我的 Makefile.am 文件中
    【解决方案2】:

    我已经使用 noinst_LTLIBRARIES 宏解决了类似的问题。

    noinst_LTLIBRARIES 宏创建静态的、不可安装的库,仅供内部使用。如果您指定 --disable-static 配置选项,也会创建所有 noinst_LTLIBRARIES 静态库。

    lib_LTLIBRARIES = libtokenclient.la
    noinst_LTLIBRARIES = libtokenclient_static.la 
    
    libtokenclient_la_SOURCES = $(TOKEN_SERVER_CLIENT_SOURCES) cDynlib.c cDynlib.h token_mod.h
    libtokenclient_la_CFLAGS = @BASE_CFLAGS@
    libtokenclient_la_CXXFLAGS = $(libtokenclient_la_CFLAGS)
    libtokenclient_la_LIBADD = @B_BASE_OS_LIBS@
    libtokenclient_la_LDFLAGS = @LT_PLUGIN_LIBS_FLAGS@ @LIBS_FLAGS@ $(TOKEN_SERVER_CLIENT_EXPORT_SYMBOLS)
    
    libtokenclient_static_la_SOURCES = $(libtokenclient_la_SOURCES)
    libtokenclient_static_la_CFLAGS = $(libtokenclient_la_CFLAGS)
    libtokenclient_static_la_CXXFLAGS = $(libtokenclient_static_la_CFLAGS)
    
    token_test_SOURCES = $(TEST_SOURCES)
    token_test_LDADD = @B_BASE_OS_LIBS@ libtokenclient_static.la
    token_test_CFLAGS = @BASE_CFLAGS@
    token_test_CXXFLAGS = $(token_test_CFLAGS)
    

    我使用 noinst_LTLIBRARIES 静态库有两个原因:

    1. 为了加快编译时间,我创建了静态库来用作代码的中间容器,这些代码应该被多次链接:代码只编译一次,否则 automake 将为每个目标编译一次相同的源文件
    2. 将代码静态链接到某个可执行文件

    【讨论】:

      【解决方案3】:

      根据LT_INIT 的 libtool 文档,可以将构建划分为两个包:主应用程序和插件。这样你就可以(理论上)调用:

      ./configure --enable-shared=plugins
      

      一切都会如你所愿。

      【讨论】:

      • 你的回答给了我很好的谷歌关键词,我找到了a tutorial。唉,这似乎也假设我用--enable-shared 构建了所有东西。不过,有几个很好的提示。但是您指向的文档没有提到“插件”。包装好的?这意味着一个子configure.in,对吧?是的,这可能会奏效。我猜,带有模块的目录会有自己的configure.in
      • 是的,完全正确。 “插件”是指动态加载的扩展。它们(主应用程序和扩展)都将获得某种子配置来配置它们。也许您可以只使用一个扩展的子配置。
      猜你喜欢
      • 2014-08-05
      • 2019-11-15
      • 1970-01-01
      • 1970-01-01
      • 2011-10-29
      • 1970-01-01
      • 2011-04-05
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多