Makefile 学习记录

Makefile中$@,$^,$<

$@——目标文件;

$^——所有依赖文件;

$<——第一个依赖文件。

例如:下面是一个Makefile:

main:main.o mytool1.o mytool2.o 

gcc -o main main.o mytool1.o mytool2.o 

gcc -o $@ $^

main.o:main.c mytool1.h mytool2.h 

gcc -c main.c 

gcc -c $< 

扫描二维码关注公众号,回复: 5492340 查看本文章

mytool1.o:mytool1.c mytool1.h 

gcc -c mytool1.c 

gcc -c $< 

mytool2.o:mytool2.c mytool2.h 

gcc -c mytool2.c
通过$@,$^,$<可以简化为:


main:main.o mytool1.o mytool2.o 

gcc -o $@ $^

main.o:main.c mytool1.h mytool2.h 

gcc -c $< 

mytool1.o:mytool1.c mytool1.h 

gcc -c $<

mytool2.o:mytool2.c mytool2.h 

gcc -c $<

--------------------- 

下面这个例子表示了,把所有的[.c]文件都编译成[.o]文件.
%.o : %.c
$(CC) -c $(CFLAGS) $(CPPFLAGS) $< -o $@

SRC = ydetect.c threadpool.c message.c scaner.c cJSON.c glob.c mylinux.c mymemc.c base64.c mySnmp.c myZlog.c mymap.c
OBJ = $(SRC:.c=.o)
SRC 变量代表的一系列 %.c文件, $(SRC:.c=.o)  等于 $(SRC:%.c=%.o)  ,相当于把 SRC 变量中 .c文件换成.o文件

OBJ就等于换成.o后的一系列文件。

%.o:%.c
    $(CC) -c $(INCLUDE) $(LIBRARY) $(CPFLAGS) $< 

%.o:%.c 的意思是 通配.o文件依赖同名的.c文件

${MODS:%=%.beam} 是Makefile 变量替换的一种方式.
其格式是 $(var:%.c=%.o)或${var:.c=.o},其意思是把.c 为结尾的变量替换成.o
%则代表任意匹配之外的字符串.
实例:
source: main.c onvif.c

object: $(var:%.c=%.o)

这个时候 %分别等于 main 与 onvif
而 object 则等于 main.o 与 onvif.o

在楼主的例子中${MODS:%=%.beam}
第一个%没有带任何过滤条件.%则表示任意字符串.
第二个%表示在字符串后面添加一个 .beam
${MODS:%=%.beam} 的意思是把为变量添加一个 .beam 后缀

1. ${MODS:%=%.beam} 是Makefile 变量替换的一种方式.
其格式是 $(var:%.c=%.o)或${var:.c=.o},其意思是把.c 为结尾的变量替换成.o
2. %则代表任意匹配之外的字符串.
实例:

1

2

source:main.c onvif.c

object:$(var:%.c=%.o)


这个时候 %分别等于 main 与 onvif
而 object 则等于 main.o 与 onvif.o

注意:

在楼主的例子中${MODS:%=%.beam}
第一个%没有带任何过滤条件.%则表示任意字符串.
第二个%表示在字符串后面添加一个 .beam
${MODS:%=%.beam} 的意思是把为变量添加一个 .beam 后缀

makefile——小例子:

《Erlang程序设计》第六章中的例子:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

hello.erl

-module(hello).

-export([start/0]).

start() ->

  io:format("Hello world ~n").

shop.erl

-module(shop).

-export([cost/1]).

cost(oranges) ->

5;

cost(newspaper) ->

8;

cost(apples) ->

2;

cost(pears) ->

9;

cost(milk) ->

7.

makefile

.SUFFIXES: .erl .beam

.erl.beam:

erlc -W $<

ERL = erl -boot start_clean

MODS = hello shop

    

all: compile

    

compile: ${MODS:%=%.beam}

@echo "make clean - clean up"

clean:

rm -rf *.beam erl_crash.dump

编译成功,会出现hello.beam和shop.beam。

通过makefile将当前目录下的所有.c文件编译成.o文件 

CC = gcc
CFLAGS = -Wall -O –g

%.o: %.c
$(CC) $(CFLAGS) -c $< -o $@

已经从高手那得到了比较好的Makefile文件,就分享给大家吧

SRC = ${wildcard *.c}
OBJ = ${patsubst %.c, %.o, $(SRC)}
CFLAGS = -g -Wall

all : $(OBJ) move

$(OBJ):%.o : %.c
$(CC) $(CFLAGS) -c $^ -o $@ 

move :
mv $(OBJ)  ../OBJS

clean:
$(RM) $(OBJ) .*.sw?

.PHONY:all clean

例子 [1]  :(一个相对复杂的例子,嵌入式编程中经常用到的,详细情况请参考 嵌入式linux应用开发完全手册)

01 src := $(shell ls *.c) /*把当前目录下所有c源代码赋给变量src*/

02 objs := $(patsubst %.c,%.o,$(src)) /*调用makefile 中的函数patsubst, 用.o文件代替.c文件*/

03

04 test: $(objs)

05 gcc -o $@ $^

06

07 %.o:%.c

08 gcc -c -o $@ $<

09

10 clean:

11 rm -f test *.o

上述Makefile中的“$@", "$^", "$<" 称为自动变量。

Makefile中wildcard的介绍

在Makefile规则中,通配符会被自动展开。但在变量的定义和函数引用时,通配符将失效。这种情况下如果需要通配符有效,就需要使用函数“wildcard”,它的用法是:$(wildcard PATTERN...) 。在Makefile中,它被展开为已经存在的、使用空格分开的、匹配此模式的所有文件列表。如果不存在任何符合此模式的文件,函数会忽略模式字符并返回空。需要注意的是:这种情况下规则中通配符的展开和上一小节匹配通配符的区别。

一般我们可以使用“$(wildcard *.c)”来获取工作目录下的所有的.c文件列表。复杂一些用法;可以使用“$(patsubst %.c,%.o,$(wildcard *.c))”,首先使用“wildcard”函数获取工作目录下的.c文件列表;之后将列表中所有文件名的后缀.c替换为.o。这样我们就可以得到在当前目录可生成的.o文件列表。因此在一个目录下可以使用如下内容的Makefile来将工作目录下的所有的.c文件进行编译并最后连接成为一个可执行文件: 

#sample Makefile

objects := $(patsubst %.c,%.o,$(wildcard *.c))

 foo : $(objects)

cc -o foo $(objects)

这里我们使用了make的隐含规则来编译.c的源文件。对变量的赋值也用到了一个特殊的符号(:=)。

1、wildcard : 扩展通配符
2、notdir : 去除路径
3、patsubst :替换通配符

例子:
建立一个测试目录,在测试目录下建立一个名为sub的子目录
$ mkdir test
$ cd test
$ mkdir sub

在test下,建立a.c和b.c2个文件,在sub目录下,建立sa.c和sb.c2 个文件

建立一个简单的Makefile
src=$(wildcard *.c ./sub/*.c)
dir=$(notdir $(src))
obj=$(patsubst %.c,%.o,$(dir) )

all:
 @echo $(src)
 @echo $(dir)
 @echo $(obj)
 @echo "end"
 
执行结果分析:
第一行输出:
a.c b.c ./sub/sa.c ./sub/sb.c

wildcard把 指定目录 ./ 和 ./sub/ 下的所有后缀是c的文件全部展开。

第二行输出:
a.c b.c sa.c sb.c
notdir把展开的文件去除掉路径信息

第三行输出:
a.o b.o sa.o sb.o

在$(patsubst %.c,%.o,$(dir) )中,patsubst把$(dir)中的变量符合后缀是.c的全部替换成.o,
任何输出。
或者可以使用
obj=$(dir:%.c=%.o)
效果也是一样的。

这里用到makefile里的替换引用规则,即用您指定的变量替换另一个变量。
它的标准格式是
$(var:a=b) 或 ${var:a=b}
它的含义是把变量var中的每一个值结尾用b替换掉a

规则

让我们先来粗略地看一看Makefile的规则。 [3] 

target ... : prerequisites ...

command

...

...

目标:依赖

执行指令 ...

target也就是一个目标文件,可以是Object File,也可以是执行文件。还可以是一个标签(Label)。

① prerequisites就是,要生成那个target所需要的文件或是目标。

② command也就是make需要执行的命令。(任意的Shell命令)

gcc -o hello hello.c -I /home/hello/include -L /home/hello/lib -lworld
上面这句表示在编译hello.c时:
(大写I小写i的I)-I /home/hello/include表示将/home/hello/include目录作为第一个寻找头文件的目录,寻找的顺序是:/home/hello/include-->/usr/include-->/usr/local/include
-L /home/hello/lib表示将/home/hello/lib目录作为第一个寻找库文件的目录,寻找的顺序是:/home/hello/lib-->/lib-->/usr/lib-->/usr/local/lib
 (大写L小写l的l)-lworld表示在上面的lib的路径中寻找libworld.so动态库文件(如果gcc编译选项中加入了“-static”表示寻找libworld.a静态库文件) 如  -lpthread 寻找线程库

以下的例子,有引用静态库 ,必须把$(LDFLAGS) 代表库的变量 放在  -o $@ $(OBJ) 后面。
$(BIN): $(OBJ)
#    $(CC) $(INCLUDE) $(LIBRARY) $(MATHFLAG) $(CPFLAGS) $(LDFLAGS) -o $@ $(OBJ)  /home/software/curl-7.53.1/lib/libcurl.a /home/software/zlog-master/src/libzlog.a /home/software/c_map-master/lib/libMyMap.a $(BUILDLIBS)
    $(CC) $(INCLUDE) $(LIBRARY) $(MATHFLAG) $(CPFLAGS)  -o $@ $(OBJ) $(LDFLAGS)  $(BUILDLIBS)

linux makefile点滴记录 Makefile 连接静态库注意事项

linux makefile点滴记录 Makefile 连接静态库注意事项

2014年03月04日 ⁄ 综合 ⁄ 共 1745字 ⁄ 字号    ⁄ 评论关闭

$? :列出当前目标所依赖的文件列表中比当前目标文件还要新的文件。

$@:当前目标的名字。

$<: 当前依赖文件的名字。

$* : 不包括后缀名的当前依赖文件的名字。

-ldl 是告诉程序,要引入动态链接库。

Makefile 连接静态库注意事项

Linux的静态库是以.a结尾的,要连接静态库有两种方法:

一种是,在编译命令最后直接加上库路径/库名称。

例如你的库在绝对目录/lib/libtest.a下面你就可以这样来编译
$(CC) $(CFLAGS) $^  -o $@  /lib/libtest.a

另外一种方法是,你可以用-L制定库德路径,用-l指定库的名称
例如库的名称为libtest.a 那么就用-ltest

CROSS_COMPILE = arm-linux-uclibc-
CC = $(CROSS_COMPILE)gcc
EXEC = armsimplescan
OBJS = simplescan.o
CFLAGS = -Wall -I/home/user/blueZ/bluez_arm/bluez-libs/include
LDFLAGS = -L/home/user/blueZ/bluez_arm/bluez-libs/lib -lbluetooth

#default:$(EXEC)
%.o: %.c
        $(CC) -c $(CFLAGS) $< -o $@

#all:$(EXEC)

$(EXEC):$(OBJS)
        $(CC) $(CFLAGS) $(OBJS) -o $@ $(LDFLAGS) -static
clean:
        rm -f $(EXEC) $(OBJS)

上面的Makefile中$(LDFLAGS)要放在$@的后面,不然不会起作用。

---------------------------------------------------------------------------------------------------------------------------------------------------------------

一.编译和链接选项:
第一步:预编译。
gcc -E hello.c -o hello.i
-E参数:GCC在完成预处理后,停止编译过程。
预处理的宏定义展开到hello.i中。

第二步:生成目标代码。
gcc -c hello.i -o hello.o
-c参数:生成目标代码。
将hello.i编译为目标代码,也可以通过源文件直接生成。
gcc -c hello.c

第三步:链接。
gcc hello.o -o hello
将生成的目标文件链接成可执行文件。
也可以通过源文件直接生成。
gcc -o hello hello.c

二.设置警告选项:
1、-pedantic 选项:
使用扩展语法的地方将产生相应的警告信息
2、-Wall 选项:
要求GCC将产生尽可能多的警告信息
3、-Werror选项:要求GCC将所有的警告当成错误进行处理

三.库依赖选项:
1、Linux下头文件和库文件默认目录:
头文件(.h): /usr/include/目录
库文件(.so, .a): /usr/lib/目录

2、常用选项:
-I选项:向GCC的头文件搜索路径中添加新的目录。
gcc -o hello hello.c -I /home/crosstar/include
要求gcc在/home/crosstar/include/目录下寻找所需要的头文件。

-L选项:向GCC的库文件搜索路径中添加新的目录。
gcc -o test test.c -L /home/crosstar/lib –lfoo
要求gcc在/home/crosstar/lib/目录下寻找所需的库文件libfoo.so

-l选项:要求GCC链接库文件libfoo.so。
注:Linux下的库文件命名约定:
通常以lib三个字母开头。
由于所有的库文件都遵循同样的规范,因此在用-l选项指定链接的库文件名时可以省去lib三个字母,也就是说GCC在对-lfoo进行处理时,会自动去链接名为libfoo.so的文件。

-static选项: 
强制使用静态链接库
gcc -o test test.c -L /home/crosstar/lib-static –lfoo
要求GCC链接时静态链接/home/crosstar/lib/目录下的libfoo.a

方法1
-static : 所有的库文件使用静态库链接

g++ -static -ltest -lfoo 
注意:libtest libfoo 都将只使用静态库,如果没有提供链接无法通过
1
2
方法 2:
这里有2个命令介绍一下:

–Bdynamic : 用于在各种可能的情况下为共享动态绑定设置首选项。

-Bstatic : 将绑定只限制于静态库。

当库的静态和动态版本都可用时,使用这2个选项在命令行首选项间进行切换。 
注意: 使用这2个命令需要配合 -Wl 选项

一个例子

g++ -Wl,-Bstatic -ltest -lfoo -Wl,-Bdynamic -ltest2

使用libtest.a 和 libfoo.a 静态库
使用libtest2.so 动态库
1
2
3
4
还有一个选项 -Wl,–as-needed 抛弃所有的无用的动态库
 

猜你喜欢

转载自blog.csdn.net/BlueBirdssh/article/details/88320534