GCC and Make Compiling, Linking and Building C/C++ Applications - 2

GCC and Make Compiling, Linking and Building C/C++ Applications - 2

https://www3.ntu.edu.sg/home/ehchua/programming/cpp/gcc_make.html

2. GNU Make

The make utility automates the mundane aspects of building executable from source code. make uses a so-called makefile, which contains rules on how to build the executables.
make 实用程序可自动从源代码构建可执行文件的日常工作。make 使用所谓的 makefile,其中包含有关如何构建可执行文件的规则。

mundane ['mʌndeɪn; mʌn'deɪn]:adj. 世俗的,平凡的,世界的,宇宙的

You can issue make --help to list the command-line options; or man make to display the man pages.
您可以发出 make --help 列出命令行选项。或 man make 来显示手册页。

2.1 First Makefile By Example

Let’s begin with a simple example to build the Hello-world program (hello.c) into executable (hello.exe) via make utility.

// hello.c
#include <stdio.h>
 
int main() {
    printf("Hello, world!\n");
    return 0;
}

Create the following file named makefile (without any file extension), which contains rules to build the executable, and save in the same directory as the source file. Use tab to indent the command (NOT spaces).
创建以下名为 makefile 的文件 (不带任何文件扩展名),该文件包含构建可执行文件的规则,并与源文件保存在同一目录中。使用 tab 缩进命令 (不是空格)。

all: hello.exe

hello.exe: hello.o
	 gcc -o hello.exe hello.o

hello.o: hello.c
	 gcc -c hello.c
     
clean:
	 rm hello.o hello.exe

Run the make utility as follows:

> make
gcc -c hello.c
gcc -o hello.exe hello.o
strong@foreverstrong:~/Desktop/makefile_work$ ll
total 16
drwxrwxr-x 2 strong strong 4096 Sep 21 14:16 ./
drwxr-xr-x 8 strong strong 4096 Sep 21 11:38 ../
-rw-rw-r-- 1 strong strong   93 Sep 21 12:09 hello.c
-rw-rw-r-- 1 strong strong  471 Sep 21 14:16 Makefile
strong@foreverstrong:~/Desktop/makefile_work$ 
strong@foreverstrong:~/Desktop/makefile_work$ cat hello.c 
// hello.c
#include <stdio.h>
 
int main() {
    printf("Hello, world!\n");
    return 0;
}

strong@foreverstrong:~/Desktop/makefile_work$ 
strong@foreverstrong:~/Desktop/makefile_work$ cat Makefile 
# ============================================================================
# Name        : Makefile
# Author      : Yongqiang Cheng
# Version     : Feb 16, 2019
# Copyright   : Copyright 2019 ForeverStrong License
# Description : Workspace in C, Ansi-style
# ============================================================================

all: hello.exe

hello.exe: hello.o
	gcc -o hello.exe hello.o

hello.o: hello.c
	gcc -c hello.c
     
clean:
	rm hello.o hello.exe
strong@foreverstrong:~/Desktop/makefile_work$

Running make without argument starts the target all in the makefile. A makefile consists of a set of rules. A rule consists of 3 parts: a target, a list of pre-requisites and a command, as follows:
运行不带参数的 make 将启动 makefile 中的目标 all。一个 makefile 由一组规则组成。规则由三部分组成:目标、先决条件列表和命令,如下所示:

target: pre-req-1 pre-req-2 ...
	command

The target and pre-requisites are separated by a colon (:). The command must be preceded by a tab (NOT spaces).
目标和先决条件之间用冒号 (:) 分隔。该命令之前必须带有一个 tab 符 (不是空格)。

When make is asked to evaluate a rule, it begins by finding the files in the prerequisites. If any of the prerequisites has an associated rule, make attempts to update those first.
当要求 make 评估规则时,它首先在先决条件中查找文件。如果任何先决条件有关联的规则,尝试先进行更新。

In the above example, the rule all has a pre-requisite hello.exe. make cannot find the file hello.exe, so it looks for a rule to create it. The rule hello.exe has a pre-requisite hello.o. Again, it does not exist, so make looks for a rule to create it. The rule hello.o has a pre-requisite hello.c. make checks that hello.c exists and it is newer than the target (which does not exist). It runs the command gcc -c hello.c. The rule hello.exe then run its command gcc -o hello.exe hello.o. Finally, the rule all does nothing.
在上面的示例中,规则 all 具有先决条件 hello.exe。make 找不到文件 hello.exe,因此它将寻找创建它的规则。规则 hello.exe 具有先决条件 hello.o。同样,它不存在,因此请 make 查找创建它的规则。规则 hello.o 具有先决条件 hello.c。检查 hello.c 存在,并且比目标 (不存在) 修改时间更新。它运行命令 gcc -c hello.c。然后,规则 hello.exe 运行其命令 gcc -o hello.exe hello.o。最后,规则 all 什么也不做。

More importantly, if the pre-requisite is not newer than than target, the command will not be run. In other words, the command will be run only if the target is out-dated compared with its pre-requisite. For example, if we re-run the make command:
更重要的是,如果先决条件不比目标条件修改时间新,则该命令将不会运行。换句话说,仅当目标与其先决条件相比修改时间晚时,命令才会运行。例如,如果我们重新运行 make 命令:

> make
make: Nothing to be done for `all'.

You can also specify the target to be made in the make command. For example, the target clean removes the hello.o and hello.exe. You can then run the make without target, which is the same as make all.
您也可以在 make 命令中指定要创建的目标。例如,目标 clean 将删除 hello.o and hello.exe。然后,您可以运行不带目标的 make,这与 make all 相同。

> make clean
rm hello.o hello.exe
 
> make
gcc -c hello.c
gcc -o hello.exe hello.o

Try modifying the hello.c and run make.

NOTES:

  • If the command is not preceded by a tab, you get an error message makefile:4: *** missing separator. Stop. (如果命令前不以 tab 开始,则会显示错误消息。)
  • If there is no makefile in the current directory, you get an error message make: *** No targets specified and no makefile found. Stop. (如果当前目录中没有 makefile,则会收到一条错误消息。)
  • The makefile can be named makefile, Makefile or GNUMakefile, without file extension. (生成文件可以命名为 makefileMakefile or GNUMakefile,而无需文件扩展名。)
strong@foreverstrong:~/Desktop/makefile_work$ make
gcc -c hello.c
gcc -o hello.exe hello.o
strong@foreverstrong:~/Desktop/makefile_work$ 
strong@foreverstrong:~/Desktop/makefile_work$ ll
total 32
drwxrwxr-x 2 strong strong 4096 Sep 21 15:15 ./
drwxr-xr-x 8 strong strong 4096 Sep 21 11:38 ../
-rw-rw-r-- 1 strong strong   93 Sep 21 12:09 hello.c
-rwxrwxr-x 1 strong strong 8600 Sep 21 15:15 hello.exe*
-rw-rw-r-- 1 strong strong 1504 Sep 21 15:15 hello.o
-rw-rw-r-- 1 strong strong  471 Sep 21 14:16 Makefile
strong@foreverstrong:~/Desktop/makefile_work$ 
strong@foreverstrong:~/Desktop/makefile_work$ ./hello.exe 
Hello, world!
strong@foreverstrong:~/Desktop/makefile_work$ 
strong@foreverstrong:~/Desktop/makefile_work$ make clean
rm hello.o hello.exe
strong@foreverstrong:~/Desktop/makefile_work$ 
strong@foreverstrong:~/Desktop/makefile_work$ make
gcc -c hello.c
gcc -o hello.exe hello.o
strong@foreverstrong:~/Desktop/makefile_work$ 
strong@foreverstrong:~/Desktop/makefile_work$ ll
total 32
drwxrwxr-x 2 strong strong 4096 Sep 21 15:17 ./
drwxr-xr-x 8 strong strong 4096 Sep 21 11:38 ../
-rw-rw-r-- 1 strong strong   93 Sep 21 12:09 hello.c
-rwxrwxr-x 1 strong strong 8600 Sep 21 15:17 hello.exe*
-rw-rw-r-- 1 strong strong 1504 Sep 21 15:17 hello.o
-rw-rw-r-- 1 strong strong  471 Sep 21 14:16 Makefile
strong@foreverstrong:~/Desktop/makefile_work$ 
strong@foreverstrong:~/Desktop/makefile_work$ make
make: Nothing to be done for 'all'.
strong@foreverstrong:~/Desktop/makefile_work$

2.2 More on Makefile

Comment & Continuation
A comment begins with a # and lasts till the end of the line. Long line can be broken and continued in several lines via a back-slash (\).
注释以 # 开头,一直持续到该行的末尾。长行可以通过反斜杠 (\) 断开并分成几行。

syntax ['sɪntæks]:n. 语法,句法,有秩序的排列
backslash ['bækslæʃ]:n. 反斜杠,反斜线符号

Syntax of Rules
A general syntax for the rules is:

target1 [target2 ...]: [pre-req-1 pre-req-2 ...]
	[command1
	 command2
	 ......]

The rules are usually organized in such as way the more general rules come first. The overall rule is often name all, which is the default target for make.
规则通常以更一般的规则排在第一位的方式进行组织。总体规则通常是名称 all,这是 make 的默认目标。

Phony Targets (or Artificial Targets)
A target that does not represent a file is called a phony target. For example, the clean in the above example, which is just a label for a command. If the target is a file, it will be checked against its pre-requisite for out-of-date-ness. Phony target is always out-of-date and its command will be run. The standard phony targets are: all, clean, install.
不代表文件的目标称为伪目标。例如,上例中的 clean 只是命令的标签。如果目标是文件,则将根据其修改时间前后的先决条件对其进行检查。伪目标始终是过时的,并且它将运行其命令。标准的伪造目标是:all, clean, install。

phony ['fəʊnɪ]:adj. 假的,欺骗的 n. 假冒者,赝品

Variables
A variable begins with a $ and is enclosed within parentheses (...) or braces {...}. Single character variables do not need the parentheses. For example, $(CC), $(CC_FLAGS), $@, $^.
变量以 $ 开头,并括在括号 (...) 或大括号 {...} 内。单字符变量不需要括号。例如,$(CC), $(CC_FLAGS), $@, $^

brace [breɪs]:v. 使做准备,抵住,绷紧,支撑,加固 n. 夹子,支架,牙箍,背带,大括号,一对,一双,曲柄,连谱号,转帆索
parenthese:n. 括号,圆括号

Automatic Variables
Automatic variables are set by make after a rule is matched. (匹配规则后,由 make 设置自动变量。) There include:

  • $@: the target filename. (目标文件名。)
  • $*: the target filename without the file extension. (目标文件名,不带文件扩展名。)
  • $<: the first prerequisite filename. (第一个先决条件文件名。)
  • $^: the filenames of all the prerequisites, separated by spaces, discard duplicates. (所有先决条件的文件名 (用空格分隔) 将丢弃重复项。)
  • $+: similar to $^, but includes duplicates. (与 $ ^ 类似,但包括重复项。)
  • $?: the names of all prerequisites that are newer than the target, separated by spaces. (比目标修改时间更新的所有先决条件的名称,用空格分隔。)

For example, we can rewrite the earlier makefile as:

all: hello.exe
 
# $@ matches the target; $< matches the first dependent
hello.exe: hello.o
	gcc -o $@ $<

hello.o: hello.c
	gcc -c $<
     
clean:
	rm hello.o hello.exe
strong@foreverstrong:~/Desktop/makefile_work$ ll
total 16
drwxrwxr-x 2 strong strong 4096 Sep 21 15:37 ./
drwxr-xr-x 8 strong strong 4096 Sep 21 11:38 ../
-rw-rw-r-- 1 strong strong   93 Sep 21 12:09 hello.c
-rw-rw-r-- 1 strong strong  512 Sep 21 15:37 Makefile
strong@foreverstrong:~/Desktop/makefile_work$ 
strong@foreverstrong:~/Desktop/makefile_work$ cat hello.c 
// hello.c
#include <stdio.h>
 
int main() {
    printf("Hello, world!\n");
    return 0;
}

strong@foreverstrong:~/Desktop/makefile_work$ 
strong@foreverstrong:~/Desktop/makefile_work$ cat Makefile 
# ============================================================================
# Name        : Makefile
# Author      : Yongqiang Cheng
# Version     : Feb 16, 2019
# Copyright   : Copyright 2019 ForeverStrong License
# Description : Workspace in C, Ansi-style
# ============================================================================

all: hello.exe
 
# $@ matches the target; $< matches the first dependent
hello.exe: hello.o
	gcc -o $@ $<

hello.o: hello.c
	gcc -c $<
     
clean:
	rm hello.o hello.exe

strong@foreverstrong:~/Desktop/makefile_work$ 
strong@foreverstrong:~/Desktop/makefile_work$ make
gcc -c hello.c
gcc -o hello.exe hello.o
strong@foreverstrong:~/Desktop/makefile_work$ 
strong@foreverstrong:~/Desktop/makefile_work$ ll
total 32
drwxrwxr-x 2 strong strong 4096 Sep 21 15:38 ./
drwxr-xr-x 8 strong strong 4096 Sep 21 11:38 ../
-rw-rw-r-- 1 strong strong   93 Sep 21 12:09 hello.c
-rwxrwxr-x 1 strong strong 8600 Sep 21 15:38 hello.exe*
-rw-rw-r-- 1 strong strong 1504 Sep 21 15:38 hello.o
-rw-rw-r-- 1 strong strong  512 Sep 21 15:37 Makefile
strong@foreverstrong:~/Desktop/makefile_work$ 
strong@foreverstrong:~/Desktop/makefile_work$ ./hello.exe 
Hello, world!
strong@foreverstrong:~/Desktop/makefile_work$ 
strong@foreverstrong:~/Desktop/makefile_work$ make clean
rm hello.o hello.exe
strong@foreverstrong:~/Desktop/makefile_work$ 
strong@foreverstrong:~/Desktop/makefile_work$ ll
total 16
drwxrwxr-x 2 strong strong 4096 Sep 21 15:38 ./
drwxr-xr-x 8 strong strong 4096 Sep 21 11:38 ../
-rw-rw-r-- 1 strong strong   93 Sep 21 12:09 hello.c
-rw-rw-r-- 1 strong strong  512 Sep 21 15:37 Makefile
strong@foreverstrong:~/Desktop/makefile_work$

Virtual Path - VPATH & vpath
You can use VPATH (uppercase) to specify the directory to search for dependencies and target files. For example,
您可以使用 VPATH (大写) 指定用于搜索依赖项和目标文件的目录。

# Search for dependencies and targets from `src` and `include` directories
# The directories are separated by space
VPATH = src include

You can also use vpath (lowercase) to be more precise about the file type and its search directory. For example,
您也可以使用 vpath (小写) 来更精确地了解文件类型及其搜索目录。

# Search for .c files in `src` directory; .h files in `include` directory
# The pattern matching character '%' matches filename without the extension
vpath %.c src
vpath %.h include

Pattern Rules
A pattern rule, which uses pattern matching character % as the filename, can be applied to create a target, if there is no explicit rule. For example,
如果没有显式规则,则可以使用将模式匹配字符 % 作为文件名的模式规则来创建目标。

# Applicable for create .o object file.
# '%' matches filename.
# $< is the first pre-requisite
# $(COMPILE.c) consists of compiler name and compiler options
# $(OUTPUT_OPTIONS) could be -o $@
%.o: %.c
	$(COMPILE.c) $(OUTPUT_OPTION) $<
 
# Applicable for create executable (without extension) from object .o object file
# $^ matches all the pre-requisites (no duplicates)
%: %.o
$(LINK.o) $^ $(LOADLIBES) $(LDLIBS) -o $@

Implicit Pattern Rules
Make comes with a huge set of implicit pattern rules. You can list all the rule via --print-data-base option.
Make 带有大量隐式模式规则。您可以通过 --print-data-base 选项列出所有规则。

2.3 A Sample Makefile

This sample makefile is extracted from Eclipse’s C/C++ Development Guide - Makefile.

# A sample Makefile
# This Makefile demonstrates and explains Make Macros, Macro Expansions, Rules, Targets, Dependencies, Commands, Goals, Artificial Targets, Pattern Rule, Dependency Rule.
# Comments start with a # and go to the end of the line.

# Here is a simple Make Macro.
LINK_TARGET = test_me.exe

# Here is a Make Macro that uses the backslash to extend to multiple lines.
# 这是一个使用反斜杠扩展到多行的 Make Macro。
OBJS =  \
 Test1.o \
 Test2.o \
 Main.o

# Here is a Make Macro defined by two Macro Expansions.
# A Macro Expansion may be treated as a textual replacement of the Make Macro.
# Macro Expansions are introduced with $ and enclosed in (parentheses).
REBUILDABLES = $(OBJS) $(LINK_TARGET)

# Here is a simple Rule (used for `cleaning` your build environment).
# It has a Target named `clean` (left of the colon `:` on the first line), no Dependencies (right of the colon), and two Commands (indented by tabs on the lines that follow).
# The space before the colon is not required but added here for clarity. (冒号前的空格不是必需的,但为清楚起见在此处添加了空格。)
clean : 
  rm -f $(REBUILDABLES)
  echo Clean done

# There are two standard Targets your Makefile should probably have: `all` and `clean`, because they are often command-line Goals. (您的 Makefile 应该有两个标准目标:all 和 clean,因为它们通常是命令行目标。)
# Also, these are both typically Artificial Targets, because they don't typically correspond to real files named `all` or `clean`. (它们通常不对应于名为 `all` or `clean` 的真实文件。)

# The rule for `all` is used to incrementally build your system.
# It does this by expressing a dependency on the results of that system, which in turn have their own rules and dependencies. (它通过表示对该系统结果的依赖性来做到这一点,而该结果又具有自己的规则和依赖性。)
all : $(LINK_TARGET)
  echo All done

# There is no required order to the list of rules as they appear in the Makefile. (规则列表在 Makefile 中显示时没有要求的顺序。)
# Make will build its own dependency tree and only execute each rule only once its dependencies' rules have been executed successfully. (Make 将构建自己的依赖关系树,并且仅在成功执行其依赖关系的规则后才执行每个规则。)

# Here is a Rule that uses some built-in Make Macros in its command:
# $@ expands to the rule's target, in this case `test_me.exe`.
# $^ expands to the rule's dependencies, in this case the three files
# main.o, test1.o, and  test2.o.
$(LINK_TARGET) : $(OBJS)
  g++ -g -o $@ $^

# Here is a Pattern Rule, often used for compile-line.
# It says how to create a file with a .o suffix, given a file with a .cpp suffix.
# The rule's command uses some built-in Make Macros:
# $@ for the pattern-matched target
# $< for the pattern-matched dependency
%.o : %.cpp
  g++ -g -o $@ -c $<

# These are Dependency Rules, which are rules without any command. (这些是相关性规则,这些规则没有任何命令。)
# Dependency Rules indicate that if any file to the right of the colon changes, the target to the left of the colon should be considered out-of-date. (依赖性规则表明,如果冒号右侧的任何文件发生更改,则冒号左侧的目标应视为已过期。)
# The commands for making an out-of-date target up-to-date may be found elsewhere (in this case, by the Pattern Rule above). 
# Dependency Rules are often used to capture header file dependencies.
Main.o : Main.h Test1.h Test2.h
Test1.o : Test1.h Test2.h
Test2.o : Test2.h

# Alternatively to manually capturing dependencies, several automated dependency generators exist. Here is one possibility (commented out)...
# 除了手动捕获依赖项之外,还存在几个自动的依赖项生成器。
# %.dep : %.cpp
#   g++ -M $(FLAGS) $< > $@
# include $(OBJS:.o=.dep)
textual ['tekstjʊəl]:adj. 本文的,按原文的

2.4 Brief Summary

I have presented the basic make features here so that you can read and understand simple makefiles for building C/C++ applications. Make is actually quite complex, and can be considered as a programming language by itself!!
我在这里介绍了基本的 make 功能,以便您可以阅读和理解用于构建 C/C ++ 应用程序的简单 makefile。Make 实际上是相当复杂的,它本身可以被视为一种编程语言!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Yongqiang Cheng

梦想不是浮躁,而是沉淀和积累。

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值