Makefile的一种写法

适用于目录下有较多源文件的情况

makefile 式列,例如:

CC = gcc
LD = gcc
TARGET = test
SRCS = $(wildcard *.c)
OBJS = $(patsubst %.c, %.o, $(SRCS))

all:$(TARGET)
$(TARGET):$(OBJS)
    $(LD) -o $@ $^

%o:%c
    $(CC) -c -o $@ $^

.PHONY:clean
clean:
    rm -f $(OBJS) $(TARGET)

使用到了GNU Make 里的 ‘wildcard’ 和 ‘patsubst’ 函数, ‘wildcard’ 功能是展开成一列所有符合由其参数描述的文件名,文件间以空格间隔。

SRCS = $(wildcard *.c)

这行会产生一个以 ‘.c’ 结尾的文件的列表,然后存入变量 SRCS 里。

函数 ‘patsubst’(patten substitude)。有三个参数,第一个是一个需要匹配的式样,第二个表示用什么来替换它,第三个是一个需要被处理的由空格分隔的字列。

OBJS = $(patsubst %.c, %.o, $(SRCS))

这行将处理所有在 SRCS中的元素,如果它的结尾是 ‘.c’ ,就用 ‘.o’ 把 ‘.c’取代。

——————-华丽的分割线——————————————-
后缀依赖:
在makefile中使用

.SUFFIXES: .c .o

来说明.c和.o是后缀。
我们可以使用后缀依赖的方式,比如:

CC = gcc
.SUFFIXES: .c .o
.c.o:
    $(CC) -c -o $@ $^
#If Target is the SO LIB , here should add '-fPIC'


# helloworld is a binary file
helloworld: test.o
    echo $@
    $(CC) -o $@ $^

test.o: test.c

我们定义.c和.o为后缀。并有后缀依赖关系.c.o:。前者为前提,后者为目标。(注意,与一般的依赖关系顺序不同)
上面的test.o和test.c有依赖关系,但没有操作。make会发现该依赖关系符合.c.o的后缀依赖,并执行该后缀依赖后面的操作。
如果项目很大型的时候,后缀依赖非常有用。符合后缀依赖的文件往往有类似的操作,我们可以将这些操作用后缀依赖表示,而避免重复输入。

——————-华丽的分割线——————————————-
Makefile选项CFLAGS,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

链接选项和路径

现代连接器在处理动态库时将链接时路径(Link-time path)和运行时路径(Run-time path)分开,用户可以通过-L指定连接时库的路径,通过-R(或-rpath)指定程序运行时库的路径,大大提高了库应用的灵活性。比如我们做嵌入式移植时#arm-linux-gcc $(CFLAGS) –o target –L/work/lib/zlib/ -llibz-1.2.3 (work/lib/zlib下是交叉编译好的zlib库),将target编译好后我们只要把zlib库拷贝到开发板的系统默认路径下即可。或者通过-rpath(或-R )、LD_LIBRARY_PATH指定查找路径。

链接器ld的选项有 -L,-rpath 和 -rpath-link,看了下 man ld,大致是这个意思:

-L: “链接”的时候,去找的目录,也就是所有的 -lFOO 选项里的库,都会先从 -L 指定的目录去找,然后是默认的地方。编译时的-L选项并不影响环境变量LD_LIBRARY_PATH,-L只是指定了程序编译连接时库的路径,并不影响程序执行时库的路径,系统还是会到默认路径下查找该程序所需要的库,如果找不到,还是会报错,类似cannot open shared object file。

-rpath-link:这个也是用于“链接”的时候的,例如你显示指定的需要 FOO.so,但是 FOO.so 本身是需要 BAR.so 的,后者你并没有指定,而是 FOO.so 引用到它,这个时候,会先从 -rpath-link 给的路径里找。

-rpath: “运行”的时候,去找的目录。运行的时候,要找 .so 文件,会从这个选项里指定的地方去找。对于交叉编译,交叉编译链接器需已经配置 –with-sysroot 选项才能起作用。也就是说,-rpath指定的路径会被记录在生成的可执行程序中,用于运行时查找需要加载的动态库。-rpath-link 则只用于链接时查找。

链接搜索顺序

直接man ld。The linker uses the following search paths to locate required shared libraries:

1.  Any directories specified by -rpath-link options.
2.  Any directories specified by -rpath options.  The difference between -rpath and -rpath-link is that directories specified by -rpath options are included in the executable and used at runtime, whereas the -rpath-link option is only effective at link time. Searching -rpath in this way is only supported by native linkers and cross linkers which have been configured with the --with-sysroot option.
3.  On an ELF system, for native linkers, if the -rpath and -rpath-link options were not used, search the contents of the environment variable "LD_RUN_PATH".
4.  On SunOS, if the -rpath option was not used, search any directories specified using -L options.
5.  For a native linker, the search the contents of the environment variable "LD_LIBRARY_PATH".
6.  For a native ELF linker, the directories in "DT_RUNPATH" or "DT_RPATH" of a shared library are searched for shared libraries needed by it. The "DT_RPATH" entries are ignored if "DT_RUNPATH" entries exist.
7.  The default directories, normally /lib and /usr/lib.
8.  For a native linker on an ELF system, if the file /etc/ld.so.conf exists, the list of directories found in that file.
    If the required shared library is not found, the linker will issue a warning and continue with the link.

Makefile 中:= ?= += =的区别

“=”是最基本的赋值。make会将整个makefile展开后,再决定变量的值。也就是说,变量的值将会是整个makefile中最后被指定的值。

 x = foo
 y = $(x) bar
 x = xyz

在上例中,y的值将会是 xyz bar ,而不是 foo bar 。

“:=”是覆盖之前的值。变量的值决定于它在makefile中的位置,而不是整个makefile展开后的最终值。

 x := foo
 y := $(x) bar
 x := xyz

在上例中,y的值将会是 foo bar ,而不是 xyz bar 了。
“?=” 是如果没有被赋值过就赋予等号后面的值
“+=” 是添加等号后面的值

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值