Makefile 在多个目录中生成文件

Makefile 在多个目录中生成文件,makefile,Makefile,我想建立一个应用程序,我有多个模块存储在多个目录。我决定遵循这个想法,即在每个目录中都有一个makefile,然后合并它。但是,作为一个初学者程序员,我仍然不知道如何做到这一点。首先,这样的“局部”生成文件是什么样子的。它们不能有main函数,因为每个二进制只能有一个,尽管当我试图编译它时,gcc会抱怨对main的引用未定义。其次,我不知道把所有这些模块放在一起会是什么样子 我将非常感谢任何帮助,但请尽量保持你的答案简单。Makefiles对我来说仍然是一种黑魔法。在你能用makefile做任何

我想建立一个应用程序,我有多个模块存储在多个目录。我决定遵循这个想法,即在每个目录中都有一个makefile,然后合并它。但是,作为一个初学者程序员,我仍然不知道如何做到这一点。首先,这样的“局部”生成文件是什么样子的。它们不能有main函数,因为每个二进制只能有一个,尽管当我试图编译它时,gcc会抱怨对main的引用未定义。其次,我不知道把所有这些模块放在一起会是什么样子


我将非常感谢任何帮助,但请尽量保持你的答案简单。Makefiles对我来说仍然是一种黑魔法。

在你能用makefile做任何事情之前,你必须知道没有makefile怎么做

<> P>因为你使用的是GCC,我会假设你的源代码是C++。 您还没有告诉我们您的目录结构是什么样子,所以我假设您在两个目录中有三个源文件:
primary/main.cc
other/foo.cc
other/bar.cc
。(我们以后可以处理像
foo.h
这样的头文件)并且您想要构建
myApp

第一步:用手做

要在一个命令中执行此操作,可以使用:

gcc -Wall primary/main.cc other/foo.cc other/bar.cc -o myApp
这将编译三个源文件,并将二进制对象链接到可执行文件
myApp

第二步:分步完成(在前一步完全完成之前不要尝试)

您可以采取中间步骤,将源文件编译为二进制对象文件,而不是使用一个命令进行构建:

gcc -Wall -c primary/main.cc -o primary/main.o
gcc -Wall -c other/foo.cc -o other/foo.o
gcc -Wall -c other/bar.cc -o other/bar.o
这将产生
alpha/main.o
beta/foo.o
beta/bar.o
。编译器不会抱怨
foo
bar
缺少
main()
函数,因为对象文件不需要函数。然后将对象链接到一个可执行文件中:

gcc -Wall primary/main.o other/foo.o other/bar.o -o myApp
第3步:在本地进行(在上一步能够完美工作之前,不要尝试此操作。)

与上一步一样,我们在
primary/
other/
中操作:

cd primary
gcc -Wall -c main.cc -o main.o
cd ../other
gcc -Wall -c foo.cc -o foo.o
gcc -Wall -c bar.cc -o bar.o
cd ..
gcc -Wall primary/main.o other/foo.o other/bar.o -o myApp
第4步:使用Makefile(在上一步工作正常之前,不要尝试此操作。)

我们可以让一个makefile执行步骤1,但这并不是真正必要的。在
primary
中编写一个makefile(即
primary/makefile
),如下所示:

main.o:
    gcc -Wall -c main.cc -o main.o
(gcc…的fromt中的空白是一个选项卡。)

现在试试这个:

cd primary
make
cd ../other
gcc -Wall -c foo.cc -o foo.o
gcc -Wall -c bar.cc -o bar.o
cd ..
gcc -Wall primary/main.o other/foo.o other/bar.o -o myApp
cd primary
make
cd ../other
make
cd ..
make
第5步:使用多个makefile(在前一步完全正常工作之前,不要尝试此操作。)

编写一个
其他/makefile

both: foo.o bar.o

foo.o:
    gcc -Wall -c foo.cc -o foo.o

bar.o:
    gcc -Wall -c bar.cc -o bar.o
以及顶部目录中的一个makefile,您正在该目录中构建
myApp

myApp:
    gcc -Wall primary/main.o other/foo.o other/bar.o -o myApp
现在试试这个:

cd primary
make
cd ../other
gcc -Wall -c foo.cc -o foo.o
gcc -Wall -c bar.cc -o bar.o
cd ..
gcc -Wall primary/main.o other/foo.o other/bar.o -o myApp
cd primary
make
cd ../other
make
cd ..
make
第6步:使用一个调用其他文件的Makefile(在上一步工作正常之前,不要尝试此操作)

编辑顶部生成文件:

myApp:
    cd primary; make
    cd other; make
    gcc -Wall primary/main.o other/foo.o other/bar.o -o myApp
现在试试:

make
如果所有这些都有效,那么您拥有的就是一个粗糙但有效的makefile系统。当您准备好卸下训练轮时,有许多改进是可能的

编辑:

如果一个子目录中有许多源文件(例如,
other/
),并且您不想手动在顶层makefile中维护列表,那么有几种方法可以处理它。这是一个:

OTHER_SOURCES := $(wildcard other/*.cc)

OTHER_OBJECTS := $(OTHER_SOURCES:.cc=.o)

myApp:
    cd primary; make
    cd other; make
    gcc -Wall primary/main.o $(OTHER_OBJECTS) -o myApp

但是,在尝试进一步优化之前,您应该让这些生成文件正常工作并理解它们。

感谢您提供的精彩教程!如果每个模块目录中有大量的文件怎么办?写第六步的最后一行会让人非常恼火。有解决办法吗?例如,将所有.o文件合并到每个目录中,或者告诉makefile从给定目录中获取所有.o文件?您也可以使用
-C
来更改目录并读取该目录中的makefile。@Aif:是的,我使用
-C
,但我试图保持原始状态。正如我所说,许多改进是可能的。(我听说,
-C
实际上并不符合POSIX…)回答得真棒!很好的分步解释:)可能重复