Linux Makefile-概述、语句格式、编写规则、多文件编程、Makefile变量分类 ...

打印 上一主题 下一主题

主题 1764|帖子 1764|积分 5292

目录
1.make
1.1 make 命令格式
2.Makefile 核心概念‌ ‌
2.1创建并运行 Makefile步骤
3. Makefile编写
3.1最基础Makefile
3.1.1利用默认make命令
 3.1.2利用make -f 命令
3.1.2.1 利用make -f 命令实验默认make操纵
3.1.2.2利用 make [ ‐f file ] [ targets ]命令
3.1.2.3利用 make [ ‐f file ] [ targets ]命令,并实验可实验程序
3.1.3 gcc编译常用组合选项
3.1.4 make 和 make all区别
3.1.4.1 all 是默认目的
3.1.4.2 all 不是默认目的
3.1.4.3 没有界说 all 命令
3.1.4.3 逼迫设置 all 为默认目的
3.2多文件编程Makefile-基础
3.3makefile变量
3.3.1 makefile 变量概述
3.3.2 makefile 的变量分类:
3.3.3 自界说变量语法
3.3.3.1自界说变量makefile多文件编程
3.3.4体系变量
3.3.5预界说变量
3.3.5.1编译器与工具
3.3.5.2. 编译选项
3.3.5.3. 文件与目录
3.3.5.4. 隐式规则中的关键变量
3.3.5.5. 常用内置变量
3.3.5.6.程序验证
4.几种多文件编程Makefile对应关系


1.make

   make是个命令,是个可实验程序,用来解析Makefile文件的命令。     终端输入:which make 查看make保存地址,在 /usr/bin/make     
  1.1 make 命令格式

  1. make [ ‐f file ] [ targets ]
复制代码
     (1)[ -f file ]:        make默认在工作目录中寻找名为GNUmakefile、makefile、Makefile的文件作为        makefile输入文件,   -f 可以指定以上名字以外的文件作为makefile输入文件          (2)[ targets ]:        若利用make命令时没有指定目的,则make工具默认会实现makefile文件内的第一个目 标   ,然后退出,指定了make工具要实现的目的,目的可以是一个或多个(多个目的间用空 格隔开)。    2.Makefile 核心概念‌ ‌

作用‌:
自动化编译和链接程序,管理项目依靠关系,避免重复编译未修改的代码。
‌基本结构:
  1. target: dependencies
  2.     command
  3. ‌target‌: 生成的目标(如可执行文件、中间文件)
  4. ‌dependencies‌: 生成目标所需的文件或目标
  5. ‌command‌: 生成目标的命令(必须以 Tab 开头)
复制代码
2.1创建并运行 Makefile步骤

基本步骤:


  • 创建文件:在项目根目录创建名为 Makefile 的文件(无后缀)。
  • 编写规则:界说目的(如可实验文件)、依靠(如 .c 和 .o 文件)和命令。
  • 运行命令:在终端实验 make 或 make <target>。
3. Makefile编写

 make 命令格式
  1. make [ ‐f file ] [ targets ]
复制代码
     (1)[ -f file ]:        make默认在工作目录中寻找名为GNUmakefile、makefile、Makefile的文件作为        makefile输入文件,   -f 可以指定以上名字以外的文件作为makefile输入文件          (2)[ targets ]:        若利用make命令时没有指定目的,则make工具默认会实现makefile文件内的第一个目 标   ,然后退出,指定了make工具要实现的目的,目的可以是一个或多个(多个目的间用空 格隔开)。    3.1最基础Makefile

  3.1.1利用默认make命令

程序:
main.c
  1. #include <stdio.h>
  2. #include "main.h"
  3. int main(int argc, char const *argv[])
  4. {
  5.         printf("main函数开始\n");
  6.         printf("ABC = %d abc = %d\n",ABC, abc);
  7.        
  8.     return 0;
  9. }
复制代码
main.h
  1. #define ABC 123
  2. #define abc 456
复制代码
makefile
  1. main:main.c main.h
  2.         gcc main.c -o main
  3.        
  4. clean:
  5.         rm main
复制代码
makefile内容解释:
main:main.c main.h //可实验文件main依靠main.c main.h
    gcc main.c -o main //由mian.c 生成可实验文件main
    
clean:
    rm main //实验 make clean 命令,删除可实验文件main
运行结果:

 3.1.2利用make -f 命令

3.1.2.1 利用make -f 命令实验默认make操纵

程序:与3.1.1利用默认make命令一样。
makefile:与3.1.1利用默认make命令一样。仅名称不同。
将可实验文件main删除,Makefile复制一份,重命名为Makefile1,实验 make -f Makefile1
也可以正常实验make命令。实验结果与默认make命令结果相同。

3.1.2.2利用 make [ ‐f file ] [ targets ]命令

程序:与3.1.1利用默认make命令一样。
makefile:
  1. test:main.c main.h
  2.         gcc main.c -o main
  3.         @echo "=== test ==="
  4.        
  5. clean:
  6.         rm main
  7.         @echo "=== clean ==="
  8. test1:
  9.         @echo "=== test1 ==="; # @符号注释见下面
  10. #echo前使用 @‌:在 echo 前添加 @ 符号,可隐藏命令本身的输出,仅显示命令的执行结果‌
  11. #终端结果: === test1 ===
  12.        
  13. #未使用 @‌:命令本身和执行结果都会显示,
  14. #终端结果: echo "=== test1 ==="
  15. #                 === test1 ===
  16. # 在 Makefile 中直接写 @echo "注释内容" # 注释内容, 注释内容会输出在终端,
  17. # 因为 # 必须出现在行首或通过 ; 分隔       
  18. test2:
  19.         @echo "=== test2 ==="; # @符号注释见上面
复制代码
(1)实验  make -f Makefile2 test1 test test2
test1 test test2 为Makefile2中的三个目的文件,实验上述命令,先运行test1内里的运行命令,在运行test运行命令,最后运行test2运行命令。
运行结果:

(2)实验 make -f Makefile2 test1 test2 clean 命令
test1 test2 clean 为Makefile2中的三个目的文件,实验上述命令,先运行test1内里的运行命令,在运行test2运行命令,最后运行clean运行命令。
运行结果:

注意:包管实验 clean命令,确保删除的文件要存在。
删除文件不存在运行结果:

3.1.2.3利用 make [ ‐f file ] [ targets ]命令,并实验可实验程序

程序:与3.1.1利用默认make命令一样。
makefile:
  1. test:main.c main.h
  2.         gcc main.c -o main
  3.         @echo "=== test ==="
  4.        
  5. clean:
  6.         rm main
  7.         @echo "=== clean ==="
  8. test1:
  9.         @echo "=== test1 ==="; # @符号注释见下面
  10. #echo前使用 @‌:在 echo 前添加 @ 符号,可隐藏命令本身的输出,仅显示命令的执行结果‌
  11. #终端结果: === test1 ===
  12.        
  13. #未使用 @‌:命令本身和执行结果都会显示,
  14. #终端结果: echo "=== test1 ==="
  15. #                 === test1 ===
  16. # 在 Makefile 中直接写 @echo "注释内容" # 注释内容, 注释内容会输出在终端,
  17. # 因为 # 必须出现在行首或通过 ; 分隔       
  18. test2:
  19.         @echo "=== test2 ==="; # @符号注释见上面
复制代码
(1)实验 make -f Makefile2 test1 test2 test;./main 命令
实验Makefile命令后,并运行生成的可实验文件

 (2)实验 make -f Makefile2 test;./main 命令
实验Makefile命令后,并运行生成的可实验文件

3.1.3 gcc编译常用组合选项

选项作用示例-o指定输出文件名gcc -c main.c -o main.o-I指定头文件搜索路径gcc -c main.c -I../include-Wall启用所有警告信息gcc -c main.c -Wall-g生成调试信息(用于 GDB)gcc -c main.c -g-O2启用优化(级别 2)gcc -c main.c -O2 3.1.4 make 和 make all区别

关键总结
场景make 行为make all 行为all 是默认目的实验 all实验 allall 不是默认目的实验第一个目的(如 build)实验 all(需存在界说)未界说 all实验第一个目的报错逼迫 .DEFAULT_GOAL=all实验 all实验 all 3.1.4.1 all 是默认目的

当 all 是默认目的时,make 和 make all 运行次序,结果相同。
程序:
main.c
  1. #include <stdio.h>
  2. int main(int argc, const char *argv[])
  3. {
  4.         int x = 60;
  5.         int y = 20;
  6.         printf("main x= %d y= %d \n", x, y);
  7.        
  8.         return 0;
  9. }
复制代码
makefile
  1. # all 是第一个目标(默认目标)
  2. all:target
  3.         echo " all开始"
  4. target:main.c
  5.         gcc main.c -o main
  6.         echo " main开始"
  7. clean:
  8.         rm main  *.o  -rf       
复制代码
运行结果:当 all 是默认目的时,make 和 make all 运行次序,结果相同。
(1)make all

(2)make

3.1.4.2 all 不是默认目的

all 不是默认目的,实验make all命令,会先实验 all依靠的命令。
程序:
 main.c
  1. #include <stdio.h>
  2. int main(int argc, const char *argv[])
  3. {
  4.         int x = 60;
  5.         int y = 20;
  6.         printf("main x= %d y= %d \n", x, y);
  7.        
  8.         return 0;
  9. }
复制代码
makefile
  1. # 若makefile命名不是 GNUmakefile、makefile、Makefile 中的一个
  2. # 要使用 make -f Makefile名称,执行make命令
  3. # all 不是第一个目标
  4. target:main.c
  5.         gcc main.c -o main
  6.         echo " main开始"
  7. all:clean  target
  8.         echo " all开始"
  9. clean:
  10.         rm main  *.o  -rf
复制代码
运行结果:
(1) 初次make 编译, 实验默认目的 target,编译 gcc main.c -o main

(2)实验make all命令,会先实验 clean命令  rm main *.o -rf,在编译gcc main.c -o main

3.1.4.3 没有界说 all 命令

 main.c
  1. #include <stdio.h>
  2. int main(int argc, const char *argv[])
  3. {
  4.         int x = 60;
  5.         int y = 20;
  6.         printf("main x= %d y= %d \n", x, y);
  7.        
  8.         return 0;
  9. }
复制代码
makefile
  1. # 若makefile命名不是 GNUmakefile、makefile、Makefile 中的一个
  2. # 要使用 make -f Makefile名称,执行make命令
  3. target:main.c
  4.         gcc main.c -o main
  5.         echo " main开始"
  6. clean:
  7.         rm main  *.o  -rf
复制代码
运行结果:make all运行报错,make正常运行。

3.1.4.3 逼迫设置 all 为默认目的

 main.c
  1. #include <stdio.h>
  2. int main(int argc, const char *argv[])
  3. {
  4.         int x = 60;
  5.         int y = 20;
  6.         printf("main x= %d y= %d \n", x, y);
  7.        
  8.         return 0;
  9. }
复制代码
makefile
  1. # 若makefile命名不是 GNUmakefile、makefile、Makefile 中的一个
  2. # 要使用 make -f Makefile名称,执行make命令
  3. # 显式设置 .DEFAULT_GOAL 为 all
  4. .DEFAULT_GOAL = all
  5. target:main.c
  6.         gcc main.c -o main
  7.         echo " main开始"
  8. all:clean  target
  9.         echo " all开始"
  10. clean:
  11.         rm main  *.o  -rf
复制代码
运行结果:逼迫设置 all 为默认目的,实验make命令,先实验all依靠的语句。


3.2多文件编程Makefile-基础

main.c
  1. #include "head.h"
  2. int main(int argc, const char *argv[])
  3. {
  4.         int x = 60;
  5.         int y = 20;
  6.         printf("%d + %d = %d\n", x, y, sum(x, y));
  7.         printf("%d - %d = %d\n", x, y, sub(x, y));
  8.        
  9.         return 0;
  10. }
复制代码
sub.c
  1. #include "head.h"
  2. int sub(int a, int b)
  3. {
  4.         return a - b;
  5. }
复制代码
sum.c
  1. #include "head.h"
  2. int sum(int a, int b)
  3. {
  4.         return a + b;
  5. }
复制代码
head.h
  1. #ifndef _HEAD_H_
  2. #define _HEAD_H_
  3. #include <stdio.h>
  4. int sum(int a, int b);
  5. int sub(int a, int b);
  6. #endif
复制代码
Makefile
  1. main:main.o sub.o sum.o
  2.         gcc main.o sub.o sum.o -o main
  3. main.o:main.c
  4.         gcc -c main.c -o main.o
  5. sub.o:sub.c
  6.         gcc -c sub.c -o sub.o
  7. sum.o:sum.c
  8.         gcc -c sum.c -o sum.o
  9. clean:
  10.         rm *.o main a.out -rf
  11.        
复制代码
Makefile语句解释:
main:main.o sub.o sum.o //可实验文件main依靠于main.o sub.o sum.o
    gcc main.o sub.o sum.o -o main //gcc 编译 main.o sub.o sum.o 生成可实验文件main
main.o:main.c //可实验文件main.o依靠于main.c
    gcc -c main.c -o main.o //gcc 编译 main.c 生成可实验文件main.o
sub.o:sub.c //可实验文件sub.o依靠于sub.c
    gcc -c sub.c -o sub.o //gcc 编译 sub.c 生成可实验文件sub.o
sum.o:sum.c //可实验文件sum.o依靠于sum.c
        gcc -c sum.c -o sum.o //gcc 编译 sum.c 生成可实验文件sum.o
clean:
    rm *.o main a.out -rf //实验 make clean删除可实验文件,所有.o文件 main a.out
实验次序:
可实验文件main依靠于main.o,main.o又依靠于main.c,先实验gcc -c main.c -o main.o,在实验gcc main.o sub.o sum.o -o main
运行结果:

3.3makefile变量

3.3.1 makefile 变量概述

   makefile   变量雷同于   C   语言中的宏,当   makefile   被   make   工具解析时,此中的变量会被展开。     变量的作用:     保存文件名列表     保存文件目录列表     保存编译器名     保存编译参数     保存编译的输出     ...    3.3.2 makefile 的变量分类:

   1  、自界说变量     在   makefile   文件中界说的变量。     make   工具传给   makefile   的变量。     2  、体系情况变量     make   工具解析   makefile   前,读取体系情况变量并设置为   makefile   的变量。     3  、预界说变量(自动变量)    3.3.3 自界说变量语法

   界说变量:     变量名  =  变量值      引用变量:     $(  变量名  )  或  ${  变量名  }      makefile   的变量名  :     makefile   变量名可以以数字开头      注意:     1  、变量是大小写敏感的     2  、变量一样寻常都在   makefile   的头部界说     3  、变量险些可在   makefile   的任何地方利用  
常用变量:
  1. 定义变量:VAR = value
  2. 使用变量:$(VAR)
  3. 常用内置变量:
  4. CC:C 编译器(默认 cc,通常指向 gcc)。
  5. CFLAGS:C 编译选项(如 -Wall -O2)。
  6. LDFLAGS:链接选项(如 -L 指定库路径)。
  7. LDLIBS:链接库(如 -lm 表示数学库)。
复制代码
3.3.3.1自界说变量makefile多文件编程

程序:
 main.c
  1. #include "head.h"
  2. int main(int argc, const char *argv[])
  3. {
  4.         int x = 60;
  5.         int y = 20;
  6.         printf("%d + %d = %d\n", x, y, sum(x, y));
  7.         printf("%d - %d = %d\n", x, y, sub(x, y));
  8.        
  9.         return 0;
  10. }
复制代码
sub.c
  1. #include "head.h"
  2. int sub(int a, int b)
  3. {
  4.         return a - b;
  5. }
复制代码
sum.c
  1. #include "head.h"
  2. int sum(int a, int b)
  3. {
  4.         return a + b;
  5. }
复制代码
head.h
  1. #ifndef _HEAD_H_
  2. #define _HEAD_H_
  3. #include <stdio.h>
  4. int sum(int a, int b);
  5. int sub(int a, int b);
  6. #endif
复制代码
Makefile
  1. CC=gcc
  2. obj=main
  3. obj1=sub
  4. obj2=sum
  5. OBJS=main.o sub.o sum.o
  6. $(obj):$(OBJS)
  7.         $(CC) $(OBJS) -o $(obj)
  8. $(obj).o:$(obj).c
  9.         $(CC) -c $(obj).c -o $(obj).o
  10. $(obj1).o:$(obj1).c
  11.         $(CC) -c $(obj1).c -o $(obj1).o
  12. $(obj2).o:$(obj2).c
  13.         $(CC) -c $(obj2).c -o $(obj2).o
  14. clean:
  15.         rm *.o $(obj) a.out -rf
复制代码
Makefile语句解释:与3.2多文件编程Makefile-基础,一样,只是替换为自界说的变量
main:main.o sub.o sum.o //可实验文件main依靠于main.o sub.o sum.o
    gcc main.o sub.o sum.o -o main //gcc 编译 main.o sub.o sum.o 生成可实验文件main
main.o:main.c //可实验文件main.o依靠于main.c
    gcc -c main.c -o main.o //gcc 编译 main.c 生成可实验文件main.o
sub.o:sub.c //可实验文件sub.o依靠于sub.c
    gcc -c sub.c -o sub.o //gcc 编译 sub.c 生成可实验文件sub.o
sum.o:sum.c //可实验文件sum.o依靠于sum.c
        gcc -c sum.c -o sum.o //gcc 编译 sum.c 生成可实验文件sum.o
clean:
    rm *.o main a.out -rf //实验 make clean删除可实验文件,所有.o文件 main a.out
实验次序:
可实验文件main依靠于main.o,main.o又依靠于main.c,先实验gcc -c main.c -o main.o,在实验gcc main.o sub.o sum.o -o main
运行结果:

3.3.4体系变量

   make   工具会拷贝体系的情况变量并将其设置为   makefile   的变量,在   makefile   中可直接读取或修改拷贝后的变量。     程序:     main.c   
  1. #include <stdio.h>
  2. int main(int argc, const char *argv[])
  3. {
  4.         int x = 60;
  5.         int y = 20;
  6.         printf("x = %d  y = %d \n", x, y);
  7.        
  8.         return 0;
  9. }
复制代码
Makefile
  1. main:main.c
  2.         gcc main.c -o main
  3.        
  4. clean:
  5.         rm main -rf
  6.         echo $(PWD)
  7.         echo $(HOME)
  8.         echo $(HOSTNAME)
  9.         echo $(MY_SHELL_NUM)
复制代码
    运行结果:    (1)先在终端实验shell脚本,设置一个预设情况变量,echo 输出一下。    MY_SHELL_NUM=123    export MY_SHELL_NUM     echo $MY_SHELL_NUM    (2)实验 make 命令,在实验 make clean 命令,shell语句的结果输出在终端。    分别输出 PWD ,HOME,HOSTNAME,MY_SHELL_NUM这四个变量的结果     
   3.3.5预界说变量

   
  1. $@ 目标名
  2. $< 依赖文件列表中的第一个文件
  3. $^ 依赖文件列表中除去重复文件的部分
  4. AR 归档维护程序的程序名,默认值为 ar
  5. ARFLAGS 归档维护程序的选项
  6. AS 汇编程序的名称,默认值为 as
  7. ASFLAGS 汇编程序的选项
  8. CC C 编译器的名称,默认值为 cc
  9. CFLAGS C 编译器的选项
  10. CPP C 预编译器的名称,默认值为$(CC) -E
  11. CPPFLAGS C 预编译的选项
  12. CXX C++编译器的名称,默认值为 g++
  13. CXXFLAGS C++编译器的选项
复制代码
3.3.5.1编译器与工具

  变量名默认值形貌示例用法CCccC 编译器CC = gccCXXg++C++ 编译器CXX = clang++ARar静态库打包工具AR = ar rcsASas汇编器AS = nasmLDld链接器LD = lld  3.3.5.2. 编译选项

   变量名形貌默认值示例用法CFLAGSC 编译选项空CFLAGS = -O2 -WallCXXFLAGSC++ 编译选项空CXXFLAGS = -std=c++17CPPFLAGS预处理惩罚选项(C/C++通用)空CPPFLAGS = -IincludeLDFLAGS链接器选项(如库路径)空LDFLAGS = -LlibLDLIBS链接的库(如 -lm)空LDLIBS = -lpthread  3.3.5.3. 文件与目录

变量名形貌默认值示例用法MAKEFILE_LIST当前 Makefile 文件名列表自动生成用于条件判断VPATH搜索源文件的目录列表空VPATH = src:libSRC自界说源文件变量无SRC = main.c utils.cOBJ自界说目的文件变量无OBJ = $(SRC:.c=.o) 3.3.5.4. 隐式规则中的关键变量

Make 根据文件后缀自动推导编译规则,以下变量控制隐式规则行为:
变量名形貌默认命令示例覆盖COMPILE.cC 文件编译命令$(CC) $(CFLAGS) $(CPPFLAGS) -cCOMPILE.c = $(CC) -O3LINK.cC 程序链接命令$(CC) $(CFLAGS) $(LDFLAGS)LINK.c = $(CC) -flto 3.3.5.5. 常用内置变量

变量名形貌示例值MAKE当前 Make 命令路径/usr/bin/makeMAKECMDGOALS用户指定的目的列表all cleanCURDIR当前工作目录/home/user/project
3.3.5.6.程序验证

 程序:
 main.c
  1. #include "head.h"
  2. int main(int argc, const char *argv[])
  3. {
  4.         int x = 60;
  5.         int y = 20;
  6.         printf("%d + %d = %d\n", x, y, sum(x, y));
  7.         printf("%d - %d = %d\n", x, y, sub(x, y));
  8.        
  9.         return 0;
  10. }
复制代码
sub.c
  1. #include "head.h"
  2. int sub(int a, int b)
  3. {
  4.         return a - b;
  5. }
复制代码
sum.c
  1. #include "head.h"
  2. int sum(int a, int b)
  3. {
  4.         return a + b;
  5. }
复制代码
head.h
  1. #ifndef _HEAD_H_
  2. #define _HEAD_H_
  3. #include <stdio.h>
  4. int sum(int a, int b);
  5. int sub(int a, int b);
  6. #endif
复制代码
Makefile
  1. CC=gcc
  2. obj=main
  3. obj1=sub
  4. obj2=sum
  5. OBJ=main.o sub.o sum.o
  6. CFLAGS=-Wall -O2   
  7. # -Wall警告相关, -O2:优化选项,兼顾编译速度和性能
  8. $(obj):$(OBJ)
  9.         $(CC) $^ -o $@
  10. $(obj).o:$(obj).c
  11.         $(CC) $(CFLAGS) -c $< -o $@
  12. $(obj1).o:$(obj1).c
  13.         $(CC) $(CFLAGS) -c $< -o $@
  14. $(obj2).o:$(obj2).c
  15.         $(CC) $(CFLAGS) -c $< -o $@
  16. clean:
  17.         rm *.o $(obj) a.out -rf
  18.        
复制代码
Makefile语句解释:

与3.3.3 自界说变量语法,一样,只是替换为预界说的变量。表达式的区别见4.几种多文件编程Makefile对应关系。
运行结果:

注:Makefile更精简表达式
Makefile1
  1. CC=gcc
  2. obj=main
  3. OBJ=main.o sub.o sum.o
  4. CFLAGS=-Wall -g
  5. $(obj):$(OBJ)
  6.         $(CC) $^ -o $@
  7. %*.o:%*.c  #使用通配符匹配,所有.c文件都去执行下面的命令
  8.         $(CC) $(CFLAGS) -c $< -o $@
  9. clean:
  10.         rm *.o $(obj) a.out -rf
复制代码
运行结果:与上述Makefile运行结果相同
(1)先在终端实验 make clean (2)终端实验 make -f Makefile1 


4.几种多文件编程Makefile对应关系

多文件编程Makefile最基础、自界说变量、预界说变量对应关系。
每一行为几种方法相同结果,不同格式的变量表达式。




免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

熊熊出没

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表