0

我正在为一个项目创建一个 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.soclassification.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
4

2 回答 2

2

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

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

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

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

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

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

有两种解决方案:

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

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

于 2012-06-15T16:56:13.907 回答
1

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

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

于 2012-06-16T14:24:49.570 回答