make file 语法
targets(目标):prerequisites(先决条件)
<tab>
command(命令)
变量
自动变量
foo.o:new1.c new2.c new3.c old1.c new3.c
$^: 代表所有的依赖文件,去重 new1.c new2.c new3.c old1.c
$+: 不去重 new1.c new2.c new3.c old1.c new3.c
$@: 代表目标 foo.o
$<: 代表第一个依赖文件 new1.c
$*: 不包括后缀名的依赖文件名 new1 old1 /tom/test <- a.%b %.c:new1.c old1.c /tom/test.c
$?: 比目标新的集合 new1.c new2.c new3.c
$%: 如果目标是链接库的一个成员,产生成员名称。
预定义变量
$(CC) c语言编译程度,默认值cc
$(CPP) c语言预先处理程序,默认值cpp
$(CFLAGS) 传给c语言编译程序的参数,没有默认值
$(LDFLAGS) 是用来制定动态Library调用的参数集
赋值运算
= 递归展开定义 OBJ = $(OBJ) tom.o 这里会无限递归
:= 简单展开定义 SRC := $(wildcard *c)
+= 附加 OBJ = $(OBJ) tom.o OBJ += ton.o
?= 条件赋值,只能定义递归展开变量,且变量未定义
宏
MYLIB = T
TOM = "test"
test:
define installt
@echo "Installing $@ in $(TOM) ..." \ ;
@echo "... done."
endef
install:test
ifdef MYLIB
$(installt)
endif
[tom@suse-tom c]$make install #碰巧目录刚好有test代码
g++ test.cpp -o test
Installing install in test ...
... done.
可以输出空格示例
NOTHING :=
ONESPACE := $(NOTHING)
str = "---hello"
str1 = "word---"
foo = who; echo $$(date) $(str) $(str1)
all:
@$(foo)
测试输出
[tom@tom-virtual-machine ~]$make
tom pts/4 2021-04-25 15:35 (192.168.3.110)
2021年 04月 25日 星期日 18:41:32 CST ---hello word---
make是依据“关系图深度优先搜索”的算法来核查目标文件及相依文件的修改时间,所以再次make时会沿着树向下检查改动文件及相关依赖。适当地引入中间结果,合理构造依赖关系图,可以节省部分编译时间。
命令前加@取消回显
命名成Makefile
或者makefile
均可,推荐使用Makefile,会与REASME等文件相近
makefile的命令行,开头必须用tab键,否则出错 Makefile missing separator. Stop.
make选项
- -k 有错误时仍执行
- -n 输出需要执行的操作,不执行
- -f <filemake> 指定make文件
- -p -f/dev/null 查看内部自动规则
[tom@suse-tom c]$make -n
gcc -c -I . main.c
gcc -c -I . csapp.c
ar -r mylib.a csapp.o
gcc -o out main.o mylib.a -lpthread
ar cru liba.a a.o #创建静态库
ar rv liba.a c.o #插入静态库
如果未指定all目标,则只创建其在makefile中找到的第一个目标
CC = gcc
CFLAGS = -Wall -g -std=c99
OBJECTS = main.o csapp.o
LIBES = .
INSTDIR = .
MYLIB = mylib.a
AR = ar -r
all:out
out:$(OBJECTS) $(MYLIB)
$(CC) $(CFLAGS) -o $@ main.o $(MYLIB) -lpthread
$(MYLIB)(csapp.o):csapp.o
$(AR) $@ $<
#$(MYLIB)(csapp.o):csapp.o
# $(AR) $@ $%
#$(MYLIB): $(MYLIB)(csapp.o)
.c.o:
$(CC) -c -I $(LIBES) $<
.PHONY:clean
clean:
-rm -f *.o $(MYLIB) test
install:out
if [ -d $(INSTDIR) ] ; \
then \
cp out $(INSTDIR)/test;\
chmod a+x $(INSTDIR)/test;\
chmod og-w $(INSTDIR)/test; \
echo "Installed in $(INSTDIR) ";\
else \
echo "Sorry, $(INSTDIR)does not exist";\
fi
伪目标
.phony为默认目标不是最新的,即使是最新的
.PHONY:clean
clean:
-rm -f *.o $(MYLIB) test
下面测试伪目标
[tom@suse-tom c]$touch clean #先添加clean,.phony为默认clean不是最新的,
[tom@suse-tom c]$make clean
make: 'clean' is up to date.
[tom@suse-tom c]$vim Makefile
[tom@suse-tom c]$make clean
rm -f *.o mylib.a test
例子
- 版本1,生成main可执行文件
main:main.o csapp.o
gcc -o main main.o csapp.o -lpthread
csapp.o:csapp.c
gcc -c -l ./csapp.h csapp.c
main.o:main.c
gcc -c -l ./csapp.h main.c
clean:
rm -f *.o
- 版本2
OBJECTS=main.o csapp.o
LIBES=-l ./csapp.h
main:$(OBJECTS)
@$(CC) -o $@ $^ -lpthread
.c.o:
$(CC) -c -I $(LIBES) $<
clean:
rm -f *.o
- 版本3,在当前目录下。这里用了make编译的隐式规则,会自动推导main.o,csapp.o,为其进行
-c
编译
main:main.o csapp.o
gcc -o main main.o csapp.o -lpthread
clean:
rm -f *.o
后缀与规则
.c.s:
@$(CC) $(CFLAGS) -nostdinc -Iinclude -S -o $*.s $<
$<
表示第一行的.c
文件,此处即把.c
编译成.s
makefile 子目录编译
- 在子目录中另写一个makefile
out:
(cd tdirectory;$(MAKE))
- 编译子目录的源文件并将目标文件置于该子目录中。
.c.o:
$(CC) $(CFLAGS) -c $(@D)/$(<F) -o $(@D)/$(@F)
#$(<F) 第一个依赖文件的文件名
参考https://www.gnu.org/software/make/manual/html_node/Automatic-Variables.html
make 编译输出彩色
代码出处https://codechina.csdn.net/mirrors/chinaran/color-compile/-/tree/master
CMakeList.txt写法
cmake_minimum_required(VERSION 3.17)
project(c___list)
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_BUILD_TYPE Debug)
set(Srcs
lmain.c
LinkList.c
)
set(Hdrs
LinkList.h
)
add_executable(${PROJECT_NAME} ${Srcs} ${Hdrs})