假设我们有一个程序由5个文件组成,源代码如下:
/*main.c*/
#include "mytool1.h"
#include "mytool2.h"
int main()
{
mytool1_print("hello mytool1!");
mytool2_print("hello mytool2!");
return 0;
}
/*mytool1.c*/
#include "mytool1.h"
#include <stdio.h>
void mytool1_print(char *print_str)
{
printf("This is mytool1 print : %s ",print_str);
}
/*mytool1.h*/
#ifndef _MYTOOL_1_H
#define _MYTOOL_1_H
void mytool1_print(char *print_str);
#endif
/*mytool2.c*/
#include "mytool2.h"
#include <stdio.h>
void mytool2_print(char *print_str)
{
printf("This is mytool2 print : %s ",print_str);
}
/*mytool2.h*/
#ifndef _MYTOOL_2_H
#define _MYTOOL_2_H
void mytool2_print(char *print_str);
#endif
首先了解一下make和Makefile。GNU make是一个工程管理器,它可以管理较多的文件。我所使用的RedHat 9.0的make版本为GNU Make version 3.79.1。使用make的最大好处就是实现了“自动化编译”。如果有一个上百个文件的代码构成的项目,其中一个或者几个文件进行了修改,make就能够自动识别更新了的文件代码,不需要输入冗长的命令行就可以完成最后的编译工作。make执行时,自动寻找Makefile(makefile)文件,然后执行编译工作。所以我们需要编写Makefile文件,这样可以提高实际项目的工作效率。
在一个Makefile中通常包含下面内容:
1、需要由make工具创建的目标体(target),通常是目标文件或可执行文件。
2、要创建的目标体所依赖的文件(dependency_file)。
3、创建每个目标体时需要运行的命令(command)。
格式如下:
target:dependency_files
<TAB>command
target:规则的目标。通常是程序中间或者最后需要生成的文件名,可以是.o文件、也可以是最后的可执行程序的文件名。另外,目标也可以是一个make执行的动作的名称,如目标“clean”,这样的目标称为“伪目标”。
dependency_files:规则的依赖。生成规则目标所需要的文件名列表。通常一个目标依赖于一个或者多个文件。
command:规则的命令行。是make程序所有执行的动作(任意的shell命令或者可在shell下执行的程序)。一个规则可以有多个命令行,每一条命令占一行。注意:每一个命令行必须以[Tab]字符开始,[Tab]字符告诉make此行是一个命令行。make按照命令完成相应的动作。这也是书写Makefile中容易产生,而且比较隐蔽的错误。命令就是在任何一个目标的依赖文件发生变化后重建目标的动作描述。一个目标可以没有依赖而只有动作(指定的命令)。比如Makefile中的目标“clean”,此目标没有依赖,只有命令。它所指定的命令用来删除make过程产生的中间文件(清理工作)。
在Makefile中“规则”就是描述在什么情况下、如何重建规则的目标文件,通常规则中包括了目标的依赖关系(目标的依赖文件)和重建目标的命令。make执行重建目标的命令,来创建或者重建规则的目标(此目标文件也可以是触发这个规则的上一个规则中的依赖文件)。规则包含了目标和依赖的关系以及更新目标所要求的命令。
Makefile中可以包含除规则以外的部分。一个最简单的Makefile可能只包含规则描述。规则在有些Makefile中可能看起来非常复杂,但是无论规则的书写是多么的复杂,它都符合规则的基本格式。
下面就可以写出第一个Makefile了。
main:main.o mytool1.o mytool2.o
gcc -o main main.o mytool1.o mytool2.o
main.o:main.c mytool1.h mytool2.h
gcc -c main.c
mytool1.o:mytool1.c mytool1.h
gcc -c mytool1.c
mytool2.o:mytool2.c mytool2.h
gcc -c mytool2.c
clean:
rm -f *.o main
在shell提示符下输入make,执行显示:
gcc -c main.c
gcc -c mytool1.c
gcc -c mytool2.c
gcc -o main main.o mytool1.o mytool2.o
执行结果如下:
[armlinux@lqm makefile-easy]$ ./main
This is mytool1 print : hello mytool1!
This is mytool2 print : hello mytool2!
这只是最为初级的Makefile,现在来对这个Makefile进行改进。
改进一:使用变量
一般在书写Makefile时,各部分变量引用的格式如下:
1. make变量(Makefile中定义的或者是make的环境变量)的引用使用“$(VAR)”格式,无论“VAR”是单字符变量名还是多字符变量名。
2. 出现在规则命令行中shell变量(一般为执行命令过程中的临时变量,它不属于Makefile变量,而是一个shell变量)引用使用shell的“$tmp”格式。
3. 对出现在命令行中的make变量同样使用“$(CMDVAR)” 格式来引用。
OBJ=main.o mytool1.o mytool2.o
make:$(OBJ)
gcc -o main $(OBJ)
main.o:main.c mytool1.h mytool2.h
gcc -c main.c
mytool1.o:mytool1.c mytool1.h
gcc -c mytool1.c
mytool2.o:mytool2.c mytool2.h
gcc -c mytool2.c
clean:
rm -f main $(OBJ)
改进二:使用自动推导
让make自动推导,只要make看到一个.o文件,它就会自动的把对应的.c文件加到依赖文件中,并且gcc -c .c也会被推导出来,所以Makefile就简化了。
CC = gcc
OBJ = main.o mytool1.o mytool2.o
make: $(OBJ)
$(CC) -o main $(OBJ)
main.o: mytool1.h mytool2.h
mytool1.o: mytool1.h
mytool2.o: mytool2.h
.PHONY: clean
clean:
rm -f main $(OBJ)
改进三:自动变量($^ $< $@)的应用
Makefile 有三个非常有用的变量,分别是$@、$^、$<。代表的意义分别是:
$@--目标文件,
$^--所有的依赖文件,
$<--第一个依赖文件。
CC = gcc
OBJ = main.o mytool1.o mytool2.o
main: $(OBJ)
$(CC) -o $@ $^
main.o: main.c mytool1.h mytool2.h
$(CC) -c $<
mytool1.o: mytool1.c mytool1.h
$(CC) -c $<
mytool2.o: mytool2.c mytool2.h
$(CC) -c $<
.PHONY: clean
clean:
rm -f main $(OBJ)
这些是最为初级的知识,现在至少可以减少编译时的工作量。细节方面的东西还需要在以后的工作和学习中不断的总结,不断的深化理解。可以 参考GNU Make手册,这里讲解的比较全面。
分享到:
相关推荐
#### 四、Makefile实例分析 以下是一个简单的 Makefile 示例,展示了如何为一个包含 8 个 C 文件和 3 个头文件的工程编写 Makefile: ```makefile # 定义目标 all: program # 定义规则 program: main.o func1.o ...
本资料集合旨在深入探讨这两个关键概念,并提供通用Makefile的实例,帮助开发者更好地理解和应用。 首先,让我们从GNU Make中文手册开始。手册详细介绍了Makefile的语法、规则和变量,以及如何编写高效的Makefile。...
例如,一个简单的 makefile 可能会包括清理目标、编译源文件、链接目标等命令,从而节省手动操作的时间。 4. 典型实例:AVR 单片机实用C语言程序设计与典型实例的书本附带光盘内容可能包括了多种应用场景的程序,如...
《GNU Makefile 中文手册》是一本针对编程者和系统管理员的重要参考资料,它详细解析了如何使用GNU make工具来自动化构建、编译和链接软件项目。makefile是这个过程中的核心,它定义了一系列规则和目标,使构建过程...
本文将详细介绍如何在Linux平台上编写makefile,并通过具体实例来帮助读者更好地理解和应用。 #### 二、makefile的重要性 在Linux或Unix系统中,makefile尤其重要,因为它不仅能够提高编译效率,还能简化复杂的...
#### 三、Makefile 实例解析 假设我们有一个简单的 C++ 项目,包含以下几个文件: - `main.cpp` - `hello.cpp` - `factorial.cpp` - `functions.h` 为了方便管理和编译,我们可以将这些文件放在一个新的目录中。 ...
- **示例**:简单的Makefile实例展示如何编写基本的规则。 - **Make的工作原理**:解析Makefile并根据规则执行相应的命令。 - **使用变量**:在Makefile中定义和使用变量以提高灵活性。 - **自动推导**:Make根据...
- **示例**:本书提供了多个实例来帮助读者理解Makefile的编写方法。 - **make的工作原理**:解释了make工具如何读取Makefile并根据其中的规则执行相应的命令。 - **变量使用**:介绍了如何在Makefile中定义和使用...
### Makefile 编写实例解析 **实例场景**:假设有一个包含8个C文件和3个头文件的工程项目,需要编写一个`Makefile`来自动化其编译过程。按照以下规则: 1. 如果工程从未被编译过,那么所有C文件都需要编译生成对应...
**实例解析**:假设一个工程包含8个C文件和3个头文件,需要编写一个Makefile文件,使其满足以下条件: 1. **初始编译**:如果工程尚未编译,则需要编译所有C文件并进行链接。 2. **增量编译**:如果工程中的部分C...
#### 二、Makefile 实例分析 以下是一个简单的 Makefile 示例,它展示了如何编译一个由多个 C 源文件组成的程序。 ```makefile # Makefile 示例 # 编译目标 edit: main.o kbd.o command.o display.o insert.o ...
#### Makefile编写实例 假设我们有一个包含8个C文件和3个头文件的工程,需要编写Makefile来指导其编译和链接。我们的Makefile规则设计如下: 1. **初始化编译**:如果工程未曾编译过,所有C文件均需编译并链接。 2...
#### 三、Makefile编写实例分析 下面以一个简单的 C 语言项目为例,说明 Makefile 的编写方法: 假设有一个包含以下文件的项目: - `main.c` - `func1.c` - `func2.c` - `func1.h` - `func2.h` 我们需要为这个...
在本项目中,“GNU makefile 项目管理源码”提供了一个学习和参考的实例集,帮助开发者深入理解makefile的工作原理和编写技巧。 首先,我们需要了解Makefile的基本结构。一个Makefile通常包含目标(target)、依赖...
为了更直观地理解Makefile的工作原理,我们可以通过一个简单的实例来探索其编写规则。假设我们有一个包含8个C文件的项目,Makefile文件中将定义这些文件的编译规则、目标文件的生成以及最终可执行文件的链接过程。...
本资料主要聚焦于两种广泛使用的自动化构建工具——Makefile和CMake,通过详细解读和实例分析,旨在帮助读者掌握这两款工具的核心原理和应用技巧。 一、Makefile基础 Makefile是Unix/Linux系统中用于自动化编译、...
以下是一个简单的 Makefile 示例,展示了如何为一个包含 8 个 C 源文件和 3 个头文件的项目编写 Makefile。 ```makefile # 定义编译器和编译选项 CC = gcc CFLAGS = -Wall -g # 定义目标文件和依赖文件 OBJS = ...
#### 四、Makefile 实例分析 下面给出一个简单的 Makefile 示例,该示例展示了如何为一个简单的 C 项目编写 Makefile: ```make CC = gcc CFLAGS = -Wall -g SOURCES = main.c func.c OBJECTS = $(SOURCES:.c=.o) ...