简简单单学会写makefile

一. 题外话

1.1 c/cc编译流程

main.cpp 为例:

编译过程

1.2 gcc编译参数( 部分)

除了前面的 -E -S -c 以外

  • -o 指定输出的文件名;
  • -Wall 启用所有警告;
  • -w 不产生任何警告;
  • -g 生成调试信息;
  • -I 指定头文件路径;
  • -l 链接共享库,小写的 l
  • -L 指定库文件路径,大写的 L
  • -D 定义编译时的宏;
  • -Werror 将所有的警告转换成错误信息;
  • -ansi 只支持 ANSI 标准的 C 语法;
  • -fexec-charset=GBK bin 文件为 GBK 编码。

所有的参数可见 Option Summary

1.3 静态库和动态库

windows 下后缀名 .lib (静态库), .dll (动态库)

linux 下后缀名 .a (静态库), .so (动态库)

只介绍 linux 下的库文件制作

1.3.1 静态库制作
命名

"lib[your_library_name].a" ,中间是静态库名字。

创建
  • 先编译成目标文件
    • g++ -c main.cpp
  • 通过 ar 工具将目标文件打包成 .a 静态库文件
    • **ar -crv libstaticmain.a main.o **

nm 可查看静态库内容。

1.3.2 动态库制作
命名

"lib[your_library_name].so" ,中间是静态库名字。

创建
  • 创建与地址无关的编译程序
    • g++ -fPIC -c main.c
  • 打包为动态库(共享库)
    • gcc -shared -o libdymain.so main.o

静态库使用和动态库是一样的,但是执行的时候找不到动态库。

解决办法:

  • 拷贝到系统的库路径下,不推荐;
  • 修改 LD_LIBRARY_PATH 环境变量,将库所在的路径添加到环境变量中;
  • 添加库路径到 /etc/ld.so.conf ,运行 sudo ldconfig -v ( -v 可加可不加 ),该命令会重建 /etc/ld.so.cache 文件。

详细解释可以参考 C++静态库与动态库

二. makefile格式

<target> : <prerequisites> 
[tab]  <commands>

target 目标, prerequisites 条件, commands 命令 。

目标不能省略,条件和命令都可以省略。

2.1 目标

目标通常是文件名,表明 make 要构建的对象。目标可以有多个,中间用空格分开。

为了防止目标和文件名冲突,产生了伪目标( phony target )

比如:

clean:
	rm -r *.o

如果当前路径下有个叫 clean 的文件,那么使用 make clean 就无法生效了。

这时添加伪目标即可解决。

.PHONY : clean

伪目标可以有多个,中间用空格隔开。

make 没有指定目标,默认执行第一个。

2.2 条件

前置条件通常是一组文件名,之间用空格分隔。它指定了"目标"是否重新构建的判断标准:只要有一个前置文件不存在,或者有过更新(前置文件的 last-modification 时间戳比目标的时间戳新),"目标"就需要重新构建。

2.3 命令

命令( commands )表示如何更新目标文件,由一行或多行的Shell命令组成。它是构建"目标"的具体指令,它的运行结果通常就是生成目标文件。

三. 两种常用的makefile书写方式

3.1 编译多文件

all : app

cc = g++
include = ../Include

.PHONY : clean all

src = $(wildcard *.cc)
obj = $(patsubst %.cc, %.o, $(src))

app : $(obj)
	$(cc) -o app -I $(include) $(obj)

%.o : %.cc
	$(cc) -c $< -I $(include) -o $@

clean:
	rm -f *.o
	rm -f app

这里的 wildcardmakefile 的内置函数,找出所有的 .cc 文件,赋值给变量 src

patsubst 函数用于模式匹配的替换,它需要 3 个参数:第一个是一个需要匹配的式样,第二个表示用什么来替换它,第三个是一个需要被处理的由空格分隔的字列。

%.o : %.cc 用到了 makefile 的模式匹配

更多可以参考 8 Functions for Transforming Text

$<$@makefile 的自动变量:

  • $@
    • $@指代当前目标,就是Make命令当前构建的那个目标。
  • $<
    • $< 指代第一个前置条件。
  • $?
    • $? 指代比目标更新的所有前置条件,之间以空格分隔。
  • $^
    • $^ 指代所有前置条件,之间以空格分隔。
  • $*
    • $* 指代匹配符 % 匹配的部分。

更多可以参考 10.5.3 Automatic Variables

3.2 生成多个可执行文件

all : hello world

cc = g++
include = ../Include

.PHONY : all clean

hello : hello.o
	$(cc) -o hello -I $(include) hello.o

world : world.o
	$(cc) -o world -I $(include) world.o

hello.o : hello.cc
	$(cc) -c hello.cc -I $(include)

world.o : world.cc
	$(cc) -c world.cc -I $(include)

clean :
	rm -f *.o
	rm -f hello world

来个更高级点的版本:

.PHONY : all clean

cc = g++
include = ../Include

src = $(wildcard *.cc)
obj = $(patsubst %.cc, %, $(src))

all : $(obj)

% : %.cc
	gcc -o $@ $^ -g

clean:
	rm -rf $(obj)

更详细可参考 Make 命令教程

总结

学会 makefile 对以后的编程还是有很大帮助的,可以大大提高自己编写代码的效率。

Linux 环境下的程序员如果不会使用GNU make来构建和管理自己的工程,应该不能算是一个合格的专业程序员,至少不能称得上是 Unix程序员。

诗情画意

青玉案·版本二
贺铸
凌波不过横塘路,但目送,芳尘去。
锦瑟华年谁与度?月桥花院,锁窗朱户,只有春知处。
碧云冉冉蘅(héng)皋(gāo)暮,彩笔新题断肠句。
试问闲情都几许?一川烟草,满城风絮,梅子黄时雨。
青玉案·版本一
贺铸
凌波不过横塘路,但目送,芳尘去。
锦瑟华年谁与度?月台花榭,锁窗朱户,只有春知处。
碧云冉冉蘅皋暮,彩笔新题断肠句。
试问闲愁都几许?一川烟草,满城风絮,梅子黄时雨。
  • 6
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值