makefile学习小结
=============2016/08/15================
上午完成makefile的试验,缩短了代码量,现在make强大,有缺省的变量,能自己推导关系,不需要gcc –MM -MG
1)需要的usr/lib等缺省目录的参数,仅仅 -lcxl, -lpthread
#LDFLAGS = -L${PWD} -L${PSLSE_DIR} -lm -lcxl -lpthread -lrt
LDFLAGS = -L${PSLSE_DIR} -lcxl –lpthread
-------------------------------------------------
2)LDLIB也是认可的参数,所以上面的一句话也可以变成如下
LDFLAGS = -L${PSLSE_DIR}
LDLIBS = -lm –lcxl –lpthread
CFLAGS += -std=gnu99 -Wall -Werror -g -Wno-comment
CPPFLAGS += -D_GNU_SOURCE
CPPFLAGS += -I${PSLSE_DIR} -I${CAPI_INC_DIR} -I${ARGCONFIG_INC_DIR} -I${CAPI_H_DIR} -I${ARGCONFIG_H_DIR} -I${CAPI_DIR} -I${ARGCONFIG_DIR}
LDFLAGS += -L${PSLSE_DIR}
LDLIBS += -lcxl -lpthread
LIBCFLAGS += -g -Wall -m64 -DDEBUG -std=gnu99
依次顺序:
cc CFLAGS CPPFLAGS -c -o 目标.c 目标.o
然后再链接
cc CFLAGS CPPFLAGS LDFLAGS 目标.c 有关联.o LDLIBS -o 目标
cc -std=gnu99 -Wall -Werror -g -Wno-comment -D_GNU_SOURCE -I../libs/pslse/libcxl -I../libs/capi/inc -I../libs/argconfig/inc -I../libs/capi/inc/capi -I../libs/argconfig/inc/argconfig -I../libs/capi/src -I../libs/argconfig/src -L../libs/pslse/libcxl textswap.c readthrd.o writethrd.o textswap_proc.o ../libs/capi/src/capi.o ../libs/capi/src/build_version.o ../libs/capi/src/wqueue_emul.o ../libs/capi/src/snooper.o ../libs/capi/src/wqueue.o ../libs/capi/src/worker.o ../libs/capi/src/fifo.o ../libs/capi/src/utils.o ../libs/argconfig/src/suffix.o ../libs/argconfig/src/report.o ../libs/argconfig/src/argconfig.o -lcxl -lpthread -o textswap
CFLAGS += -std=gnu99 -Wall -Werror -g -Wno-comment
CPPFLAGS += -D_GNU_SOURCE
CPPFLAGS
+= -I${PSLSE_DIR} -I${CAPI_INC_DIR} -I${ARGCONFIG_INC_DIR}
-I${CAPI_H_DIR} -I${ARGCONFIG_H_DIR} -I${CAPI_DIR} -I${ARGCONFIG_DIR}
LDFLAGS += -L${PSLSE_DIR}
LDLIBS += -lcxl -lpthread
LIBCFLAGS += -g -Wall -m64 -DDEBUG -std=gnu99
Objects = readthrd.o writethrd.o textswap_proc.o
Objects += $(patsubst %.c,%.o,$(wildcard ${CAPI_DIR}/*.c ${ARGCONFIG_DIR}/*.c))
APP = textswap unittest searchtest lfsrtest iotest
all: ${APP}
#depends1.mk :
# echo "begin to generate depends1.mk"
# echo $(shell cd ${CAPI_DIR}); pwd \
# @$(CC) $(CPPFLAGS) -MM -MG $(wildcard *.c) $(wildcard *.cpp) > depends1.mk
#
#-include depends1.mk
${APP}: ${Objects}
---------------------------------------------------------------
3)
3.1目标可以是多重,同一个目标可以写多次.
clean::
xxxxx
clean::
yyyyy
1. 双冒号规则中:
对于一个没有依赖而只有命令行的双冒号规则,当引用此目标时,规则的命令将会被无条件执行。
而普通单冒号规则,当规则的目标文件存在时,此规则的命令永远不会被执行(目标文件永远是最新的)。
3.2
执行多个目标的方法,写在all后面
如:
ALL = textswap unitest
all:${ALL}
${APP}: ${Objects}
4)-L{$LIBDIR}指向 动态库,静态库。
编译会先找动态库.so,如果没有,再找静态库.a
LDFLAGS += -L${PSLSE_DIR}
但是使用的是动态库,则需要设置$LD_LIBRARY_PATH+= ,指向.so的位置。
否则只在/usr/lib 等系统目录以及键入程序运行的目录查找
如果动态库和静态库都存在那么会优先链接动态库,如果找不到动态库,就直接使用静态库。
如果为了调试要强制使用静态库,可以在CFLAGS中加入-static (但是其缺点就是static是指所有库的目录下的静态库,如果想一部分是静态库,一部分是动态库,则无法工作
比如出现如此问题
bs/argconfig/src/report.o ../libs/argconfig/src/argconfig.o -lcxl -lpthread -o textswap
/usr/bin/ld: cannot find -lpthread
/usr/bin/ld: cannot find -lc
collect2: error: ld returned 1 exit status
因为也调用了动态库
LDFLAGS += -L${PSLSE_DIR}
LDLIBS += -lcxl -lpthread
-lcxl,-lptheread 只有.so文件,没有.a文件
一个方法是直接指明.a,根据顺序赋值给LDLIBS,写在前方
CFLAGS += -std=gnu99 -Wall -Werror -g -Wno-comment
CPPFLAGS += -D_GNU_SOURCE
CPPFLAGS += -I${PSLSE_DIR} -I${CAPI_INC_DIR} -I${ARGCONFIG_INC_DIR} -I${CAPI_H_DIR} -I${ARGCONFIG_H_DIR} -I${CAPI_DIR} -I${ARGCONFIG_DIR}
LDFLAGS += -L${PSLSE_DIR}
LDLIBS += ${PSLSE_DIR}/libcxl.a -lpthread
LIBCFLAGS += -g -Wall -m64 -DDEBUG -std=gnu99
5)patsubst函数是吧某一个集合,完成替换
如下这样写是错误的
Objects += $(patsubst %.c,%.o,${CAPI_DIR} ${ARGCONFIG_DIR})
改为
Objects += $(patsubst %.c,%.o,$(wildcard ${CAPI_DIR}/*.c ${ARGCONFIG_DIR}/*.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时在网上看到一篇文章,介绍了使用函数wildcard得到指定目录下所有的C语言源程序文件名的方法,这下好了,不用手工一个一个指定需要编译的.c文件了,方法如下:
SRC = $(wildcard *.c)
等于指定编译当前目录下所有.c文件,如果还有子目录,比如子目录为inc,则再增加一个wildcard函数,象这样:
SRC = $(wildcard *.c) $(wildcard inc/*.c)
yxr注:
其实 SRC = $(wildcard *.c inc/*.c)也可以,wildcard可以带多个参数
==================2016/08/12 ===========
----------------
执行shell中命令
PATH="/data/" all:
echo ${PATH}
echo $$PATH
例子中的第一个${PATH}引用的是Makefile中的变量,而不是shell中的PATH环境变量,后者引用的事Shell中的PATH环境变量。
如果是shell的 $$ (进程id) 如何输出它?
已经了解到:$$$$ ($$->$)
在makefile里面也可以这样调shell
如: CURRENT_DIR=$(shell pwd)
contents := $(shell cat foo)
files := $(shell echo *.c)
------------------
depends.mk deps:
@if [ 'x${V}' = 'x' ]; \
then \
echo " DEPENDS"; \
else \
echo $(CC) $(CPPFLAGS) -MM -MG $(wildcard *.c) $(wildcard *.cpp) \> depends.mk; \
fi
@$(CC) $(CPPFLAGS) -MM -MG $(wildcard *.c) $(wildcard *.cpp) > depends.mk
-include depends.mk
--------------
-include depends.mk有两个点:一是 - 表示如果没有depends.mk,也不报错
另一点是运行make的时候,强制执行depends.mk这个目标下的动作!!!!
--------------
-----强制目标-----
target:
因为没有命令,所以make target ,与makefile 所在目录下是否存在与target 同名的文件没有直接关系。
-----双冒号规则-----
target::
commands
无论makefile 所在目录下存不存在与target 同名文件,make target 导致commands 的执行,与使用'.PHONY' 定义的伪目标效果相同。
-----------------------------------------------------------------
http://blog.csdn.net/wzw88486969/article/details/11739737
如果一个规则没有命令或者依赖,而且它的目标不是一个存在的文件名,在执行此规则时,目标总会被认为是最新的。也就是说,这个规则一旦被执行,make 就认为它所表示的目标已经被更新过。当将这样的目标(FORCE)作为一个规则的依赖时(如上的 vmlinux: ),由于依赖总被认为是被更新过的,所以作为依赖所在的规则定义的命令总会被执行。
http://blog.chinaunix.net/uid-27057175-id-4432189.html
待看
?????
但是如下这句话不能运行
test:
@echo "hello:OBJ_DIR=${OBJ_DIR}"
或者如下也不行
---------------------
test:PORCE
@echo "hello:OBJ_DIR=${OBJ_DIR}"
PHONY+=FORCE
FORCE:
.PHONY: $(PHONY)
-------------------
但是案例可以成功的运行,见鬼?????!!!!!
LIBCAPI=${LIBCAPI_DIR}/libcapi.a
LIBARGCONFIG=${LIBARGCONFIG_DIR}/libargconfig.a
LIBCXL=${PSLSE_DIR}/libcxl.a
CXL_FLAGS_HACK=-I$(abspath ${PSLSE_DIR}) -DPAGED_RANDOMIZER=0 -g
${LIBCAPI}: FORCE
$(MAKE) -C ${LIBCAPI_DIR}
echo "shanon:FORCE successfully!"
===================2016/08/12
2.6 函数 (Functions) $()
makefile 里的函数跟它的变量很相似——使用的时候,你用一个 $ 符号跟开括号,函 数名,空格后跟一列由逗号分隔的参数,最后 用关括号结束。例如,在 GNU Make 里 有一个叫 'wildcard' 的函 数,它有一个参数,功能是展开成一列所有符合由其参数 描述的文 件名,文件间以空格间隔。你可以像下面所示使用这个命令:
SOURCES = $(wildcard *.c)
这行会产生一个所有以 '.c' 结尾的文件的列表,然后存入变量 SOURCES 里。当然你不需要一定要把结果存入一个变量。
另一个有用的函数是 patsubst ( patten substitude, 匹配替 换的缩写)函数。它 需要3个参数——第一个是一个需要匹配的 式样,第二个表示用什么来替换它,第三 个是一个需要被处理的 由空格分隔的字列。例如,处理那个经过上面定义后的变量,
OBJS = $(patsubst %.c,%.o,$(SOURCES))
这行将处理所有在 SOURCES 字列中的字(一列文件名),如果它的 结尾是 '.c' ,就 用 '.o' 把 '.c' 取代。注意这里的 % 符号将匹 配一个或多个字符,而它每次所匹配 的字串叫做一个‘柄’(stem) 。 在第二个参数里, % 被解读成用第一参数所匹配的 那个柄。
-------------
它使用变量 CC 做为编译器(象我们在前面的例子),
并且传递变量 CFLAGS (给 C 编译器,C++ 编译器用 CXXFLAGS ),
CPPFLAGS ( C 预 处理器旗 标),
TARGET_ARCH (现在不用考虑这个),然后它加 入旗标 '-c' ,后面跟变量 $< (第一个依靠名),然后是旗 标 '-o' 跟变量 $@ (目的文件名)。
depends.mk deps:
@if [ 'x${V}' = 'x' ]; \
then \
echo " DEPENDS"; \
else \
echo $(CC) $(CPPFLAGS) -MM -MG $(wildcard *.c) $(wildcard *.cpp) \> depends.mk; \
fi
$(CC) $(CPPFLAGS) -MM -MG $(wildcard *.c) $(wildcard *.cpp) > depends.mk
-include depends.mk
========================================
文件需要先编译,再链接
编译
cc -c
链接
cc -o
目标:依赖文件
动作
=========
摘抄:
需要注意的是,如果相关行写成一行,“命令”之前用分号“;”隔开,如果分成多行书写的话,后续的行务必以tab字符为先导。
对于makefile 而言,空格字符和tab字符是不同的。
所有规则所在的行必须以tab键开头,而不是空格键。初学者一定对此保持警惕,因为这是新手最容易疏忽的地方,因为 几个空格键跟一个tab键在肉眼是看不出区别的,但make命令却能明察秋毫,非常敏感。
此外,如果在makefile文件中的行尾加上空格键的话,也会导致make命令运行失败。。
@的作用
应该是取消回显
@$(CC) $(CPPFLAGS) -MM -MG $(wildcard *.c) $(wildcard *.cpp) > depends.mk
则这个命令不显示!但是会执行
ar产生静态库.a文件
libargconfig.a: $(patsubst %.c,%.o,$(wildcard *.c))
=======
在$(patsubst %.c,%.o,$(dir) )中,patsubst把$(dir)中的变量符合后缀是.c的全部替换成.o,
patsubst表示把dir中的.c文件转为.o文件
===========
减号, 横杠的作用
表示即使命令执行返回错误,仍然执行
命令出错
每当命令运行完后,make会检测每个命令的返回码,如果命令返回成功,那么make会执行下一条命令,当规则中所有的命令成功返回后,这个规则就 算是成功完成了。如果一个规则中的某个命令出错了(命令退出码非零),那么make就会终止执行当前规则,这将有可能终止所有规则的执行。
有些时候,命令的出错并不表示就是错误的。例如mkdir命令,我们一定需要建立一个目录,如果目录不存在,那么mkdir就成功执行,万 事大吉,如果目录存在,那么就出错了。我们之所以使用mkdir的意思就是一定要有这样的一个目录,于是我们就不希望mkdir出错而终止规则的运行。
为了做到这一点,忽略命令的出错,我们可以在Makefile的命令行前加一个减号“-”(在Tab键之后),标记为不管命令出不出错都认为是成功的。如:
clean:
-rm -f *.o
还有一个全局的办法是,给make加上“-i”或是“--ignore-errors”参数,那么,Makefile中所有命令都会忽略错误。而如 果一个规则是以“.IGNORE”作为目标的,那么这个规则中的所有命令将会忽略错误。这些是不同级别的防止命令出错的方法,你可以根据你的不同喜欢设 置。
===
多个目标,静态模式和自动依赖
静态模式可以更加容易地定义多目标的规则,可以让我们的规则变得更加的有弹性和灵活。我们还是先来看一下语法:
<targets...>: <target-pattern>: <prereq-patterns ...>
<commands>
...
targets定义了一系列的目标文件,可以有通配符。是目标的一个集合。
target-parrtern是指明了targets的模式,也就是的目标集模式。
prereq-parrterns是目标的依赖模式,它对target-parrtern形成的模式再进行一次依赖目标的定义。
这样描述这三个东西,可能还是没有说清楚,还是举个例子来 说明一下吧。如果我们的<target-parrtern>定义成“%.o”,意思是我们的集合中都是以“.o”结尾的,而如果我们 的<prereq-parrterns>定义成“%.c”,意思是对<target-parrtern>所形成的目标集进行二次 定义,其计算方法是,取<target-parrtern>模式中的“%”(也就是去掉了[.o]这个结尾),并为其加上[.c]这个结尾, 形成的新集合。
所以,我们的“目标模式”或是“依赖模式”中都应该有“%”这个字符,如果你的文件名中有“%”那么你可以使用反斜杠“\”进行转义,来标明真实的“%”字符。
看一个例子:
objects = foo.o bar.o
all: $(objects)
$(objects): %.o: %.c
$(CC) -c $(CFLAGS) $< -o $@
上面的例子中,指明了我们的目标从$object中获 取,“%.o”表明要所有以“.o”结尾的目标,也就是“foo.o bar.o”,也就是变量$object集合的模式,而依赖模式“%.c”则取模式“%.o”的“%”,也就是“foobar”,并为其加下“.c”的后 缀,于是,我们的依赖目标就是“foo.cbar.c”。而命令中的“$<”和“$@”则是自动化变量,“$<”表示所有的依赖目标集(也就 是“foo.c bar.c”),“$@”表示目标集(也褪恰癴oo.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”的内容。其的它内容,我就不用多说了吧。这个例字展示了Makefile中更大的弹性。
3.8 自动生成依赖性
在Makefile中,我们的依赖关系可能会需要包含一系列的头文件,比如,如果我们的main.c中有一句“#include "defs.h"”,那么我们的依赖关系应该是:
main.o : main.c defs.h
但是,如果是一个比较大型的工程,你必需清楚哪些C文件包 含了哪些头文件,并且,你在加入或删除头文件时,也需要小心地修改Makefile,这是一个很没有维护性的工作。为了避免这种繁重而又容易出错的事情, 我们可以使用C/C++编译的一个功能。大多数的C/C++编译器都支持一个“-M”的选项,即自动找寻源文件中包含的头文件,并生成一个依赖关系。例 如,如果我们执行下面的命令:
cc -M main.c
其输出是:
main.o : main.c defs.h
于是由编译器自动生成的依赖关系,这样一来,你就不必再手动书写若干文件的依赖关系,而由编译器自动生成了。需要提醒一句的是,如果你使用GNU的C/C++编译器,你得用“-MM”参数,不然,“-M”参数会把一些标准库的头文件也包含进来。
gcc-M main.c的输出是:
main.o: main.c defs.h /usr/include/stdio.h /usr/include/features.h \
/usr/include/sys/cdefs.h /usr/include/gnu/stubs.h \
/usr/lib/gcc-lib/i486-suse-linux/2.95.3/include/stddef.h \
/usr/include/bits/types.h /usr/include/bits/pthreadtypes.h \
/usr/include/bits/sched.h /usr/include/libio.h \
/usr/include/_G_config.h /usr/include/wchar.h \
/usr/include/bits/wchar.h /usr/include/gconv.h \
/usr/lib/gcc-lib/i486-suse-linux/2.95.3/include/stdarg.h \
/usr/include/bits/stdio_lim.h
gcc-MM main.c的输出则是:
main.o: main.c defs.h
举例:
[shannon@CentOS7-64 src]$ gcc -MM textswap.c
textswap.o: textswap.c textswap.h readthrd.h writethrd.h version.h
makefile学习小结的更多相关文章
- flex学习小结
接触到flex一个多月了,今天做一个学习小结.如果有知识错误或者意见不同的地方.欢迎交流指教. 画外音:先说一下,我是怎么接触到flex布局的.对于正在学习的童鞋们,我建议大家没事可以逛逛网站,看看人 ...
- Python 学习小结
python 学习小结 python 简明教程 1.python 文件 #!/etc/bin/python #coding=utf-8 2.main()函数 if __name__ == '__mai ...
- [转]Windows平台下Makefile学习笔记
Windows平台下Makefile学习笔记(一) 作者:朱金灿 来源:http://blog.csdn.net/clever101 决心学习Makefile,一方面是为了解决编译开源代码时需要跨编译 ...
- react学习小结(生命周期- 实例化时期 - 存在期- 销毁时期)
react学习小结 本文是我学习react的阶段性小结,如果看官你是react资深玩家,那么还请就此打住移步他处,如果你想给一些建议和指导,那么还请轻拍~ 目前团队内对react的使用非常普遍,之 ...
- objective-c基础教程——学习小结
objective-c基础教程——学习小结 提纲: 简介 与C语言相比要注意的地方 objective-c高级特性 开发工具介绍(cocoa 工具包的功能,框架,源文件组织:XCode使用介绍) ...
- pthread多线程编程的学习小结
pthread多线程编程的学习小结 pthread 同步3种方法: 1 mutex 2 条件变量 3 读写锁:支持多个线程同时读,或者一个线程写 程序员必上的开发者服务平台 —— DevSt ...
- ExtJs学习笔记之学习小结LoginDemo
ExtJs学习小结LoginDemo 1.示例:(登录界面) <!DOCTYPE html> <html> <head> <meta charset=&quo ...
- 点滴的积累---J2SE学习小结
点滴的积累---J2SE学习小结 什么是J2SE J2SE就是Java2的标准版,主要用于桌面应用软件的编程:包括那些构成Java语言核心的类.比方:数据库连接.接口定义.输入/输出.网络编程. 学习 ...
- (转) Parameter estimation for text analysis 暨LDA学习小结
Reading Note : Parameter estimation for text analysis 暨LDA学习小结 原文:http://www.xperseverance.net/blogs ...
随机推荐
- pymongo 3.3 使用笔记
#首先安装pymongo sudo pip install pymongo || sudo easy_install pymongo #demo均在交互解释器下进行 from pymongo impo ...
- c语言求平面上2个坐标点的直线距离、求俩坐标直线距离作为半径的圆的面积、递归、菲波那次数列、explode
#include <stdio.h> #include <math.h> #include <string.h> char explode( char * str ...
- Android 中pid与uid的作用与区别
PID:为Process Identifier, PID就是各进程的身份标识. 程序一运行系统就会自动分配给进程一个独一无二的PID.进程中止后PID被系统回收,可能会被继续分配给新运行的程序,但是在 ...
- F - To the Max
Given a two-dimensional array of positive and negative integers, a sub-rectangle is any contiguous s ...
- for循环相关
循环语句是指令式编程的常见语句,Scala对其加以改进,成为适应函数式风格的利器. for循环中的变量,没有val或者var,是因为变量的类型,完全是集合中的元素的类型.作用域持续到括号结束. 在sc ...
- python windows终端窗口下输出编码错误
windows简体中文版下终端默认字符集gbk,执行chcp 65001临时修改字符集. 修改默认字符集:注册表HKEY_CURRENT_USER\Console项中CodePage值修改为65001
- Linux分区介绍
分区的大小主要取决于个人的选择,以下内容可能会有一定帮助:/boot - 200 MB 实际需求大约 100 MB,如果有多个内核/启动镜像同时存在,建议分配 200 或者 300 MB./ - 15 ...
- Android学习七:new Date使用
1.例子 学习时间函数,并实现了简单的多个按钮监听同一个事件的方法 2.代码 代码很简单,也很清晰 package com.example.datetime; import java.text.Sim ...
- c#定义全局条件编译符号
在"工程"上单机右键,"属性"--->"生成"--->"条件编译符号"后边的输入框中,输入自定义的条件编译变 ...
- C# 深拷贝通用方法
C#深拷贝通用方法(引用类型的拷贝) /// <summary> /// 深度COPY /// </summary> /// <typeparam name=" ...