linux 编程第一步:学会写 makefile 及用make命令

来源:互联网 发布:淘宝客服怎么联系啊 编辑:程序博客网 时间:2024/06/01 16:20

1) make命令: 终端输入 main 或vim 命令输入:main

make 会调用 makefile文件进行编译连接构造程序。命令会依次搜索当前目录下名为makefile、Makefile、GNUmakefile的文件。建议采用Makefile为名字,目录下子目录或文件名首字母为小写,这样有利于查找。

make最常用的三个选项:

-k:   指定发现错误时仍然继续,发现所有未编译成功的源文件

-n:    输出执行步骤,而不真正执行

-f:     指定特定的makefile文件名

-jN;  同时执行N条命令,以缩短编译的时间,j是jobs的首字母


2) makefile的格式

 makefile由一组的目标+依赖关系+规则组成,目标一般指可执行文件或.o目标文件,依赖关系定义目标与源文件的关系,规则定义了目标的创建方式,以下是基本的格式:

 all : 目录1 目标2 ...

目标1:依赖

        规则

目标2:依赖

        规则

clean:

        -rm *.o

install: 目标1 

        ........

注意:规则一行必须以制表符开头

多目标下可以通过命令参数指定执行的目标,如 make clean 或 make install

可以通过gcc的-MM选项来产生依赖关系表,如 gcc -MM main.c  hello.c  分别得到main.c hello.c  的依赖关系


3) makefile的特殊字符以及宏定义

makefile文件中的注释以#号开头,直到该行结束。一行代表一个命令,所以一行写不完时需要在行尾添加反斜杠 “\”如下:

@if [ -d $(dir) ]; \

    then \

    cp fi $(dir); \

fi

@表示执行这些规则之前不在标准输出上显示命令本身。另一常用的特殊字符  -  告诉命令忽略所有的错误,例如-rm

可以添加宏来增加灵活性或设置编译器的选项。语句为MACRONAME=value,引用为$(MACRONAME)或${MACRONAME}。常用的内置宏如下表:

        $?        当前目标所依赖的文件列表中比当前目标文件还要新的文件

        $@       当前目标的名字

        $<         当前依赖文件的名字

        $*          当前依赖文件的名字,不包括后缀名 ($*.o)


4) 规则

make 自带了很多的内置规则,可以简化makefile文件的内容,甚至不需要写 makefile,如在main.c 里面写hello world,然后命令行输入make main就可以了编译完成了,也可以通过宏来改变默认行为如 make CC=gcc CFLAGS="-Wall -g" main。 可以通过make -p打印出所有内置规则,内容极其多。


后缀规则:根据不同的后缀名编译源文件

模式规则:自定义规则来编译某种源文件

示例1:.cpp文件编译成.o文件

.cpp.o:

        $(CC)  -xc++ $(CFLAGS) -I$(INCLUDE) -c $<


示例2:.c文件编译成.a文件 (库文件)

.c.a:

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

        $(AR)  $(ARFLAGS)  $@   $*.o

第一条规则编译所有的文件($<) 为.o文件

第二条规则将所有的.o文件($*.o)生成目标文件($@),   $(AR)和$(ARFLAGS) 默认值分别为命令ar 和 选项rv

生成库文件的语法是lib(file.o),可以直接拿来用而不需要定义上面示例2的规则来生成,如 mylib.a:  mylib.a(file1.o) mylib.a(file2.o)


5) 子目录

大型项目中往往需要分为多个子目录,每个子目录生成各自的函数库,再由多个函数库生成可执行文件,就像是VS一个解决方案下面有很多个项目。可以用两种方法来做这事。

第一种方法是在子目录里编写makefile文件

mylib.a

        { cd mylibdir; $(MAKE) }

注意:括号把两个命令放在一个shell里面处理


第二种方法是添加宏,改写后缀规则

.c.o:

        $(CC)   $(CFLAGS)   -c  $(@D)/$(<F)   -o  $(@D)/$(@F)

字母D和F分别代表目录和文件

用如下依赖和规则来更新库

mylib.a: mydir/2.o  mydir/3.o

        ar  -rv   mylib.a   $?


注意某些函数对于gcc 需要指明选项才能编译过,如 vsnprintf需要 -std=c99


all: main

# which compiler
CC=gcc

# where are include files kept
INCLUDE=.

# options for debug
CFLAGS=-g -Wall -ansi

# options for release
#CFLAGS=-o -Wall -ansi

# local libraries
MYLIB=hello.a

main: main.o $(MYLIB)
$(CC) -o main main.o $(MYLIB)
main.o: main.c hello.h
$(CC) -I$(INCLUDE) $(CFLAGS) -c main.c
hello.o: hello.c hello.h
$(CC) -I$(INCLUDE) $(CFLAGS) -c hello.c
$(MYLIB): $(MYLIB)(hello.o)

# or use inner regular to bulid archive
# .c.a:
# $(CC) -I$(INCLUDE) $(CFLAGS) -c $<
# $(AR) $(ARFLAGS) $@ $*.o

# use "make clean" to execute this object
clean:
-rm main.o $(MYLIB)


-I  包含头文件目录

-L 包含库文件目录

-o 生成目标可执行文件

-c 编译文件,生成.o文件


以上知识基本能学会编写makefile文件,在实际中不断学习才是真理,更详细的可以参考《linux 程序设计》《跟我一起写makefile》

参考

原创粉丝点击