EMACS & 程序 编程点滴...

天下难事必作于易,天下大事必作于细

Lastupdated: 2010-01-02

MakeFile经验

TOP符号说明

符号 说明
$* 工作目标的主文件名
$@ 工作目标的名称
$? 时间戳在工作目标之后的所有必要文件
$% 档案文件成员结构中的文件名元素
$< 第一个必要条件
$^ 所有必要条件
$+ 同$^, 不过包含所有重复的条件(解决链接依存的问题)

TOP文件关联

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
32
33
# 利用以下的缩写关联各类文件
c.s:
        $(CC) $(CFLAGS) -S -o $*.s $<
s.o:
        $(AS) -c -o $*.o $<
c.o:
        $(CC) $(CFLAGS) -c -o $*.o $<

# SOURCE (将目录下所有的.c文件作为对象文件)
SRCS = $(shell ls *.c)
OBJS = $(notdir $(SRCS:.c=.o))

# 生成目标对象
TARGET  = xxx.o

.PHONY: all
all: $(TARGET)

$(TARGET): .depend $(OBJS)
    $(LD) $(LFLAGS) -o $@ $(OBJS)

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


###########################################

## 没有规则的依赖关系
$(OBJS): Makefile xxx.h
## Makefile更新时,需重新编译目标文件
## 头文件更新时,需重新编译目标文件
## 源代码间的依赖关系(包括头文件),用 gcc -M 或 mkdep 生成


TOP函数大全1

TOP字符串函数

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
# 返回字符串链表中条件相符的值
$(filter pattern ...,text)
# eg. $(filter %.c, $(all_source))

# 返回字符串链表中条件不相符的值
$(filter-out pattern ...,text)
# eg. $(filter-out %.h, $(all_source))

# 搜索字符串
$(findstring string...,text)
#eg. $(findstring /root/work/emma2th, $(PWD))

# 搜索和替换
$(subst search-string,replace-string,text)
# objects = $(subst .c,.o, $(sources))

# 具通配符能力的搜索与替换
$(patsubst search-pattern,replace-pattern,text)
#eg. $(patsubst %/,%, $(directory-path))

# 统计单词的数量
$(words text)

# 返回第n个单词
$(words n,text)

# 返回第一个单词
$(firstword text)

# 返回指定范围内的单词
$(wordlist start,end,text)

TOP杂项函数

1
2
3
4
5
6
7
8
9
10
11
# 排序并移除重复的项目
$(sort list)

# 运行shell
$(shell command)
# eg. 创建一组目录
#REQUIRED_DIRS = ...
#_MKDIRS := $(shell for d in $(REQUIRED_DIRS); \
#             do                               \
#               [[ -d $$d ]] || mkdir -p $$d;  \
#             done)

TOP文件名函数

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
# 匹配指定文件
$(wildcard pattern ...)
# eg. sources := $(wildcard *.c *.h)    所有源文件
#      dot-emacs-exists := $(wildcard ~/.emacs)  该文件有无?

# 返回每个单词的目录部分
$(dir list . . . )

# 返回文件路径的文件名部分
$(notdir name . . . )

# 返回单词的后缀
$(suffix name . . . )

# 返回文件名部分,不含后缀
$(basename name . . . )

# 添加后缀
$(addsuffix suffix,name . . . )

# 添加前缀
$(addprefix prefix,name . . . )

# 衔接前缀与后缀(链表中各元素对应)
$(join prefix-list,suffix-list)

# 移除前导和接在后面的空格
$(strip text)

TOP流程控制函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
$(if condition,then-part,else-part)
# eg. PATH_SEP := $(if $(COMSPEC),;,:)

# 输出错误信息, 程序退出
$(error text)

# 输出警告,程序不退出
$(warning text)

# 循环控制
$(foreach variable,list,body)
# eg. 测试一组变量是否定义过
#VARIABLE_LIST := SOURCES OBJECTS HOME
#$(foreach i,$(VARIABLE_LIST), \
#  $(if $($i),,                \
#    $(shell echo $i has no value > /dev/stderr)))

# 查找变量来自何处
$(origin variable)
# 环境变量,makefile,命令行等等

TOP自定义函数

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
# $(call has-duplicates, word-list) 是否包含重复内容
has-duplicates = $(filter               \
                   $(words $1)          \
                   $(words $(sort $1))))

# $(call source-dirs, dir-list)  搜索源文件的路径
source-dirs = $(sort                             \
                $(dir                            \
                  $(shell find $1 -name '*.c'))))

# $(call get-java-class-name, file-name) 返回java类名
get-java-class-name = $(notdir $(subst .java,,$1))

# $(call same-suffix, file-list)  所有单词是否有相同后缀
same-suffix = $(filter 1 $(words $(sort $(suffix $1))))

# $(call find-program,wildcard-pattern) 查找可执行程序
find-program = $(wildcard                       \
                 $(addsuffix /$1,               \
                   $(sort                       \
                     $(subst :, ,               \
                       $(subst ::,:.:,          \
                         $(patsubst :%,.:%,     \
                           $(patsubst %:,%:.,$(PATH))))))))
find:
        @echo $(words $(call find-program,*))

# $(call assert,condition,message) 普通assert
define assert
  $(if $1,,$(error Assertion failed: $2))
endef

# $(call assert-file-exists,wildcard-pattern) 文件是否存在
define assert-file-exists
  $(call assert,$(wildcard $1),$1 does not exist)
endef

# $(call assert-not-null,make-variable) 检查make变量是否为空
define assert-not-null
  $(call assert,$($1),The variable "$1" is null)
endef

# $(call assert-defined,variable-name) 检查变量是否未定义
define assert-defined
  $(call assert,                          \
    $(filter-out undefined,$(origin $1)), \
    '$1' is undefined)
endef


# $(call grep-string, search-string, word-list) 单词中搜索子字符串
define grep-string
$(strip                                         \
  $(foreach w, $2,                               \
    $(if $(findstring $1, $w),                   \
      $w)))
endef
words := count_words.c counter.c lexer.l lexer.h counter.h
find-words:
        @echo $(call grep-string,un,$(words))

# $(call make-dir, directory)  创建目录
make-dir = $(if $(wildcard $1),,$(MKDIR) -p $1)

$(config): $(config_template)
        $(call make-dir, $(dir $@))
        $(M4) $^ > $@

# $(call collect-names, root-dir, dir-list, suffix1-opt, suffix2-opt) 建立文件列表
define collect-names
  echo Making $@ from directory list...
  cd $1;                                                    \
  shopt -s nullglob;                                        \
  for f in $(foreach file,$2,'$(file)'); do                 \
    files=( $$f$(if $3,/*.{$3$(if $4,$(comma)$4)}) );       \
    if (( $${#files[@]} > 0 ));                             \
    then                                                    \
      printf '"%s"\n' $${files[@]};                         \
    else :; fi;                                             \
  done
endef
#eg. 创建图像文件列表
#%.images:
#       @$(call collect-names,$(SOURCE_DIR),$^,gif,jpeg) > $@

# $(call program-variables,variable-prefix,file-list) 利用eval解析程序变量--版本1
define program-variables
  $(eval $1_sources = $(filter %.c,$2))
  $(eval $1_headers = $(filter %.h,$2))
  $(eval $1_objects = $(subst .c,.o,$(filter %.c,$2)))
  $($1_objects): $($1_headers)
endef
ls: $(ls_objects)
$(eval $(call program-variables,ls,ls.c ls.h glob.c glob.h))

#$(call program-variables,variable-prefix,file-list) 利用eval解析程序变量--版本2
define program-variables
  $(eval $1_sources = $(filter %.c,$2))
  $(eval $1_headers = $(filter %.h,$2))
  $(eval $1_objects = $(subst .c,.o,$(filter %.c,$2)))
  programs += $1
  $1: $($1_objects)
  $($1_objects): $($1_headers)
endef

# Place all target here, so it is the default goal.
all:
$(eval $(call program-variables,ls,ls.c ls.h glob.c glob.h))
$(eval $(call program-variables,cp,...))
$(eval $(call program-variables,mv,...))
$(eval $(call program-variables,ln,...))
$(eval $(call program-variables,rm,...))

# Place the programs prerequisite here where it is defined.
all: $(programs)

# $(call source-to-object, source-file-list)
source-to-object = $(subst .c,.o,$(filter %.c,$1)) \
                   $(subst .y,.o,$(filter %.y,$1)) \
                   $(subst .l,.o,$(filter %.l,$1))

# $(call make-library, library-name, source-file-list)
define make-library
  libraries += $1
  sources   += $2
  $1: $(call source-to-object,$2)
        $(AR) $(ARFLAGS) $$@ $$^
endef
#eg.
# local_src := $(wildcard $(subdirectory)/*.c)
# $(eval $(call make-library, $(subdirectory)/libcodec.a, $(local_src)))

# $(call make-depend,source-file,object-file,depend-file)  产生依存文件
define make-depend
  $(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -M $1 | \
  $(SED) 's,\($$(notdir $2)\) *:,$$(dir $2) $3: ,' > $3.tmp
  $(MV) $3.tmp $3
endef

%.o: %.c
        $(call make-depend,$<,$@,$(subst .o,.d,$@))
        $(COMPILE.c) -o $@ $<

# $(call get-file, variable-name)
define get-file
  $(strip                                       \
    $($1)                   \
    $(if $(call file-exists-eval,$1),,          \
      $(warning The file referenced by variable \
                '$1' ($($1)) cannot be found)))
endef

# $(call file-exists-eval, variable-name)
define file-exists-eval
  $(strip                                       \
    $(if $($1),,$(warning '$1' has no value))   \
    $(wildcard $($1)))

# $(call file-exists, wildcard-pattern)
file-exists = $(wildcard $1)

# $(call check-file, file-list)
define check-file
  $(foreach f, $1,              \
    $(if $(call file-exists, $($f)),,       \
      $(warning $f ($($f)) is missing)))
endef

1. 参考《GNU Make项目管理》,《GNU make中文手册》

© www.yifeiyang.net
net tracking

                                                                                                 stats