Makefile泛谈

Makefile基础概念

相当于一个编译器,在没有IDE的情况下,可以用cmd命令执行Makefile文件来编译工程。

工作原理

在默认的方式下,也就是我们只输入 make 命令。那么

  1. make 会在当前目录下找名字叫“Makefile”或者“makefile”的文件。
  2. 如果找到,它会找文件中的第一个目标文件(target),在上面的例子中,他会找到“all”这个目标,并把这个文件作为最终的目标文件。(Makefile 中的第一个目标会被作为其默认目标)
  3. 如果all 文件不存在,或是 all 所依赖的后面的 .o 文件的文件修改时间要比 all这个文件新,那么他就会执行后面所定义的命令来生成all 这个文件。
  4. 如果 all所依赖的.o 文件也存在,那么 make 会在当前文件中找目标为.o 文件的依赖性,如果找到则再根据那一个规则生成.o 文件。
  5. 你的 C 文件和 H 文件是存在的,于是 make 会生成 .o 文件,然后再用 .o 文件生成执行文件。

这就是整个 make 的依赖性,make 会一层又一层地去找文件的依赖关系,直到最终编译出第一个目标文件。

显式规则

目标文件: 依赖文件 ... 可以有很多个
	执行命令 (可以有一些选项)

1、目标文件就是要生成的文件。
2、依赖文件就是源头。
3、执行命令:即通过执行命令由依赖文件生成目标文件。注意每条命令之前必须有一个tab

隐式规则

又称为自动推导。

可以自动推导文件以及文件依赖关系后面的命令,于是我们就没必要去在每一个[.o]文件后都写上类似的命令,因为我们的 make 会自动识别并自己推导命令。只要 make 看到一个[.o]文件,它就会自动的把[.c]文件加在依赖关系中,如果 make找到一个 a.o,那么 a.c,就会是 a.o 的依赖文件,并且 cc -c a.c 也会被推导出来。下面举个例子:

文件结构

hello.c hello.h list.c list.h main.c makefile

Makefile最初的内容

main:mian.o hello.o
    gcc main.o he11o.o -o main
mian.o:main.c hello.h
    gcc -c main.c 
he11o.o: hello.c hello.h
    gcc -c he11o.c
clean:
    rm -f *.o main

可以通过变量指定目标文件(后面会讲到,咱们先在这里接触下,看不懂不要紧)

OBJ=mian.o he11o.o
main:$(OBJ)
    gcc $(OBJ) -o main
mian.o:main.c hello.h
    gcc -c main.c 
he11o.o: hello.c hello.h
    gcc -c he11o.c
clean:
    rm -f *.o main

利用隐式规则

OBJ=mian.o he11o.o
main:$(OBJ)
    gcc $(OBJ) -o main
mian.o:hello.h
he11o.o:hello.h
clean:
    rm -f *.o main

利用$符号(后面会讲到,咱们先在这里接触下,看不懂不要紧)

OBJ=mian.o he11o.o
CC=gcc
TARGETS=main
$(TARGETS):$(OBJ)
    $(CC) $^ -o $@
%.o:%.c
    $(CC) -c $<
clean:
    rm -f *.o $@

符号

All目标

Makefile文件默认只生成第一个目标文件即完成编译,但是我们可以通过all 指定所需要生成的目标文件,也就是我们编译的终极目标。

all: target1 target2 target3
target1:
# 编译规则1
target2:
# 编译规则2
target3:
# 编译规则3

all被设置为第一个目标,并且target1、target2和target3被列为all的依赖。当你在命令行中运行make时,make命令会寻找并执行all目标规则,这将依次执行target1、target2和target3的编译。


$符号

$符号表示取变量的值
$^ 表示所有的依赖文件
$@ 表示生成的目标文件
$< 表示第一个依赖文件
$? 代表依赖文件列表中被改变过的所有文件
$* 代表与通过模式规则匹配的目标文件相对应的部分。例如,若目标是foo.o,则$*将表示foo。

@符号

@符号用于禁止显示命令自身,只输出命令执行结果。

@echo $(@F)

$(@F)是一个自动化变量,表示当前目标文件的名称(不包括路径)。

%符号

%.c匹配所有.c文件

%.o:%.c
    gcc -c $<

用路径下所有.c文件都各自生成一个.o文件

#符号

也就是单行注释,Makefile没有多行注释。

变量赋值

=

使用 “=”进行赋值,变量的值是整个Makefile中最后被指定的值。

VIR_A = A
VIR_B = $(VIR_A) B
VIR_A = AA

最后VIR_B的值是AA B,而不是A B,会把整个变量展开。

:=

直接赋值,赋予当前位置的值。

VIR_A := A
VIR_B := $(VIR_A) B
VIR_A := AA

最后BIR_B的值是A B,即根据当前位置进行赋值。

?=

表示如果该变量没有被赋值,赋值予等号后面的值。

VIR ?= new_value

如果VIR在之前没有被赋值,那么VIR的值就为new_value。

+=

表示将符号后面的值添加到前面的变量后面

常用函数

取目录函数dir

从字符串中取出目录部分,目录部分是指最后一个反斜杠(“/”)之前的部分。

dir src/foo.c hacks

取到的是“src/./

shell函数

可以借助这个函数来执行一些shell能够执行的命令

$(shell pwd)

这样就可以执行pwd命令了

ALL_DIRS = $(shell "find" $(SRC_PATH) -type d)

-type d参数用于限定find命令只返回路径(无文件名)。

ALL_DIRS将包含通过find命令获取的指定目录下的所有子目录路径列表。

过滤函数filter

过滤掉一个指定的字符串

FILE = a.c b.h c.s d.cpp   
SRC = $(filter %.c, $(FILE))

留下所有.c文件,最后SRC = a.c

排除函数filter-out

FILE = a.c b.h c.s d.cpp   
SRC = $(filter-out %.c, $(FILE))

去掉所有.c文件,最后SRC = b.h c.s d.cpp

通配符函数wildcard

支持“*”,“?”,“[...]” ,“~”通配符

SRC = $(wildcard ./*.c)

匹配当前目录下所有.c 文件,并将其赋值给SRC变量。

wildcard $(dir)/*.c

匹配所有目录下.c文件

扩展通配符函数patsubst

文件名替换

sources := main.c foo.c bar.c
objects := $(patsubst %.c,%.o,$(sources))

将sources中所有的.c文件名替换为.o,所以objects的值将是 main.o foo.o bar.o。

wildcard $(dir)/*.c

在某个目录中获取所有以 .c 扩展名结尾的文件路径。

$(dir) 是一个变量,表示当前迭代的目录。

/*.c 表示在该目录中搜索所有以 .c 结尾的文件。

目录替换

vpath := src/foo
new_vpath := $(patsubst src/%,obj/%,$(vpath))

将vpath中的src/替换为obj/,所以new_vpath的值将是 obj/foo。

文件扩展名替换

txt_files := file1.txt file2.txt file3.txt
md_files := $(patsubst %.txt,%.md,$(txt_files))

将txt_files中所有的.txt文件名替换为.md,所以md_files的值将是 file1.md file2.md file3.md。

添加前缀

names := apple orange banana
prefixed_names := $(patsubst %,fruit_%,$(names))

为names中的每个名字添加了前缀"fruit_",所以prefixed_names的值将是 fruit_apple fruit_orange fruit_banana。

从路径中提取文件名(去除路径)

full_paths := /home/user/main.c /home/user/foo.c
file_names := $(patsubst /home/user/%.c,%,$(full_paths))

从full_paths中提取了每个文件的文件名,所以file_names的值将是 main foo。

循环函数foreach

$(foreach dir, $(DIRS), $(wildcard $(dir)/*.c))

遍历所有DIRS(纯目录,无文件名)里面的.c文件,以带目录的方式返回。

去除路径notdir

OBJ=$(notdir  a/b/c.cpp, aaa.cpp)

将带路径的文件名去除路径,只保留文件名。

提取前缀basename

返回字符串 “.”之前的所有字段

SRC := src/main.c src/hello.c
OBJ := $(basename $(SRC)) 

返回文件名序列 <names> 的前缀序列,如果文件没有前缀,则返回空字串。

最后返回src/main src/hello

添加前缀addprefix

给字符串中的每一个子串前加上一个前缀

SOURCE = main.c foo.c bar.c
OBJ = $(PWD)
add_source = $(addprefix $(OBJ)/, $(SOURCE))

这样就给每个文件前面添加了路径

字符串替换函数subst

$(subst from,to,text),对 text 文本执行文本替换:每次出现的 from 都替换为 to。

$(subst ee,EE,feet on the street)

生成值 fEEt on the strEEt

foreach遍历集合所有元素

ALL_SRCS = $(foreach dir, $(DIRS), $(wildcard $(dir)/*.c))

VPATH

注意区分大小写,是两个变量来的。

执行时,首先会搜索当前目录下是否存在所需的文件,如果没有,则去VPATH这个变量的值所对应的路径寻找文件。VPATH变量可以给多个路径赋值,各路径之间可以用空格或者冒号隔开,执行make命令时,搜索的顺序是按照书写时的顺序进行的。

伪目标 .PHONY

伪目标只是一个标签,clean是个伪目标没有依赖文件。当目标文件已存在时,忽略,继续执行规则。

clean:
        rm -rf $(OBJ) all.out
 
.PHONY: clean ALL

清理

清理make命令所产生的所有文件

 clean:
        rm -rf $(OBJ) hello.out

clear

删除中间生成.o文件

clear:
    rm *.o

指定路径

头文件路径

一般都是通过"-I"来指定头文件路径

CFLAGS=-I/home/develop/include
app:*.c
    gcc $(CFLAGS) -o app

指定库文件路径

一般都是通过"-L"来指定头文件路径

CFLAGS=-L/home/develop/lib1 -L/home/develop/lib2
app:*.c
    gcc $(CFLAGS) -o app

宏定义

-D macro=xxx
相当于在头文件中定义:#define   macro   xxx

参数选择

编译的时候有很多参数可以选择,在这里举点例子。

-cpu=rh850g3kh:指定编译器的目标CPU架构为rh850g3kh。
-bsp generic:使用通用的BSP(板级支持包)。
-dwarf2:使用DWARF2调试信息格式。
-nothreshold:禁用阈值优化。
-preprocess_assembly_files:对汇编文件进行预处理。
-fsoft:启用软浮点支持。
-list:生成一个列表文件。
-object_dir=$(OBJ_OUTPUT_DIR):指定目标文件的输出目录为$(OBJ_OUTPUT_DIR)。
--no_additional_output:不生成额外的输出文件。
-callgraph:生成函数调用图。
-Ogeneral:启用一般优化级别。
-Mx:启用所有的警告信息。
-e _RESET:指定程序入口点为_RESET。
-D__GHS__:定义一个名为__GHS__的宏。
-elf:生成ELF可执行文件格式的输出。
-no_v850_simd:禁用V850 SIMD(单指令多数据)指令集。
-g:生成调试信息。
-passsource:将源代码传递给后续处理阶段。
-v:详细显示编译过程中的操作信息。
-w:禁用警告信息的显示。
-nofpu:禁用FPU(浮点运算单元)支持。
-nomacro:禁用宏展开。
-b0:设置链接器的起始地址为0。
-DSAIOS_GLOBAL_A1SAMPLE_ENABLE=$(SAIOS_GLOBAL_A1SAMPLE_ENABLE):定义一个名为SAIOS_GLOBAL_A1SAMPLE_ENABLE的宏,并将其值设置为$(SAIOS_GLOBAL_A1SAMPLE_ENABLE)。
-c:表示生成目标文件而不进行链接,即只进行编译而不进行链接。
-c99:表示使用C99标准进行编译,启用C99的新特性和语法。
-map="$(TARGET_OUTPUT_DIR)/$(CURRENT_APPL_NAME).map":表示生成一个链接地图文件,将其指定为TARGET_OUTPUT_DIR目录下的CURRENT_APPL_NAME.map。
-o "$(TARGET_OUTPUT_DIR)/$(CURRENT_APPL_NAME).out":表示指定输出文件的名称和路径,将其设置为TARGET_OUTPUT_DIR目录下的CURRENT_APPL_NAME.out
-M:自动找寻源文件中包含的头文件,并生成一个依赖关系。
 -c,执行汇编阶段,生成 object 目标文件。
-E,执行预处理阶段,生成预处理文件。
-S,执行编译阶段,生成汇编代码文件。
-o [FILE],生成指定的输出文件,用在生成可执行文件时。
-O0,不进行优化处理。
-O,等同于 -O1 优化生成代码。
-O2,比 -O1 进一步优化。
-O3,比 -O2 更进一步优化,包括 inline 函数。
-w,不生成任何警告信息。
W,只生成编译器认为会出现错误的警告。
-Wall,生成所有警告信息。
-g,生成调试信息,GNU 调试器调试时可利用该信息。
-ansi,只支持 ANSI 标准的 C 语法,这一选项将禁止 GNU C 的一些些特色,例如 asm 或 typeof 关键词。
-DMACRO,以字符串 “1” 定义 MACRO 宏。
-DMACRO=DEFN,以字符串 “DEFN” 定义 MACRO 宏。
-IDIRECTORY,指定额外的头文件搜索路径 DIRECTORY。
-LDIRECTORY,指定额外的函数库搜索路径 DIRECTORY。
-shared,生成共享目标文件。通常用在建立共享库时。
-static,静态连接,即禁止使用共享连接。
-UMACRO,取消对 MACRO 宏的定义。
-w,不生成任何警告信息。
-W,只生成编译器认为会出现错误的警告。
-Wall,生成所有警告信息。
-Waddress,使用可疑的内存地址时给出警告。
-Waggregate-return,当返回结构,联合或数组时给出警告。
-Waliasing,为可能的虚参重叠给出警告。
-Walign-commons,对 COMMON 块对齐的警告。
-Wampersand,若延续字符常量中缺少 & 则给出警告,不支持 C 语言。
-Warray-bounds,当数组访问越界时给出警告。
-Warray-temporaries,创建临时数组时给出警告,不支持 C 语言。
-Wattributes,当对属性的使用不合适时给出警告。
-Wbad-function-cast,当把函数转换为不兼容类型时给出警告。
-Wbuiltin-macro-redefined,当内建预处理宏未定义或重定义时给出警告。
-Wc++-compat,当在 C 语言中使用了 C 与 C++ 交集以外的构造时给出警告。
-Wcast-align,当转换指针类型导致对齐边界增长时给出警告。
-Wcast-qual,当类型转换丢失限定信息时给出警告。
-Wchar-subscripts,当下标类型为 char 时给出警告。
-Wenum-compare,对不同枚举类型之间的比较给出警告。
-Wformat,对 printf/scanf/strftime/strfmon 中的格式字符串异常给出警告
-Wfloat-equal,当比较浮点数是否相等时给出警告。
-Wignored-qualifiers,当类型限定符被忽略时给出警告。
-Wimplicit,对隐式函数声明给出警告。
-Wimplicit-function-declaration,对隐式函数声明给出警告。
-Wimplicit-int,当声明未指定类型时给出警告。
-Winline,当内联函数无法被内联时给出警告。
-Wmain,对可疑的 main 声明给出警告。
-Wswitch-enum,当使用枚举类型作为 switch 变量但又缺少某个 case 时给出警告。
-Wuninitialized,自动变量未初始化时警告。
-Wunused-value,当一个表达式的值未被使用时给出警告。
-Wunused-variable,有未使用的变量时警告。
-Wvla,使用变长数组时警告。
-Wreturn-type,当 C 函数的返回值默认为 int,或者 C++ 函数的返回类型不一致时给出警告。
-Wredundant-decls,对同一个对象多次声明时给出警告。
-Wold-style-cast,程序使用 C 风格的类型转换时给出警告,不支持 C 语言。
-Wempty-body,当 if 或 else 语句体为空时给出警告。
-Winit-self,对初始化为自身的变量给出警告。
-Wlong-long,当使用 -pedantic 时不对 long long 给出警告。
-Wmissing-prototypes,全局函数没有原型时给出警告。
-Wnonnull,当将 NULL 传递给需要非 NULL 类型的参数的函数时给出警告。
-Wparentheses,可能缺少括号的情况下给出警告。
-Wunused,启用所有关于 xx未使用 的警告。
-Wvolatile-register-var,当一个寄存器变量被声明为 volatile 时给出警告。
-Wundef,当 #if 指令中用到未定义的宏时给出警告。
-Wenum-compare,对不同枚举类型之间的比较给出警告。
-Wdouble-promotion,对从 float 到 double 的隐式转换给出警告。
-Wnested-externs,当 extern 声明不在文件作用域时给出警告。
-Wformat-zero-length,对长度为 0 的格式字符串给出警告。
-Wendif-labels,当 #elif 和 #endif 后面跟有其他标识符时给出警告。
-Wdiv-by-zero,对编译时发现的零除给出警告。
-Wunused-macros,当定义在主文件中的宏未被使用时给出警告。
-Wunused-function,有未使用的函数时警告。
-Wswitch-default,当使用枚举类型作为开关变量,但没有提供 default 语句时给出警告。
-Wunused-label,有未使用的标号时警告。
-Wprotocol,当继承来的方法未被实现时给出警告,不支持 C 语言。
-O0,不进行优化处理。
-O,即等同于 -O1,在不影响编译速度的前提下,尽量采用一些优化算法降低代码大小,和提高目标代码运行速度。
-O2,该优化选项会牺牲部分编译速度,采用几乎所有的目标配置支持的优化算法以提高目标代码运行速度。
-O3,最大化速度(maximize speed),会增加代码大小,即提高目标代码的并行执行能力。
-Os,优选代码空间(favor code space)即优化生成目标文件的大小。
-Og,启用全局优化(enable global optimization),为了能够生成更好的调试信息,精心挑选部分与调试不冲突的优化选项。
-Ofast,使用最高级别的优化选项来编译代码,可以无视严格的语言标准以提高程序的执行速度。
-Fa [file],命名程序集列表文件(name assembly listing file。
-Fo,命名对象文件(name object file。
-FA [sc],配置程序集列表(configure assembly listing。
-Fp,命名预编译头文件(name precompiled header file。
-Fd [file],命名 .PDB 文件(name .PDB file)。
-Fr [file],命名源浏览器文件(name source browser file。
-Fe,命名可执行文件(name executable file)。
-FR [file],命名扩展 .SBR 文件(name extended .SBR file)。
-Fm [file],命名映射文件(name map file)。
-FI,命名强制包含文件(name forced include file)。
-C,不吸取注释(don’t strip comments)。
-U,移除预定义宏(remove predefined macro)。
-D {=|#},定义宏(define macro)。
-u,移除所有预定义宏(remove all predefined macros)。
-E,将预处理定向到标准输出(preprocess to stdout)。
-I,添加到包含文件的搜索路径(add to include search path)。
-EP,将预处理定向到标准输出,不要带行号(preprocess to stdout, no #line)。
-X,忽略 “标准位置”(ignore “standard places”)。
-P,预处理到文件(preprocess to file)。
--version,显示 GCC 详细版本信息。
-o [FILE],生成指定的输出文件,用在生成可执行文件时。
-c,执行汇编阶段,生成 object 目标文件。
-E,执行预处理阶段,生成预处理文件。
-S,执行编译阶段,生成汇编代码文件。
-x [language] [file name],根据约定 C 语言的后 缀名称是 .c ,如果不是 .c,则需要使用该选项指定文件类型,例如 -x c++ hello.a。
-w,不生成任何警告信息。
-W,只生成编译器认为会出现错误的警告。
-Wall,生成所有警告信息。
-g,生成调试信息到目标文件中,将编译时的调试信息保存到本地文件中(stabs,COFF,XCOFF,DWARF)。
-ggdb,为 GDB 产生调试信息,包含 GDB 的扩展。
-ggdb[level],设定产生何种等级的调试信息, level 为 1-3,1 最少,3 最多,例如 -ggdb3。
-pipe,在多个编译过程之间使用管道。
-static,静态连接,即禁止使用共享连接。
-ansi,C 模式下支持所有 ISO C90 标准的 C 程序, C++ 模式下去除对 GNU C++ 扩展的支持(GNU 扩展会与 ISO C++ 冲突)。
-std=,确定编译语言的标准,例如 -std=c11,目前只在编译 C 和 C++ 时有效 -fno-asm 不将 asm,inline,typeof 作为关键字,可以用他们做变量名等。
-funsigned-char,将 char 的数据类型设为 unsigned,即无符号。
-fsigned-char,正好相反,将 char 设为 signed,即有符号。
-fsyntax-only,只检查语法错误,不做其他任何事。
-pedantic,显示所有的 ISO C 和 ISO C++ 的警告,并且拒绝所有使用禁止扩展的程序。
-ftime-report,统计编译消耗的时间并显示报告。
-fmem-report,显示所有的静态内存分配。
-ftest-coverage,为 gcov 工具产生数据文件。
-DMACRO,以字符串 “1” 定义 MACRO 宏。
-DMACRO=DEFN,以字符串 “DEFN” 定义 MACRO 宏。
-IDIRECTORY,指定额外的头文件搜索路径 DIRECTORY。
-LDIRECTORY,指定额外的函数库搜索路径 DIRECTORY。
-shared,生成共享目标文件。通常用在建立共享库时。
-UMACRO,取消对 MACRO 宏的定义。
-M,生成文件关联的信息。包含目标文件所依赖的所有源代码
-MM,和 -M 一样,但是它将忽略由 #include 造成的依赖关系。
-MD,和 -M 相同,但是输出将导入到 .d 文件。
-MMD,和 -MM 相同,但是输出将导入到 .d 文件。
-I [dir],表示将 dir 目录添加到头文件搜索路径中,这样就可以直接使用 #include<header.h> 的形式进行包含。
-I-[dir],表示将指定的目录从头文件搜索路径中移除,移除后将不再该路径搜索头文件。
-idirafter [dir],在指定的头文件搜索路径里面查找失败,则到这里指定的目录中查找。
-L [dir],制定编译的时候,指定库的搜索路径,告诉编译器在 dir 目录中查找库文件,例如指定搜索我们自定义库。
-l[library name],指定编译时候使用的库,例如指定数学库 gcc hello.c -lm。

正斜杠/和反斜杠\


/:正斜杠多用于选项

del /F /Q    #强制删除只读文件 安静模式

\:反斜杠在 Makefile 中通常用于转义特殊字符或者路径。这是因为反斜杠在许多操作系统中被用作路径分隔符,因此为了在 Makefile 中正确使用它,需要使用双反斜杠(\\)来表示一个反斜杠字符。例如,C:\\Users\\TS\\file.txt 表示在 Windows 系统中的路径 C:\Users\TS\file.txt。

在表示路径当中,有时候正反斜杠可以混着用,这个要看工具。

表示路径的时候最好还是要加一句,把正斜杠替换成反斜杠。

$(subst /,\,$(OBJ_OUTPUT_DIR))

重定向

1>nul(即>nul)

> 是标准输出重定向符号,用于将命令的标准输出(通常是在终端或命令提示符中显示的内容)重定向到空设备(nul)。这样,命令的输出将被丢弃,不会在终端显示。

2>nul

2> 是标准错误输出重定向符号,用于将命令的错误输出重定向到空设备(nul)。这样,命令的错误消息将被丢弃,不会在终端显示。

实例

经典实例

CC := g++  
CFLAGS := -g  
TARGET := test  
SRCS := $(wildcard *.cpp)  
OBJS := $(patsubst %cpp,%o,$(SRCS))  

all:$(TARGET)  
%.o:%.cpp  
    $(CC) $(CFLAGS) -c $< -o $@ 
$(TARGET):$(OBJS)  
    $(CC) $(CFLAGS) -o $@  
clean:  
    rm -rf $(TARGET) *.o  

嵌套实例

主Makefile(Makefile)

SUBDIRS = subdir1 subdir2

.PHONY: all $(SUBDIRS)

all: $(SUBDIRS)

$(SUBDIRS):
    $(MAKE) -C $@

clean:
    for dir in $(SUBDIRS); do \
        $(MAKE) -C $$dir clean; \
    done

在主Makefile中,我们定义了一个变量SUBDIRS,它包含要构建的子目录名称。.PHONY指令用于指明all$(SUBDIRS)是伪目标,而不是实际存在的文件。

all目标依赖于$(SUBDIRS),并通过运行$(MAKE) -C $@命令进入每个子目录,执行子目录中的Makefile。

clean目标会遍历$(SUBDIRS),并通过运行$(MAKE) -C $$dir clean命令在每个子目录中执行clean目标。

子目录Makefile(subdir1/Makefile 和 subdir2/Makefile)

all:
    $(MAKE) -C subdir1
    $(MAKE) -C subdir2

clean:
    $(MAKE) -C subdir1 clean
    $(MAKE) -C subdir2 clean

在子目录的Makefile中,我们使用相同的方式来调用$(MAKE)命令进入其他子目录并执行相应的目标。

通过这种嵌套Makefile的结构,我们可以在主Makefile中定义整个项目的构建流程,然后在子目录的Makefile中定义各自的构建规则。这样可以实现清晰的模块化,并确保每个子目录可以独立构建。

运行主Makefile中的make命令将会进入每个子目录,依次执行各自的Makefile。运行主Makefile中的make clean命令将会在每个子目录中执行clean目标。

亲身经历问题

注释不能在命令里面

提示“文件名、目录名或卷标语法不正确。”但是查过文件名目录名都是对的。

发现问题在注释那一行,连续几行的命令里面是不允许有空行或者注释的!!!

注释不能在目标之间

下面的也是,哪怕用空行隔开了,也不能加注释!!!

all: $(CURRENT_APPL_NAME).a

# @echo $(ALL_SRCS_NOWITH_PATH)//这行有问题
# @echo $(CINCLUDE)//这行有问题
	
AR_INSTALL_DIR = C:\MinGW\bin
AR=$(AR_INSTALL_DIR)\ar.exe

make: Nothing to be done for  all

有时候会看到这个错误,它只是告诉你,生成文件已经存在,不用重新编译,没啥要做的。但是有个可能,你改了Makefile或者源文件,但是由于make的时候先从最后的生成文件来检查,有最后的生成文件就不会重新编译所有的中间文件或者查找源文件,这时候要先clean再重新编译。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

不吃鱼的羊

你的鼓励将是我创作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值