Makefile案例
makefileforeach用法
makefileforeach用法Makefile中的foreach用法是用来遍历一个列表,并为每个元素执行一系列的操作。
它的语法如下:$(foreach <var>,<list>,<text>)其中,<var>是一个变量名,<list>是一个以空格分隔的字符串列表,<text>是要执行的一系列操作。
在执行foreach指令时,会将列表中的每个元素分别赋值给<var>,然后执行<text>中的操作。
下面我们来详细了解foreach的用法。
1.基本语法首先,让我们看一个简单的例子,假设我们有一个列表包含a、b和c三个元素,我们想要为每个元素打印一条消息:candidates := a b c$(foreach candidate,$(candidates),$(info Processing candidate: $(candidate)))在这个例子中,我们使用了两个内置函数:$(info ...)用于打印消息,$(foreach ...)用于遍历列表。
执行结果如下:Processing candidate: aProcessing candidate: bProcessing candidate: c2.执行命令除了打印消息,我们也可以使用foreach执行一系列的命令。
例如,假设我们有一个文件列表,我们想要将每个文件复制到一个目标目录中:files := file1.txt file2.txt file3.txtdestination := /path/to/destination/$(foreach file,$(files),cp $(file) $(destination))3.生成目标除了执行命令,我们还可以使用foreach生成目标。
假设我们有一个列表包含源文件的名称,我们想为每个源文件生成一个对应的目标文件:sources := source1.c source2.c source3.cobjects := $(foreach source,$(sources),$(source:.c=.o))在这个例子中,我们使用了一个替换函数$(source:.c=.o),它的作用是将源文件的后缀.c替换为.o。
c语言makefile编写实例
c语言makefile编写实例Makefile是用来管理程序编译的工具,可以方便地管理程序的编译过程。
使用Makefile可以大大简化程序的编译过程,提高程序的可维护性。
Makefile的语法比较简单,主要由目标、依赖和命令三部分组成。
下面我们以一个简单的C程序为例,来介绍如何使用Makefile进行编译。
假设我们有一个名为hello.c的程序,代码如下:```c#include <stdio.h>int main(){printf("Hello, world!\n");return 0;}```我们需要使用gcc编译器将其编译成可执行文件。
下面是一个简单的Makefile:```makefilehello: hello.cgcc -o hello hello.c```这个Makefile很简单,它定义了一个名为hello的目标,该目标依赖于hello.c文件,并使用gcc命令将其编译成可执行文件。
如果我们在终端中输入make命令,Makefile会自动执行编译过程:```$ makegcc -o hello hello.c```Makefile还可以定义多个目标,每个目标可以有多个依赖和多个命令。
下面是一个稍微复杂一些的Makefile:```makefileCC=gccCFLAGS=-Wall -gall: hello goodbyehello: hello.o$(CC) $(CFLAGS) -o hello hello.ogoodbye: goodbye.o$(CC) $(CFLAGS) -o goodbye goodbye.ohello.o: hello.c$(CC) $(CFLAGS) -c hello.cgoodbye.o: goodbye.c$(CC) $(CFLAGS) -c goodbye.cclean:rm -f *.o hello goodbye```这个Makefile定义了两个目标:all和clean。
Makefile 语法分析
Makefile 语法分析第一部分VERSION = 2# 给变量VERSION赋值PATCHLEVEL = 6# 给变量PATCHLEVEL赋值SUBLEVEL = 22# 给变量SUBLEVEL赋值EXTRAVERSION = .6# 给变量EXTRAVERSION赋值NAME = Holy Dancing Manatees, Batman!# 给变量NAME赋值# *DOCUMENTATION*# To see a list of typical targets execute "make help"# More info can be located in ./README# Comments in this file are targeted only to the developer, do not# expect to learn how to build the kernel reading this file.# Do not:# o use make's built-in rules and variables# (this increases performance and avoid hard-to-debug behavour);# o print "Entering directory ...";MAKEFLAGS += -rR --no-print-directory# 操作符“+=”的作用是给变量(“+=”前面的MAKEFLAGS)追加值。
# 如果变量(“+=”前面的MAKEFLAGS)之前没有定义过,那么,“+=”会自动变成“=”;# 如果前面有变量(“+=”前面的MAKEFLAGS)定义,那么“+=”会继承于前次操作的赋值符;# 如果前一次的是“:=”,那么“+=”会以“:=”作为其赋值符# 在执行make时的命令行选项参数被通过变量“MAKEFLAGS”传递给子目录下的make程序。
makefile--参数传递、条件判断、include(五)
makefile--参数传递、条件判断、include(五)在多个Makefile嵌套调⽤时,有时我们需要传递⼀些参数给下⼀层Makefile。
⽐如我们在顶层Makefile⾥⾯定义的打开调试信息变量DEBUG_SYMBOLS,我们希望在进⼊⼦⽬录执⾏⼦Makefile时该变量仍然有效,这是需要将该变量传递给⼦Makefile,那怎么传递呢?这⾥有两种⽅法:1. 在上层Makefile中使⽤”export”关键字对需要传递的变量进⾏声明。
⽐如:1 2DEBUG_SYMBOLS = TRUE export DEBUG_SYMBOLS当不希望将⼀个变量传递给⼦ make 时,可以使⽤指⽰符 “unexport”来声明这个变量。
export⼀般⽤法是在定义变量的同时对它进⾏声明。
如下:1export DEBUG_SYMBOLS = TRUE2. 在命令⾏上指定变量。
⽐如:1$(MAKE) -C xxx DEBUG_SYMBOLS = TRUE这样在进⼊⼦⽬录xxx执⾏make时该变量也有效。
像编程语⾔⼀样,Makefile也有⾃⼰的条件语句。
条件语句可以根据⼀个变量值来控制make的执⾏逻辑。
⽐较常⽤的条件语句是ifeq –else-endif、ifneq-else-endif、ifdef-else-endif。
ifeq关键字⽤来判断参数是否相等。
⽐如判断是否⽣成调试信息可以这么⽤:1 2 3 4 5 6ifeq ($(DEBUG_SYMBOLS), TRUE) >---CFLAGS += -g -Wall -Werror -O0 else>---CFLAGS += -Wall -Werror -O2 endifIfneq和ifeq作⽤相反,此关键字是⽤来判断参数是否不相等。
ifdef关键字⽤来判断⼀个变量是否已经定义。
后两个关键字⽤法和ifeq类似。
现在我们继续改进我们上⼀节的Makefile,上⼀节的Makefile完成Makefile的嵌套调⽤,每⼀个模块都有⾃⼰的Makefile。
软件开发中的BUG案例
软件开发中的BUG案例1 概述众所周知,软件开发过程中BUG是难以避免的。
但是⼀个训练有素的程序员却能将BUG的出现率尽可能的降低。
本⽂档将BUG粗略地分为⼏个⼤类,以便于学习参考。
程序结构和处理逻辑类:包括程序的结构,算法的选择和实现等。
可移植性类:包括跨平台代码的移植、封装等。
可维护性类:包括诊断性代码、测试⽀持、注释、命名风格等。
其他问题:不好归类的BUG、实践技巧等。
2 程序结构和处理逻辑2.1 ##某Linux应⽤程序采⽤了DailyBuild,为了⾃动维护其构建版本号,我们将每⽇构建的版本号单独定义为:#define BUILDNO?“0001”需要引⽤该版本号的地⽅采⽤了预编译操作符“##”:#define VERSION?“8.0.”##BUILDNO””#define VERSION_STR “8.0.”##BUILDNO” Special Release for RedHat Linux 8.0”这在GCC 3.3之前⼯作得很好,可是换成了 GCC 3.3.1 后,出现了错误:foo.c:127:33: pasting ""8.0."" and "BUILDNO" does not give a valid preprocessing token解决的办法很简单,就是将“##”去掉。
结尾的空串””也是多余的。
操作符“##”的⽤途主要是⽤于宏展开时将参数保留为字符串形式,例如:#define __CONCAT(x, y)?x##y__CONCAT(foo, bar)2.2 变量初始化某系统⽀持UNIX命令⾏风格的命令,例如:SHOW SETTINGS等。
其语法分析代码中使⽤了⼀个全局字符串数组,⽤于记录某些特殊的语法⽚断。
可是该变量不是每次语法分析启动前都初始化的,导致以下现象发⽣了:某个命令执⾏第⼀次没有问题,但连续执⾏4次就会导致系统内部的内存检查模块报告异常。
makefile make install 用法举例
makefile make install 用法举例Makefile是一种用于自动化编译和构建软件的工具,它可以根据不同的构建目标(如编译、安装等)自动生成相应的构建指令。
在Makefile中,可以使用make命令来执行构建任务,其中make install是一种常用的构建指令,用于安装软件包。
一、Makefile的创建在创建Makefile之前,需要了解项目的基本结构和依赖关系,并根据需求定义不同的构建目标。
Makefile通常包含多个规则,每个规则定义了一个特定的构建目标及其对应的构建指令。
以下是一个简单的Makefile示例,用于编译一个C语言程序:```makefileCC=gccCFLAGS=-Wall -gSRC=main.c utils.cOBJ=$(SRC:.c=.o)all: $(SRC) Makefile $(OBJ)$(CC) $(CFLAGS) $(OBJ) -o program%.o: %.c$(CC) $(CFLAGS) -c $< -o $@clean:rm -f $(OBJ) $(EXE) *.o core* *~ .depend```在这个示例中,我们定义了两个规则:all规则和%.o规则。
all规则用于定义编译和链接指令,而%.o规则用于定义编译指令。
在执行make命令时,Makefile会根据当前目录下的Makefile和源文件自动生成相应的构建指令。
二、make install的使用make install是Makefile中常用的一种构建指令,用于将软件包安装到目标系统中。
使用make install命令时,需要指定安装的目标目录和安装选项。
下面是一个简单的示例:假设我们有一个名为myapp的软件包,将其安装到/usr/local/目录下:```bashmake install prefix=/usr/local/```在这个示例中,我们使用make install命令将myapp软件包安装到/usr/local/目录下。
c++的makefile实例
1. 将上述代码保存到一个名为 "Makefile"(注意大小写)的文件中。 2. 将 "your_program" 替换为你的目标程序的名称。 3. 将 "main.cpp"、"file1.cpp" 和 "file2.cpp" 替换为你的源代码文件的名称(如果有更 多文件,可以继续添加)。 4. 运行命令 `make` 来编译和构建你的程序。
c++的makefile实例
- `%.o: %.cpp`:这个规则用于编译每个源代码文件。它将每个 .cpp 文件编译为对应的 .o 文件。
- `clean`:这个规则用于清理生成的目标文件和目标程序。
你可以根据你的实际需要修改和调整这个 Makefile,例如添加其他编译选项、链接库等 。运行命令 `make clean` 可以删除生成的目标文件和目标程序。
all: $(TARGET)
$(TARGET): $(OBJS) $(CC) $(CFLAGS) -o $@ $^
%.o: %.cpp $(CC) $(CFLAGS) -c $< -o $@
clean:
rm -f $(OBJS) $(TARGET)
c++的makefile实例
在这个示例中,你需要做以下几个步骤:
c++的makefile实例
这个 Makefile 的规则解释如下:
- `CC`:定义了编译器的名称(在这里使用了 g++)。 - `CFLAGS`:定义了编译器的选项(在这里使用了 -std=c++11 和 -Wall)。 - `TARGET`:定义了目标程序的名称。 - `SRCS`:定义了源代码文件的名称。 - `OBJS`:定义了目标文件的名称(通过将源文件的扩展名 .cpp 替换为 .o 而得到)。 - `all`:这是一个默认目标,用于构建目标程序。它依赖于 $(TARGET)。 - `$(TARGET)`:这个规则用于构建目标程序。它依赖于 $(OBJS)。通过 $(CC) 命令将目 标文件链接在一起生成最终的可执行文件。
makefile循环语句
makefile循环语句(原创版)目录1.Makefile 简介2.Makefile 循环语句的作用3.Makefile 循环语句的语法4.Makefile 循环语句的示例5.Makefile 循环语句的注意事项正文1.Makefile 简介Makefile 是一种构建脚本,用于自动构建和编译源代码。
它最初用于 Unix 系统,但现在已经广泛应用于各种操作系统,如 Linux、macOS 等。
Makefile 可以根据源代码的变化自动重新编译目标文件,从而提高了开发效率。
2.Makefile 循环语句的作用在 Makefile 中,循环语句用于处理一系列相似的任务。
通过使用循环语句,可以避免重复编写相同的代码,使 Makefile 更加简洁和易于维护。
3.Makefile 循环语句的语法Makefile 循环语句的基本语法如下:```循环名:for 变量名 in 列表; do# 循环体内容done```其中,循环名是一个标识符,用于表示循环的开始和结束。
变量名是要迭代的变量,列表是一个包含多个元素的列表,用空格分隔。
循环体内容是循环执行的任务。
4.Makefile 循环语句的示例以下是一个 Makefile 循环语句的示例:```all:for src in src1 src2 src3; doobj := $(src).o$(CC) $(CFLAGS) -c $src -o $objdone```在这个示例中,循环名为“all”,变量名为“src”,列表为“src1 src2 src3”。
循环体内容是使用 C 编译器编译源代码文件并生成目标文件。
5.Makefile 循环语句的注意事项在使用 Makefile 循环语句时,需要注意以下几点:- 循环名应该具有唯一性,避免重复定义。
- 列表中的元素应该使用空格分隔,而不是逗号或其他分隔符。
- 在循环体内,可以使用自动变量(如$@、$%等)来表示当前迭代的变量。
cmakelist生成makefile的方法
cmakelist生成makefile的方法
要使用CMake生成Makefile,需要创建一个CMakeLists.txt文件,并在其中描述项目的构建过程和依赖关系。
以下是一个简单的CMakeLists.txt文件的示例:
```
cmake_minimum_required(VERSION 3.10)
project(MyProject)
# 添加源文件
add_executable(MyExecutable main.cpp)
# 添加依赖库
target_link_libraries(MyExecutable MyLibrary)
# 指定编译选项
target_compile_options(MyExecutable PRIVATE -Wall -Wextra)
# 指定安装目标
install(TARGETS MyExecutable DESTINATION bin)
```
然后,可以使用命令行工具执行以下命令来生成Makefile并构建项目:
```
mkdir build
cd build
cmake ..
make
```
在以上命令中,`mkdir build`用于创建一个叫做build的文件夹,`cd build`用于进入该文件夹,`cmake ..`用于生成Makefile,
`make`用于根据Makefile构建项目。
执行完毕后,可在build文件夹中找到生成的可执行文件。
当然,还有更多的CMake命令和选项可以用来控制项目的构
建过程,以满足更多的需求。
详情请参考CMake的官方文档。
makefile gcc编译
makefile gcc编译
Makefile 是一个用来组织代码编译的工具,而 GCC 是一个常用的 C 和 C++ 编译器。
在 Makefile 中使用 GCC 进行编译可以通过以下步骤完成:
1. 创建一个名为 "Makefile" 的文本文件,并确保它位于你的项目根目录下。
2. 在 Makefile 中定义你的编译规则。
例如,假设你有一个名为 "main.c" 的源文件需要编译成可执行文件 "app",你可以这样编写 Makefile:
make.
app: main.c.
gcc -o app main.c.
在这个例子中,我们定义了一个名为 "app" 的目标,它依赖于"main.c" 这个源文件。
当你运行 "make" 命令时,Make 工具会根
据这个规则来执行编译。
3. 打开终端,进入到包含 Makefile 的项目目录下。
4. 运行命令 "make"。
Make 工具会读取 Makefile 文件,并执行其中定义的编译规则。
在这个例子中,它会使用 GCC 编译器来编译 "main.c" 并生成可执行文件 "app"。
需要注意的是,Makefile 可以包含更复杂的规则和变量定义,以及支持多个源文件的编译。
你可以根据你的项目需求来进一步扩展和定制 Makefile 文件。
总之,通过合理编写 Makefile 并结合使用 GCC 编译器,你可以高效地组织和管理你的代码编译过程。
makefile中的gcc -c -o语法
文章标题:深度探讨makefile中的gcc -c -o语法在makefile中,gcc -c -o是一个非常重要的语法结构,用于编译源文件并生成目标文件。
在本文中,我将对这个语法进行深入探讨,帮助你更好地理解它的用途和功能,并运用到实际的项目中。
1. gcc -c -o的基本概念在makefile中,gcc -c -o用于将源文件编译成目标文件。
其中,-c表示编译但不信息,-o用于指定编译后生成的目标文件名。
这个语法结构在实际的项目中非常常见,尤其是在大型的软件开发过程中。
2. 深入理解gcc -c -o的作用通过gcc -c -o,我们可以将源文件编译成目标文件,然后再将多个目标文件信息起来,生成可执行文件。
这样的分步编译方式可以提高编译的效率,尤其是在一个项目中包含大量源文件的情况下。
另外,通过指定-o参数,我们可以自定义目标文件的生成规则和命名规范,让项目结构更加清晰和灵活。
3. 实际应用案例举一个实际的例子,比如我们有一个项目包含多个源文件,分别是main.c、function1.c和function2.c。
我们可以使用gcc -c -o将这些源文件分别编译成目标文件main.o、function1.o和function2.o,然后通过gcc将这些目标文件信息起来,生成可执行文件。
这样的分步编译方式可以提高项目的维护性和灵活性。
4. 对于gcc -c -o的个人观点和理解个人认为,gcc -c -o是一个非常实用的编译选项,尤其是在大型的软件开发项目中。
通过这个选项,我们可以更加灵活地管理项目的结构,提高编译效率,同时也让代码更加清晰和易于维护。
在实际的项目中,我经常使用这个选项来进行分步编译,以便更好地管理和组织代码。
5. 总结通过本文的深入探讨,相信你对makefile中的gcc -c -o语法有了更深入的理解。
这个语法不仅在软件开发中非常常见,而且也非常实用。
通过灵活运用这个选项,我们可以更好地管理和组织项目,提高代码的可维护性和开发效率。
Makefile经典教程(最掌握这部分足够---因为汇集全部精华)!!!!!!!!!!
Makefile经典教程0 Makefile概述什么是makefile?或许很多Winodws的程序员都不知道这个东西,因为那些Windows的IDE都为你做了这个工作,但我觉得要作一个好的和professional的程序员,makefile还是要懂。
这就好像现在有这么多的HTML的编辑器,但如果你想成为一个专业人士,你还是要了解HTML的标识的含义。
特别在Unix下的软件编译,你就不能不自己写makefile了,会不会写makefile,从一个侧面说明了一个人是否具备完成大型工程的能力。
因为,makefile关系到了整个工程的编译规则。
一个工程中的源文件不计数,其按类型、功能、模块分别放在若干个目录中,makefile定义了一系列的规则来指定,哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂的功能操作,因为makefile就像一个Shell脚本一样,其中也可以执行操作系统的命令。
makefile带来的好处就是——“自动化编译”,一旦写好,只需要一个make命令,整个工程完全自动编译,极大的提高了软件开发的效率。
make是一个命令工具,是一个解释makefile中指令的命令工具,一般来说,大多数的IDE都有这个命令,比如:Delphi的make,Visual C++的nmake,Linux下GNU的make。
可见,makefile都成为了一种在工程方面的编译方法。
现在讲述如何写makefile的文章比较少,这是我想写这篇文章的原因。
当然,不同产商的make各不相同,也有不同的语法,但其本质都是在“文件依赖性”上做文章,这里,我仅对GNU的make进行讲述,我的环境是RedHat Linux 8.0,make的版本是3.80。
必竟,这个make是应用最为广泛的,也是用得最多的。
而且其还是最遵循于IEEE 1003.2-1992 标准的(POSIX.2)。
在这篇文档中,将以C/C++的源码作为我们基础,所以必然涉及一些关于C/C++的编译的知识,相关于这方面的内容,还请各位查看相关的编译器的文档。
Makefile使用总结
Makefile使⽤总结1. Makefile 简介Makefile 是和 make 命令⼀起配合使⽤的.很多⼤型项⽬的编译都是通过 Makefile 来组织的, 如果没有 Makefile, 那很多项⽬中各种库和代码之间的依赖关系不知会多复杂. Makefile的组织流程的能⼒如此之强, 不仅可以⽤来编译项⽬, 还可以⽤来组织我们平时的⼀些⽇常操作. 这个需要⼤家发挥⾃⼰的想象⼒.本篇博客是基于⽽整理的, 有些删减, 追加了⼀些⽰例.⾮常感谢 gunguymadman_cu 提供如此详尽的Makefile介绍, 这正是我⼀直寻找的Makefile中⽂⽂档.1.1 Makefile 主要的 5个部分 (显⽰规则, 隐晦规则, 变量定义, ⽂件指⽰, 注释)Makefile基本格式如下:target ... : prerequisites ...command......其中,target - ⽬标⽂件, 可以是 Object File, 也可以是可执⾏⽂件prerequisites - ⽣成 target 所需要的⽂件或者⽬标command - make需要执⾏的命令 (任意的shell命令), Makefile中的命令必须以 [tab] 开头1. 显⽰规则 :: 说明如何⽣成⼀个或多个⽬标⽂件(包括⽣成的⽂件, ⽂件的依赖⽂件, ⽣成的命令)2. 隐晦规则 :: make的⾃动推导功能所执⾏的规则3. 变量定义 :: Makefile中定义的变量4. ⽂件指⽰ :: Makefile中引⽤其他Makefile; 指定Makefile中有效部分; 定义⼀个多⾏命令5. 注释 :: Makefile只有⾏注释 "#", 如果要使⽤或者输出"#"字符, 需要进⾏转义, "\#"1.2 GNU make 的⼯作⽅式1. 读⼊主Makefile (主Makefile中可以引⽤其他Makefile)2. 读⼊被include的其他Makefile3. 初始化⽂件中的变量4. 推导隐晦规则, 并分析所有规则5. 为所有的⽬标⽂件创建依赖关系链6. 根据依赖关系, 决定哪些⽬标要重新⽣成7. 执⾏⽣成命令2. Makefile 初级语法2.1 Makefile 规则2.1.1 规则语法规则主要有2部分: 依赖关系和⽣成⽬标的⽅法.语法有以下2种:target ... : prerequisites ...command...或者target ... : prerequisites ; commandcommand...*注* command太长, 可以⽤ "\" 作为换⾏符2.1.2 规则中的通配符* :: 表⽰任意⼀个或多个字符:: 表⽰任意⼀个字符[...] :: ex. [abcd] 表⽰a,b,c,d中任意⼀个字符, [^abcd]表⽰除a,b,c,d以外的字符, [0-9]表⽰ 0~9中任意⼀个数字~ :: 表⽰⽤户的home⽬录2.1.3 路径搜索当⼀个Makefile中涉及到⼤量源⽂件时(这些源⽂件和Makefile极有可能不在同⼀个⽬录中),这时, 最好将源⽂件的路径明确在Makefile中, 便于编译时查找. Makefile中有个特殊的变量VPATH就是完成这个功能的.指定了VPATH之后, 如果当前⽬录中没有找到相应⽂件或依赖的⽂件, Makefile 回到VPATH指定的路径中再去查找.. VPATH使⽤⽅法:vpath <directories> :: 当前⽬录中找不到⽂件时, 就从<directories>中搜索vpath <pattern> <directories> :: 符合<pattern>格式的⽂件, 就从<directories>中搜索vpath <pattern> :: 清除符合<pattern>格式的⽂件搜索路径vpath :: 清除所有已经设置好的⽂件路径# ⽰例1 - 当前⽬录中找不到⽂件时, 按顺序从 src⽬录 ../parent-dir⽬录中查找⽂件VPATH src:../parent-dir# ⽰例2 - .h结尾的⽂件都从 ./header ⽬录中查找VPATH %.h ./header# ⽰例3 - 清除⽰例2中设置的规则VPATH %.h# ⽰例4 - 清除所有VPATH的设置VPATH2.2 Makefile 中的变量2.2.1 变量定义 ( = or := )OBJS = programA.o programB.oOBJS-ADD = $(OBJS) programC.o# 或者OBJS := programA.o programB.oOBJS-ADD := $(OBJS) programC.o其中 = 和 := 的区别在于, := 只能使⽤前⾯定义好的变量, = 可以使⽤后⾯定义的变量测试 =# Makefile内容OBJS2 = $(OBJS1) programC.oOBJS1 = programA.o programB.oall:@echo $(OBJS2)# bash中执⾏make, 可以看出虽然 OBJS1 是在 OBJS2 之后定义的, 但在 OBJS2中可以提前使⽤$ makeprogramA.o programB.o programC.o测试 :=# Makefile内容OBJS2 := $(OBJS1) programC.oOBJS1 := programA.o programB.oall:@echo $(OBJS2)# bash中执⾏make, 可以看出 OBJS2 中的 $(OBJS1) 为空$ makeprogramC.o2.2.2 变量替换# Makefile内容SRCS := programA.c programB.c programC.cOBJS := $(SRCS:%.c=%.o)all:@echo "SRCS: " $(SRCS)@echo "OBJS: " $(OBJS)# bash中运⾏make$ makeSRCS: programA.c programB.c programC.cOBJS: programA.o programB.o programC.o2.2.3 变量追加值 +=# Makefile内容SRCS := programA.c programB.c programC.cSRCS += programD.call:@echo "SRCS: " $(SRCS)# bash中运⾏make$ makeSRCS: programA.c programB.c programC.c programD.c2.2.4 变量覆盖 override作⽤是使 Makefile中定义的变量能够覆盖 make 命令参数中指定的变量语法:override <variable> = <value>override <variable> := <value>override <variable> += <value>下⾯通过⼀个例⼦体会 override 的作⽤:# Makefile内容 (没有⽤override)SRCS := programA.c programB.c programC.call:@echo "SRCS: " $(SRCS)# bash中运⾏make$ make SRCS=nothingSRCS: nothing################################################## Makefile内容 (⽤override)override SRCS := programA.c programB.c programC.call:@echo "SRCS: " $(SRCS)# bash中运⾏make$ make SRCS=nothingSRCS: programA.c programB.c programC.c2.2.5 ⽬标变量作⽤是使变量的作⽤域仅限于这个⽬标(target), ⽽不像之前例⼦中定义的变量, 对整个Makefile都有效.语法:<target ...> :: <variable-assignment><target ...> :: override <variable-assignment> (override作⽤参见变量覆盖的介绍)⽰例:# Makefile 内容SRCS := programA.c programB.c programC.ctarget1: TARGET1-SRCS := programD.ctarget1:@echo "SRCS: " $(SRCS)@echo "SRCS: " $(TARGET1-SRCS)target2:@echo "SRCS: " $(SRCS)@echo "SRCS: " $(TARGET1-SRCS)# bash中执⾏make$ make target1SRCS: programA.c programB.c programC.cSRCS: programD.c$ make target2 <-- target2中显⽰不了 $(TARGET1-SRCS)SRCS: programA.c programB.c programC.cSRCS:2.3 Makefile 命令前缀Makefile 中书写shell命令时可以加2种前缀 @ 和 -, 或者不⽤前缀.3种格式的shell命令区别如下:不⽤前缀 :: 输出执⾏的命令以及命令执⾏的结果, 出错的话停⽌执⾏前缀 @ :: 只输出命令执⾏的结果, 出错的话停⽌执⾏前缀 - :: 命令执⾏有错的话, 忽略错误, 继续执⾏⽰例:# Makefile 内容 (不⽤前缀)all:echo"没有前缀"cat this_file_not_existecho"错误之后的命令" <-- 这条命令不会被执⾏# bash中执⾏make$ makeecho"没有前缀" <-- 命令本⾝显⽰出来没有前缀 <-- 命令执⾏结果显⽰出来cat this_file_not_existcat: this_file_not_exist: No such file or directorymake: *** [all] Error 1############################################################ Makefile 内容 (前缀 @)all:@echo "没有前缀"@cat this_file_not_exist@echo "错误之后的命令" <-- 这条命令不会被执⾏# bash中执⾏make$ make没有前缀 <-- 只有命令执⾏的结果, 不显⽰命令本⾝cat: this_file_not_exist: No such file or directorymake: *** [all] Error 1############################################################ Makefile 内容 (前缀 -)all:-echo"没有前缀"-cat this_file_not_exist-echo"错误之后的命令" <-- 这条命令会被执⾏# bash中执⾏make$ makeecho"没有前缀" <-- 命令本⾝显⽰出来没有前缀 <-- 命令执⾏结果显⽰出来cat this_file_not_existcat: this_file_not_exist: No such file or directorymake: [all] Error 1 (ignored)echo"错误之后的命令" <-- 出错之后的命令也会显⽰错误之后的命令 <-- 出错之后的命令也会执⾏2.4 伪⽬标伪⽬标并不是⼀个"⽬标(target)", 不像真正的⽬标那样会⽣成⼀个⽬标⽂件.典型的伪⽬标是 Makefile 中⽤来清理编译过程中中间⽂件的 clean 伪⽬标, ⼀般格式如下: .PHONY: clean <-- 这句没有也⾏, 但是最好加上clean:-rm -f *.o2.5 引⽤其他的 Makefile语法: include <filename> (filename 可以包含通配符和路径)⽰例:# Makefile 内容all:@echo "主 Makefile begin"@make other-all@echo "主 Makefile end"include ./other/Makefile# ./other/Makefile 内容other-all:@echo "other makefile begin"@echo "other makefile end"# bash中执⾏make$ lltotal 20K-rw-r--r-- 1 wangyubin wangyubin 125 Sep 2316:13 Makefile-rw-r--r-- 1 wangyubin wangyubin 11K Sep 2316:15 <-- 这个⽂件不⽤管drwxr-xr-x 2 wangyubin wangyubin 4.0K Sep 2316:11 other$ ll other/total 4.0K-rw-r--r-- 1 wangyubin wangyubin 71 Sep 2316:11 Makefile$ make主 Makefile beginmake[1]: Entering directory `/path/to/test/makefile'other makefile beginother makefile endmake[1]: Leaving directory `/path/to/test/makefile'主 Makefile end2.6 查看C⽂件的依赖关系写 Makefile 的时候, 需要确定每个⽬标的依赖关系.GNU提供⼀个机制可以查看C代码⽂件依赖那些⽂件, 这样我们在写 Makefile ⽬标的时候就不⽤打开C源码来看其依赖那些⽂件了.⽐如, 下⾯命令显⽰内核源码中 virt/kvm/kvm_main.c 中的依赖关系$ cd virt/kvm/$ gcc -MM kvm_main.ckvm_main.o: kvm_main.c iodev.h coalesced_mmio.h async_pf.h <-- 这句就可以加到 Makefile 中作为编译 kvm_main.o 的依赖关系2.7 make 退出码Makefile的退出码有以下3种:0 :: 表⽰成功执⾏1 :: 表⽰make命令出现了错误2 :: 使⽤了 "-q" 选项, 并且make使得⼀些⽬标不需要更新2.8 指定 Makefile,指定特定⽬标默认执⾏ make 命令时, GNU make在当前⽬录下依次搜索下⾯3个⽂件 "GNUmakefile", "makefile", "Makefile",找到对应⽂件之后, 就开始执⾏此⽂件中的第⼀个⽬标(target). 如果找不到这3个⽂件就报错.⾮默认情况下, 可以在 make 命令中指定特定的 Makefile 和特定的⽬标.⽰例:# Makefile⽂件名改为 MyMake, 内容target1:@echo "target [1] begin"@echo "target [1] end"target2:@echo "target [2] begin"@echo "target [2] end"# bash 中执⾏make$ lsMakefile$ mv Makefile MyMake$ lsMyMake$ make <-- 找不到默认的 Makefilemake: *** No targets specified and no makefile found. Stop.$ make -f MyMake <-- 指定特定的Makefiletarget [1] begintarget [1] end$ make -f MyMake target2 <-- 指定特定的⽬标(target)target [2] begintarget [2] end2.9 make 参数介绍make 的参数有很多, 可以通过 make -h 去查看, 下⾯只介绍⼏个我认为⽐较有⽤的.参数含义--debug[=<options>]输出make的调试信息, options 可以是 a, b, v-j --jobs同时运⾏的命令的个数, 也就是多线程执⾏ Makefile-r --no-builtin-rules禁⽌使⽤任何隐含规则-R --no-builtin-variabes禁⽌使⽤任何作⽤于变量上的隐含规则-B --always-make假设所有⽬标都有更新, 即强制重编译2.10 Makefile 隐含规则这⾥只列⼀个和编译C相关的.编译C时,<n>.o 的⽬标会⾃动推导为 <n>.c# Makefile 中main : main.ogcc -o main main.o#会⾃动变为:main : main.ogcc -o main main.omain.o: main.c <-- main.o 这个⽬标是隐含⽣成的gcc -c main.c2.11 隐含规则中的命令变量和命令参数变量2.11.1 命令变量, 书写Makefile可以直接写 shell时⽤这些变量.下⾯只列出⼀些C相关的变量名含义RM rm -fAR arCC ccCXX g++⽰例:# Makefile 内容all:@echo $(RM)@echo $(AR)@echo $(CC)@echo $(CXX)# bash 中执⾏make, 显⽰各个变量的值$ makerm -farccg++2.11.2 命令参数变量变量名含义ARFLAGS AR命令的参数CFLAGS C语⾔编译器的参数CXXFLAGS C++语⾔编译器的参数⽰例: 下⾯以 CFLAGS 为例演⽰# test.c 内容#include <stdio.h>int main(int argc, char *argv[]){printf ("Hello Makefile\n");return 0;}# Makefile 内容test: test.o$(CC) -o test test.o# bash 中⽤make来测试$ lltotal 24K-rw-r--r-- 1 wangyubin wangyubin 69 Sep 2317:31 Makefile-rw-r--r-- 1 wangyubin wangyubin 14K Sep 2319:51 <-- 请忽略这个⽂件-rw-r--r-- 1 wangyubin wangyubin 392 Sep 2317:31 test.c$ makecc -c -o test.o test.ccc -o test test.o <-- 这个是⾃动推导的$ rm -f test test.o$ make CFLAGS=-Wall <-- 命令中加的编译器参数⾃动追加⼊下⾯的编译中了cc -Wall -c -o test.o test.ccc -o test test.o2.12 ⾃动变量Makefile 中很多时候通过⾃动变量来简化书写, 各个⾃动变量的含义如下:⾃动变量含义$@⽬标集合$%当⽬标是函数库⽂件时, 表⽰其中的⽬标⽂件名$<第⼀个依赖⽬标. 如果依赖⽬标是多个, 逐个表⽰依赖⽬标$?⽐⽬标新的依赖⽬标的集合$^所有依赖⽬标的集合, 会去除重复的依赖⽬标$+所有依赖⽬标的集合, 不会去除重复的依赖⽬标$*这个是GNU make特有的, 其它的make不⼀定⽀持3. Makefile ⾼级语法3.1 嵌套Makefile在 Makefile 初级语法中已经提到过引⽤其它 Makefile的⽅法. 这⾥有另⼀种写法, 并且可以向引⽤的其它 Makefile 传递参数.⽰例: (不传递参数, 只是调⽤⼦⽂件夹 other 中的Makefile)# Makefile 内容all:@echo "主 Makefile begin"@cd ./other && make@echo "主 Makefile end"# ./other/Makefile 内容other-all:@echo "other makefile begin"@echo "other makefile end"# bash中执⾏make$ lltotal 28K-rw-r--r-- 1 wangyubin wangyubin 104 Sep 2320:43 Makefile-rw-r--r-- 1 wangyubin wangyubin 17K Sep 2320:44 <-- 这个⽂件不⽤管drwxr-xr-x 2 wangyubin wangyubin 4.0K Sep 2320:42 other$ ll other/total 4.0K-rw-r--r-- 1 wangyubin wangyubin 71 Sep 2316:11 Makefile$ make主 Makefile beginmake[1]: Entering directory `/path/to/test/makefile/other'other makefile beginother makefile endmake[1]: Leaving directory `/path/to/test/makefile/other'主 Makefile end⽰例: (⽤export传递参数)# Makefile 内容export VALUE1 := export.c <-- ⽤了 export, 此变量能够传递到 ./other/Makefile 中VALUE2 := no-export.c <-- 此变量不能传递到 ./other/Makefile 中all:@echo "主 Makefile begin"@cd ./other && make@echo "主 Makefile end"# ./other/Makefile 内容other-all:@echo "other makefile begin"@echo "VALUE1: " $(VALUE1)@echo "VALUE2: " $(VALUE2)@echo "other makefile end"# bash中执⾏make$ make主 Makefile beginmake[1]: Entering directory `/path/to/test/makefile/other'other makefile beginVALUE1: export.c <-- VALUE1 传递成功VALUE2: <-- VALUE2 传递失败other makefile endmake[1]: Leaving directory `/path/to/test/makefile/other'主 Makefile end*补充* export 语法格式如下:export variable = valueexport variable := valueexport variable += value3.2 定义命令包命令包有点像是个函数, 将连续的相同的命令合成⼀条, 减少 Makefile 中的代码量, 便于以后维护.语法:define <command-name>command...endef⽰例:# Makefile 内容define run-hello-makefile@echo -n "Hello"@echo " Makefile!"@echo "这⾥可以执⾏多条 Shell 命令!"endefall:$(run-hello-makefile)# bash 中运⾏make$ makeHello Makefile!这⾥可以执⾏多条 Shell 命令!3.3 条件判断条件判断的关键字主要有 ifeq ifneq ifdef ifndef语法:<conditional-directive><text-if-true>endif# 或者<conditional-directive><text-if-true>else<text-if-false>endif⽰例: ifeq的例⼦, ifneq和ifeq的使⽤⽅法类似, 就是取反# Makefile 内容all:ifeq ("aa", "bb")@echo "equal"else@echo "not equal"endif# bash 中执⾏make$ makenot equal⽰例: ifdef的例⼦, ifndef和ifdef的使⽤⽅法类似, 就是取反# Makefile 内容SRCS := program.call:ifdef SRCS@echo $(SRCS)else@echo "no SRCS"# bash 中执⾏make$ makeprogram.c3.4 Makefile 中的函数Makefile 中⾃带了⼀些函数, 利⽤这些函数可以简化 Makefile 的编写.函数调⽤语法如下:$(<function> <arguments>)# 或者${<function> <arguments>}<function> 是函数名<arguments> 是函数参数3.4.1 字符串函数字符串替换函数: $(subst <from>,<to>,<text>)功能: 把字符串<text> 中的 <from> 替换为 <to>返回: 替换过的字符串# Makefile 内容all:@echo $(subst t,e,maktfilt) <-- 将t替换为e# bash 中执⾏make$ makemakefile模式字符串替换函数: $(patsubst <pattern>,<replacement>,<text>)功能: 查找<text>中的单词(单词以"空格", "tab", "换⾏"来分割) 是否符合 <pattern>, 符合的话, ⽤ <replacement> 替代.返回: 替换过的字符串# Makefile 内容all:@echo $(patsubst %.c,%.o,programA.c programB.c)# bash 中执⾏make$ makeprogramA.o programB.o去空格函数: $(strip <string>)功能: 去掉 <string> 字符串中开头和结尾的空字符返回: 被去掉空格的字符串值# Makefile 内容VAL := " aa bb cc "all:@echo "去除空格前: " $(VAL)@echo "去除空格后: " $(strip $(VAL))# bash 中执⾏make去除空格前: aa bb cc去除空格后: aa bb cc查找字符串函数: $(findstring <find>,<in>)功能: 在字符串 <in> 中查找 <find> 字符串返回: 如果找到, 返回 <find> 字符串, 否则返回空字符串# Makefile 内容VAL := " aa bb cc "all:@echo $(findstring aa,$(VAL))@echo $(findstring ab,$(VAL))# bash 中执⾏make$ makeaa过滤函数: $(filter <pattern...>,<text>)功能: 以 <pattern> 模式过滤字符串 <text>, *保留* 符合模式 <pattern> 的单词, 可以有多个模式返回: 符合模式 <pattern> 的字符串# Makefile 内容all:@echo $(filter %.o %.a,program.c program.o program.a)# bash 中执⾏make$ makeprogram.o program.a反过滤函数: $(filter-out <pattern...>,<text>)功能: 以 <pattern> 模式过滤字符串 <text>, *去除* 符合模式 <pattern> 的单词, 可以有多个模式返回: 不符合模式 <pattern> 的字符串# Makefile 内容all:@echo $(filter-out %.o %.a,program.c program.o program.a)# bash 中执⾏make$ makeprogram.c排序函数: $(sort <list>)功能: 给字符串 <list> 中的单词排序 (升序)返回: 排序后的字符串# Makefile 内容all:@echo $(sort bac abc acb cab)# bash 中执⾏make$ makeabc acb bac cab取单词函数: $(word <n>,<text>)功能: 取字符串 <text> 中的第<n>个单词 (n从1开始)返回: <text> 中的第<n>个单词, 如果<n> ⽐ <text> 中单词个数要⼤, 则返回空字符串# Makefile 内容all:@echo $(word 1,aa bb cc dd)@echo $(word 5,aa bb cc dd)@echo $(word 4,aa bb cc dd)# bash 中执⾏make$ makeaadd取单词串函数: $(wordlist <s>,<e>,<text>)功能: 从字符串<text>中取从<s>开始到<e>的单词串. <s>和<e>是⼀个数字.返回: 从<s>到<e>的字符串# Makefile 内容all:@echo $(wordlist 1,3,aa bb cc dd)@echo $(word 5,6,aa bb cc dd)@echo $(word 2,5,aa bb cc dd)# bash 中执⾏make$ makeaa bb ccbb单词个数统计函数: $(words <text>)功能: 统计字符串 <text> 中单词的个数返回: 单词个数# Makefile 内容all:@echo $(words aa bb cc dd)@echo $(words aabbccdd)@echo $(words )# bash 中执⾏make$ make41⾸单词函数: $(firstword <text>)功能: 取字符串 <text> 中的第⼀个单词返回: 字符串 <text> 中的第⼀个单词# Makefile 内容all:@echo $(firstword aa bb cc dd)@echo $(firstword aabbccdd)@echo $(firstword )# bash 中执⾏make$ makeaaaabbccdd3.4.2 ⽂件名函数取⽬录函数: $(dir <names...>)功能: 从⽂件名序列 <names> 中取出⽬录部分返回: ⽂件名序列 <names> 中的⽬录部分# Makefile 内容all:@echo $(dir /home/a.c ./bb.c ../c.c d.c)# bash 中执⾏make$ make/home/ ./ ../ ./取⽂件函数: $(notdir <names...>)功能: 从⽂件名序列 <names> 中取出⾮⽬录部分返回: ⽂件名序列 <names> 中的⾮⽬录部分# Makefile 内容all:@echo $(notdir /home/a.c ./bb.c ../c.c d.c)# bash 中执⾏make$ makea.c bb.cc.cd.c取后缀函数: $(suffix <names...>)功能: 从⽂件名序列 <names> 中取出各个⽂件名的后缀返回: ⽂件名序列 <names> 中各个⽂件名的后缀, 没有后缀则返回空字符串# Makefile 内容all:@echo $(suffix /home/a.c ./b.o ../c.a d)# bash 中执⾏make$ make.c .o .a取前缀函数: $(basename <names...>)功能: 从⽂件名序列 <names> 中取出各个⽂件名的前缀返回: ⽂件名序列 <names> 中各个⽂件名的前缀, 没有前缀则返回空字符串# Makefile 内容all:@echo $(basename /home/a.c ./b.o ../c.a /home/.d .e)# bash 中执⾏make$ make/home/a ./b ../c /home/加后缀函数: $(addsuffix <suffix>,<names...>)功能: 把后缀 <suffix> 加到 <names> 中的每个单词后⾯返回: 加过后缀的⽂件名序列# Makefile 内容all:@echo $(addsuffix .c,/home/a b ./c.o ../d.c)# bash 中执⾏make$ make/home/a.c b.c ./c.o.c ../d.c.c加前缀函数: $(addprefix <prefix>,<names...>)功能: 把前缀 <prefix> 加到 <names> 中的每个单词前⾯返回: 加过前缀的⽂件名序列# Makefile 内容all:@echo $(addprefix test_,/home/a.c b.c ./d.c)# bash 中执⾏make$ maketest_/home/a.c test_b.c test_./d.c连接函数: $(join <list1>,<list2>)功能: <list2> 中对应的单词加到 <list1> 后⾯返回: 连接后的字符串# Makefile 内容all:@echo $(join a b c d,1234)@echo $(join a b c d,12345)@echo $(join a b c d e,1234)# bash 中执⾏make$ makea1 b2 c3 d4a1 b2 c3 d4 5a1 b2 c3 d4 e3.4.3 foreach语法:$(foreach <var>,<list>,<text>)⽰例:# Makefile 内容targets := a b c dobjects := $(foreach i,$(targets),$(i).o)all:@echo $(targets)@echo $(objects)# bash 中执⾏make$ makea b c da.ob.oc.od.o3.4.4 if这⾥的if是个函数, 和前⾯的条件判断不⼀样, 前⾯的条件判断属于Makefile的关键字语法:$(if <condition>,<then-part>)$(if <condition>,<then-part>,<else-part>)⽰例:# Makefile 内容val := aobjects := $(if $(val),$(val).o,nothing)no-objects := $(if $(no-val),$(val).o,nothing)all:@echo $(objects)@echo $(no-objects)# bash 中执⾏make$ makea.onothing3.4.5 call - 创建新的参数化函数语法:$(call <expression>,<parm1>,<parm2>,<parm3>...)⽰例:# Makefile 内容log = "====debug====" $(1) "====end===="all:@echo $(call log,"正在 Make")# bash 中执⾏make$ make====debug==== 正在 Make ====end====3.4.6 origin - 判断变量的来源语法:$(origin <variable>)返回值有如下类型:类型含义undefined<variable> 没有定义过default<variable> 是个默认的定义, ⽐如 CC 变量environment<variable> 是个环境变量, 并且 make时没有使⽤ -e 参数file<variable> 定义在Makefile中command line<variable> 定义在命令⾏中override<variable> 被 override 重新定义过automatic<variable> 是⾃动化变量⽰例:# Makefile 内容val-in-file := test-fileoverride val-override := test-overrideall:@echo $(origin not-define) # not-define 没有定义@echo $(origin CC) # CC 是Makefile默认定义的变量@echo $(origin PATH) # PATH 是 bash 环境变量@echo $(origin val-in-file) # 此Makefile中定义的变量@echo $(origin val-in-cmd) # 这个变量会加在make的参数中@echo $(origin val-override) # 此Makefile中定义的override变量@echo $(origin @) # ⾃动变量, 具体前⾯的介绍# bash 中执⾏make$ make val-in-cmd=val-cmdundefineddefaultenvironmentfilecommand lineoverrideautomatic3.4.7 shell语法:$(shell <shell command>)它的作⽤就是执⾏⼀个shell命令, 并将shell命令的结果作为函数的返回.作⽤和 `<shell command>` ⼀样, ` 是反引号3.4.8 make 控制函数产⽣⼀个致命错误: $(error <text ...>)功能: 输出错误信息, 停⽌Makefile的运⾏# Makefile 内容all:$(error there is an error!)@echo "这⾥不会执⾏!"# bash 中执⾏make$ makeMakefile:2: *** there is an error!. Stop.输出警告: $(warning <text ...>)功能: 输出警告信息, Makefile继续运⾏# Makefile 内容all:$(warning there is an warning!)@echo "这⾥会执⾏!"# bash 中执⾏make$ makeMakefile:2: there is an warning!这⾥会执⾏!3.5 Makefile中⼀些GNU约定俗成的伪⽬标如果有过在Linux上, 从源码安装软件的经历的话, 就会对 make clean, make install ⽐较熟悉.像 clean, install 这些伪⽬标, ⼴为⼈知, 不⽤解释就⼤家知道是什么意思了.下⾯列举⼀些常⽤的伪⽬标, 如果在⾃⼰项⽬的Makefile合理使⽤这些伪⽬标的话, 可以让我们⾃⼰的Makefile看起来更专业, 呵呵 :)伪⽬标含义all所有⽬标的⽬标,其功能⼀般是编译所有的⽬标clean删除所有被make创建的⽂件install安装已编译好的程序,其实就是把⽬标可执⾏⽂件拷贝到指定的⽬录中去print列出改变过的源⽂件tar把源程序打包备份. 也就是⼀个tar⽂件dist创建⼀个压缩⽂件, ⼀般是把tar⽂件压成Z⽂件. 或是gz⽂件TAGS更新所有的⽬标, 以备完整地重编译使⽤check 或 test⼀般⽤来测试makefile的流程。
通用makefile模板
############################################################# # Generic Makefile for C/C++ Program## License: GPL (General Public License)# Author: whyglinux <whyglinux AT gmail DOT com># Date: 2006/03/04 (version 0.1)# 2007/03/24 (version 0.2)# 2007/04/09 (version 0.3)# 2007/06/26 (version 0.4)# 2008/04/05 (version 0.5)## Description:# ------------# This is an easily customizable makefile template. The purpose is to# provide an instant building environment for C/C++ programs.## It searches all the C/C++ source files in the specified directories,# makes dependencies, compiles and links to form an executable.## Besides its default ability to build C/C++ programs which use only# standard C/C++ libraries, you can customize the Makefile to build# those using other libraries. Once done, without any changes you can# then build programs using the same or less libraries, even if source# files are renamed, added or removed. Therefore, it is particularly# convenient to use it to build codes for experimental or study use.## GNU make is expected to use the Makefile. Other versions of makes# may or may not work.## Usage:# ------# 1. Copy the Makefile to your program directory.# 2. Customize in the "Customizable Section" only if necessary:# * to use non-standard C/C++ libraries, set pre-processor or compiler# options to <MY_CFLAGS> and linker ones to <MY_LIBS># (See Makefile.gtk+-2.0 for an example)# * to search sources in more directories, set to <SRCDIRS># * to specify your favorite program name, set to <PROGRAM># 3. Type make to start building your program.## Make Target:# ------------# The Makefile provides the following targets to make:# $ make compile and link# $ make NODEP=yes compile and link without generating dependencies # $ make objs compile only (no linking)# $ make tags create tags for Emacs editor# $ make ctags create ctags for VI editor# $ make clean clean objects and the executable file# $ make distclean clean objects, the executable and dependencies# $ make help get the usage of the makefile##========================================================== =================## Customizable Section: adapt those variables to suit your program.##========================================================= =================# The pre-processor and compiler options.MY_CFLAGS =# The linker options.MY_LIBS =# The pre-processor options used by the cpp (man cpp for more). CPPFLAGS = -Wall# The options used in linking as well as in any direct use of ld.LDFLAGS =# The directories in which source files reside.# If not specified, only the current directory will be serached.SRCDIRS =# The executable file name.# If not specified, current directory name or `a.out' will be used.PROGRAM =## Implicit Section: change the following only when necessary.##========================================================= =================# The source file types (headers excluded).# .c indicates C source files, and others C++ ones.SRCEXTS = .c .C .cc .cpp .CPP .c++ .cxx .cp# The header file types.HDREXTS = .h .H .hh .hpp .HPP .h++ .hxx .hp# The pre-processor and compiler options.# Users can override those variables from the command line.CFLAGS = -g -O2CXXFLAGS= -g -O2# The C program compiler.#CC = gcc# The C++ program compiler.#CXX = g++# Un-comment the following line to compile C programs as C++ ones.#CC = $(CXX)# The command used to delete file.#RM = rm -fETAGS = etagsETAGSFLAGS =CTAGS = ctagsCTAGSFLAGS =## Stable Section: usually no need to be changed. But you can add more.##========================================================= =================SHELL = /bin/shEMPTY =SPACE = $(EMPTY) $(EMPTY)ifeq ($(PROGRAM),)CUR_PATH_NAMES = $(subst /,$(SPACE),$(subst $(SPACE),_,$(CURDIR)))PROGRAM = $(word $(words $(CUR_PATH_NAMES)),$(CUR_PATH_NAMES))ifeq ($(PROGRAM),)PROGRAM = a.outendifendififeq ($(SRCDIRS),)SRCDIRS = .endifSOURCES = $(foreach d,$(SRCDIRS),$(wildcard $(addprefix$(d)/*,$(SRCEXTS))))HEADERS = $(foreach d,$(SRCDIRS),$(wildcard $(addprefix $(d)/*,$(HDREXTS))))SRC_CXX = $(filter-out %.c,$(SOURCES))OBJS = $(addsuffix .o, $(basename $(SOURCES)))DEPS = $(OBJS:.o=.d)## Define some useful variables.DEP_OPT = $(shell if `$(CC) --version | grep "GCC" >/dev/null`; then \echo "-MM -MP"; else echo "-M"; fi )DEPEND = $(CC) $(DEP_OPT) $(MY_CFLAGS) $(CFLAGS) $(CPPFLAGS)DEPEND.d = $(subst -g ,,$(DEPEND))COMPILE.c = $(CC) $(MY_CFLAGS) $(CFLAGS) $(CPPFLAGS) -c COMPILE.cxx = $(CXX) $(MY_CFLAGS) $(CXXFLAGS) $(CPPFLAGS) -c LINK.c = $(CC) $(MY_CFLAGS) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS)LINK.cxx = $(CXX) $(MY_CFLAGS) $(CXXFLAGS) $(CPPFLAGS) $(LDFLAGS).PHONY: all objs tags ctags clean distclean help show# Delete the default suffixes.SUFFIXES:all: $(PROGRAM)# Rules for creating dependency files (.d).#------------------------------------------%.d:%.c@echo -n $(dir $<) > $@@$(DEPEND.d) $< >> $@%.d:%.C@echo -n $(dir $<) > $@@$(DEPEND.d) $< >> $@%.d:%.cc@echo -n $(dir $<) > $@@$(DEPEND.d) $< >> $@%.d:%.cpp@echo -n $(dir $<) > $@@$(DEPEND.d) $< >> $@%.d:%.CPP@echo -n $(dir $<) > $@@$(DEPEND.d) $< >> $@%.d:%.c++@echo -n $(dir $<) > $@@$(DEPEND.d) $< >> $@%.d:%.cp@echo -n $(dir $<) > $@@$(DEPEND.d) $< >> $@%.d:%.cxx@echo -n $(dir $<) > $@@$(DEPEND.d) $< >> $@# Rules for generating object files (.o). #---------------------------------------- objs:$(OBJS)%.o:%.c$(COMPILE.c) $< -o $@%.o:%.C$(COMPILE.cxx) $< -o $@%.o:%.cc$(COMPILE.cxx) $< -o $@%.o:%.cpp$(COMPILE.cxx) $< -o $@%.o:%.CPP$(COMPILE.cxx) $< -o $@%.o:%.c++$(COMPILE.cxx) $< -o $@%.o:%.cp$(COMPILE.cxx) $< -o $@%.o:%.cxx$(COMPILE.cxx) $< -o $@# Rules for generating the tags.#-------------------------------------tags: $(HEADERS) $(SOURCES)$(ETAGS) $(ETAGSFLAGS) $(HEADERS) $(SOURCES)ctags: $(HEADERS) $(SOURCES)$(CTAGS) $(CTAGSFLAGS) $(HEADERS) $(SOURCES)# Rules for generating the executable.#-------------------------------------$(PROGRAM):$(OBJS)ifeq ($(SRC_CXX),) # C program$(LINK.c) $(OBJS) $(MY_LIBS) -o $@@echo Type ./$@ to execute the program.else # C++ program$(LINK.cxx) $(OBJS) $(MY_LIBS) -o $@@echo Type ./$@ to execute the program.endififndef NODEPifneq ($(DEPS),)sinclude $(DEPS)endifendifclean:$(RM) $(OBJS) $(PROGRAM) $(PROGRAM).exedistclean: clean$(RM) $(DEPS) TAGS# Show help.help:@echo 'Generic Makefile for C/C++ Programs (gcmakefile) version 0.5' @echo 'Copyright (C) 2007, 2008 whyglinux <whyglinux@>' @echo@echo 'Usage: make [TARGET]'@echo 'TARGETS:'@echo ' all (=make) compile and link.'@echo ' NODEP=yes make without generating dependencies.'@echo ' objs compile only (no linking).'@echo ' tags create tags for Emacs editor.'@echo ' ctags create ctags for VI editor.'@echo ' clean clean objects and the executable file.'@echo ' distclean clean objects, the executable and dependencies.'@echo ' show show variables (for debug use only).'@echo ' help print this message.'@echo@echo 'Report bugs to <whyglinux AT gmail DOT com>.'# Show variables (for debug use only.)show:@echo 'PROGRAM :' $(PROGRAM)@echo 'SRCDIRS :' $(SRCDIRS)@echo 'HEADERS :' $(HEADERS)@echo 'SOURCES :' $(SOURCES)@echo 'SRC_CXX :' $(SRC_CXX)@echo 'OBJS :' $(OBJS)@echo 'DEPS :' $(DEPS)@echo 'DEPEND :' $(DEPEND)@echo 'COMPILE.c :' $(COMPILE.c)@echo 'COMPILE.cxx :' $(COMPILE.cxx)@echo 'link.c :' $(LINK.c)@echo 'link.cxx :' $(LINK.cxx)## End of the Makefile ## Suggestions are welcome ## All rights reserved ################################################################。
sv 中的makefile 写法
SV(SystemVerilog)是一种硬件描述语言,用于设计和验证数字电路。
在进行SV代码编写的过程中,makefile是一种非常有用的工具,可以帮助组织和管理SV项目中的代码文件。
本文将介绍SV中makefile的写法,希望能为SV开发者提供一些参考和帮助。
1. 为什么需要makefile在SV项目中,通常会涉及到多个源文件、库文件、测试文件等。
使用makefile可以帮助我们轻松地组织和管理这些文件,实现自动化编译、信息和运行测试的功能。
makefile还可以帮助我们避免重复编译文件,提高开发效率。
2. makefile的基本结构makefile由一系列规则组成,每个规则由一个目标、依赖列表和命令组成。
一个基本的makefile看起来像这样:```makefiletarget: dependenciesmand```其中,target表示规则的目标文件,dependencies表示该目标文件的依赖文件mand表示需要执行的命令。
3. 使用变量在makefile中,我们可以使用变量来定义一些常量,方便我们在后续的规则中使用。
例如:```makefileSV_SRC = file1.sv file2.sv file3.sv```这样,我们就可以在后续的规则中使用$(SV_SRC)来表示这些文件,而不需要重复地写出它们的文件名。
4. 基本规则在SV项目中,常见的makefile规则包括编译规则、信息规则和运行测试规则。
以下是一个简单的例子:```makefileall: $(SV_SRC)vlog $(SV_SRC)sim: allvsim top_module```在这个例子中,我们定义了两个规则,分别是all和sim。
all规则依赖于$(SV_SRC)中的文件,使用vlog命令对这些文件进行编译。
sim规则依赖于all规则,使用vsim命令来运行测试。
5. 使用通配符在makefile中,我们还可以使用通配符来表示一类文件。
Makefile中用宏定义进行条件编译-CSDN博客
Makefile中用宏定义进行条件编译-CSDN博客在源代码里面如果这样是定义的:#ifdef MACRONAME//可选代码#endif那在makefile里面gcc -D MACRONAME=MACRODEF或者gcc -D MACRONAME这样就定义了预处理宏,编译的时候可选代码就会被编译进去了。
对于GCC编译器,有如下选项:-D macro=string,等价于在头文件中定义:#define macro string。
例如:-D TRUE=true,等价于:#define TRUE true-D macro,等价于在头文件中定义:#define macro 1,实际上也达到了定义:#define macro的目的。
例如:-D LINUX,等价于:#define LINUX 1(与#define LINUX作用类似)。
--define-macro macro=string与-D macro=string作用相同。
如:TEST.C 文件#include <stdio.h>#include <stdlib.h>main(){#ifdef p1 printf('Hello p1');#else printf('Hello p2');#endif }1.编译: gcc -o test test.c运行: ./test输出: Hello p22.编译: gcc -o test test.c -D p1运行: ./test输出: Hello p1还有另外一种使用方式:Makefile写法:$(SERVER_NAME):$(SERVER_OBJ) $(COM_OBJS) $(CC) -Wall -pthread -D KRC_SERVER_NAME=$(SERVER_NAME)_FLAG C代码中用法:#if KRC_SERVER_NAME == krc_search_FLAG#elif KRC_SERVER_NAME == krc_feedback_FLAG#else#endif注意:其中的两个参数为宏定义,不能使用常量定义,因为需要在预编译阶段就要确定其值!#define krc_search_FLAG 1#define krc_feedback_FLAG 2这种用法也能实现条件编译的作用,而且更好!。
makefile elseif函数
makefile elseif函数在Makefile中,可以通过使用`if`和`else`指令结合条件判断来实现条件逻辑。
然而,Makefile本身并不直接支持`elseif`函数。
如果需要使用`elif`条件判断,可以通过嵌套使用多个`if`指令来模拟`elseif`的效果。
下面是一个示例的Makefile,其中演示了如何使用`if`和`elseif`条件逻辑:```makefileCONFIG := debugifeq ($(CONFIG),debug)CFLAGS := -g -O0else ifeq ($(CONFIG),release)CFLAGS := -O2else ifeq ($(CONFIG),profile)CFLAGS := -pg -O2else$(error Unknown CONFIG: $(CONFIG))endif$(info CFLAGS: $(CFLAGS))# 更多规则和任务...```在上述示例中,首先定义了一个名为`CONFIG`的变量,表示编译配置。
根据不同的配置,使用不同的优化选项来设置`CFLAGS`变量。
如果`CONFIG`的值未知,则产生一个错误。
通过在`ifeq`指令中使用`$(CONFIG)`和期望的配置值进行比较,可以实现条件判断。
`elseif`效果则是通过嵌套使用`ifeq`指令来实现的。
最后,使用`$(info)`函数来输出`CFLAGS`的值。
注意,Makefile中的条件判断是根据变量值来进行判断的,需要确保变量的值在比较之前已经赋值。
makefile 中$(shell )用法
makefile 中$(shell )用法标题:Makefile中的$(shell )用法详解在编程中,自动化是提高效率的关键。
而在C/C++的开发过程中,Makefile是一个非常重要的工具,它可以自动编译和链接源代码,极大地提高了开发效率。
本文将详细讲解Makefile中的一个重要命令$(shell),并结合实例说明其用法。
一、$(shell)的基本概念在Makefile中,$(shell)是一个内置函数,它的功能是执行shell命令,并将命令的结果返回。
例如:```foo = $(shell echo hello world)```在这个例子中,`$(shell echo hello world)`会被替换为"hello world"。
二、$(shell)的应用场景1. 获取系统信息:$(shell)可以用来获取系统的相关信息,如当前的时间、日期、用户名等。
例如:```time=$(shell date +%T)user=$(shell whoami)```2. 调用其他命令或脚本:$(shell)可以调用其他命令或脚本来完成一些复杂的任务。
例如:```files=$(shell find . -name "*.c")```3. 在规则中使用:$(shell)也可以直接在规则中使用,用于动态生成依赖文件或者目标文件。
例如:```foo:@echo "Compiling $@..."$(CC) -o $@ $(shell echo *.c)```三、$(shell)的注意事项虽然$(shell)的功能强大,但在使用时也需要注意一些问题。
1. 执行速度:由于$(shell)需要启动一个子shell来执行命令,因此如果频繁使用,可能会对性能产生影响。
所以在可能的情况下,尽量减少$(shell)的使用。
2. 命令输出:$(shell)会捕获命令的标准输出,但不会捕获标准错误输出。
海思makefile结构解析
海思makefile结构解析全文共四篇示例,供读者参考第一篇示例:海思芯片是一家领先的半导体公司,在国际市场上拥有广泛的市场份额。
海思芯片的产品广泛应用在手机、网络通信、物联网、智能家居等领域,其芯片性能卓越,在同行业内享有很高的声誉。
在海思芯片的开发中,makefile是一个非常重要的工具,它负责管理整个项目的编译、链接和部署过程,帮助开发人员更高效地完成工作。
makefile是一个用于自动化编译的脚本文件,通过编写makefile 文件,可以告诉计算机如何编译源代码,生成可执行文件。
海思makefile结构解析主要包括以下几个部分:1. 定义变量:在makefile中定义变量是非常重要的,可以方便地管理项目的路径、编译参数等信息。
海思makefile中通常会定义一些常用的变量,比如CC表示编译器的路径,CXX表示C++编译器的路径,CFLAGS表示编译参数等。
通过定义这些变量,可以在整个makefile中直接引用,减少了代码的冗余,提高了代码的可维护性。
2. 设置编译规则:在makefile中,通常会定义一些编译规则,告诉make工具如何编译源文件和生成可执行文件。
海思makefile中的编译规则通常使用模式匹配的方式,比如"%.c:%.o"表示将所有的.c文件编译为.o文件,而"%.o:%.c"则表示将所有的.o文件根据对应的.c文件进行重新编译。
通过这些编译规则,make工具可以根据需要自动化地完成整个项目的编译过程。
3. 定义目标:在makefile中通常会定义一些目标,这些目标可以是编译生成可执行文件的命令,也可以是清理生成的临时文件的命令。
海思makefile中的目标通常包括all、clean、install等,通过定义这些目标,可以方便地管理整个项目的编译和部署过程。
4. 调用外部工具:在海思makefile中,通常会调用一些外部工具来完成一些特定的任务,比如编译器、链接器、打包工具等。
makefile 中foreach与ifeq范例
makefile 中foreach与ifeq范例makefile是一种用于构建和管理项目的工具,它使用类似于shell脚本的语法,可以自动化地编译、链接和测试代码。
在makefile中,foreach和ifeq是两个非常有用的指令,用于迭代和条件判断。
本文将一步一步地介绍makefile中的foreach和ifeq指令,并提供相应的范例。
一、foreach 指令在makefile中,foreach指令用于迭代一组值,并在每次迭代中执行相应的操作。
foreach语法如下:(foreach var, list, text)其中,var是一个变量名,list是一个包含多个值的列表,text是需要在每次迭代中执行的操作。
让我们通过一个范例来演示foreach指令的使用。
假设有一个变量LANGUAGES包含了多种编程语言的名称,我们需要为每种编程语言生成对应的目标文件。
可以使用foreach指令来实现这个需求。
makefileLANGUAGES := C C++ Java Pythonall:echo "Building targets for the following languages: (LANGUAGES)"(foreach lang, (LANGUAGES), \echo "Building target for (lang)"; \(CC) -c (lang).c -o (lang).o; \)在上述例子中,我们定义了LANGUAGES变量,并使用foreach指令遍历LANGUAGES列表,为每个编程语言生成对应的目标文件。
在每次的迭代中,我们首先输出了要构建的目标语言的名称,然后使用CC变量的值编译对应的源文件。
二、ifeq 指令ifeq指令用于在makefile中进行条件判断。
它的语法如下:ifeq (arg1, arg2)...else...endif其中,arg1和arg2是需要进行比较的两个参数。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
Makefile案例本章目标(1)make与Makefile介绍(2)Makefile基本规则(3)简单的Makefile编写(4)Make自动化变量(5)Makefile编译多个可执行文件(6)make常用内嵌函数(7)多级目录Makefile案例一:基本的Makefile编写touch main.c add.c add.h sub.c sub.hvim Makefilemain:main.o add.o sub.ogcc -Wall -g main.o add.o sub.o -o mainmain.o:main.cgcc -Wall -g -c main.c -o main.oadd.o:add.c add.hgcc -Wall -g -c add.c -o add.osub.o:sub.c sub.hgcc -Wall -g -c sub.c -o sub.omake(解释结果)再次make(没有改动文件;解释结果)touch sub.h再次make(改动了sub.h;解释结果)增加伪目标cleanclean:rm -f main main.o add.o sub.omake clean(对应VS中的“清除”)ls(看一下删除后的结果)make main.o(表示只需要生成main.o;对应VS中的“编译”).PHONY:clean(显示指定clean是一个伪目标)#.PHONY:clean(注释用#)解释如果没有.PHONY:clean会出现什么情况(1.当前目录没有clean文件;2.当前目录有clean 文件(touch clean);make clean就会出错)案例二:自定义和自动化变量(1)makefile有重复,可以自定义变量(2)makefile自动化变量$@ 规则的目标文件名$< 规则的第一个依赖文件名$^ 规则的所有依赖文件列表main:main.o add.o sub.omain 规则的目标文件名main.o 规则的第一个依赖文件名main.o add.o sub.o 规则的所有依赖文件列表.PHONY:cleanOBJECTS=main.o add.o sub.o #自定义变量CC=gccCFLAGS=-Wall -gmain:$(OBJECTS)$(CC) $(CFLANGS) $^ -o $@main.o:main.c$(CC) $(CFLANGS) -c $< -o $@add.o:add.c add.h$(CC) $(CFLANGS) -c $< -o $@sub.o:sub.c sub.h$(CC) $(CFLANGS) -c $< -o $@clean:rm -f main $(OBJECTS)makefile文件名(1)Makefile(2)makefile(3)其他文件名:如Make.makefile(使用的时候需要选项-f)为了演示清楚:clean:echo “begin to delete...”对比:@echo “begin to delete...”@gcc ...案例三:Makefile编译多个可执行文件例子:test1.c和test2.c都有main函数.PHONY:clean all或.PHONY:cleanBIN=test1 test2all:$(BIN)clean:rm -f $(BIN)make后就可以生成可执行文件test1 test2查看输出:cc test1.c -o test1cc test2.c -o test2解释:(all是一个伪目标)隐含推导规则:同名的.c文件生成同名的可执行文件(不使用隐含规则,使用显式规则).PHONY:clean allBIN=test1 test2all:$(BIN)test1:test1.ogcc -Wall -g $^ -o $@test2:test2.ogcc -Wall -g $^ -o $@clean:rm -f *.o $(BIN)make之后观察输出,并解释tes1.o和tes2.o的产生也依赖自动推导规则案例四:模式规则和后缀规则模式规则:%.o:%.c后缀规则:.c.o:.PHONY:clean allBIN=test1 test2all:$(BIN)%.o:%.cgcc -Wall -g -c $< -o $@test1:test1.ogcc -Wall -g $^ -o $@test2:test2.ogcc -Wall -g $^ -o $@clean:rm -f *.o $(BIN)解释输出结果用.c.o:gcc -Wall -g -c $< -o $@结果类似%.o:%.c(增加变量CC=gcc CFLAGS=-Wall -g)注释掉下面信息,看结果test1:test1.ogcc -Wall -g $^ -o $@test2:test2.ogcc -Wall -g $^ -o $@增加test3.c增加pub.c pub.h(test3依赖文件test3.c pub.h pub.c)增加test4.c(作为测试程序;在BIN后加test4就行,轻松)make常用内嵌函数(1)函数调用$(function arguments)(2)$(wildcard PA TTERN)当前目录下匹配模式的文件如src=$(wildcard *.c)(3)$(patsubst PA TTERN,REPLACEMENT,TEXT) 模式替换函数如$(patsubst %.c,%.o,$src)等价于$(src:.c=.o)(4)shell函数执行shell命令如$(shell ls -d */)(显示目录)案例五:多级目录Makefile二级或三级目录例子// main.c// bll目录:bll.c bll.h// bll/test目录:test.c test.h// ui目录:ui.c ui.h// dal目录:dal.c dal.hMakefile.PHONY:cleanCC=gccCFLAGS=-Wall -gBIN=mainSUBDIR=$(shell ls -d */)ROOTSRC=$(wildcard *.c)ROOTOBJ=$(ROOTSRC:%.c=%.o)SUBSRC=$(shell find $(SUBDIR) -name '*.c')SUBOBJ=$(SUBSRC:%.c=%.o)$(BIN):$(ROOTOBJ) $(SUBOBJ)$(CC) $(CFLAGS) -o $(BIN) $(ROOTOBJ) $(SUBOBJ) .c.o:$(CC) $(CFLAGS) -c $< -o $@clean:rm -f $(BIN) $(ROOTOBJ) $(SUBOBJ)解释和演示案例六:多级目录的Makefile//test1目录:Makefile test1.c//test2目录:Makefile test2.cpp先看MakefileSUBDIRS=test1 test2.PHONY:default all clean $(SUBDIRS)all clean:$(MAKE) $(SUBDIRS) TARGET=$@$(SUBDIRS):$(MAKE) -C $@ $(TARGET)再看makefile的输出结果,进行解释结果:make test1 test2 TARGET=allmake[1]: Entering directory `/home/panlei/linux/makefile/mulmakefile'make -C test1 allmake[2]: Entering directory `/home/panlei/linux/makefile/mulmakefile/test1'----- make all in /home/panlei/linux/makefile/mulmakefile -----gcc -c test1.cgcc test1.o -o test1make[2]: Leaving directory `/home/panlei/linux/makefile/mulmakefile/test1'make -C test2 allmake[2]: Entering directory `/home/panlei/linux/makefile/mulmakefile/test2'----- make all in /home/panlei/linux/makefile/mulmakefile -----g++ -Wall -g -c -o test2.o test2.cppg++ -Wall -g test2.o -o test2make[2]: Leaving directory `/home/panlei/linux/makefile/mulmakefile/test2'make[1]: Leaving directory `/home/panlei/linux/makefile/mulmakefile'解释:make test1 test2 TARGET=all ($(MAKE)=make)make -C test1 all (-C:等价于make all test1/Makefile;传递all,执行test/Makefile)test1/MakefileCC=gccBIN=test1OBJS=test1.o.PHONY:all clean printall:print $(BIN)print:@echo "----- make all in $(PWD) -----"$(BIN):$(OBJS)$(CC) $(OBJS) -o $@%.o:%.c$(CC) -c $<clean:@echo "----- make clean in $(PWD) -----"rm -f $(BIN) $(OBJS)test2/MakefileCXX=g++OBJS=test2.oCPPFLAGS=-Wall -g.PHONY:all clean printall:print $(BIN)print:@echo "----- make all in $(PWD) -----"$(BIN):$(OBJS)$(CXX) $(OBJS) -o $@%.o:%.cpp$(CXX) -c $<clean:@echo "----- make clean in $(PWD) -----"rm -f $(BIN) $(OBJS)只看编译顺序:make -n一般来说,如果存在多级目录,那么再用makefile的时候,最好在每个目录下也写一个简单的子makefile,这样在总目录下写一个总的makefile,然后再总的makefile中调用子makefile,这样写起来就会比较清晰,编译顺序是要看总makefile中的步骤。