[041]一个简单的Makefile教程

Makefile 是一个简单的组织代码编译的方式。这个教程没有深入的讲解make,但能够帮助初学者快速并且容易的创建自己的中型规模以下项目的makefiles。

一个简单例子

首先让我们创建三个文件,hellomake.c,hellofunc.c及hellomake.h,这三个文件是一个典型的main程序。
hellomake.c

#include <hellomake.h>

int main() {
  // call a function in another file
  myPrintHelloMake();
  return(0);
}

hellofunc.c

#include <stdio.h>
#include <hellomake.h>

void myPrintHelloMake(void) {

  printf("Hello makefiles!\n");

  return;
}

hellomake.h

/*
example include file
*/

void myPrintHelloMake(void);

通常我们通过下面的命令编译这些代码集合:

gcc -o hellomake hellomake.c hellofunc.c -I.

上面命令编译两个cpp文件,并生成可执行文件hellomake,“-I.”是gcc需要的include文件,上面命令指当前目录,主要为hellomake.h。makefile可以免于我们每次在测试、修改、调试的时候都要重复的在命令行敲上面的命令,尤其我们需要添加更多.c文件时,makefile会为我们节省大量时间。下面就让我们开始写makefile吧!

最简单的makefile就像下面的示例:
Makefile 1

hellomake: hellomake.c hellofunc.c
     gcc -o hellomake hellomake.c hellofunc.c -I.

如果你把上面规则放在一个叫Makefile或makefile的文件中,然后在命令行敲make命令,就会按你在makefile中写的进行编译操作。

  • make后没有参数,则执行makefile文件中的第一条规则。
  • 把命令依赖的文件列表放在第一行的“:”后,make就清楚,如果这些文件任意一个改变,规则hellomake就会被重新编译执行。

现在我们已经能够避免重复敲冗长的编译命令。
有一个特别重要的说明,为了使代码更加有效率,我们在makefile所有的gcc命令前写一个声明标签,如下:
Makefile 2

CC=gcc
CFLAGS=-I.

hellomake: hellomake.o hellofunc.o
     $(CC) -o hellomake hellomake.o hellofunc.o $(CFLAGS)

上面我们定义的常量CC和CFLAGS将告诉make,我们如何编译hellomake.c和hellofunc.c。宏常量CC是C编译器使用的,CFLAGS是传递给编译命令的一个便签列表。通过放对象文件:hellomake.o 和 hellofunc.o在规则的依赖列表中,make就知道它首先要逐一的编译.c文本,然后执行hellomake。

使用上面的makefile形式,对于小规模的工程是有效的。然而有一个重要的事情没有说明:include的文件的依赖。如果我们改变了hellomake.h,make将不会重新编译.c文件。为了补充这个缺点,我们需要告诉make,所有的.c文件依赖的.h文件,示例如下:
Makefile 3

CC=gcc
CFLAGS=-I.
DEPS = hellomake.h

%.o: %.c $(DEPS)
    $(CC) -c -o $@ $< $(CFLAGS)

hellomake: hellomake.o hellofunc.o 
    $(CC) -o hellomake hellomake.o hellofunc.o $(CFLAGS)

这个首先添加了一个宏DEPS,它是.c文件依赖的.h文件的集合。然后我们定义了一个新规则,主要应用于所有已.o结尾的文件,这个规则告诉.o文件在宏DEPS中包含的所依赖的.c文本和.h文件。它也会告诉make,为了生成.o文件,make需要编译.c文件。“-c”标签表明生成对象文件,“-o @ <”是依赖列表中的第一个选项,宏“CFLAGS”含义就如上面定义的。

为了简化我们的编写,我们使用特殊的宏“@ ^”,它们分别是“:”左侧和右侧内容,为了使所有的编译规则更加一般化,下面的例子,把所有的依赖文件都列在宏DEPS内,把所有的对象文件都列下宏OBJ内:
Makefile 4

CC=gcc
CFLAGS=-I.
DEPS = hellomake.h
OBJ = hellomake.o hellofunc.o 

%.o: %.c $(DEPS)
    $(CC) -c -o $@ $< $(CFLAGS)

hellomake: $(OBJ)
    $(CC) -o $@ $^ $(CFLAGS)

而且如果我们想放我们的.h文件在include目录下,我们的源码文件在src目录下,并且放一些本地依赖库文件在lib目录下,那我们怎么办呢?而且我们如何隐藏这些烦人的出现在所有地方的.o文件呢?
下面的makefile定义了include和lib目录的路径,并且把对象文件放在了src目录的obj子目录下。它还定义了一个你想包含的库的宏,例如math库-lm。这个makefile应该被放在src目录下。这个makefile还有一个规则,如果执行make clean,将会清空你的源文件和对象目录。“.PYONY”规则使得make免于加参数clean的清理操作。

Makefile 5

IDIR =../include
CC=gcc
CFLAGS=-I$(IDIR)

ODIR=obj
LDIR =../lib

LIBS=-lm

_DEPS = hellomake.h
DEPS = $(patsubst %,$(IDIR)/%,$(_DEPS))

_OBJ = hellomake.o hellofunc.o 
OBJ = $(patsubst %,$(ODIR)/%,$(_OBJ))


$(ODIR)/%.o: %.c $(DEPS)
    $(CC) -c -o $@ $< $(CFLAGS)

hellomake: $(OBJ)
    gcc -o $@ $^ $(CFLAGS) $(LIBS)

.PHONY: clean

clean:
    rm -f $(ODIR)/*.o *~ core $(INCDIR)/*~ 

现在你已经有一个特别好的用来管理小型和中型规模项目的makefile,你可以增加更多规则到你的makefile,你甚至能创建调用其它规则的规则。对于更多makefiles和make函数,可以访问GNU Make Manual,这里可以得到更多我们想知道的。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章