分别创建对象文件然后在Makefile中将它们链接在一起的目的是什么? [英] What is the purpose of creating object files separately and then linking them together in a Makefile?

查看:136
本文介绍了分别创建对象文件然后在Makefile中将它们链接在一起的目的是什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当使用gcc编译器时,它将在一个步骤中链接和编译。但是,将源文件转换为对象文件,然后在最后链接它们似乎是惯用的。对我来说,这似乎是不必要的。这不仅会使您的目录与一堆目标文件混乱,但它会使Makefile变得复杂,当您可以简单地将所有源文件都粘贴到您的编译器。例如,以下是我认为简单的:

  .PHONY:all 

SOURCES = $ (wildcard * .cpp)

all:default
默认值:
g ++ $(SOURCES)-o test

这变得很简单:

  g ++ main.cpp test.cpp  - 但是,使用模式规则的更复杂的Makefile会使每个文件的输出变得混乱。。例如:

  .PHONY:all 

SOURCES = $(wildcard * .cpp)
OBJECTS = $(SOURCES:.cpp = .o)

%.o:%.cpp
g ++ -c -o $ @ $&

all: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

对我来说,这似乎不必要的复杂和容易出错。那么这个做法的原因是什么?

解决方案

为什么要写一个Makefile而不是写一个简单的shell脚本?在你认为简单的例子中,你不使用make的任何功能,你甚至可以编写一个简单的shell脚本来理解关键字 build clean ,就是这样!



你实际上在质疑Makefiles而不是shell脚本,我的回答。



还要注意,在简单的情况下,我们编译和链接三个中等大小的文件,任何方法可能是令人满意的。因此,我将考虑一般情况,但使用Makefile的许多好处只对大型项目很重要。一旦我们学到了最好的工具,使我们能够掌握复杂的情况,我们也想在简单的情况下使用它。



shell脚本的过程范例编译错误like like



编写Makefile类似于编写一个稍微改变透视的shell脚本。在shell脚本中,我们描述了一个问题的程序性解决方案:我们可以开始使用未定义的函数以非常抽象的方式描述整个过程,并且我们改进这个描述,直到我们达到最基本的描述层次,其中一个过程只是一个简单的shell命令。在Makefile中,我们不介绍任何抽象,但是我们专注于我们想要生成的文件以及如何生成它们。这很好,因为在UNIX中,一切都是一个文件,因此每个处理由一个程序完成,它从输入文件读取其输入数据,做一些计算和写结果在一些输出文件中。



如果我们想计算复杂的东西,我们必须使用很多输入文件,输出用作其他程序的输入,等等,直到我们产生了包含我们的结果的最终文件。如果我们翻译计划以使我们的最终文件在shell脚本中准备好一堆程序,那么处理的当前状态是隐式的::计划执行者知道它在哪里,因为它正在执行给定的过程,其隐含地保证这样的和这样的计算已经完成,也就是说,这样的和这样的中间文件已经准备好了。现在,哪些数据描述了计划执行者在哪里?



无意义的观察是在正好是已经准备好的中间文件的集合,这正是我们写Makefiles时明确的数据。



无害的观察实际上是shell脚本和Makefile之间的概念差异,这解释了Makefile在编译作业和类似作业中的所有shell脚本的优点。当然,要充分体会这些优势,我们必须写入正确的 Makefile,这对初学者可能很难。



继续中断的任务,它位于



当我们使用Makefile描述一个编译作业时,我们可以轻松地中断它,并在以后恢复。这是无害的观察结果。只要在shell脚本中付出相当大的努力就可以达到类似的效果。



Make使得可以轻松地处理项目的多个版本



您观察到Makefiles会使用目标文件混淆源代码树。但是Makefile实际上可以被参数化以将这些目标文件存储在专用目录中,而高级Makefile允许我们同时有几个目录包含具有不同选项的项目的几个构建。 (例如,启用了不同的功能,或调试版本等)这也是无害的观察结果 Makefiles实际上围绕中介文件集。



使得易于并行构建



我们可以轻松地并行构建一个程序,因为这是许多版本的 make 。这也是无害的观察的结果:因为计划执行者在哪里是Makefile中的显式数据,所以 make 来推理。在shell脚本中实现类似的效果需要付出很大的努力。



Makefile是容易扩展的



特殊的观点 - 也就是说,作为无害的观察的另一个结果 - 用于写Makefiles,我们可以很容易地扩展它们。例如,如果我们决定所有的数据库I / O样板代码都应该用自动工具编写,我们只需在Makefile中写入自动工具用作输入的文件来编写样板代码。没什么,没有更多。我们可以在我们喜欢的地方添加这个描述, make 会得到它。在shell脚本构建中执行这样的扩展将比必要的更难。



这种可扩展性简化是Makefile代码重用的一个很大的动机。


When using the gcc compiler, it will link and compile in one step. However, it appears to be idiomatic to turn source files into object files and then link them at the end. To me, this seems unnecessary. Not only does this clutter up your directories with a bunch of object files, but it complicates the Makefile when you can simply tack on all the source files to your compiler. For example, here's what I consider to be simple:

.PHONY: all

SOURCES = $(wildcard *.cpp)

all: default
default:
    g++ $(SOURCES) -o test

Which neatly becomes:

g++ main.cpp test.cpp -o test

However, more complicated Makefiles which use pattern rules would clutter the output for each and every file. For example:

.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

To me, this seems unnecessary complicated and error prone. So what are the reason(s) for this practice?

解决方案

Why do you want to write a Makefile and not write a simple shell script? In the example that you consider simple, you make no use of any feature of make, you could even write a simple shell script that understands the keywords build and clean, and that's it!

You are actually questioning about the point of writing Makefiles instead of shell scripts, and I will address this in my answer.

Also note that in the simple case where we compile and link three moderately sized files, any approach is likely to be satisfying. I will therefore consider the general case but many benefits of using Makefiles are only important on larger projects. Once we learned the best tool which allows us to master complicated cases, we want to use it in simple cases as well.

The procedural paradigm of shell scripts is wrong for compilation-like jobs

Writing a Makefile is similar to writing a shell script with a slight change of perspective. In a shell script, we describe a procedural solution to a problem: we can start to describe the whole procedure in very abstract terms using undefined functions, and we refine this description until we reached the most elementary level of description, where a procedure is just a plain shell command. In a Makefile, we do not introduce any abstraction, but we focus on the files we want to produce and how we can produce them. This works well because in UNIX, everything is a file, therefore each treatment is accomplished by a program which reads its input data from input files, do some computation and write the results in some output files.

If we want to compute something complicated, we have to use a lot of input files which are treated by programs whose outputs are used as inputs to other programs, and so on until we have produced our final files containing our result. If we translate the plan to prepare our final file into a bunch of procedures in a shell script, then the current state of the processing is made implicit: the plan executor knows "where it is at" because it is executing a given procedure, which implicitly guarantees that such and such computations were already done, that is, that such and such intermediary files were already prepared. Now, which data describes "where the plan executor is at" ?

Innocuous observation The data which describes "where the plan executor is at" is precisely the set of intermediary files which were already prepared, and this is exactly the data which is made explicit when we write Makefiles.

This innocuous observation is actually the conceptual difference between shell scripts and Makefiles which explains all the advantages of Makefiles over shell scripts in compilation jobs and similar jobs. Of course, to fully appreciate these advantages, we have to write correct Makefiles, which might be hard for beginners.

Make makes it easy to continue an interrupted task where it was at

When we describe a compilation job with a Makefile, we can easily interrupt it and resume it later. This is a consequence of the innocuous observation. A similar effect can only be achieved with considerable efforts in a shell script.

Make makes it easy to work with several builds of a project

You observed that Makefiles will clutter the source tree with object files. But Makefiles can actually be parametrised to store these object files in a dedicated directory, and advanced Makefiles allow us to have simultaneously several directories containing several builds of a project with distinct options. (For instance, with distinct features enabled, or debug versions, etc.) This is also consequence of the innocuous observation that Makefiles are actually articulated around the set of intermediary files.

Make makes it easy to parallelise builds

We can easily build a program in parallel since this is a standard function of many versions of make. This is also consequence of the innocuous observation: because "where the plan executor is at" is an explicit data in a Makefile, it is possible for make to reason about it. Achieving a similar effect in a shell script would require a great effort.

Makefiles are easily extensible

Because of the special perspective — that is, as another consequence of the innocuous observation — used to write Makefiles, we can easily extend them. For instance, if we decide that all our database I/O boilerplate code should be written by an automatic tool, we just have to write in the Makefile which files should the automatic tool use as inputs to write the boilerplate code. Nothing less, nothing more. And we can add this description pretty much where we like, make will get it anyway. Doing such an extension in a shell script build would be harder than necessary.

This extensibility ease is a great incentive for Makefile code reuse.

这篇关于分别创建对象文件然后在Makefile中将它们链接在一起的目的是什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆