Makefile 编写教程(由简至难)

2023-05-16

目录

  • 一、测试代码
  • 二、.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 = gcc
 TARGET = prog
 OBJS = main.o add.o
 INCLUDE = -I./include
 $(TARGET):$(OBJS)
     $(CC) $(OBJS) -o $(TARGET)   
 %.o:%.c
     $(CC) $(INCLUDE) -c $^ -o $@                                                                                                                                                                           
 
 .PHONY:clean
 clean:
     rm *.o prog

逐行解释:

  • CC = gcc= 号在Makefile中是声明变量并给变量赋值的意思。这里声明了一个 自定义变量 CC,并用gcc编译器赋值。

  • TARGET = prog:声明Makefile目标文件,也就是这个Makefile最终目标是生成一个叫prog的文件。一般这种最终输出的文件都用TARGET来承载

  • INCLUDE = -I./include :用-I 选项指定自己写的头文件的路径。-I和路径之间有没有空格都行,一般没有空格

  • ** ( T A R G E T ) : (TARGET): (TARGET):(OBJS) **
    ** $(CC) $(OBJS) -o $(TARGET) **:
    格式

要生成的目标文件:生成目标文件所需要依赖的所有文件
	编译命令
  • %.o:%.c : %是Makefile的一个通配符。这句话的作用是将所有的.c文件自动编译成同名的.o文件。比如,有了这句话,那么1.c就会自动编译成1.o2.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 = gcc
 TARGET = prog
 SOURCE = $(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:clean
 clean:
     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:clean
 clean:
     rm *.o $(TARGET) 

接下来,就是修改我们最开始的那个Makefile

 CC = gcc
 TARGET = prog
 SOURCE = $(wildcard ./src/*.c) #获取src目录下所有.c文件
 OBJS = $(patsubst %.c, %.o, $(SOURCE))
 INCLUDE = -I./include
 LIBS = -lsub
 LIBPATH = -L./lib
 
 $(TARGET):$(OBJS)
     $(CC) $(OBJS) -o $(TARGET)  $(LIBPATH) $(LIBS)
 
 %.o : %.c
     $(CC) $(INCLUDE) -c -o $@ $<                                                                                                                                                                           
 
 .PHONY:clean
 clean:
     rm $(OBJS) $(TARGET)

第5、6行,编译时需要用 -L 指定静态库的路径,用 -l 指定静态库。
注意: 链接静态库是编译的最后一步链接做的事情。所以要加在第10行,而且只能加在末尾,如果直接跟在 $(CC)后面,make时会提示找不到静态库里的函数

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Makefile 编写教程(由简至难) 的相关文章

  • VSLAM算法中的数学基础知识详细了解

    学习SLAM经验告诉我 xff0c 入门SLAM一般只需要两种两个方面的条件 xff0c 一是要有扎实的数学基础 xff0c 二是要有强大的动手编程能力 xff0c 但是这两个条件对于刚入门的同学来说 xff0c 极具挑战性 学习SLAM的
  • 2021互联网大厂职级对应薪资一览表

    原文连接 xff1a https mp weixin qq com s nYNZjJJzrO0Sc5h2AEPnaQ 互联网大厂新入职员工各职级薪资对应表 xff08 技术线 xff09 图片数据来源 xff1a 知乎加 上面的表格不排除有
  • “undefined reference to“ 问题及解决方法 实例分析

    在实际编译代码的过程中 xff0c 我们经常会遇到 34 undefined reference to 34 的问题 xff0c 简单的可以轻易地解决 xff0c 但有些却隐藏得很深 xff0c 需要花费大量的时间去排查 工作中遇到了各色各
  • int 占几个字节

    4个字节或2个字节 xff0c 主要看操作系统 xff0c 和编译器有关 xff0c 一个int的大小是操作系统的一个字长 TC是16位系统程序 xff0c 所以int是16bit xff0c 也就是两个字节 在32位linux和32位或6
  • ORBSLAM3 VIO初始化

    按照规矩 xff0c 先讲一下ORBSLAM3中的初始化大致流程 根据ORB SLAM3的论文介绍 xff0c IMU的初始化方法是基于下面3点 xff1a 1 xff09 纯视觉SLAM可以提供很好的位姿估计 xff0c 所以可以用纯视觉
  • 不一样的静态初始化——OpenVins

    今天讲一下黄国权老师实验室开源的OpenVins工程中的IMU初始化 xff0c 一般VIO初始化分为两种 xff0c 一种是静态初始化 xff0c 一种是动态初始化 xff0c 而OpenVins则利用加速度的方差差异将运动分为两种状态
  • CMakeList.txt的指令以及实例介绍

    一 Cmake 简介 cmake xff08 Cross platform make xff09 是一个开源的跨平台自动化构建系统 xff0c 用来管理程序构建 xff0c 不依于特定的编译器 所谓的跨平台就是可以在Windows xff0
  • 语法错误( error: array bound is not an integer constant before ‘]’ token)

    include lt iostream gt include lt cstdio gt using namespace std int N 61 100 int a N N int main 编译出现了 Error array bound
  • 使用ADB出现了system/bin/sh: adb: not found&system/bin/sh: pull: not found错误

    在使用ADB传送文件的时候出现了system bin sh adb not found amp system bin sh pull not found错误 解决办法 xff1a 可能你在使用adb pull 之前你使用了adb shell
  • 回环检测之决策模型

    前面我们已经讲了如何描述场景 xff0c 让机器人尽可能的了解周围环境 xff0c 那么了解了之后 xff0c 如何判断出是回环的呢 xff1f 本节讨论如何建立决策模型来根据当前场景描述和地图信息识别出可能的闭环 合理的决策模型可有效提高
  • 回环检测之DBoW2

    前面我们已经讲了回环检测中用的一些方法 xff0c 今天主要介绍一下现在用的最多的词袋模型 DBoW2 这里就不在细讲回环检测的定义 xff0c 具体可以看看我的前面的博客 xff0c 而回环检测在SLAM中的作用可以从下面的图片中大致有一
  • 快速解决rosdep update一直不通过问题

    以前安装ROS的时候遇到rosdep update不通过 xff0c 需要很多次测试才能通过 xff0c 能通过完全靠运气 xff0c 也找了网上很多种方法 xff0c 比较麻烦 xff0c 今天这里说一下一位大神帅鱼提供的一个方法 xff
  • Matlab读取文本数据

    用Nastran的时候 xff0c 想把bdf文件里的节点坐标导出来 xff0c 但是坐标的格式很奇怪 xff0c 见下图 xff1a 会发现这种科学计数法中间没有字母E或e xff0c 直接用Matlab中的load函数读取的话 xff0
  • 为学弟学妹熬夜的一份零基础 C++ 开发学习路线

    大家好 xff0c 我是帅地 之前写过几篇学习路线的文章 前端开发学习路线 Java 后端开发学习路线 一般开发岗主流的就是 Java 后台开发 xff0c 前端开发以及 C 43 43 后台开发 xff0c 现在 Go 开发也是越来越多了
  • ars408_ros驱动问题

    0 ars408 ros驱动 mkdir folder mkdir folder src cd folder src git clone https github com sergiocasaspastor myrepository git
  • Tensorflow实战:LSTM原理及实现(详解)

    LSTM规避了标准RNN中梯度爆炸和梯度消失的问题 xff0c 所以会显得更好用 xff0c 学习速度更快 下图是最基本的LSTM单元连接起来的样子 上图为一层LSTM单元连接起来的样子 xff0c 在工业上 xff0c LSTM是可以像一
  • Gazebo版本升级7.0--->7.16

    GPU issues The GPU problems reported in this issue have been solved with this pull request for the gazebo7branch The Gaz
  • 机器人局部动态避障算法dwa解析

    简介 dwa算法全称叫动态窗口法 xff08 dynamic window approach xff09 xff0c 其算法过程主要分为仿真获取机器人的运动轨迹 对轨迹进行评价选择最优轨迹两个主要过程 xff0c 动态窗口表达的是仿真的运动
  • 应届生应该如何准备校招

    大家好 xff0c 我是羽峰 xff0c 今天要和大家分享的是应届生应该如何准备校招 xff0c 希望该文章对一些今年要找工作的朋友有一些帮助 还是老话 xff0c 我是羽峰 xff0c 希望我所分享的文章能为您及更多的朋友带来帮助 欢迎转
  • docker容器迁移到其他服务器

    以把旧服务器的mysql容器迁移到虚拟机上为例 1 旧服务器查看路径映射 首先查看mysql容器的路径映射 span class token function docker span inspect mysql 2 基本数据由旧服务器迁移到

随机推荐