makefile初识

Makefile初识

  Makefile定义了整个工程的编译规则,一个工程中的头文件和源文件不计数,其按类型、功能、模块分别放在若干目录中,makefile定义了一系列的规则来指定,那些文件需要先编译,那些文件后编译。

  首先了解一下Linux下的GCC(GNU Compiler Collextion):这是一个工具集,包含gcc(跟大写的不一样),g++等编译器和ar,nm等工具集。GCC编译器程序的编译有4个阶段:预编译->编译和优化->汇编->链接,下面以c代码作例子:源代码(*.c) 【预编译 -E】 预处理后的代码(*.i) 【编译和优化 -S】 汇编代码(*.s) 【汇编 -c】 目标文件(*.o) 【链接】 可执行文件。

  一些命令选项:

  gcc hello.c /* 生成可执行文件,名字为默认的a.out。gcc后面的不知可以是*.c文件,同样也可以是*.o或其他。*/

  gcc -o hello hello.c  /* 生成可执行文件,名字接在-o后面,即hello */

  gcc -E hello.c      /* 经过预编译的过程,默认名字格式,产生hello.i */

  gcc -S hello.c      /* 经过预编译与编译优化的过程,名字为默认的hello.s */

  gcc -c hello.c     /* 经过了预编译和编译优化及汇编的过程,产生目标文件,名字为默认的hello.o */

  其他选项:

  gcc -D宏名,gcc -DOS_LINUX则相当于在预编译的时候添加了#define OS_LINUX,即当出现#ifdef OS_LINUX的时候,就会满足条件。

  gcc -Idir,将头文件的搜索路径扩大,包含dir目录

  gcc -Ldir,将链接时实用的链接库搜索路径扩大,包含dir目录,gcc优先使用共享程序库。

  gcc -static,仅使用静态程序库进行链接。

  gcc -0n,n为数字,优化程序执行速度和占用空间,常用的是2,gcc -02

 

Makefile的规则

target...:prerequisites ...

  command

  ...

  ...

target目标文件,prerequisites是要生成target所需要的文件或是目标。command是make需要执行的命令。

一下面的例子为例,贯穿整个makefile的编写过程。

目录结构:

project

  main.c

  include/

    add.h

    sub.h

  src/

    add_int.c

    add_float.c

    sub_int.c

    sub_float.c

 

add.h

1 #ifndef _ADD_H_
2 #define _ADD_H_
3 
4 extern void add_int(void);
5 extern void add_float(void);
6 
7 #endif

 

sub.h

1 #ifndef _ADD_H_
2 #define _ADD_H_
3 
4 extern void sub_int(void);
5 extern void sub_float(void);
6 
7 #endif

 

 

add_int.c

1 #include <stdio.h>
2 #include "add.h"
3 
4 void add_int(void)
5 {
6     printf("add_int.\n");
7 }

 

 

add_float.c

1 #include <stdio.h>
2 #include "add.h"
3 
4 void add_float(void)
5 {
6     printf("add_float.\n");
7 }

 

 

sub_int.c

#include <stdio.h>
#include "sub.h"

void sub_int(void)
{
    printf("sub_int.\n");
}

 

 

sub_float.c

#include <stdio.h>
#include "sub.h"

void sub_float(void)
{
    printf("sub_float.\n");
}

 

 

main.c

#include <stdio.h>
#include "add.h"
#include "sub.h"

int main(void)
{
    add_int();
    add_float();
    sub_int();
    sub_float();
    return 0;
}

 

 

makefile的编写

 1 #bin/bash
 2 
 3 target: add_int.o add_float.o sub_int.o sub_float.o main.o
 4     gcc src/add_int.o src/add_float.o src/sub_int.o src/sub_float.o main.o -o target
 5 
 6 add_int.o: src/add_int.c include/add.h
 7     gcc -o src/add_int.o -c src/add_int.c  -Iinclude
 8 
 9 add_float.o: src/add_float.c include/add.h
10     gcc -o src/add_float.o -c src/add_float.c  -Iinclude
11 
12 sub_int.o: src/sub_int.c include/sub.h
13     gcc -o src/sub_int.o -c src/sub_int.c  -Iinclude
14 
15 sub_float.o: src/sub_float.c include/sub.h
16     gcc -o src/sub_float.o -c src/sub_float.c  -Iinclude
17 
18 main.o: main.c include/add.h include/sub.h
19     gcc -o main.o -c main.c -Iinclude
20 
21 clean:
22     rm -f target src/add_int.o src/add_float.o src/sub_int.o src/sub_float.o

 

 

makefile 使用变量 

可是使用变量对上述makefile进行修改。一般变量使用大写字母。

$(CC) -o $(TARGET) $(OBJS) $(CFLAGS)

CC = gcc

TARGET = target

OBJS = src/add_int.o src/add_float.o src/sub_int.o src/sub_float.o main.o

CFLAGS = -Iinclude -O2

预定义的变量

自动变量

模式匹配

使用自动变量来简化规则书写。

main.o:%.o:%.c

  $(CC) -o $@ -c $< $(CFLAGS)

 

使用变量和模式匹配来重写上述makefile

#bin/bash

CC = gcc
OBJS = src/add_int.o src/add_float.o src/sub_int.o src/sub_float.o main.o
CFLAGS = -Iinclude -O2
TARGET = target

$(TARGET):$(OBJS)
    $(CC) $^ -o $@ $(CFLAGS)

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

.PHONY:clean
clean:
    rm $(OBJS) $(TARGET)

 

 

搜索路径:

在大的系统中,存在很多目录,手动的-I的方法添加目录不方便,所有使用VPATH变量,他可以自动找到指定文件的目录并添加到文件上。

使用方法:VPATH = path1:path2......

使用冒号隔开,记得在最后加上当前目录。

#bin/bash

CC = gcc
OBJS = add_int.o add_float.o sub_int.o sub_float.o main.o
VPATH = src:. CFLAGS
= -Iinclude -O2 TARGET = target $(TARGET):$(OBJS) $(CC) $^ -o $@ $(CFLAGS) $(OBJS):%.o:%.c $(CC) -o $@ -c $< $(CFLAGS) .PHONY:clean clean: rm *.o $(TARGET)

 

 

自动推导规则:使用命令make编译扩展名为c的C语言文件的时候,源文件的编译规则不用明确给出。

#bin/bash

CC = gcc
OBJS = src/add_int.o src/add_float.o src/sub_int.o src/sub_float.o main.o
CFLAGS = -Iinclude -O2
TARGET = target

$(TARGET):$(OBJS)
    $(CC) $^ -o $@ $(CFLAGS)

.PHONY:clean
clean:
    rm $(OBJS) $(TARGET)

 

 

递归make

当有多人在多个目录进行程序开发时,并且每个人负责一个模块,二文件在相对独立的目录中,这是由同一个Makefile维护代码的编译会出现一些问题。

1、递归调用的方式:make命令有递归的作用,他可以递归调用每个子目录的Makefile。假设目标add和sub都有Makefile,则可以用一下两种方式:

add:

  cd add && $(MAKE)

add:

  $(MAKE) -c add

 

目录变更

project\

  add\

    add.h

    add_int.c

    add_float.c

  sub\

    sub.h

    sub_int.c

    sub_float.c

 

posted @ 2016-05-19 17:16  pingfandfy  阅读(205)  评论(0编辑  收藏  举报