编写 Makefile文件 (一)

参考:《linux程序设计(第四版)》

本文的编写从简单到复杂,一步一步完成Makefile文件的编写和完善。首先看一下我们的程序有哪些文件:

文件内的程序也很简单,就是输出该文件已经被调用,代码如下:

void funcPrintf(void)
{
    printf("------ func.c ------\n");
}

 如果我们想要编译一个文件,首先想到的是在shell 下执行gcc命令,那么我们先通过几个shell脚本来实现文件的编译。

#! /bin/bash 

set -ev

gcc -o myApp main.c func.c func.h

echo "bulid successful!"

下面是执行结果,编译生成了myApp,程序包含了main.c 和 func.c ,运行程序后打印在了终端上。 

实际上我们是执行了gcc -o myApp main.c func.c func.h命令完成了程序的编译,那么我们看一下如何用Makefile文件来完成这个操作。

myApp: main.c func.o
    gcc -o myApp main.c func.o

func.o: func.h func.c
    gcc -c func.h func.c

我们分解了一步,提出了一个func.o 进行单独编译。其实完全可以写成下面的样子。

myApp: main.c func.h func.c
    gcc -o myApp main.c func.h func.c

 然后我们在Makefile文件所在目录执行make命令即可完成编译。

很显然,从目前的情况看Makefile让我们程序编译变得更加复杂,因为我们不得不去遵守Makefile的一些规则。

1. myApp 最终生成的目标文件

2. :后面的这些内容是编译生成目标文件所依赖的文件

3. gcc -o myApp main.c func.h func.c 是编译生产目标文件需要执行的指令(指令需要以TAB开头

上面就是Makefile的基本规则,可以理解为按照一定的规则将编译的shell 脚本写进一个名叫Makefile的文件,然后执行make指令后系统就会根据Makefile文件的规则执行编译shell指令。

既然上面的Makefile文件有两个,其中一个将func.o文件单独列出来了,这里就补充一下:我们用命令编译的时候可以分成两步:

gcc -c func.h func.c
gcc -o myApp main.c func.o
    

先生成连接文件func.o然后再连接func.o文件生成myApp,只是在Makefile文件编写时需要先告诉make指令编译生成myApp需要依赖main.c和func.o,然后make就会去寻找func.o文件。接着make发现生成func.o又依赖func.c和func.h文件,需要执行的指令是gcc -c func.h func.c 。总结一下:make会从最终目标出发,依次找到每个依赖,每个依赖的依赖....

编译过程中会生成各种文件,因此需要clean一下,添加一下clean指令。完善一下我们的Makefile文件,增加clean操作,删除连接文件、预编译文件和最终生成的目标文件。

myApp: main.c func.o
    gcc -o myApp main.c func.o

func.o: func.h func.c
    gcc -c func.h func.c

clean:
    -rm func.o *.h.gch myApp

执行 make clean 

插播一个知识点,不做过多解释,链接库

老规矩先上shell脚本:

#! /bin/bash 

set -ev

gcc lib.c lib.h -fPIC -shared -o lib.so

# 编译生成链接库指令
gcc -o myApp main.c func.c func.h lib.so

cp lib.so /usr/lib

echo "bulid successful!"

 对比Makefile脚本:

myApp: main.c func.o lib.so
    gcc -o myApp main.c func.o lib.so

func.o: func.h func.c
    gcc -c func.h func.c

lib.so: lib.c lib.h
    gcc lib.c lib.h -fPIC -shared -o lib.so

clean:
    -rm func.o *.h.gch myApp *.so

通过上面的操作我们可以完成Makefile文件的编写,也能完成所有的工作,但是看上去不是那么的灵活。接下来需要讲一下变量,先上Makefile文件:

all: myApp

CC: gcc

INCLUDE = .

CFLAGS = -g -Wall -ansi

#CFLAGS = -O -Wall –ansi

myApp: main.c func.o lib.so
    $(CC) -o myApp main.c func.o lib.so

func.o: func.h func.c
    $(CC)  -I$(INCLUDE) -c func.h func.c

lib.so: lib.c lib.h
    $(CC)  -I$(INCLUDE) lib.c lib.h -fPIC -shared -o lib.so

clean:
    -rm func.o *.h.gch myApp *.so

install:
    cp *.so /usr/lib ;\
    echo "make install";\
    ./myApp;\
    echo "myApp running ...";

例子很简单,用了两个变量 CC: gcc 指定了编译器, CFLAGS = -g -Wall -ansi 指定了编译等级,变量引用使用方法$(变量名),上面的Makefile文件的执行结果如下:

Makefile本身也规定了几个常用的变量:

$@  表示目标文件

$^  表示所有的依赖文件

$<  表示第一个依赖文件

$?  表示比目标还要新的依赖文件列表

all: myApp

CC: gcc

INCLUDE = .

CFLAGS = -g -Wall -ansi

#CFLAGS = -O -Wall –ansi

myApp: main.c func.o lib.so
    $(CC) $(CFLAGS) -o $@ $^

func.o: func.h func.c
    $(CC)  -I$(INCLUDE) $(CFLAGS) -c $^

lib.so: lib.c lib.h
    $(CC)  -I$(INCLUDE) $(CFLAGS) $^ -fPIC -shared -o $@

clean:
    -rm func.o *.h.gch myApp *.so

install:
    cp *.so /usr/lib ;\
    echo "make install";\
    ./myApp;\
    echo "myApp running ...";

这个Makefile文件除了增加了一个install 操作之外,其他的动作和上面的Makefile文件规定的一致,只是用变量做了替代。解释一下install,可以理解为一些列shell操作来完成程序的安装,其实并不一定是安装操作,比如上面的install操作只是将库文件拷贝进入/usr/lib目录并且执行了该文件。

我们还有两个文件在file文件夹内,现在我们也将这两个文件的编译加入进去。当然这里是一种简单的方法,后面介绍如何多文件夹递归编译。

all: myApp

CC: gcc

INCLUDE = .

INSTDIR = /usr/lib

CFLAGS = -g -Wall -ansi

#CFLAGS = -O -Wall –ansi

myApp: main.c func.o lib.so file.o
    $(CC) $(CFLAGS) -o $@ $^

func.o: func.h func.c
    $(CC)  -I$(INCLUDE) $(CFLAGS) -c $^

lib.so: lib.c lib.h
    $(CC)  -I$(INCLUDE) $(CFLAGS) $^ -fPIC -shared -o $@

file.o: file/file.c file/file.h
    $(CC)  -I$(INCLUDE) $(CFLAGS) -c $^

clean:
    -rm *.o *.h.gch myApp *.so

install:
    cp *.so $(INSTDIR) ;\
    echo "make install";\
    ./myApp;\
    echo "myApp running ...";

 

最后经过了修改和完善我们完成了最终的Makefile文件:

INCLUDE = .

INSTDIR = /usr/lib

CFLAGS = -g -Wall -ansi
#CFLAGS = -O -Wall –ansi

TARGET = myApp

all: $(TARGET)

CC: gcc

$(TARGET): main.c func.o lib.so file.o
    $(CC) $(CFLAGS) -o $@ $^

func.o: func.h func.c
    $(CC)  -I$(INCLUDE) $(CFLAGS) -c $^

lib.so: lib.c lib.h
    $(CC)  -I$(INCLUDE) $(CFLAGS) $^ -fPIC -shared -o $@

file.o: file/file.c file/file.h
    $(CC)  -I$(INCLUDE) $(CFLAGS) -c $^

.PHONY: clean
clean:
    -rm *.o *.h.gch $(TARGET) *.so

install:
    cp *.so $(INSTDIR) ;\
    echo "make install";\
    ./$(TARGET);\
    echo "$(TARGET) running ...";

 

  • 8
    点赞
  • 58
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值