Chinaunix首页 | 论坛 | 博客
  • 博客访问: 437688
  • 博文数量: 71
  • 博客积分: 26
  • 博客等级: 民兵
  • 技术积分: 1246
  • 用 户 组: 普通用户
  • 注册时间: 2012-07-23 14:46
个人简介

linux --- 一切皆文件

文章分类

全部博文(71)

文章存档

2021年(1)

2019年(2)

2018年(4)

2017年(7)

2016年(11)

2015年(1)

2014年(2)

2013年(33)

2012年(10)

分类: LINUX

2016-02-23 01:27:02

文件搜寻

当依赖或者目标和Makefile不在同一个目录时,可通过VPATH(全部字母大写)来制定目标和依赖所在的目录。
make先查找当前目录,当前目录查找不到才会去VPATH制定的目录下查找。
VPATH = /root/headers:../include:/usr/include     #多个目录之间通过":"分开

VPATH是一个很泛的指定,所有当前目录下找不到的文件都会去VPATH指定的目录下查找。
更精细的指定,可通过vpath(全部字母小写)指定,用法如下:
可以出现多个vpath,根据先后顺序查找

添加查找规则:
vpath %.h ../include
vpath %.c ../src
vpath % ../common

删除查找规则
vpath %.h

清楚所有已经设置好的索引目录:
vpath

在使用目录索引时,最要在规则中使用自动化变量($@,$^,$<等),这样就能获取到从VPATH中,索引到文件的完整路径。

当依赖是一个-lNAME时,make会自动将-lNAME扩充成libNAKE.so
1:首先会在当前目录查找此动态库是否存在
2:如果当前目录没找到,则通过VPATH,vpath指定的目录查找
3:如果以上都未找到,则会去系统目录查找/lib,/usr/lib等目录查找
4:如果没有找到动态库。则make会去查找相应的静态库libNAME.a
5:如果都没有找到,则报错。

foo: foo.c -lcurses
    gcc -o $@ $^

伪目标

1:通过.PHONY声明一个伪目标为clean,伪目标不是一个文件,而是一个标签。需要运行时只能通过make clean来指定clean这个目标执行。
.PHONY: clean
clean:
    @-rm -rf *.o

2:当需要执行一个make而把多个不相互依赖的目标同时执行,则可以使用all这个伪目标。

all: prog1 prog2 prog3
.PHONY: all

prog1: a.c a.h
    gcc -o $@ $^

prog2: c.c c.h
    gcc -o $@ $^

prog3: c.c c.h
    gcc -o $@ $^

3:伪目标也可作为依赖
.PHONY: clean clean1 clean2

clean: clean1 clean2
    @-rm -rf *.a

clean1:
    @-rm -rf *.o

clean2:
    @-rm -rf *.tmp

4:伪目标用于并行和递归过程

方法1:
SUBDIRS = foo bar
subdirs:
    @set -e;    \                    #set -e 设定当执行出现异常时,立即退出
    for dir in $(SUBDIRS);do \
        $(MAKE) -C $$dir;  \
    done

方法2:(可指定执行顺序)

SUBDIRS = foo bar
.PHONY: subdirs $(SUBDIRS)

subdirs: $(SUBDIRS)

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

foo: bar        #此句话的含义是bar在foo之前先执行

强制目标

如果一个规则没有命令或者依赖,并且目标不是一个存在的文件名。
FORCE:; ,执行类似的规则,目标总会被更新,依赖这个目标的目标,也会同时被更新。

foo: foo.c FORCE
    gcc -o $@ $^

FORCE:

以上的例子,foo每次执行make都会重新编译。

多目标

bigoutput littleoutput: text.g

    command text.g -$(subst output,,$@) >$@

等价于:
    
bigoutput:text.g

    commond text.g -big > bigoutput

littleputput:text.g

    commond text.g -little > littleoutput

多规则

对于一个多规则的目标,重建此目标的命令只能出现在一个规则中(可以是多条命令)。
如果多个规则同时给出重建此目标的命令,make将使用最后一个规则中所定义的命令,同时提示错误信息

静态模式

TARGET(目标集合):target-pattern(每个目标文件):prereq-patterns(每个目标文件对应的依赖)
    COMMOND

Example:

objects = a.o b.o c.el

all:$(objects)

$(filter %.o, $(object)):%.o:%.c
    gcc -c $(CFLAGS) $< -o $@

以上Makefile相当于:
通过filter函数过滤出所需要的.o文件。
a.o:a.c
    gcc -c $(CFLAGS$< -o $@

b.o:b.c
    gcc -c $(CFLAGS$< -o $@

注意:all:$(objects)这句话必须要的,否则只会执行第一个a.o:a.c的规则。静态规则可以指定需要执行的目标,比默认规则好用。

$*自动变量,获取目标的名字(不带后缀)

Example:

all: a.o b.o 

a.o b.o:%.o:%.c
    @echo $* "===>" $@

OutPut:
    a ===> a.o
    b ===> b.o

双冒号规则:

双冒号规则:允许同一个文件 作为 多个规则的目标。但是都必须使用双冒号!!

Example:

a.o::foo.c
    gcc -o $@ -c $<

a.o::bar.c
    gcc -o $@ -c $<

以上两条在makefile中是合法的。如果是单冒号的话,makefile则会提示错误。

双冒号与单冒号的区别:
    1:目标没有依赖时,双冒号不管目标是否存在,每次都会编译。单冒号的情况下,如果目标已存在,则不会再进行编译。
    2:通过一个目标作为多个双冒号的规则时,每个规则都会独立的,顺序执行。单冒号都是为了生成一个目标,此目标不依赖的规则不会执行。
    3:一个目标的多个双冒号规则,其中一个依赖更新了,只会执行其中的一个规则。

自动生成依赖:

file a.c:
#include
#include "a.h"

int main(void)
{
    printf("%s %d\n", __func__, __LINE__);
    return 0;
}

使用gcc -M a.c,产生的依赖是带有标准库的头文件的:
a.o: a.c /usr/include/stdio.h /usr/include/features.h \
 /usr/include/sys/cdefs.h /usr/include/bits/wordsize.h \
 /usr/include/gnu/stubs.h /usr/include/gnu/stubs-32.h \
 /usr/lib/gcc/i686-redhat-linux/4.4.6/include/stddef.h \
 /usr/include/bits/types.h /usr/include/bits/typesizes.h \
 /usr/include/libio.h /usr/include/_G_config.h /usr/include/wchar.h \
 /usr/lib/gcc/i686-redhat-linux/4.4.6/include/stdarg.h \
 /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h a.h

使用gcc -MM a.c,将标准库头文件不输出,只输出项目中出现的头文件:
a.o: a.c a.h

自动产生依赖,建议使用方法:

%.d:%.c
    $(CC) -MM $(CFLAGS) $< > $@.$$$$;\
    sed 's,\($*\)\.o[ :]*,\1.o $@:,g' <$@.$$$$ > $@;\
    rm -rf $@.$$$$

命令第一行:生成目标文件的依赖
    foo.o: foo.c foo.h

命令第二行:将foo.o替换成foo.o foo.d。
    $*自动化变量(foo),\1是标签,表示前面括号中的内容,实则为foo。将foo.o替换成foo.o foo.d。存入foo.d文件中。
    foo.o foo.d: foo.c foo.h
    
命令第三行:将临时文件删除。


生成foo.o foo.d: foo.c foo.h,为什么要讲foo.d加入到目标中呢??
回答:首先将foo.o:foo.c foo.h放入到foo.d中,因此又产生了一个文件foo.d,那foo.d的依赖和foo.o是一样的。所以将foo.d放入到依赖中,一开更新时foo.d和foo.o同时被更新。

通过include将.d文件引用进来
src_file = foo.c
sinclude $(src_file: .c = .d)

Example:

TARGET_1依赖OBJS_1,OBJS_1通过.d文件进行编译。

$(TARGET_1):$(OBJS_1)
$(CC) $(OBJS_1) $(LDFLAGS) -o $(TARGET_1)

sinclude $(OBJS_1:.o=.d)

%.d:%.c
    $(CC) -MM $(CFLAGS) $< > $@.$$$$;\
    sed 's,\($*\)\.o[ :]*,\1.o $@:,g' <$@.$$$$ > $@;\
    rm -rf $@.$$$$

阅读(1713) | 评论(0) | 转发(0) |
0

上一篇:Makefile 规则(三)

下一篇:Makefile 命令(五)

给主人留下些什么吧!~~