Makefile 基础语法和变量详解

发布时间:2023-07-22 11:35:53 作者:yexindonglai@163.com 阅读(765)

1、什么是makefile

当我们在写单个c或者cpp文件时,可直接用以下命令来编译文件

  1. # 编译c文件
  2. gcc main.c -o main
  3. # 编译c++文件
  4. g++ main.cpp -o main

但是当我们项目中有很多文件的时候,就不能用这种命令来编译了,首先成本太高,其次维护麻烦;所以大神们开发出了 makefile;可以同时编译多个文件;并且会自动检测出哪些文件是修改过的,只编译修改过的文件,

只编译修改过的文件原理

刚刚说过,makefile只会编译那些已经修改过的文件,如果未修改就不会再次编译,提升了效率,那他是什么原理呢,其实很简单,就是每次执行make的时候都会去检测c/cpp文件的修改时间;如果发现修改时间有变动,就会去重新编译;是不是很简单呢

编写规则
  1. target ... : prerequisites ...
  2. command
  3. ...
  4. ...

2、实战

首先准备三个文件 student.h、student.cpp 和主程序 main.cpp

student.h

  1. #ifndef NAKEFILE_PROJECT_STUDEN_H
  2. #define NAKEFILE_PROJECT_STUDEN_H
  3. int getAge();
  4. #endif //NAKEFILE_PROJECT_STUDEN_H

student.cpp

  1. #include "student.h"
  2. int getAge(){
  3. return 1;
  4. }

main.cpp

  1. #include <iostream>
  2. #include "student.h"
  3. int main() {
  4. std::cout << "Hello, World!" << std::endl;
  5. std::cout << "getAge:"<<getAge() << std::endl;
  6. return 0;
  7. }
编写makefile

注意:下面的缩进,必须用tab键,不能用4个空格键代替,否则会报错

而且,makefile的前后的顺序没有要求,在编译的时候会自动推导;

  1. main : main.o student.o
  2. g++ -o main main.o student.o
  3. main.o:main.cpp
  4. g++ -c main.cpp
  5. studen.o: student.cpp student.h
  6. g++ -c student.cpp student.h
  7. clean :
  8. rm main main.o student.o
目录结构

执行makefile

进入项目目录,执行名命令make,完美,没有报错;

执行完后,会发现目录下多了三个文件,分别是main、main.o、student.o

到这一步,程序就已经编译好了,也生成执行文件了;

运行

运行makefile有一个前提,就是必须得在当前目录下有makefile文件;否则是无法运行的;
接下来在执行main文件,在控制台输入 ./main后,发现是可以正常运行的;打印结果也和预期一样

修改后再编译

接下来我们将文件修改一下,在执行make命令,在main.cpp文件中,的hello world!后面加上yexindong,如下:

  1. #include <iostream>
  2. #include "student.h"
  3. int main() {
  4. std::cout << "Hello, World! yeindong" << std::endl;
  5. std::cout << "getAge:"<<getAge() << std::endl;
  6. return 0;
  7. }

执行make命令,发现只编译了main.cpp文件,其他文件的编译动作并没有执行;

3、变量

使用 Makefile 进行规则定义的时候,为了写起来更加灵活,我们可以在里边使用变量。makefile 中的变量分为三种:

  • 自定义变量:用户自己定义的变量;
  • 预定义变量:在 Makefile 中有一些已经定义的变量,用户可以直接使用这些变量
  • 自动变量:Makefile 中的规则语句中经常会出现目标文件和依赖文件,自动变量用来代表这些规则中的目标文件和依赖文件,并且它们只能在规则的命令中使用。比如$*$+

变量使用方法

  1. $(变量名)
3.1、自定义变量

makefile中变量的赋值有以下几种方式

  • 简单赋值(:=)
  • 递归赋值(=)
  • 条件赋值(?=)
  • 追加赋值(+=)

接下来我们用自定义变量来重新修改下上面的makefile文件

  1. # 声明student_file变量,值为:student.cpp student.h
  2. student_file:=student.cpp student.h
  3. # 声明main_file变量,值为:main.cpp
  4. main_file:=main.cpp
  5. # 声明main_and_student_o_file变量,值为:main.o student.o
  6. main_and_student_o_file:=main.o student.o
  7. main : $(main_and_student_o_file)
  8. g++ -o main $(main_and_student_o_file)
  9. main.o:$(main_file)
  10. g++ -c $(main_file)
  11. studen.o: $(student_file)
  12. g++ -c $(student_file)
  13. clean :
  14. rm main $(main_and_student_o_file)
3.2、预定义变量

在 Makefile 中有一些已经定义的变量,用户可以直接使用这些变量,不用进行定义。在进行编译的时候,某些条件下 Makefile 会使用这些预定义变量的值进行编译。这些预定义变量的名字一般都是大写的,经常采用的预定义变量如下表所示:

变 量 名 含 义 默 认 值
AR 生成静态库库文件的程序名称 ar
AS 汇编编译器的名称 as
CC C 语言编译器的名称 cc
CPP C 语言预编译器的名称 $(CC) -E
CXX C++ 语言编译器的名称 g++
FC FORTRAN 语言编译器的名称 f77
RM 删除文件程序的名称 rm -f
ARFLAGS 生成静态库库文件程序的选项 无默认值
ASFLAGS 汇编语言编译器的编译选项 无默认值
CFLAGS C 语言编译器的编译选项 无默认值
CPPFLAGS C 语言预编译的编译选项 无默认值
CXXFLAGS C++ 语言编译器的编译选项 无默认值
FFLAGS FORTRAN 语言编译器的编译选项 无默认
3.3、自动变量

Makefile 中的变量除了用户自定义变量和预定义变量外,还有一类自动变量。Makefile 中的规则语句中经常会出现目标文件和依赖文件,自动变量用来代表这些规则中的目标文件和依赖文件,并且它们只能在规则的命令中使用。

变 量 含 义
$* 表示目标文件的名称,不包含目标文件的扩展名
$+ 表示所有的依赖文件,这些依赖文件之间以空格分开,按照出现的先后为顺序,其中可能 包含重复的依赖文件
$< 表示依赖项中第一个依赖文件的名称
$? 依赖项中,所有比目标文件时间戳晚的依赖文件,依赖文件之间以空格分开
$@ 表示目标文件的名称,包含文件扩展名
$^ 依赖项中,所有不重复的依赖文件,这些文件之间以空格分开

关键字c++