makefile教程

来源:互联网 发布:妙味云课堂js视频下载 编辑:程序博客网 时间:2024/04/25 04:06

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多个目标

通常制作不知一个目标文件或者将多组命令集中到一个位置来执行是很用用的。可以通过拓展Makefile文件来达到这一目的
例子:多个目标
文件Makefile3:

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命令忽略所有错误
-rm main.o 2.o 3.o
install: myapp
# @:告诉make在执行某条命令钱不要将该命令显示在标准输出上。
@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 exsit"; \
    fi

执行命令:
$ rm *.o myapp
$ 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
$ make -f Makefile3
make: Nothing to be done for `all'.
$ make -f Makefile3 install 
gcc -o myapp main.o 2.o 3.o
cp: `myapp' and `./myapp' are the same file
Installed in .
$ make -f Makefile3 clean
rm main.o 2.o 3.o


例子解析:
1,特殊目标all只指定了myapp这一个目标。因此,如果在执行make命令时未指定目标,它的默认目标就是创建目标myapp。
---两个新增的目标:
2,目标clean用rm删除目标文件。减号含义是让make命令忽略rm命令的执行结果,这意味着,即使由于目标文件不存在而导致rm命令返回错误,命令make clean也会执行成功
3,用于制作目标clean的贵子并未给目标clean定义任何依赖关系行clean:后面是空的,因此该目标总被认为是过时的,所以在执行make clean是,该目标对应的规则总会被执行。
4,目标install依赖于myapp,所以make命令知道它必须首先创建myapp。
5,反斜杠\表示shell脚本命令在逻辑上处于同一行,分号表示分隔开同一行的命令
6,@表示make在执行执行这些规则之前不会在标准输出上显示命令本身。
7,目标install感顺序执行多个命令将应用程序安装到其最终位置。可以将这些命令用符号&&连接起来,它会在执行下一个命令前检查上个命令是否执行成功。

1.6内置规则

make命令本身带有大量的内置规则,可以极大的简化Makefile的内容。
创建文件foo。
#include <stdlib.h>#include <stdio.h>int main(){    printf("Hello World\n");    exit (EXIT_SUCCESS);}
用make命令来编译它:
yuccess@ubuntu:~/LinuxPrograms/tar/ch09$ make foo
gcc -g -Wall -ansi    foo.c   -o foo
上述默认行为可以通过给宏赋予新值来改变:
yuccess@ubuntu:~/LinuxPrograms/tar/ch09$ rm foo
yuccess@ubuntu:~/LinuxPrograms/tar/ch09$ make CC=gcc CFLAGS="-Wall -g" foo
gcc -Wall -g    foo.c   -o foo
有了这些内置规则,可简化Makefile3:
all: myapp# Which compilerCC=gcc# Where to installINSTDIR=/usr/local/bin# Where are include files keptINCLUDE=.# Options for developmentCFLAGS=-g -Wall -ansi# Options for release# CFLAGS=-O -Wall -ansi# Local LibrariesMYLIB=mylib.amyapp: main.o $(MYLIB)$(CC) -o myapp main.o $(MYLIB)$(MYLIB): $(MYLIB)(2.o) $(MYLIB)(3.o)main.o: main.c a.h2.o: 2.c a.h b.h3.o: 3.c b.h c.hclean:-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

执行命令:
$ rm foo
$ 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

我们看Makefile4文件中的下面两行:
MYLIB=mylib.amyapp: main.o $(MYLIB)$(CC) -o myapp main.o $(MYLIB)$(MYLIB): $(MYLIB)(2.o) $(MYLIB)(3.o)

上面最后一行的默认行为是:
ar rv mylib.a 2.o
r - 2.o
ar rv mylib.a 3.o
r - 3.o
经此,我们也学习到了创建函数库的方法。

1.7 后缀和模式规则

特殊语法:
.<old_suffix>.<new_suffix>
例:
.SUFFIX: .cpp
.cpp.o
$(CC) -xc++ $(CFLAGS) -I(INCLUDE) -c $<
或使用通配符语法:
%.cpp: %o
$(CC) -xc++ $(CFLAGS) -I(INCLUDE) -c $<

1.8用make管理函数库

库是预先编译好的函数的集合,在该库文件中包含了一组目标文件。
用于管理函数库的语法是:
lib(file.o)
含义是目标文件是存储在函数库lib.a中的。make命令用一个内置规则来管理函数库:
.c.a:
$(cc) -c $(FLAGS) $<
$(AR) $(ARFLAGS) $@ $*.o

1.9 makefile文件和子目录

见《linux程序设计》P329

2 使用过程的小技巧

可以先敲ctrl-v组合键,再敲tab键,这样就不会被转换成空格了

编译所有.c文件为可执行文件

CFLAGS = -g -Wall -WerrorLDFLAGS = -lpthreadsrc = $(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





1 0
原创粉丝点击