Makefile 编写教程(由简至难)
目录
- 一、测试代码
- 二、.c 文件与Makefile同级
- 三、.c文件与Makefile不同级
- 四、链接静态库
一、测试代码
本文以将main.c
add.c
common.h
三个文件编译成一个可执行文件为例,来讲解Makefile的编写。以下是每个文件的代码(很简单,测试用)
1.main.c
#include <stdio.h>#include "common.h" int main(){int a = 1;int b = 2;printf("add(%d, %d) = %d\n",a, b, add(a,b));return 0;}
2.add.c
int add(int a, int b)
{return a+b;
}
3.common.h
#ifndef __COMMON_H__
#define __COMMON_H__extern int add(int a, int b);#endif
二、.c 文件与Makefile同级
将.c 文件放在Makefile同级目录,然后单独建一个目录.h头文件,如图。
以下是 Makefile 原文:
CC = gccTARGET = progOBJS = main.o add.oINCLUDE = -I./include$(TARGET):$(OBJS)$(CC) $(OBJS) -o $(TARGET) %.o:%.c$(CC) $(INCLUDE) -c $^ -o $@ .PHONY:cleanclean:rm *.o prog
逐行解释:
CC = gcc:
=
号在Makefile中是声明变量并给变量赋值的意思。这里声明了一个 自定义变量 CC,并用gcc编译器赋值。TARGET = prog:声明Makefile目标文件,也就是这个Makefile最终目标是生成一个叫prog的文件。一般这种最终输出的文件都用
TARGET
来承载INCLUDE = -I./include :用
-I
选项指定自己写的头文件的路径。-I
和路径之间有没有空格都行,一般没有空格** (TARGET):(TARGET):(TARGET):(OBJS) **
** $(CC) $(OBJS) -o $(TARGET) **:
格式
要生成的目标文件:生成目标文件所需要依赖的所有文件编译命令
%.o:%.c : %是Makefile的一个通配符。这句话的作用是将所有的.c文件自动编译成同名的.o文件。比如,有了这句话,那么
1.c
就会自动编译成1.o
,2.c
就会自动编译成2.o
INCLUDE应该加在哪里
程序在预处理时就会把头文件的内容展开,所以在调用 -c 选项 将 .c 文件编译成 .o文件时,就要指定头文件路径,否则会报错,提示找不到头文件路径通配符的作用
符号 | 描述 |
---|---|
$^ | 所有依赖文件的集合,用空格分开,如果其中有重复的依赖文件,则只保留一个。比如依赖文件有三个: 1.c, 2.c, 1.c,那么$^拿到的只有 1.c 和 2.c 两个文件,舍弃了一个1.c |
$< | 依赖文件中的第一个文件。如果依赖文件是以 “%” 定义的,那么 $< 就是依赖文件的集合。一般不会有重复的依赖文件,所以上面的 Makefile,用 $^ 替换掉 $< 也是可以的 |
$+ | 与 $^ 一样,只是如果有重复的依赖文件,不会舍弃重复的依赖文件 |
$@ | 目标文件的集合 |
三、.c文件与Makefile不同级
.c
文件放在src
目录,.h
文件放在include
目录,目录结构如图:
以下是 Makefile 原文:
CC = gccTARGET = progSOURCE = $(wildcard ./src/*.c) #获取src目录下所有.c文件OBJS = $(patsubst %.c, %.o, $(SOURCE))INCLUDE = -I./include$(TARGET):$(OBJS) $(CC) $(OBJS) -o $(TARGET) #另一种写法: $(CC) -o $(TARGET) $(OBJS)%.o:%.c$(CC) $(INCLUDE) -c $^ -o $@ #另一种写法: $(CC) $(INCLUDE) -c -o $@ $^ .PHONY:cleanclean:rm $(OBJS) $(TARGET)
这里只有第3、4行需要注意,相当于用这两行内容可以找到指定目录下的文件
- 第3行
wilcard
是获取src目录下所有的.c文件 - 第4行
patsubst
是列出SOURCE
中 .c文件对应的所有 .o 文件
四、链接静态库
在前面的基础上,新建目录lib
,创建sub.c
将sub.c
编译成静态库libsub.a
,代码如下:
int sub(int a, int b)
{return a - b; }
编译成静态库的命令
gcc -c sub.c -o sub.o
ar crv libsub.a sub.o
补充: 如果静态库依赖于多个源文件,则依次编译得到.o,然后将所有的.o编译成 .a 静态库。
eg. 要将1.c、2.c、3.c编译成一个静态库,则ar crv libXXX.a 1.o 2.o 3.o
当然,除了用命令编译,也可以写成在lib
目录下写一个Makefile,我就是这么做的,如下。(这个Makefile只用于编译静态库)
CC = gcc
TARGET = libsub.a
OBJS = sub.o
$(TARGET):$(OBJS)ar crv $(TARGET) $(OBJS)
%.o:%.c$(CC) -c -o $@ $<
.PHONY:cleanclean:rm *.o $(TARGET)
接下来,就是修改我们最开始的那个Makefile
CC = gccTARGET = progSOURCE = $(wildcard ./src/*.c) #获取src目录下所有.c文件OBJS = $(patsubst %.c, %.o, $(SOURCE))INCLUDE = -I./includeLIBS = -lsubLIBPATH = -L./lib$(TARGET):$(OBJS)$(CC) $(OBJS) -o $(TARGET) $(LIBPATH) $(LIBS)%.o : %.c$(CC) $(INCLUDE) -c -o $@ $< .PHONY:cleanclean:rm $(OBJS) $(TARGET)
第5、6行,编译时需要用 -L 指定静态库的路径,用 -l 指定静态库。
注意: 链接静态库是编译的最后一步链接
做的事情。所以要加在第10行,而且只能加在末尾,如果直接跟在 $(CC)
后面,make
时会提示找不到静态库里的函数
Makefile 编写教程(由简至难)相关推荐
- 简单Makefile编写教程
Makefile编写 1. make和Makefile的介绍 1.1 make工具 利用make工具可以自动完成编译工作.这些工作包括: 如果仅仅修改了某几个源文件,则只重新编译这几个源文件: 如果某 ...
- Linux编写makefile详细教程
Linux下编写 makefile 详细教程 近期在学习Linux下的C编程,买了一本叫<Linux环境下的C编程指南>读到makefile就越看越迷糊,可能是我的理解能不行. 于是goo ...
- Makefile经典教程(掌握这些足够)
http://blog.csdn.net/ruglcc/article/details/7814546 拉轰的专栏 少壮不努力 老大徒伤悲 目录视图 摘要视图 订阅 新版极客头条上线,每天一大波干货 ...
- linux下MaKefile编写
Linux下编写 makefile 详细教程 近期在学习Linux下的C编程,买了一本叫<Linux环境下的C编程指南>读到makefile就越看越迷糊,可能是我的理解能不行. 于是goo ...
- Makefile经典教程
支持原创,请移步陈浩大神博客: http://blog.csdn.net/haoel/article/details/2886 makefile很重要 什么是makefile?或许很多Winodws的 ...
- Makefile 入门教程
1.Makefile简介 Makefile 定义了软件开发过程中,项目工程编译链.链接的方法和规则. 由 IDE 自动生成或者开发者手动书写. Unix(MAC OS.Solaris)和Linux(R ...
- Billy Belceb病毒编写教程---Win32篇
正在处理中,请稍后-- Billy Belceb病毒编写教程---Win32篇 翻译:onlyu ...
- [翻译]Billy Belceb 病毒编写教程for Win32
Billy Belceb病毒编写教程---Win32篇 翻译:onlyu ...
- Linux下的makefile编写 ——陈皓《跟我一起写Makefile》学习笔记(一)
Linux下的makefile编写 前言 本人记笔记习惯使用OneNote,在学习LinuxC++过程中发现deepin上没有大佬开发或者移植,本人技术也不精,所以决定写博客记笔记(只是习惯问题,并没 ...
- Linux下Makefile编写语法
原创 Linux下Makefile编写语法 2016-07-29 08:31:53 Datrilla 阅读数 1386更多 分类专栏: Linux Makefile 版权声明:本文为博主原创文章,遵循 ...
最新文章
- aspx文件、aspx.cs文件、aspx.designer.cs文件之讲解
- 后量子密码芯片研究取得重大突破,论文入选ISSCC 2022和CHES 2022
- Oracle数据库中调用Java类开发存储过程、函数的方法
- ubuntu中的fi语法_Shell脚本语法--if/then/elif/else/fi
- Redis 为什么这么快
- ssl2331OJ1373-鱼塘钓鱼 之3【dp】
- leetcode1438. 绝对差不超过限制的最长连续子数组
- java49_java培训 java49条基础知识
- 填写数独 洛谷P1784
- 【PAT乙】1064 朋友数 (20分) set用法
- 基于物品的协同过滤算法实现图书推荐系统
- 408计算机考试科目英语数学,关于计算机考研408的那些事儿
- 从高排到低变成小楼梯儿歌_新学期50首幼儿园常规儿歌,收藏了就能用上!
- 强化学习读书笔记(一)
- 逻辑回归实例,特征预处理
- 微光集市-JWT和Token在本项目中的应用(版本5.0)
- Ubuntu 21.04(arm64) 基于sanp安装Nextcloud,挂载本地硬盘
- c++语言中string类型,c++string类型占几个字节
- editplus中文乱码问题解决
- Python自动化开发【1】:Python简介和入门