makefile使用
linux make手册:http://www.gnu.org/software/make/manual/make.html
一篇文章:
假设我们有一个程序由5个文件组成,源代码如下:
/*main.c*/
#include "mytool1.h"
#include "mytool2.h"
int main()
{
mytool1_print("hello mytool1!");
mytool2_print("hello mytool2!");
return 0;
}
/*mytool1.c*/
#include "mytool1.h"
#include stdio.h>
void mytool1_print(char *print_str)
{
printf("This is mytool1 print : %s ",print_str);
}
/*mytool1.h*/
#ifndef _MYTOOL_1_H
#define _MYTOOL_1_H
void mytool1_print(char *print_str);
#endif
/*mytool2.c*/
#include "mytool2.h"
#include stdio.h>
void mytool2_print(char *print_str)
{
printf("This is mytool2 print : %s ",print_str);
}
/*mytool2.h*/
#ifndef _MYTOOL_2_H
#define _MYTOOL_2_H
void mytool2_print(char *print_str);
#endif
首先了解一下make和Makefile。GNU make是一个工程管理器,它可以管理较多的文件。我所使用的RedHat
9.0的make版本为GNU Make version
3.79.1。使用make的最大好处就是实现了“自动化编译”。如果有一个上百个文件的代码构成的项目,其中一个或者几个文件进行了修改,make就能
够自动识别更新了的文件代码,不需要输入冗长的命令行就可以完成最后的编译工作。make执行时,自动寻找Makefile(makefile)文件,然
后执行编译工作。所以我们需要编写Makefile文件,这样可以提高实际项目的工作效率。
在一个Makefile中通常包含下面内容:
1、需要由make工具创建的目标体(target),通常是目标文件或可执行文件。
2、要创建的目标体所依赖的文件(dependency_file)。
3、创建每个目标体时需要运行的命令(command)。
格式如下:
target:dependency_files
TAB>command
target:规则的目标。通常是程序中间或者最后需要生成的文件名,可以是.o文件、也可以是最后的可执行程序的文件名。另外,目标也可以是一个make执行的动作的名称,如目标“clean”,这样的目标称为“伪目标”。
dependency_files:规则的依赖。生成规则目标所需要的文件名列表。通常一个目标依赖于一个或者多个文件。
command:规则的命令行。是make程序所有执行的动作(任意的shell命令或者可在shell下执行的程序)。一个规则可以有多
个命令行,每一条命令占一行。注意:每一个命令行必须以[Tab]字符开始,[Tab]字符告诉make此行是一个命令行。make按照命令完成相应的动
作。这也是书写Makefile中容易产生,而且比较隐蔽的错误。命令就是在任何一个目标的依赖文件发生变化后重建目标的动作描述。一个目标可以没有依赖
而只有动作(指定的命令)。比如Makefile中的目标“clean”,此目标没有依赖,只有命令。它所指定的命令用来删除make过程产生的中间文件
(清理工作)。
在Makefile中“规则”就是描述在什么情况下、如何重建规则的目标文件,通常规则中包括了目标的依赖关系(目标的依赖文件)和重建目
标的命令。make执行重建目标的命令,来创建或者重建规则的目标(此目标文件也可以是触发这个规则的上一个规则中的依赖文件)。规则包含了目标和依赖的
关系以及更新目标所要求的命令。
Makefile中可以包含除规则以外的部分。一个最简单的Makefile可能只包含规则描述。规则在有些Makefile中可能看起来非常复杂,但是无论规则的书写是多么的复杂,它都符合规则的基本格式。
下面就可以写出第一个Makefile了。
main:main.o mytool1.o mytool2.o
gcc -o main main.o mytool1.o mytool2.o
main.o:main.c mytool1.h mytool2.h
gcc -c main.c
mytool1.o:mytool1.c mytool1.h
gcc -c mytool1.c
mytool2.o:mytool2.c mytool2.h
gcc -c mytool2.c
clean:
rm -f *.o main
在shell提示符下输入make,执行显示:
gcc -c main.c
gcc -c mytool1.c
gcc -c mytool2.c
gcc -o main main.o mytool1.o mytool2.o
执行结果如下:
[armlinux@lqm makefile-easy]$ ./main
This is mytool1 print : hello mytool1!
This is mytool2 print : hello mytool2!
这只是最为初级的Makefile,现在来对这个Makefile进行改进。
改进一:使用变量
一般在书写Makefile时,各部分变量引用的格式如下:
1. make变量(Makefile中定义的或者是make的环境变量)的引用使用“$(VAR)”格式,无论“VAR”是单字符变量名还是多字符变量名。
2. 出现在规则命令行中shell变量(一般为执行命令过程中的临时变量,它不属于Makefile变量,而是一个shell变量)引用使用shell的“$tmp”格式。
3. 对出现在命令行中的make变量同样使用“$(CMDVAR)” 格式来引用。
OBJ=main.o mytool1.o mytool2.o
make:$(OBJ)
gcc -o main $(OBJ)
main.o:main.c mytool1.h mytool2.h
gcc -c main.c
mytool1.o:mytool1.c mytool1.h
gcc -c mytool1.c
mytool2.o:mytool2.c mytool2.h
gcc -c mytool2.c
clean:
rm -f main $(OBJ)
改进二:使用自动推导
让make自动推导,只要make看到一个.o文件,它就会自动的把对应的.c文件加到依赖文件中,并且gcc -c .c也会被推导出来,所以Makefile就简化了。
CC = gcc
OBJ = main.o mytool1.o mytool2.o
make: $(OBJ)
$(CC) -o main $(OBJ)
main.o: mytool1.h mytool2.h
mytool1.o: mytool1.h
mytool2.o: mytool2.h
.PHONY: clean
clean:
rm -f main $(OBJ)
如果执行make clean出现这个错误:
E:\Linux\gcc\example>make clean
rm -f main main.o mytool1.o mytool2.o
0 [main] rm 6296 stdio_init: couldn't make stderr distinct from stdout
我是在cmd.exe出现这个错误的,用cygwin 自带的terminal执行就没有这个错误了。
改进三:自动变量($^ $
CC = gcc
OBJ = main.o mytool1.o mytool2.o
main: $(OBJ)
$(CC) -o $@ $^
main.o: main.c mytool1.h mytool2.h
$(CC) -c $
mytool1.o: mytool1.c mytool1.h
$(CC) -c $
mytool2.o: mytool2.c mytool2.h
$(CC) -c $
.PHONY: clean
clean:
rm -f main $(OBJ)
这些是最为初级的知识,现在至少可以减少编译时的工作量。细节方面的东西还需要在以后的工作和学习中不断的总结,不断的深化理解。可以 参考GNU Make手册,这里讲解的比较全面。
本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u2/81377/showart_1287410.html
转:跟我一起写 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++的编译的知识,相关于这方面的内容,还请各位查看相关的编译器的文档。这里所默认的编译器是UNIX下的GCC和CC。
0.1 关于程序的编译和链接
在此,我想多说关于程序编译的一些规范和方法,一般来说,无论是C、C++、还是pas,首先要把源文件编译成中间代码文件,在Windows下也就是 .obj 文件,UNIX下是 .o 文件,即 Object File,这个动作叫做编译(compile)。然后再把大量的Object File合成执行文件,这个动作叫作链接(link)。
编译时,编译器需要的是语法的正确,函数与变量的声明的正确。对于后者,通常是你需要告诉编译器头文件的所在位置(头文件中应该只是声明,而定义应该放在C/C++文件中),只要所有的语法正确,编译器就可以编译出中间目标文件。一般来说,每个源文件都应该对应于一个中间目标文件(O文件或是OBJ文件)。
链接时,主要是链接函数和全局变量,所以,我们可以使用这些中间目标文件(O文件或是OBJ文件)来链接我们的应用程序。链接器并不管函数所在的源文件,只管函数的中间目标文件(Object File),在大多数时候,由于源文件太多,编译生成的中间目标文件太多,而在链接时需要明显地指出中间目标文件名,这对于编译很不方便,所以,我们要给中间目标文件打个包,在Windows下这种包叫“库文件”(Library File),也就是 .lib 文件,在UNIX下,是Archive File,也就是 .a 文件。
总结一下,源文件首先会生成中间目标文件,再由中间目标文件生成执行文件。在编译时,编译器只检测程序语法,和函数、变量是否被声明。如果函数未被声明,编译器会给出一个警告,但可以生成Object File。而在链接程序时,链接器会在所有的Object File中找寻函数的实现,如果找不到,那到就会报链接错误码(Linker Error),在VC下,这种错误一般是:Link 2001错误,意思说是说,链接器未能找到函数的实现。你需要指定函数的ObjectFile.
好,言归正传,GNU的make有许多的内容,闲言少叙,还是让我们开始吧。
http://blog.csdn.net/lastsweetop/article/details/5659244
http://blog.csdn.net/changli_90/article/details/7881905
静态模式
静态模式可以更加容易地定义多目标的规则,让规则变得更加的有弹性和灵活。
...
targets定义了一系列的目标文件,可以有通配符,是目标的一个集合。
target-parrtern是指明了targets的模式,也就是目标集模式。
prereq-parrterns是目标的依赖模式,它对target-parrtern形成的模式再进行一次依赖目标的定义。
这样描述这三个东西,可能还没说清楚,还是举个例子来说明一下吧。如果我们的
所以,“目标模式”或是“依赖模式”中都应该有“%”这个字符,如果你的文件名中有“%”那么你可以使用反斜杠“\”进行转义,来标明真实的“%”字符。
看一个例子:
objects = foo.o bar.o
all: $(objects)
$(objects): %.o: %.c
$(CC) -c $(CFLAGS) $< -o $@
(这里怎么理解 $(objects): %.o: %.c ???
写makefile,下面的依赖怎么理解,为什么俩冒号?百度知道的一个问题:
例子
$(C_OBJS):$(P_OouDIR)/%.o:%.c
。。。。。(commands)
其中 C_OBJS变量为带路径的.o文件名如 .bin/test.o,P_OouDIR为./bin目录
这就是makefile的静态模式规则。
- Here is the syntax of a static pattern rule:
- targets ...: target-pattern: prereq-patterns ...
- recipe
- ...
参见gnu makefile 手册 section 4.11
意思就是说
$(C_OBJS) 中有很多文件,假设各种各样的都有 (实际中肯定是你自己定义的,不会乱七八糟)
看看这些文件里面,找出匹配符合 $(P_OouDIR)/%.o的。 既然P_OouDIR为./bin目录,那么就是看看那些匹配模式 ./bin/%.o,显然,一般来说按你的定义,都会匹配的。
然后,这里面的.o都依赖各自对应的.c
也就是说
$(C_OBJS):$(P_OouDIR)/%.o:%.c
和规则
$(P_OouDIR)/%.o:%.c
完全是等价的,在你这里。
但是一般性而言,并不等价,比如$(C_OBJS)还定义了其它文件,比如 ./lib/xxx.o
静态模式规则的好处,是能精确定义,哪个文件,依赖哪个文件。规定了预选范围。
%.o:%.c 则是泛泛而谈,只要匹配,就是这样。
看这边文章:http://blog.chinaunix.net/uid-20564848-id-218435.html
)
上面的例子中,指明了我们的目标从$object中获取,“%.o”表明要所有以“.o”结尾的目标,也就是“foo.o bar.o”,也就是变量$object集合的模式,而依赖模式“%.c”则取模式“%.o”的“%”,也就是“foo bar”,并为其加下“.c”的后缀,于是我们的依赖目标就是“foo.c bar.c”;而命令中的“$<”和“$@”则是自动化变量,“$<”表示所有的依赖目标集(也就是“foo.c bar.c”),“$@”表示目标集(也就是“foo.o bar.o”)。于是,上面的规则展开后等价于下面的规则:
foo.o : foo.c
$(CC) -c $(CFLAGS) foo.c -o foo.o
bar.o : bar.c
$(CC) -c $(CFLAGS) bar.c -o bar.o
试想,如果我们的“%.o”有几百个,那种我们只要用这种很简单的“静态模式规则”就可以写完一堆规则,实在是太有效率了。“静态模式规则”的用法很灵活,如果用得好,那会一个很强大的功能。再看一个例子:
files = foo.elc bar.o lose.o
$(filter %.o,$(files)): %.o: %.c
$(CC) -c $(CFLAGS) $< -o $@
$(filter %.elc,$(files)): %.elc: %.el
emacs -f batch-byte-compile $<
$(filter %.o,$(files))表示调用Makefile的filter函数,过滤“$filter”集,只要其中模式为“%.o”的内容。
3、自动化变量
在上述的模式规则中,目标和依赖文件都是一系例的文件,那么我们如何书写一个命令来完成从不同的依赖文件生成相应的目标?因为在每一次的对模式规则的解析时,都会是不同的目标和依赖文件。
自动化变量就是完成这个功能的。在前面,我们已经对自动化变量有所提涉,相信你看到这里已对它有一个感性认识了。所谓自动化变量,就是这种变量会把模式中所定义的一系列的文件自动地挨个取出,直至所有的符合模式的文件都取完了。这种自动化变量只应出现在规则的命令中。
下面是所有的自动化变量及其说明:
$@
表示规则中的目标文件集。在模式规则中,如果有多个目标,那么,"$@"就是匹配于目标中模式定义的集合。
$%
仅当目标是函数库文件中,表示规则中的目标成员名。例如,如果一个目标是"foo.a(bar.o)",那么,"$%"就是"bar.o","$@"就是"foo.a"。如果目标不是函数库文件(Unix下是[.a],Windows下是[.lib]),那么,其值为空。
$<
依赖目标中的第一个目标名字。如果依赖目标是以模式(即"%")定义的,那么"$<"将是符合模式的一系列的文件集。注意,其是一个一个取出来的。
$?
所有比目标新的依赖目标的集合。以空格分隔。
$^
所有的依赖目标的集合。以空格分隔。如果在依赖目标中有多个重复的,那个这个变量会去除重复的依赖目标,只保留一份。
$
这个变量很像"$^",也是所有依赖目标的集合。只是它不去除重复的依赖目标。
$*
这个变量表示目标模式中"%"及其之前的部 分。如果目标是"dir/a.foo.b",并且目标的模式是"a.%.b",那么,"$*"的值就是"dir/a.foo"。这个变量对于构造有关联的 文件名是比较有较。如果目标中没有模式的定义,那么"$*"也就不能被推导出,但是,如果目标文件的后缀是make所识别的,那么"$*"就是除了后缀的 那一部分。例如:如果目标是"foo.c",因为".c"是make所能识别的后缀名,所以,"$*"的值就是"foo"。这个特性是GNU make的,很有可能不兼容于其它版本的make,所以,你应该尽量避免使用"$*",除非是在隐含规则或是静态模式中。如果目标中的后缀是make所不 能识别的,那么"$*"就是空值。
当你希望只对更新过的依赖文件进行操作时,"$?"在显式规则中很有用,例如,假设有一个函数库文件叫"lib",其由其它几个object文件更新。那么把object文件打包的比较有效率的Makefile规则是:
lib : foo.o bar.o lose.o win.o
ar r lib $?
在上述所列出来的自动量变量中。四个变量($@、$<、$%、$*)在扩展时只会有一个 文件,而另三个的值是一个文件列表。这七个自动化变量还可以取得文件的目录名或是在当前目录下的符合模式的文件名,只需要搭配上"D"或"F"字样。这是 GNU make中老版本的特性,在新版本中,我们使用函数"dir"或"notdir"就可以做到了。"D"的含义就是Directory,就是目录,"F"的 含义就是File,就是文件。
下面是对于上面的七个变量分别加上"D"或是"F"的含义:
$(@D)
表示"$@"的目录部分(不以斜杠作为结尾),如果"$@"值是"dir/foo.o",那么"$(@D)"就是"dir",而如果"$@"中没有包含斜杠的话,其值就是"."(当前目录)。
$(@F)
表示"$@"的文件部分,如果"$@"值是"dir/foo.o",那么"$(@F)"就是"foo.o","$(@F)"相当于函数"$(notdir $@)"。
"$(*D)"
"$(*F)"
和上面所述的同理,也是取文件的目录部分和文件部分。对于上面的那个例子,"$(*D)"返回"dir",而"$(*F)"返回"foo"
"$(%D)"
"$(%F)"
分别表示了函数包文件成员的目录部分和文件部分。这对于形同"archive(member)"形式的目标中的"member"中包含了不同的目录很有用。
"$("$(
分别表示依赖文件的目录部分和文件部分。
"$(^D)"
"$(^F)"
分别表示所有依赖文件的目录部分和文件部分。(无相同的)
"$( D)"
"$( F)"
分别表示所有依赖文件的目录部分和文件部分。(可以有相同的)
"$(?D)"
"$(?F)"
分别表示被更新的依赖文件的目录部分和文件部分。
最后想提醒一下的是,对于"$<",为了避免产生不必要的麻烦,我们最好给$后面的那个特定字符都加上圆括号,比如,"$(<)"就要比"$<"要好一些。
还得要注意的是,这些变量只使用在规则的命令中,而且一般都是"显式规则"和"静态模式规则"(参见前面"书写规则"一章)。其在隐含规则中并没有意义。
一篇文章:
Linux学习笔记——例说makefile 头文件查找路径
0.前言 从学习C语言开始就慢慢开始接触makefile,查阅了很多的makefile的资料但总感觉没有真正掌握makefile,如果自己动手写一个makefile总觉得非常吃力。所以特意借助博客总结makefile的相关知识,通过例子说明makefile的具体用法。 例说makefile分为以下几个部分,更多内容请参考【例说makefile索引博文】 1.只有单个C文件 2.含有多个C文件 3.需要包括头文件路径 4.增加宏定义 5.增加系统共享库 6.增加自定义共享库 7.一个实际的例子 【代码仓库】——makefile-example 代码仓库位于bitbucket,可借助TortoiseHg(GUI工具)克隆代码或者在网页中直接下载zip包。 1.三个C文件和三个头文件 此处的例子稍微复杂些但更接近实际情况。 文件结果如下:根目录中包含test.c makefileh和文件夹test-add和文件夹test-sub。 test.c makefile 【test-add】test-add.c test-add.h 【test-sub】test-sub.c test-sub.h 【test.c】 [cpp] view plaincopy
- #include
- #include
- #include
- int main(void)
- {
- int a = 3;
- int b = 2;
- printf("a=%d\n", a);
- printf("b=%d\n", b);
- printf("a+b=%d\n", add(a,b));
- printf("a-b=%d\n", sub(a,b));
- return 0;
- }

- #include
- int add(int a, int b)
- {
- return a+b;
- }

- #ifndef __TEST_ADD
- int add(int a, int b);
- #endif

- #include "test-sub.h"
- int sub(int a, int b)
- {
- return a-b;
- }

- #ifndef __TEST_SUB
- int sub(int a, int b);
- #endif
# 指令编译器和选项 CC=gcc CFLAGS=-Wall -std=gnu99 # 目标文件 TARGET=test SRCS = test.c \ ./test-add/test-add.c \ ./test-sub/test-sub.c INC = -I./test-add -I./test-sub OBJS = $(SRCS:.c=.o) $(TARGET):$(OBJS) # @echo TARGET:$@ # @echo OBJECTS:$^ [tab]$(CC) -o $@ $^ clean: [tab]rm -rf $(TARGET) $(OBJS) %.o:%.c [tab]$(CC) $(CFLAGS) $(INC) -o $@ -c $<
上面的makefile要好好理解:
$(SRCS:.c=.o) 表示把SRCS中.c替换成.o
Makefile变量替换引用 将.o替换成.c Makefile中替换变量结尾的字符
【具体说明】
【1】相比于单个文件和多个文件的makefile,通过变量INC制定了头文件路径。头文件路径之间通过空格隔开。
【2】编译规则%.o:%.c中加入了头文件参数$(CC) $(CFLAGS) $(INC) -o $@ -c $<,那么在编译的过程中便会出现
gcc -Wall -std=gnu99 -I./test-add -I./test-sub -o test.o -c test.c。和单个文件和多个文件的makefile相比增加了头文件路径参数。
【3】SRCS变量中,文件较多时可通过“\”符号续行。
【编译】
make clean && make
【控制台输出】
rm -rf test test.o ./test-add/test-add.o ./test-sub/test-sub.o
gcc -Wall -std=gnu99 -I./test-add -I./test-sub -o test.o -c test.c
gcc -Wall -std=gnu99 -I./test-add -I./test-sub -o test-add/test-add.o -c test-add/test-add.c
gcc -Wall -std=gnu99 -I./test-add -I./test-sub -o test-sub/test-sub.o -c test-sub/test-sub.c
gcc -o test test.o test-add/test-add.o test-sub/test-sub.o
从控制台的输出可以看出,通过make clean清除上一次的可执行文件和目标文件,然后依次编译各个C文件,在编译的过程中制定了头文件路径,最后把3个目标文件链接为最终可执行文件。
这个系列http://blog.csdn.net/xukai871105/article/details/37083675 非常好。
http://blog.csdn.net/shuaishuai80/article/details/6202529
更多:
http://wiki.ubuntu.org.cn/index.php?title=%E8%B7%9F%E6%88%91%E4%B8%80%E8%B5%B7%E5%86%99Makefile&variant=zh-cn
http://blog.csdn.net/kesaihao862/article/details/7332528
makefile接受参数:
make out=test_1.c ------------------------- file_name=$(out) target=$(basename $(file_name)) all: $(target) $(target): gcc -o $(target) $file_name再例:
TARGET=$(out)
all:$(TARGET)
g++ `pkg-config opencv --libs --cflags opencv` $(TARGET)
以上是Makefile 文件。编译带opencv库的程序,只要输入类似 make out=hellow.c 非常方便
makefile文件之间参数传递:
http://blog.csdn.net/shallnet/article/details/37657597?utm_source=tuicool
条件判断:
ifeq ($(CC),gcc)
libs=$(libs_for_gcc)
else
libs=$(normal_libs)
endif
CFLAGS、CXXFLAGS、LDFLAGS与LIBS
CFLAGS 表示用于 C 编译器的选项,
CXXFLAGS 表示用于 C++ 编译器的选项。
这两个变量实际上涵盖了编译和汇编两个步骤。
CFLAGS: 指定头文件(.h文件)的路径,如:CFLAGS=-I/usr/include -I/path/include。同样地,安装一个包时会在安装路径下建立一个include目录,当安装过程中出现问题时,试着把以前安装的包的include目录加入到该变量中来。
LDFLAGS:gcc 等编译器会用到的一些优化参数,也可以在里面指定库文件的位置。用法:LDFLAGS=-L/usr/lib -L/path/to/your/lib。每安装一个包都几乎一定的会在安装目录里建立一个lib目录。如果明明安装了某个包,而安装另一个包时,它愣是 说找不到,可以抒那个包的lib路径加入的LDFALGS中试一下。
LIBS:告诉链接器要链接哪些库文件,如LIBS = -lpthread -liconv
简单地说,LDFLAGS是告诉链接器从哪里寻找库文件,而LIBS是告诉链接器要链接哪些库文件。不过使用时链接阶段这两个参数都会加上,所以你即使将这两个的值互换,也没有问题。
有时候LDFLAGS指定-L虽然能让链接器找到库进行链接,但是运行时链接器却找不到这个库,如果要让软件运行时库文件的路径也得到扩展,那么我们需要增加这两个库给"-Wl,R":
LDFLAGS = -L/var/xxx/lib -L/opt/mysql/lib -Wl,R/var/xxx/lib -Wl,R/opt/mysql/lib
如果在执行./configure以前设置环境变量export LDFLAGS="-L/var/xxx/lib -L/opt/mysql/lib -Wl,R/var/xxx/lib -Wl,R/opt/mysql/lib" ,注意设置环境变量等号两边不可以有空格,而且要加上引号(shell的用法)。那么执行configure以后,Makefile将会设置这个选项,链 接时会有这个参数,编译出来的可执行程序的库文件搜索路径就得到扩展了。
参考了:http://www.cnblogs.com/ai616818/archive/2011/06/30/2094909.html
addprefix:
函数名称:加前缀函数—addprefix。
函数功能:为“NAMES…”中的每一个文件名添加前缀“PREFIX”。参数“NAMES…”是空格分割的文件名序列,将“SUFFIX”添加到此序列的每一个文件名之前。
返回值:以单空格分割的添加了前缀“PREFIX”的文件名序列。
函数说明:
示例:
$(addprefix src/,foo bar)
返回值为“src/foo src/bar”。
$(shell pwd)和$(pwd)有什么区别
Makefile里面好像必须加shell,直接用$(pwd)好象不行。
我刚才试了一下,把这几行保存成Makefile,然后make可以看到结果
P=$(shell pwd) # 这样可以输出路径
#P=$(pwd) # 这样没有输出
all:
echo $P
http://www.cnblogs.com/wang_yb/p/3990952.html
shell 用的是大括号, Makefile两种都行.但是在命令里用shell变量的是候就需要大括号.
- all:
- curr_dir=`pwd`; \
- echo ${curr_dir}; \
- echo $(LOGNAME); \
- echo ${LOGNAME}
cur_dir := ${shell pwd}
long_bit = ${shell getconf LONG_BIT}
makefile .SUFFIXES
跟我学makefile中提到:
2.2.1 预定义隐含规则
可以在makefile文件中重载这些隐含规则。也可以取消预定义的隐含规则,只要不在后面写命令就可以了。make命令的参数‘-r’也能把缺省的后缀列表清空,从而删除所有预定义的隐含规则。
如果预定义的隐含规则的依赖出现在后缀列表中,则该预定义的隐含规则也称为后缀规则。如果更改了后缀列表,那些依赖的后缀没有出现在新后缀列表中的预定义的隐含规则将被禁止。
后缀是特殊目标.SUFFIXES的依赖名。例如:
.SUFFIXES: # 删除缺省的后缀列表
.SUFFIXES:.cpp .obj #把.cpp和.obj添加到后缀列表中。
2.2.2 隐含规则链
有时生成一个文件需要使用多个隐含规则组成的序列,这样的隐含规则序列称为隐含规则链。同一条隐含规则不能在隐含规则链中出现两次或两次以上。
通常情况下,任何在makefile文件中提及的目标和依赖都不是中间文件。但是,我们可以特别指定一些文件为中间文件,只需将这些文件指定为特殊目标.INTERMEDIATE的依赖。如果.INTERMEDIATE没有依赖文件,它将不会发生作用。
为了阻止自动删除中间文件,可以将需要保留的中间文件指定为特殊目标.SECONDARY的依赖。.SECONDARY的依赖被处理为中间文件,但它们永远不能自动删除。如果.SECONDARY没有依赖文件,则所有的目标都将被处理为中间文件。
也可以将一个隐含规则的目标格式作为特殊目标.PRECIOUS的依赖,这样就可以保留那些由该隐含规则创建的中间文件。
2.2.3 后缀规则
后缀规则已经被格式规则代替,分为单后缀和双后缀规则。
双后缀规则: 等同于格式规则:
.c.o: %.o: %.c
…… ……
单后缀规则: 等同于格式规则:
.c %: %.c
…… ……
后缀规则不能有任何属于它们自己的依赖,而格式规则可以有依赖文件。例如:
%.o:%.c hello.h
……
没有命令的后缀规则没有意义,它们并不像没有命令的格式规则那样移去以前的规则。
老式风格的"后缀规则"
后缀规则是一个比较老式的定义隐含规则的方法。后缀规则会被模式规则逐步地取代。因为模式规则更强更清晰。为了和老版本的Makefile兼容,GNU make同样兼容于这些东西。后缀规则有两种方式:"双后缀"和"单后缀"。
双后缀规则定义了一对后缀:目标文件的后缀和依赖目标(源文件)的后缀。如".c.o"相当于"%o : %c"。单后缀规则只定义一个后缀,也就是源文件的后缀。如".c"相当于"% : %.c"。
后缀规则中所定义的后缀应该是make所认识的,如果一个后缀是make所认识的,那么这个规则就是单后缀规则,而如果两个连在一起的后缀都被 make所认识,那就是双后缀规则。例如:".c"和".o"都是make所知道。因而,如果你定义了一个规则是".c.o"那么其就是双后缀规则,意义就是".c"是源文件的后缀,".o"是目标文件的后缀。如下示例:
.c.o: $(CC) -c $(CFLAGS) $(CPPFLAGS) -o $@ $<
后缀规则不允许任何的依赖文件,如果有依赖文件的话,那就不是后缀规则,那些后缀统统被认为是文件名,如:
.c.o: foo.h $(CC) -c $(CFLAGS) $(CPPFLAGS) -o $@ $<
这个例子,就是说,文件".c.o"依赖于文件"foo.h",而不是我们想要的这样:
%.o: %.c foo.h $(CC) -c $(CFLAGS) $(CPPFLAGS) -o $@ $<
后缀规则中,如果没有命令,那是毫无意义的。因为他也不会移去内建的隐含规则。
而要让make知道一些特定的后缀,我们可以使用伪目标".SUFFIXES"来定义或是删除,如:
.SUFFIXES: .hack .win
把后缀.hack和.win加入后缀列表中的末尾。
.SUFFIXES: # 删除默认的后缀 .SUFFIXES: .c .o .h # 定义自己的后缀
先清除默认后缀,后定义自己的后缀列表。
make的参数"-r"或"-no-builtin-rules"也会使用得默认的后缀列表为空。而变量"SUFFIXE"被用来定义默认的后缀列表,你可以用".SUFFIXES"来改变后缀列表,但请不要改变变量"SUFFIXE"的值。