【问题标题】:Recursive Makefile with Shared Libs具有共享库的递归 Makefile
【发布时间】:2012-06-15 16:37:54
【问题描述】:

我正在为一个项目创建一个 Makefile。我有 Makefiles 的以下结构:

./Makefile
./classification/Makefile
./misc/Makefile
./APP/Makefile
./qr/libs/Makefile

我正在执行递归make。在每个目录中,我都有一个生成共享库的 Makefile。因此,在./classification 文件夹中,我将生成classification.so,从而生成其他目录。一般来说,它们具有以下结构:

include ../standard_defs.mk

xCFLAGS=$(CFLAGS) -fPIC

SOURCES=help.cpp
OBJECTS=$(SOURCES:.cpp=.o)
EXECUTABLE=misc.so

xxDET=detection/$(EXECUTABLE)
export xxDET;

all: $(SOURCES) $(EXECUTABLE)

$(EXECUTABLE): $(OBJECTS) 
    $(CC) $(OBJECTS) -shared -o $@


.cpp.o:
    $(CC) $(xCFLAGS) $< -c

clean:
    rm -f $(OBJECTS) $(EXECUTABLE)

而主 Makefile (./Makefile) 的结构如下:

CFLAGS=`pkg-config opencv --cflags`
LDFLAGS=`pkg-config opencv --libs`

include standard_defs.mk

SOURCES=DataFormatDetResult.cpp  InputDataFiles.cpp  InputImage.cpp \
    InputManager.cpp  main.cpp  maths.cpp  misc.cpp

OBJECTS=$(SOURCES:.cpp=.o)
EXECUTABLE=featureExtractor

all: $(LIBS) $(SOURCES) $(EXECUTABLE) 

$(EXECUTABLE): $(OBJECTS)
    make -C misc
    make -C qr/libs
    make -C classification
    make -C APP
    $(CC) $(CFLAGS) $(OBJECTS) -o $@ $(LDFLAGS) misc/misc.so qr/libs/ap.so classification/classification.so APP/app.so

.cpp.o:
    $(CC) $(CFLAGS) $< -c

clean:
    make -C misc clean
    make -C qr/libs clean
    make -C APP clean
    make -C classification clean
    rm -f *.o $(EXECUTABLE)

错误

当我尝试编译主 Makefile 时,出现以下链接错误:

classification/classification.so: undefined reference to `Help::InsertHelpType(std::basic_string<char, std::char_traits<char>, std::allocator<char> >)'
classification/classification.so: undefined reference to `Help::Help()'
collect2: ld returned 1 exit status
make: ** [featureExtractor] Erro 1

misc.so 包含Help 类,似乎classification.so 在最终编译中找不到它。但是,如果我运行 make -C ./classification/,我不会收到任何错误。

问题 1

如何解决这个链接问题?

失败的解决方案

我尝试将misc.so 链接到classification.so,在./classification/Makefile 中执行此操作:

$(EXECUTABLE): $(OBJECTS)
    $(CC) $(OBJECTS) -shared -o $@ $(LDFLAGS) ../misc/misc.so

但它没有用。我得到的只是一个新的警告

/usr/bin/ld: warning: ../misc/misc.so, needed by classification/classification.so, not found (try using -rpath or -rpath-link)

问题 2

有没有更好的方法来为这个项目创建一个 Makefile?


编辑 1: 如果我运行 make -C ./classification/,它会生成 ./classification/classification.so 而不会出错。然后,如果我在./ 中运行make,我会得到同样的错误。


编辑 2: 当我运行 nm --format sysv misc.so | grep Help 时,我得到了:

$ nm --format sysv misc.so | grep Help
HelpTypes           |0000000000205120|   D  |            OBJECT|0000000000000038|     |.data
_ZN11HelpControl9PrintHelpEv|0000000000002180|   T  |              FUNC|000000000000082e|     |.text
_ZN11HelpControlC1Ev|00000000000029b0|   T  |              FUNC|0000000000000187|     |.text
_ZN11HelpControlC2Ev|00000000000029b0|   T  |              FUNC|0000000000000187|     |.text
_ZN4Help14InsertHelpTypeESs|0000000000001ac0|   T  |              FUNC|0000000000000126|     |.text
_ZN4Help9PrintHelpEi|0000000000001bf0|   T  |              FUNC|000000000000020d|     |.text
_ZN4HelpC1Ev        |0000000000001e00|   T  |              FUNC|000000000000021a|     |.text
_ZN4HelpC2Ev        |0000000000001e00|   T  |              FUNC|000000000000021a|     |.text
_ZN4HelpD1Ev        |0000000000003090|   W  |              FUNC|000000000000039b|     |.text
_ZN4HelpD2Ev        |0000000000003090|   W  |              FUNC|000000000000039b|     |.text
_ZNSt8_Rb_treeISsSt4pairIKSs4HelpESt10_Select1stIS3_ESt4lessISsESaIS3_EE8_M_eraseEPSt13_Rb_tree_nodeIS3_E|0000000000003430|   W  |              FUNC|0000000000000526|     |.text

【问题讨论】:

  • 你的意思是如果你make -C ./classification然后make,Make构建可执行文件(featureExtractor)没有错误?没有关于 undefined Help 方法的投诉?
  • 不,当我运行make -C ./classification 时,它会生成./classification/classification.so 而不会出现错误。当我在./ 中运行make 时,我得到了同样的错误。
  • 进入./misc 并尝试nm --format sysv misc.so | grep Help 看看你会得到什么。
  • 我将输出放在我的问题中,在 EDIT 2 中。

标签: makefile


【解决方案1】:

尝试摆脱递归 Makefile。尽管它们有些常见,recursive make is inherently broken。它们很常见的主要原因是,当你有 automake 和 autoconf 时,这是构建的。然而,autoconf 和 automake 都竭尽全力使递归 make 结构正确,而且我似乎还没有任何人在没有这些工具的情况下获得正确的递归 make 结构。

只有少数使用递归 make 本身并没有被破坏,例如 Cmake 使用递归 makefile 的方式。但是同样,这些 makefile 是由自动化工具构建的,因此手动也很难做到这一点。

编辑:这是文章的简短摘要。

递归 makefile 的主要问题是,它使 make 无法构建完整的依赖关系图,而它需要以正确的顺序构建东西。递归 make 最初适用于需要一次构建多个项目的情况,它们之间没有任何依赖关系。只要在递归结构中存在依赖关系,make 就会使修复顺序变得非常困难。在最好的情况下,留下一个可以构建的系统,但在编辑一些文件后尝试重建它时会中断。我见过很多情况,其中递归 make 搞砸了,因此应用程序的一部分与编辑前从源编译的库链接,另一部分与编辑后从源编译的库链接。这会导致应用程序突然中断,它会奇迹般地出现在make clean &amp;&amp; make 之后。

在其他情况下,递归 make 可能会完全搞乱构建。当目标以绝对错误的顺序开始执行时,就是这种情况。这意味着普通的构建是不可能的。您的示例似乎是其中一种情况。虽然我没有仔细研究过,但似乎 make 并没有正确构建所有需要的库,因为它并不完全了解依赖关系。

在几乎所有情况下,当使用递归 make 时,并行 make 是完全不可能的。至少我还没有看到可以可靠地与 make -j X 一起使用的手动递归 make 结构。

有两种解决方案:

  • 使用其中一种工具构建 makefile,例如 autotools 或 cmake。但是,这需要再学习一种工具。这些工具的可用性也备受争议(至少对于自动工具而言)。

  • 通过提供一个 makefile 来摆脱递归结构,make 可以从中导出完整的依赖关系图。我已经看到有些人实际上在一个文件中执行此操作,即使有多个库和自动源检测,但我不会,所以我不推荐这样做。更好的是拥有多个文件,每个子目录一个,然后使用include 将它们组合成目录树根目录下的一个大文件。这种方式 make 只能在树的根部调用,但它总是会知道完整的依赖集。这种方式也是文章推荐的。

【讨论】:

  • 你建议我使用这些工具之一吗?哪一个:autoconfautomakecmake
  • 嗯,不,不一定。我认为 autotools(即 autoconf 和 automake)是一种在不同路径下安装不同库集的不同系统下配置项目的好方法。 Cmake 类似,但也尝试多平台。然而,如果系统配置是众所周知的,几乎不需要其他依赖项,那么这些工具完全是多余的。在这种情况下,手写的 makefile 是最好的方法。我链接的文章中有一些想法,但我会在编辑中再次总结要点。
  • 下次我不会使用递归 Makefile。如果我需要对一个小项目做一个Makefile,我会研究如何使用那些include来创建一个单独的Makefile;如果是更大的项目,我会使用cmakeautotools。对于这个问题的项目,特别是最好的解决方案是使用cmake,因为它会在不同的计算机和配置下编译。谢谢!
【解决方案2】:

您没有给我们足够的信息来重现错误,因此这可能需要多次迭代。

misc/ 中,我们需要一种方法来测试Help 类。如果您还没有,请在misc/ 中为此目的编写一些简单的代码:

//test_help.cpp
#include "help.h"

int main()
{
  Help H;

  return(0);
}

试试看:

make test_help.o help.o
g++ test_help.o help.o -o test_help
./test_help

然后是图书馆:

make misc.so
g++ test_help.o misc.so -o test_help
./test_help

然后将test_help.cpp移动到上层目录并从那里尝试:

make test_help.o
g++ test_help.o misc/misc.so -o test_help
./test_help

然后在主 Makefile 中添加一条规则:

test_help: test_help.o
    make -C misc
    $(CC) $(CFLAGS) $< -o $@ misc/misc.so
    ./$@

并尝试make clean ; make test_help

【讨论】:

  • 1) 我已经尝试了第一个测试,它没有问题。 2) 当我运行第二个测试时,我得到:./test_help: error while loading shared libraries: misc.so: cannot open shared object file: No such file or directory 3) 第三个测试没有任何问题 4) 第四个测试返回错误:misc/misc.so: undefined reference to 'ReportError(char const*, ...)' collect2: ld returned 1 exit status make: ** [test_help] Erro 1
  • 做这个测试我意识到要编译help.o我需要./misc.o,其中包含ReportError(char const*, ...)的声明。因此,为了进行测试,我不得不在编译命令中添加../misc.o,例如:g++ test_help.o help.o ../misc.o -o test_help。请注意,misc.omisc.so 不同
  • 谢谢@Beta。使用您的测试我可以修复错误。我只需将misc.{cpp,h} 移动到misc/ 目录并更改其他源文件中的includes。 misc.so 没有正确编译,因为这些源文件丢失了。你通过的测试用例非常有用,当我再次遇到 Makefile 问题时我会使用它,主要是如果我正在为一个我不完全熟悉的项目开发一个——比如这个。
  • 很高兴能帮上忙。请记住,图书馆意味着一种信仰行为。
猜你喜欢
  • 2010-10-27
  • 2017-10-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-07-28
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多