Make命令

使用Make命令只会在必要时重新编译所有受改动影响的源文件。而不会因为只改动了一个文件而重新编译整个项目。

Make命令不仅仅用于编译程序,无论何时,当需要通过多个输入文件来生成输出文件时,你都可以利用它来完成任务,它的其他用法还包括文档处理。

make命令选项和参数:

  • -k 让make命令在发现错误时仍然继续执行下去,而不是在检测到第一个错误时就停止。
  • -n 让make命令输出将要执行的操作步骤,而不真正执行这些操作。
  • -f 告诉make命令将哪一个文件作为makefile文件。若没有使用这个参树,则make命令将在当前目录下查找名makefile的文件,如果makefile文件不存在,则查找Makefile文件。

Makefile文件

Make命令本身是无法了解应该如何建立应用程序的,所以我们必须为其提供一个文件,告诉它应用程序应该如何构造,这个文件就是Makefile文件。

makefile文件一般都会和项目的其他源文件放在同一个目录下,同一台机器上可以同时存在许多不同的makefile文件。事实上,如果管理的是一个大项目,可以用多个不同的makefile文件来分别管理项目的不同部分。

依赖关系

写法:先写目标规则的名称,然后紧跟着一个冒号,接着是空格或者制表符tab,最后是用空格或制表符tab隔开的文件列表。示例:

myapp: main.o 2.o 3.o
main.o: mian.c a.h
2.o: 2.c a.h b.h
3.o: 3.c b.h c.h

解释:上述makefile中表示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来一次创建多个目标。如果没有指定all目标,则make命令将只创建它在文件makefile中找到的第一个目标。

all: myapp1 myapp2 myapp3

创建规则

makefile文件的第二部分内容是规则,它们定义了目标的创建方式。示例:

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
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命令处理makefile文件中定义的依赖关系,确定需要创建的文件以及创建顺序。虽然把如何创建目标myapp列在最前面,但make命令能够自行判断出创建文件的正确顺序。

宏定义

在makefile中可以通过语句MACRONAME=value在makefile文件中定义宏,引用宏的方法是使用make命令可以编译java吗_make命令可以编译java吗{MACRONAME}。示例:

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
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

内置宏:

  • $?  当前目标所依赖的文件列表中比当前目标文件还要新的文件
  • $@  当前目标的名字
  • $<  当前依赖文件的名字
  • $*  不包括后缀名的当前依赖文件的名字

特殊字符

在makefile中,通常使用下面两个有用的特殊字符,它们出现在命令之前.

  • -:让make命令忽略所有错误。
  • @:让make在执行某条命令前不要将该命令显示在标准输出上。

clean和install

可以makefile文件中增加一个clean选项来删除不需要的目标文件,增加一个install选项来将编译成功的应用程序安装到另一个目录下。示例:

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
#where to install
INSTDIR = /usr/local/bin

myapp: main.o 2.o 3.o
    $(CC) -o myapp 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:
    -rm main.o 2.o 3.o
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

几点需要注意的地方:

  • 特殊目标all指定myapp这一目标,如果在执行make命令时未指定目标,它的默认行为就是创建目标myapp。
  • 目标clean行后面是空的,因此该目标总是被认为是过时的,所以在执行make命令时,如果指定目标clean,则该目标所对应的规则总是会被执行。
  • 目标intsall依赖于myapp,所以make命令知道它必须首先创建myapp,然后才能执行制作该目标所需的其它命令。