使用gcc编译器时,它将一步链接和编译.但是,将源文件转换为目标文件然后在最后链接它们似乎是惯用的.对我来说,这似乎是不必要的.这不仅会使您的目录与一堆目标文件混乱,而且当您可以简单地将所有源文件添加到编译器时,它会使Makefile复杂化.例如,我认为这很简单:
.PHONY: all
SOURCES = $(wildcard *.cpp)
all: default
default:
g++ $(SOURCES) -o test
Run Code Online (Sandbox Code Playgroud)
整齐地成为:
g++ main.cpp test.cpp -o test
Run Code Online (Sandbox Code Playgroud)
但是,使用模式规则的更复杂的Makefile会使每个文件的输出混乱.例如:
.PHONY: all
SOURCES = $(wildcard *.cpp)
OBJECTS = $(SOURCES:.cpp=.o)
%.o: %.cpp
g++ -c -o $@ $<
all: default
default: $(OBJECTS)
g++ -o test $^
clean:
rm -rf *.o
g++ -c -o main.o main.cpp
g++ -c -o test.o test.cpp
g++ -o test main.o test.o
Run Code Online (Sandbox Code Playgroud)
对我来说,这似乎是不必要的复杂和容易出错.那么这种做法的原因是什么?
Mic*_*ald 12
为什么要编写Makefile而不是编写简单的shell脚本?在您考虑简单的例子,你让没有使用make的任何功能,你甚至可以编写一个能理解关键字简单的shell脚本build和clean,这就是它!
你实际上是在质疑Makefiles而不是shell脚本的问题,我将在我的回答中解决这个问题.
另请注意,在我们编译和链接三个中等大小的文件的简单情况下,任何方法都可能令人满意.因此,我将考虑一般情况,但使用Makefile的许多好处只对大型项目很重要.一旦我们学会了使我们能够掌握复杂案例的最佳工具,我们也希望在简单的情况下使用它.
编写Makefile类似于编写一个稍微改变透视的shell脚本.在shell脚本中,我们描述了一个问题的过程解决方案:我们可以使用未定义的函数以非常抽象的术语开始描述整个过程,并且我们会对这个描述进行优化,直到我们达到最基本的描述级别,其中一个过程就是一个普通的shell命令.在Makefile中,我们不介绍任何抽象,但我们关注的是我们想要生成的文件以及如何生成它们.这很有效,因为在UNIX中,一切都是文件,因此每个处理都是由一个程序完成的,该程序从输入文件中读取输入数据,进行一些计算并将结果写入一些输出文件.
如果我们想要计算复杂的东西,我们必须使用很多输入文件,这些输入文件由程序处理,其输出用作其他程序的输入,依此类推,直到我们生成包含结果的最终文件为止.如果我们将计划转换为将最终文件准备到shell脚本中的一系列过程中,那么处理的当前状态是隐式的:计划执行器知道"它在哪里",因为它正在执行给定的过程,隐含地保证已经完成了这样的和这样的计算,也就是说,已经准备好了这样的和这样的中间文件.现在,哪些数据描述了"计划执行者所在的位置"?
无害的观察 描述"计划执行者所在的位置"的数据正是已经准备好的中间文件集,这正是我们编写Makefile时明确的数据.
这种无害的观察实际上是shell脚本和Makefile之间的概念差异,它解释了Makefile在编译作业和类似作业中相对于shell脚本的所有优点.当然,要充分理解这些优点,我们必须编写正确的 Makefile,这对初学者来说可能很难.
当我们使用Makefile描述编译作业时,我们可以轻松地中断它并在以后恢复它.这是无害观察的结果.只有在shell脚本中付出相当大的努力才能实现类似的效果.
您发现Makefile会使源文件与对象文件混乱.但Makefiles实际上可以进行参数化以将这些目标文件存储在专用目录中,而高级Makefile允许我们同时拥有包含具有不同选项的项目的多个构建的多个目录.(例如,启用了不同的功能或调试版本等)这也是无害的观察结果,即Makefiles实际上围绕着一组中间文件进行了表达.
我们可以轻松地并行构建程序,因为这是许多版本的标准功能make.这也是无害观察的结果:因为"计划执行者所在的位置"是Makefile中的显式数据,因此可以对其make进行推理.在shell脚本中实现类似的效果需要付出很大的努力.
由于特殊的观点 - 也就是说,作为无害观察的另一个结果- 用于编写Makefile,我们可以轻松地扩展它们.例如,如果我们决定所有数据库I/O样板代码都应该由自动工具编写,我们只需要在Makefile中写入自动工具用作编写样板代码的输入的文件.没有更少,仅此而已.我们可以在我们喜欢的地方添加这个描述,make无论如何都会得到它.在shell脚本构建中执行此类扩展将比必要更难.
这种可扩展性简易性是Makefile代码重用的一个很大的动力.
| 归档时间: |
|
| 查看次数: |
1006 次 |
| 最近记录: |