makefile 中 $@ $^ % 使用
makefile中的特殊符号及关键字

makefile中的特殊符号及关键字1.常见⾃动变量和含义* :表⽰⽬标⽂件的名称,不包含⽬标⽂件的扩展名。
+ :表⽰所有的依赖⽂件,这些依赖⽂件之间以空格分开,按照出现的先后为顺序,其中可能包含重复的依赖⽂件。
< :表⽰依赖项中第⼀个依赖⽂件的名称:依赖项中,所有⽬标⽂件时间戳晚的⽂件(表⽰修改过),依赖⽂件间以空格分开@ :⽬标项中⽬标⽂件的名称^ :依赖项中,所有不重复的依赖⽂件,以空格分开。
2.预定义变量Makefile中常⽤的变量及含义AR⽣成静态库库⽂件的程序名称arAS汇编编译器的名称asCC C语⾔编译器的名称ccCPP C语⾔预编译器的名称$(CC) -ECXX C++语⾔编译器的名称g++FC FORTRAN语⾔编译器的名称f77RM删除⽂件程序的名称rm -fARFLAGS⽣成静态库库⽂件程序的选项⽆默认值ASFLAGS汇编语⾔编译器的编译选项⽆默认值CFLAGS C语⾔编译器的编译选项⽆默认值CPPFLAGS C语⾔预编译器的编译选项⽆默认值CXXFLAGS C++语⾔编译器的编译选项⽆默认值FFLAGS FORTRAN语⾔编译器的编译选项⽆默认值3.设置搜索路径 指定需要搜索的⽬录, make 会⾃动找到指定⽂件的⽬录并添加到⽂件上。
VPATH = path1:path2:...4.递归make对于规模⽐较⼤的程序,需要多个⼈在多个⽬录下进⾏开发。
如果只⽤⼀个 Makefile 来维护就会⽐较⿇烦,因此可以在每个⽬录下建⽴⾃⼰的 Makefile ,然后在总控 Makefile 中调⽤⼦⽬录的 Makefile ⽂件。
⽬录结构如下:.├── add│├── add_float.c│├── add.h│├── add_int.c│└── Makefile├── main.c├── Makefile└── sub├── Makefile├── sub_float.c├── sub.h└── sub_int.c1.递归调⽤的⽅式add:cd add && $(MAKE)它等价于add:$(MAKE) -C add2.总控MakefileCC = gccCFLAGS = -O2TARGET = cacuexport OBJSDIR = $(shell pwd)/objs$(TARGET):$(OBJSDIR) main.o$(MAKE) -C add$(MAKE) -C sub$(CC) -o $(TARGET) $(OBJSDIR)/*.o$(OBJSDIR):mkdir -p $@main.o:%.o:%.c$(CC) -c $< -o $(OBJSDIR)/$@ $(CFLAGS) -Iadd -Isubclean:-$(RM) $(TARGET)-$(RM) $(OBJSDIR)/*.o如果总控 Makefile 中的⼀些变量需要传递给下层的 Makefile,可以使⽤ export 命令。
make makefile 的参数

make makefile 的参数make是一个常用的构建工具,用于自动化编译和构建软件项目。
makefile是make工具的配置文件,用于描述项目的构建规则和依赖关系。
本文将介绍makefile的参数,包括常用的参数及其用法。
一、常用参数及其用法1. -f 文件名:指定makefile的文件名,默认为"makefile"或"Makefile"。
通过该参数,可以使用其他名称的makefile文件。
2. -C 目录:指定make命令的工作目录。
在执行make命令时,会切换到指定的目录,并在该目录下查找makefile文件进行构建。
3. -n:显示执行make命令时的操作,但不实际执行。
通过该参数,可以预览make命令的执行过程,检查构建规则是否正确。
4. -p:显示make命令的内置变量和规则。
通过该参数,可以查看make命令的内部工作机制,了解makefile文件的编写规则和使用方法。
5. -B:强制重新构建目标文件。
通过该参数,可以忽略文件的时间戳,强制重新执行构建规则,生成新的目标文件。
6. -j 并发数:指定make命令的并发执行数。
通过该参数,可以提高构建速度,同时执行多个任务。
7. -s:静默模式,不显示执行的命令。
通过该参数,可以减少输出信息,使构建过程更加清晰。
二、makefile的构建规则makefile由一系列构建规则组成,每个规则定义了目标文件、依赖文件和构建命令。
make命令根据构建规则,自动判断需要更新的文件,并执行相应的构建命令。
构建规则的基本格式如下:目标文件: 依赖文件构建命令其中,目标文件是要生成的文件,依赖文件是目标文件依赖的文件,构建命令是生成目标文件的命令。
构建规则中的目标文件和依赖文件可以是文件名,也可以是变量。
通过使用变量,可以提高makefile的可维护性和灵活性。
构建命令可以是任意的Shell命令,包括编译、链接、拷贝等操作。
Makefile条件编译debug版和release版

Makefile条件编译debug版和release版⼀般,在开发测试阶段⽤debug版本,⽽上线发布⽤release版本。
使⽤Makefile定制编译不同版本,避免修改程序和Makefile⽂件,将会⼗分⽅便。
读了⼀些资料,找到⼀个解决⽅法,Makefile预定义宏与条件判断,结合make预定义变量,进⾏条件编译。
⽐如,有⼀个test.cpp,包含这段代码#ifdef debug//your code#endif你希望在debug版本要执⾏它,在release版本不执⾏。
我们可以写这样的⼀个Makefile:1 ver = debug23 ifeq ($(ver), debug)4 ALL: test_d5 CXXFLAGS = -c -g -Ddebug6else7 ALL: test_r8 CXXFLAGS = -c -O39 endif1011 test_d: test.do12 g++ -o $@ $^1314 test_r: test.ro15 g++ -o $@ $^1617 %.do: %.cpp18 g++ $(CXXFLAGS) $< -o $@1920 %.ro: %.cpp21 g++ $(CXXFLAGS) $< -o $@简单说⼀下,Makefile根据ver的不同定义了不同的编译选项CXXFLAGS与输出程序ALL,debug版本输出程序是test_d,release版本输出程序是test_rdebug版本编译选项是"-c -g -Ddebug",release版本编译选项是"-c -O3"debug版本object⽂件后缀是".do",release版本object⽂件后缀是".ro"debug版本编译选项使⽤"-D"定义宏debug,使得your code能够执⾏。
makefile正则表达式

makefile正则表达式makefile是一种常用的工具,可以用于自动化构建和管理项目。
在makefile中,正则表达式是一个强大的工具,可以帮助我们更方便地匹配和处理文本内容。
makefile中常用的正则表达式包括:1. ^(起始符):匹配字符串的开头。
2. $(结束符):匹配字符串的结尾。
3. .(点号):匹配除了换行符外的任意一个字符。
4. *(星号):匹配前面的字符出现0个或多个。
5. +(加号):匹配前面的字符出现1个或多个。
6. ?(问号):匹配前面的字符出现0个或1个。
7. [ ](中括号):匹配中括号中任意一个字符。
8. [^ ](中括号取反):匹配不在中括号中的任意一个字符。
9. ( )(圆括号):将括号中的内容视为一个整体,可以和其他正则表达式一起使用。
除了这些常用的正则表达式外,还有一些特殊的符号和语法可以帮助我们更精确地匹配文本内容,比如:1. (反斜杠):转义符,可以将特殊字符转义为普通字符。
2. |(竖线):或运算符,可以匹配多个表达式中的一个。
3. { }(花括号):重复次数符号,可以指定一个字符或表达式的重复次数。
在使用正则表达式时,我们需要注意一些事项,比如:1. 正则表达式是区分大小写的。
2. 正则表达式中的空格和换行符也会被匹配。
3. 正则表达式可能会匹配到我们不需要的内容,因此需要通过进一步筛选和处理来达到我们的目的。
总之,正则表达式在makefile中的应用非常广泛,可以帮助我们更方便地编写自动化构建和管理脚本。
熟练掌握正则表达式的使用方法,可以极大地提高我们的工作效率。
Makefile中的几个常见的符号及其含义

Makefile中的⼏个常见的符号及其含义= 是最基本的赋值:= 是覆盖之前的值= 是如果没有被赋值过就赋予等号后⾯的值+= 是添加等号后⾯的值“=”和“:=”的区别:1、“=”make会将整个makefile展开后,再决定变量的值。
也就是说,变量的值将会是整个makefile中最后被指定的值。
看例⼦: x = fooy = $(x) barx = xyz在上例中,y的值将会是 xyz bar ,⽽不是 foo bar 。
2、“:=”“:=”表⽰变量的值决定于它在makefile中的位置,⽽不是整个makefile展开后的最终值。
x := fooy := $(x) barx := xyz在上例中,y的值将会是 foo bar ,⽽不是 xyz bar 了。
'@' 符号的使⽤通常makefile会将其执⾏的命令⾏在执⾏前输出到屏幕上。
如果将‘@’添加到命令⾏前,这个命令将不被make回显出来。
例如:@echo --compiling module----; // 屏幕输出 --compiling module----echo --compiling module----; // 没有@ 屏幕输出echo --compiling module----' - ' 符号的使⽤通常删除,创建⽂件如果碰到⽂件不存在或者已经创建,那么希望忽略掉这个错误,继续执⾏,就可以在命令前⾯添加 -, -rm dir;-mkdir aaadir;ref:https:///u012989012/article/details/80572043。
交叉编译makefile编写

交叉编译makefile编写交叉编译Makefile编写在软件开发中,我们通常会遇到需要在不同平台上编译程序的情况。
当我们需要在一台主机上编译运行另一种架构的程序时,就需要进行交叉编译。
而Makefile作为一种构建工具,可以帮助我们自动化编译过程,提高开发效率。
本文将介绍如何编写适用于交叉编译的Makefile,以实现在不同平台上的程序构建。
一、了解交叉编译概念交叉编译是指在一台主机上编译生成另一种架构的可执行文件。
通常情况下,我们在本机上编写并编译程序,然后在本机上运行。
但是,当我们需要在不同的平台上运行程序时,由于不同平台的指令集、库文件等差异,我们就需要使用交叉编译来生成适用于目标平台的可执行文件。
二、Makefile的基本结构Makefile是一种用于描述程序构建过程的文件,它包含了一系列规则(rules),每个规则由一个或多个目标(target)和依赖项(dependencies)组成。
当某个目标的依赖项发生变化时,Make工具会根据规则自动更新目标文件。
一个基本的Makefile结构如下所示:```target: dependenciescommand```其中,target表示目标文件,dependencies表示目标文件的依赖项,command表示生成目标文件的命令。
三、交叉编译的Makefile编写在编写交叉编译的Makefile之前,我们需要了解目标平台的相关信息,如架构、编译器、库文件等。
以ARM架构为例,我们可以使用arm-linux-gnueabi-gcc作为交叉编译器。
我们需要定义一些变量,用于指定交叉编译工具链和相关参数:```CC = arm-linux-gnueabi-gccCFLAGS = -Wall -O2```其中,CC表示编译器,CFLAGS表示编译参数。
接下来,我们可以定义目标文件和依赖项:```TARGET = myprogramSRCS = main.c foo.c bar.cOBJS = $(SRCS:.c=.o)```其中,TARGET表示目标文件,SRCS表示源文件列表,OBJS表示目标文件列表。
makefile文件——Inference Rules(推导规则)

Inference Rules(推导规则)Inference rules(下文简称IR)是一个模板,它用于决定如何从一个具有某种扩展名的文件构造出一个具有另一种扩展名的文件。
NMAKE通过IR来确定用来更新target的命令以及推导target的dependents。
IR的好处在于它满足了像我这样的懒人的需要。
只要提供了正确的IR,则描述语句块就可以极大地化简。
请看下面的例子:foo.obj :上面的语句将会运作得很好。
是不是觉得很吃惊呢?事实上,NMAKE在处理该语句的时候,它首先在当前目录下搜索基本名为foo的文件(假设当前目录下有一个foo.c文件)。
然后它查找一个后缀列表(suffix list),里面的每一项包含了从一种类型的文件构造另一种类型的文件需要调用的命令和参数的相关信息。
在NMAKE预定义的列表中,foo.c到foo.obj的构造命令为CL。
最后NMAKE调用CL,编译foo.c。
呵呵,这么一长串的操作一条简单的语句就搞定了,是不是很方便呢!当出现下列情况之一时,NMAKE就会尝试使用IR:l NMAKE遇到一个没有任何命令的描述语句块。
此时NMAKE就会搜索后缀列表,试图找到一个匹配的命令来构造target。
l 无法找到某个dependent,并且该dependent没有作为target出现在其它dependent line中(即它不是一个pseudotarget)。
此时NMAKE就会搜索给定的目录以及后缀列表,试图找到一个IR来构造出该dependent。
l 一个target没有dependent,并且描述语句块中没有给出指令。
此时NMAKE就会试图找出一个IR来构造出该target。
l 一个target在NMAKE的命令行中给出,但在makefile里没有该target的相关信息(或根本就没有makefile)。
此时NMAKE就会试图找出一个IR来构造出该target。
makefile循环语句

在Makefile中,可以使用循环语句来自动化构建规则和操作。
Makefile的循环语句使用`$(foreach)`宏函数来实现。
下面是一个示例,展示如何使用Makefile循环语句来自动构建多个目标文件:
```makefile
SOURCES = file1.c file2.c file3.c
OBJ_FILES = $(addprefix obj/,$(SOURCES:.c=.o))
all: $(OBJ_FILES)
gcc -o myprogram $^
obj/%.o: %.c
gcc -c $< -o $@
clean:
rm -rf obj/
```
在上面的示例中,`SOURCES`变量包含了多个C源文件,`OBJ_FILES`变量通过使用`$(foreach)`宏函数和`$(addprefix)`函数来生
成目标文件的前缀路径。
然后,在默认规则中,使用`$(foreach)`宏函数来遍历`OBJ_FILES`变量,并构建每个目标文件。
最后,使用`gcc`编译器链接所有目标文件生成最终的可执行文件`myprogram`。
当需要清理所有生成的目标文件时,可以执行`make clean`命令。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
makefile 中$@ $^ %< 使用/kesaihao862/article/details/7332528这篇文章介绍在LINUX下进行C语言编程所需要的基础知识。
在这篇文章当中,我们将会学到以下内容:源程序编译Makefile的编写程序库的链接程序的调试头文件和系统求助1.源程序的编译在Linux下面,如果要编译一个C语言源程序,我们要使用GNU的gcc编译器。
下面我们以一个实例来说明如何使用gcc编译器。
假设我们有下面一个非常简单的源程序(hello.c):int main(int argc,char**argv){printf("Hello Linux\n");}要编译这个程序,我们只要在命令行下执行:gcc -o hello hello.cgcc 编译器就会为我们生成一个hello的可执行文件。
执行./hello就可以看到程序的输出结果了。
命令行中gcc表示我们是用gcc来编译我们的源程序,-o 选项表示我们要求编译器给我们输出的可执行文件名为hello 而hello.c是我们的源程序文件。
gcc编译器有许多选项,一般来说我们只要知道其中的几个就够了。
-o 选项我们已经知道了,表示我们要求输出的可执行文件名。
-c选项表示我们只要求编译器输出目标代码,而不必要输出可执行文件。
-g选项表示我们要求编译器在编译的时候提供我们以后对程序进行调试的信息。
知道了这三个选项,我们就可以编译我们自己所写的简单的源程序了,如果你想要知道更多的选项,可以查看gcc的帮助文档,那里有着许多对其它选项的详细说明。
2.Makefile的编写假设我们有下面这样的一个程序,源代码如下:/* main.c */#include "mytool1.h"#include "mytool2.h"int main(int argc,char **argv){mytool1_print("hello");mytool2_print("hello");}/* mytool1.h */#ifndef _MYTOOL_1_H#define _MYTOOL_1_Hvoid mytool1_print(char *print_str);#endif/* mytool1.c */#include "mytool1.h"void mytool1_print(char *print_str){printf("Thisis mytool1 print %s\n",print_str);}/* mytool2.h */#ifndef_MYTOOL_2_H#define _MYTOOL_2_Hvoidmytool2_print(char *print_str);#endif/* mytool2.c */#include "mytool2.h"void mytool2_print(char *print_str){printf("Thisis mytool2 print %s\n",print_str);}当然由于这个程序是很短的我们可以这样来编译gcc -c main.cgcc -c mytool1.cgcc -c mytool2.cgcc -o main main.o mytool1.o mytool2.o这样的话我们也可以产生main程序,而且也不时很麻烦。
但是如果我们考虑一下如果有一天我们修改了其中的一个文件(比如说mytool1.c)那么我们难道还要重新输入上面的命令?也许你会说,这个很容易解决啊,我写一个SHELL脚本,让她帮我去完成不就可以了。
是的对于这个程序来说,是可以起到作用的。
但是当我们把事情想的更复杂一点,如果我们的程序有几百个源程序的时候,难道也要编译器重新一个一个的去编译?为此,聪明的程序员们想出了一个很好的工具来做这件事情,这就是make。
我们只要执行以下make,就可以把上面的问题解决掉。
在我们执行make之前,我们要先编写一个非常重要的文件。
--Makefile。
对于上面的那个程序来说,可能的一个Makefile的文件是:# 这是上面那个程序的Makefile文件main:main.o mytool1.o mytool2.ogcc -o main main.o mytool1.o mytool2.omain.o:main.c mytool1.h mytool2.hgcc -c main.cmytool1.o:mytool1.c mytool1.hgcc -c mytool1.cmytool2.o:mytool2.cmytool2.hgcc -c mytool2.c有了这个Makefile文件,不过我们什么时候修改了源程序当中的什么文件,我们只要执行make命令,我们的编译器都只会去编译和我们修改的文件有关的文件,其它的文件她连理都不想去理的。
下面我们学习Makefile是如何编写的。
在Makefile中也#开始的行都是注释行.Makefile中最重要的是描述文件的依赖关系的说明。
一般的格式是:target:componentsTAB rule第一行表示的是依赖关系。
第二行是规则。
比如说我们上面的那个Makefile 文件的第二行main:main.o mytool1.o mytool2.o表示我们的目标(target)main的依赖对象(components)是main.o mytool1.o mytool2.o 当倚赖的对象在目标修改后修改的话,就要去执行规则一行所指定的命令。
就象我们的上面那个Makefile第三行所说的一样要执行gcc -o main main.o mytool1.o mytool2.o 注意规则一行中的TAB表示那里是一个TAB键Makefile有三个非常有用的变量。
分别是$@,$^,$<代表的意义分别是:$@--目标文件,$^--所有的依赖文件,$<--第一个依赖文件。
如果我们使用上面三个变量,那么我们可以简化我们的Makefile文件为:# 这是简化后的Makefilemain:main.o mytool1.o mytool2.ogcc -o $@$^main.o:main.c mytool1.h mytool2.hgcc -c $<mytool1.o:mytool1.c mytool1.hgcc -c $<mytool2.o:mytool2.c mytool2.hgcc -c $<经过简化后我们的Makefile是简单了一点,不过人们有时候还想简单一点。
这里我们学习一个Makefile的缺省规则.c.o:gcc -c $<这个规则表示所有的 .o文件都是依赖与相应的.c文件的。
例如mytool.o依赖于mytool.c这样Makefile还可以变为:# 这是再一次简化后的Makefilemain:main.o mytool1.o mytool2.ogcc -o $@ $^.c.o:gcc -c $<好了,我们的Makefile 也差不多了,如果想知道更多的关于Makefile规则可以查看相应的文档。
3.程序库的链接试着编译下面这个程序/* temp.c */#includeint main(int argc,char **argv){double value;printf("Value:%f\n",value);}这个程序相当简单,但是当我们用gcc -o temp temp.c 编译时会出现下面所示的错误。
/tmp/cc33Kydu.o:In function `main':/tmp/cc33Kydu.o(.text+0xe):undefined reference to`log'collect2:ld returned 1 exit status出现这个错误是因为编译器找不到log的具体实现。
虽然我们包括了正确的头文件,但是我们在编译的时候还是要连接确定的库。
在Linux 下,为了使用数学函数,我们必须和数学库连接,为此我们要加入-lm 选项。
gcc -o temp temp.c -lm这样才能够正确的编译。
也许有人要问,前面我们用printf函数的时候怎么没有连接库呢?是这样的,对于一些常用的函数的实现,gcc编译器会自动去连接一些常用库,这样我们就没有必要自己去指定了。
有时候我们在编译程序的时候还要指定库的路径,这个时候我们要用到编译器的-L选项指定路径。
比如说我们有一个库在/home/hoyt/mylib下,这样我们编译的时候还要加上-L/home/hoyt/mylib。
对于一些标准库来说,我们没有必要指出路径。
只要它们在起缺省库的路径下就可以了。
系统的缺省库的路径/lib /usr/lib /usr/local/lib 在这三个路径下面的库,我们可以不指定路径。
还有一个问题,有时候我们使用了某个函数,但是我们不知道库的名字,这个时候怎么办呢?很抱歉,对于这个问题我也不知道答案,我只有一个傻办法。
首先,我到标准库路径下面去找看看有没有和我用的函数相关的库,我就这样找到了线程(thread)函数的库文件(libpthread.a)。
当然,如果找不到,只有一个笨方法。
比如我要找sin这个函数所在的库。
就只好用nm -o /lib/*.so|grep sin>~/sin 命令,然后看~/sin文件,到那里面去找了。
在sin文件当中,我会找到这样的一行libm-2.1.2.so:00009fa0 W sin 这样我就知道了sin在libm-2.1.2.so库里面,我用-lm选项就可以了(去掉前面的lib 和后面的版本标志,就剩下m了所以是-lm)。
如果你知道怎么找,请赶快告诉我,我回非常感激的。
谢谢!4.程序的调试我们编写的程序不太可能一次性就会成功的,在我们的程序当中,会出现许许多多我们想不到的错误,这个时候我们就要对我们的程序进行调试了。
最常用的调试软件是gdb.如果你想在图形界面下调试程序,那么你现在可以选择xxgdb.记得要在编译的时候加入-g选项.关于gdb的使用可以看gdb的帮助文件。
由于我没有用过这个软件,所以我也不能够说出如何使用。
不过我不喜欢用gdb.跟踪一个程序是很烦的事情,我一般用在程序当中输出中间变量的值来调试程序的。
当然你可以选择自己的办法,没有必要去学别人的。