make命令和Makefile
最常用的三个参数:
-k :作用是让make命令在发现错误是仍然执行。可以利用这一选项在一次操作中发现所有未编译成功的源文件
-n :让make命令输出将要执行的操作步骤,而不是真正执行这些操作。
-f <filename> :告诉make命令将哪个文件作为makefile文件。
1.1依赖关系
依赖关系定义了最终应用程序的每个文件与源文件之间的关系。 例如有3个源文件和3个头文件,如下:
/* main.c */
#include <stdlib.h>
#include "a.h"
extern void function_two();
extern void function_three();
int main()
{
function_two();
function_three();
exit (EXIT_SUCCESS);
}
/* 2.c */
#include "a.h"
#include "b.h"
void function_two() {
}
/* 3.c */
#include "b.h"
#include "c.h"
void function_three() {
}
最终的应用程序依赖于文件main.o、2.o、3.o
在makefile中这些规则的写法是:先写目标名称,然后紧跟着一个冒号,接着是空格或制表符tab,最后是文件列表。如下:
myapp; main.o 2.o 3.o
main.o: main.c a.h
2.o: 2.c a.h b.h
3.o: 3.c b.h c.h
如果想一次创建多个文件,可以利用伪目标all。假设应用程序有二进制文件myapp和使用手册myapp.1组成。可以使用如下定义:
all: myapp myapp.1
强调:如果未指定一个all目标,则make命令只创建在文件Makefile中的第一个目标。
1.2规则
Makefile文件第二部分内容是规则,他们定义了目标的创建方式。(注意,规则所在的行必须以tab开头)
例子:一个简单的Makefile文件
文件名Makefile1,内容如下:
myapp: main.o 2.o 3.o
gcc -o myapp main.o 2.o 3.o
main.o: main.c a.h
gcc -c main.c (注意千万别写成了gcc -o main.o main.c a.h)
2.o: 2.c a.h b.h
gcc -c 2.c
3.o: 3.c b.h c.h
gcc -c 3.c
执行命令:
$ make -f Makefile1
gcc -o myapp main.o 2.o 3.o
例子解析:
由于在我的当前目录下存在2.o 和 3.o、main.o文件所以输出中没有 “gcc -c main.c gcc -c 2.c gcc -c 3.c”。下面看看我们将2.o删除会发生什么情况:
$ make -f Makefile1
gcc -c 2.c
gcc -o myapp main.o 2.o 3.o
1.3注释以#开头
1.4Makefile文件中的宏
通过语句MACRONAME=value定义宏,$(MACRONAME)来引用。如果想把一个宏的值设置为空,在=后面留空。
例子:带宏定义的makefile文件Makefile2:
all: myapp
#which compiler
CC = gcc
#where are include files kept
INCLUDE=
#Options for development
CFLAGS= -g -Wall -ansi
#Options for release
#CFLAGS= -O -Wall -ansi
myapp: main.o 2.o 3.o
$(CC) -o myapp main.o 2.o 3.o(注意!!!不是$(CC) -I$(INCLUDE) $(CFLAGS) main.o 2.o 3.o)
main.o: main.c a.h
$(CC) -I$(INCLUDE) $(CFLAGS) -c main.c
2.o: 2.c a.h b.h
$(CC) -I$(INCLUDE) $(CFLAGS) -c 2.c
3.o: 3.c b.h c.h
$(CC) -I$(INCLUDE) $(CFLAGS) -c 3.c
执行命令:
$ rm *.o myapp
$ make -f Makefile2
gcc -I. -g -Wall -ansi -c main.c
gcc -I. -g -Wall -ansi -c 2.c
gcc -I. -g -Wall -ansi -c 3.c
gcc -o myapp main.o 2.o 3.o
例子解析:将几个常用的宏列出:这几个宏在使用前才展开。
宏 | 定义 |
$? | 当前目标所依赖的文件列表中比当前目标文件还要新的内容 |
$@ | 当前目标的名字 |
$< | 当前依赖文件的名字 |
$* | 不包括后缀名的当前依赖文件的名字 |
1.5多个目标
all: myapp
#which compiler
CC = gcc
#where to install
INSTDIR=/usr/local/bin
#where are include files kept
INCLUDE=
#Options for development
CFLAGS= -g -Wall -ansi
#Options for release
#CFLAGS= -O -Wall -ansi
myapp: main.o 2.o 3.o
$(CC) -o myapp main.o 2.o 3.o(注意!!!不是$(CC) -I$(INCLUDE) $(CFLAGS) main.o 2.o 3.o)
main.o: main.c a.h
$(CC) -I$(INCLUDE) $(CFLAGS) -c main.c
2.o: 2.c a.h b.h
$(CC) -I$(INCLUDE) $(CFLAGS) -c 2.c
3.o: 3.c b.h c.h
$(CC) -I$(INCLUDE) $(CFLAGS) -c 3.c
clean:$ make -f Makefile3
gcc -I. -g -Wall -ansi -c main.c
gcc -I. -g -Wall -ansi -c 2.c
gcc -I. -g -Wall -ansi -c 3.c
gcc -o myapp main.o 2.o 3.o
gcc -o myapp main.o 2.o 3.o
cp: `myapp' and `./myapp' are the same file
$ make -f Makefile3 clean
rm main.o 2.o 3.o
1.6内置规则
#include <stdlib.h>
#include <stdio.h>
int main()
{
printf("Hello World\n");
exit (EXIT_SUCCESS);
}
用make命令来编译它:
gcc -g -Wall -ansi foo.c -o foo
yuccess@ubuntu:~/LinuxPrograms/tar/ch09$ make CC=gcc CFLAGS="-Wall -g" foo
gcc -Wall -g foo.c -o foo
all: myapp
# Which compiler
CC=gcc
# Where to install
INSTDIR=/usr/local/bin
# Where are include files kept
INCLUDE=.
# Options for development
CFLAGS=-g -Wall -ansi
# Options for release
# CFLAGS=-O -Wall -ansi
# Local Libraries
MYLIB=mylib.a
myapp: main.o $(MYLIB)
$(CC) -o myapp main.o $(MYLIB)
$(MYLIB): $(MYLIB)(2.o) $(MYLIB)(3.o)
main.o: main.c a.h
2.o: 2.c a.h b.h
3.o: 3.c b.h c.h
clean:
-rm main.o 2.o 3.o $(MYLIB)
install: myapp
@if [ -d $(INSTDIR) ]; \
then \
cp myapp $(INSTDIR);\
chmod a+x $(INSTDIR)/myapp;\
chmod og-w $(INSTDIR)/myapp;\
echo "Installed in $(INSTDIR)";\
else \
echo "Sorry, $(INSTDIR) does not exist";\
fi
执行命令:
$ make -f Makefile4
ar rv mylib.a 2.o
r - 2.o
ar rv mylib.a 3.o
r - 3.o
gcc -o myapp main.o mylib.a
MYLIB=mylib.a
myapp: main.o $(MYLIB)
$(CC) -o myapp main.o $(MYLIB)
$(MYLIB): $(MYLIB)(2.o) $(MYLIB)(3.o)
上面最后一行的默认行为是:
r - 2.o
ar rv mylib.a 3.o
r - 3.o
1.7 后缀和模式规则
1.8用make管理函数库
lib(file.o)
1.9 makefile文件和子目录
2 使用过程的小技巧
编译所有.c文件为可执行文件
CFLAGS = -g -Wall -Werror
LDFLAGS = -lpthread
src = $(wildcard *.c)
target = $(patsubst %.c, %, ${src})
.PHONY: all clean
%:%.c
$(CC) ${CFLAGS} ${LDFLAGS} $^ -o $@
all: ${target}
clean:
rm -f ${target}
参考: http://blog.csdn.net/bytxl/article/details/38614857