带有共享库的递归Makefile

时间:2012-06-15 16:37:54

标签: makefile

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

./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

2 个答案:

答案 0 :(得分:2)

尝试摆脱递归的Makefile。虽然它们有点普遍,recursive make is inherently broken。它们很常见的主要原因是因为当你使用automake和autoconf时,这就是构建。然而,autoconf和automake都有很长的篇幅才能使递归的make结构正确而且我还没有看到任何人在没有这些工具的情况下获得递归的make结构。

只有少数几种用法,其中递归make本身并未被破坏,例如Cmake使用递归makefile的方式。但同样,这些makefile是由自动化工具构建的,所以这也很难手动完成。

编辑:以下是该文章的简短摘要。

递归makefile的主要问题是,它保持make构建完整的依赖图,这是以正确的顺序构建东西所需要的。递归make最初适用于需要一次构建多个项目而不需要它们之间存在任何依赖关系的情况。只要在递归结构中存在依赖关系,make就会很难修复订单。在最好的情况下,然后留下一个可以构建的系统,但是在编辑一些文件后尝试重建它时会中断。我已经看到很多情况,其中递归使得混乱,因此应用程序的一部分与编辑之前从源编译的库链接,另一部分链接到编辑后从源编译的库。这导致应用程序突然中断,这将在make clean && make之后奇迹般地出现。

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

在几乎所有情况下,当使用递归make时,完全无法实现并行make。至少我还没有看到一个可以与make -j X一起使用的手动递归制作结构。

有两种解决方案:

  • 使用其中一个工具构建makefile,例如autotools或cmake。然而,这需要学习一个更多的工具。此外,这些工具的可用性备受争议(至少对于autotools而言)。

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

答案 1 :(得分: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