前言

本文展示了一个比较完整的企业项目级别的Makefile文件,包括了:文件调用,源文件、头文件、库文件指定,软件版本号、宏定义,编译时间,自动目录等内容。

1、目录架构

本文中所采用的目录架构,在企业项目开发中十分常见:源文件都放在src目录中,头文件都放在inc目录中,并且这两个目录都可以有对应的子目录。库文件放在lib目录中,makefile相关文件放在build目录中,编程生成的程序放在自动生成的output目录中。目录结构展示如下:

.
├── build
│   ├── Makefile
│   └── srcpathconfig.mk
├── code
│   ├── inc
│   │   ├── com
│   │   └── func
│   │       └── fun.h
│   └── src
│       ├── com
│       │   └── main.c
│       └── func
│           └── fun.c
└── lib├── inc│   └── mylib.h└── libs└── libmylib.so

2、源文件及Makefile内容

本文所用到的所有文件,也可以直接到我的公众号,后台回复“ mk ”获取。

源文件

/* fun.h */
#ifndef __FUN_H__
#define __FUN_H__void fun();#endif/* fun.c */
#include <stdio.h>void fun()
{#ifdef MACRO_DEFprintf("macro definition enable!\n");
#endif#ifdef COMPILER_IS_ARM_LINUX_GCCprintf("The compilation target is arm!\n");
#endif#ifdef COMPILER_IS_LINUX_GCCprintf("The compilation target is linux!\n");
#endifprintf("This is fun()!\n");
}/* mylib.h */
void mylib();/* libmylib.so */
// mylib()函数,打印This is mylib()!/* main.c */
#include "fun.h"
#include "mylib.h"int main()
{ fun();mylib();return 0;
}

srcpathconfig.mk

这个文件的内容,其实也可以放在Makefile中,本案例单独用一个文件来配置路径,是为了后期好管理

#源文件目录
SRCCODEDIRS   :=../code/src/func \../code/src/com \#头文件目录
SRCHEADDIRS   :=../code/inc/func \../code/inc/com \#lib文件目录
LIBFILEDIRS := ../lib/libs#lib头文件目录
LIBHEADDIRS := ../lib/inc/#lib文件
LIBFILE := -lmylib

Makefile

#引用其他文件
include srcpathconfig.mk#时间信息
tmpbuildtm := `date |sed 's/ /_/g'`
TMPBUILDTM = $(tmpbuildtm)#软件版本
APPVERSION = 1.0.0.0#不同的目标采用不同的宏定义
ifeq ($(MAKECMDGOALS),arm)
COMPILEMACRO += COMPILER_IS_ARM_LINUX_GCC
else
COMPILEMACRO += COMPILER_IS_LINUX_GCC MACRO_DEF
endif#循环获取源文件和中间件
SRCFILE := $(foreach d,$(SRCCODEDIRS),$(wildcard $(addprefix $(d)/*,.c)))
OBJFILE := $(patsubst %.c,%.o,$(SRCFILE))#宏定义,源文件路径,头文件路径
CURCMPLMACRO   := $(addprefix -D ,$(COMPILEMACRO))
CURSRCHEADDIRS := $(addprefix -I ,$(SRCHEADDIRS))
CURLIBHEADDIRS := $(addprefix -I ,$(LIBHEADDIRS))#程序输出路径
OUTPUTDIR := ../output#编译器及选项
CC := gcc
CFLAGS := -Wall -cRM := rm
RMFLAGS := -rf#目标文件
TARGETNAME = app$(TARGETNAME):$(OBJFILE)@mkdir -p $(OUTPUTDIR)@echo ""@echo "all files have been compiled , now begin to link every obj for excutable file"@echo ""@echo "linking............"@echo $(OBJFILE)@$(CC)  -o $(OUTPUTDIR)/$(TARGETNAME).$(APPVERSION) $(OBJFILE) -L$(LIBFILEDIRS) $(LIBFILE)@echo ""@echo "linked ok," $(TARGETNAME) "has been created"@echo ""@echo $(TMPBUILDTM)%.o: %.c@echo ""@echo "start " $< "......compiling"@$(CC) $(CURCMPLMACRO) $(CFLAGS) $(CURSRCHEADDIRS) $(CURLIBHEADDIRS) $< -o $@@echo "created " $@@echo "end   " $< "......compiled ok"@echo "".PHONY: arm cleanarm:$(TARGETNAME)clean:@-$(RM) $(RMFLAGS) $(TARGETNAME) $(OBJFILE) $(OUTPUTDIR)

3、效果演示

输入make 或者 make arm ,打印如下

start  ../code/src/func/fun.c ......compiling
created  ../code/src/func/fun.o
end    ../code/src/func/fun.c ......compiled okstart  ../code/src/com/main.c ......compiling
created  ../code/src/com/main.o
end    ../code/src/com/main.c ......compiled okall files have been compiled , now begin to link every obj for excutable filelinking............
../code/src/func/fun.o ../code/src/com/main.olinked ok, app has been createdFri_Mar__3_22:14:09_PST_2023

生成的文件架构如下

.
├── build
│   ├── Makefile
│   └── srcpathconfig.mk
├── code
│   ├── inc
│   │   ├── com
│   │   └── func
│   │       └── fun.h
│   └── src
│       ├── com
│       │   ├── main.c
│       │   └── main.o
│       └── func
│           ├── fun.c
│           └── fun.o
├── lib
│   ├── inc
│   │   └── mylib.h
│   └── libs
│       └── libmylib.so
└── output└── app.1.0.0.0

运行output中生成的app.1.0.0.0程序

/* 由make命令编译生成的app.1.0.0.0 */macro definition enable!
The compilation target is linux!
This is fun()!
This is mylib()
/* 由make arm命令编译生成的app.1.0.0.0 */The compilation target is arm!
This is fun()!
This is mylib()

4、Makefile内容解析

4.1 文件调用

include srcpathconfig.mk

相当于把srcpathconfig.mk的内容都拿过来,srcpathconfig.mk中的变量,在Makefile文件中都可以直接使用。

4.2 编译时间

tmpbuildtm := `date |sed 's/ /_/g'`
TMPBUILDTM = $(tmpbuildtm)@echo $(TMPBUILDTM)

这个是把当前的时间,保存到TMPBUILDTM变量中,可以运用到源码中,本案例只是打印一下此变量。

4.3 软件版本

APPVERSION = 1.0.0.0
@$(CC)  -o $(OUTPUTDIR)/$(TARGETNAME).$(APPVERSION) $(OBJFILE) -L$(LIBFILEDIRS) $(LIBFILE)

开发过程中,我们会有多个版本的程序,可以在程序加上版本号作为后缀。

4.4 宏定义

ifeq ($(MAKECMDGOALS),arm)
COMPILEMACRO += COMPILER_IS_ARM_LINUX_GCC
else
COMPILEMACRO += COMPILER_IS_LINUX_GCC MACRO_DEF
endifCURCMPLMACRO   := $(addprefix -D ,$(COMPILEMACRO))%.o: %.c@$(CC) $(CURCMPLMACRO) $(CFLAGS) $(CURSRCHEADDIRS) $(CURLIBHEADDIRS) $< -o $@

makefile中也可以使用条件判断,具体用法这里不多做介绍。

MAKECMDGOALS,是make命令后面跟的目标,比如make arm,那么MAKECMDGOALS的值就为arm。

这里利用MAKECMDGOALS的值来选择使用哪些宏定义,假如make 后面跟的是arm,宏定义则是COMPILER_IS_ARM_LINUX_GCC,假如make后面跟的不是arm,宏定义则是COMPILER_IS_LINUX_GCC和MACRO_DEF。

这些宏定义在fun.c中有使用,对应的是打印不同的内容。在实际项目中,宏定义的作用很广,可以用来跨平台开发,也可以用来调试打印。

4.5 源文件及中间件

SRCFILE := $(foreach d,$(SRCCODEDIRS),$(wildcard $(addprefix $(d)/*,.c)))
OBJFILE := $(patsubst %.c,%.o,$(SRCFILE))

由于我们的源文件是放在src目录下的不同子目录中,所以使用了foreach函数来循环获取。简单说明一下,foreach后面跟着的d,是中间变量,这一行的作用就是将SRCCODEDIRS的路径下的.c文件,逐个逐个拿出来,加上对应的路径前缀。

关于foreach的函数的具体使用方法,不做过多介绍。

4.6 头文件

SRCHEADDIRS   :=../code/inc/func \../code/inc/com \LIBHEADDIRS := ../lib/inc/                CURSRCHEADDIRS := $(addprefix -I ,$(SRCHEADDIRS))
CURLIBHEADDIRS := $(addprefix -I ,$(LIBHEADDIRS))%.o: %.c@$(CC) $(CURCMPLMACRO) $(CFLAGS) $(CURSRCHEADDIRS) $(CURLIBHEADDIRS) $< -o $@

将普通头文件和库头文件的存放路径单独用变量表示

4.7 库文件

LIBFILEDIRS := ../lib/libs
LIBFILE := -lmylib$(TARGETNAME):$(OBJFILE)@$(CC)  -o $(OUTPUTDIR)/$(TARGETNAME).$(APPVERSION) $(OBJFILE) -L$(LIBFILEDIRS) $(LIBFILE)

将库文件的名字和存放路径单独用变量表示

4.8 编译选项

CC := gcc
CFLAGS := -Wall -cRM := rm
RMFLAGS := -rf

CC := gcc,指定编译器为gcc;CFLAGS 和RMFLAGS中的内容可以根据需求调整,所以单独拿出来,-Wall是表示编译的时候可以产生告警,便于分析。

4.9 自动目录

OUTPUTDIR := ../output@mkdir -p $(OUTPUTDIR)@-$(RM) $(RMFLAGS) $(TARGETNAME) $(OBJFILE) $(OUTPUTDIR)

make命令会自动创建output目录,用来存放生成的目标文件。

make clean会将此目录及目录中的所有内容都删除

4.10 打印信息

TARGETNAME = app$(TARGETNAME):$(OBJFILE)@mkdir -p $(OUTPUTDIR)@echo ""@echo "all files have been compiled , now begin to link every obj for excutable file"@echo ""@echo "linking............"@echo $(OBJFILE)@$(CC)  -o $(OUTPUTDIR)/$(TARGETNAME).$(APPVERSION) $(OBJFILE) -L$(LIBFILEDIRS) $(LIBFILE)@echo ""@echo "linked ok," $(TARGETNAME) "has been created"@echo ""@echo $(TMPBUILDTM)%.o: %.c@echo ""@echo "start " $< "......compiling"@$(CC) $(CURCMPLMACRO) $(CFLAGS) $(CURSRCHEADDIRS) $(CURLIBHEADDIRS) $< -o $@@echo "created " $@@echo "end   " $< "......compiled ok"@echo ""

所有@echo的内容,都是为了编译的时候,打印一些信息,方便查看才加上去的,实际上有真正有用的是下面这些

TARGETNAME = app$(TARGETNAME):$(OBJFILE)@mkdir -p $(OUTPUTDIR)@$(CC)  -o $(OUTPUTDIR)/$(TARGETNAME).$(APPVERSION) $(OBJFILE) -L$(LIBFILEDIRS) $(LIBFILE)%.o: %.c@$(CC) $(CURCMPLMACRO) $(CFLAGS) $(CURSRCHEADDIRS) $(CURLIBHEADDIRS) $< -o $@

———————————————————————————————

码字不易,点个赞再走吧!

欢迎关注我的同名公众号,这里有更多好料等着你哦!

轻松玩转Makefile | 企业项目级Makefile实例相关推荐

  1. makefile指定头文件路径_玩转Makefile | 企业项目Makefile实例

    我是良许,世界500强外企 Linux 工程师,专业生产 Linux 干货,欢迎关注我的知乎「良许Linux」,欢迎点赞,收藏! 1. 前言 本教程展示了一个比较完整的企业项目级别的Makefile文 ...

  2. clickhouse集群表删除_携程用ClickHouse轻松玩转每天十亿级数据更新

    作者介绍 蔡岳毅,携程酒店大数据高级研发经理,负责酒店数据智能平台研发,大数据技术创新工作.喜欢探索研究大数据的开源技术框架. 一.背景 携程酒店每天有上千表,累计十多亿数据更新,如何保证数据更新过程 ...

  3. cbp2make转codeblock项目为Makefile

    可以将codeblock项目生成MakeFile 编译好cbp2make放入/usr/bin,/etc/ld.so.conf中增加可执行文件的路径即可 cbp2make -in *.cbp -out ...

  4. 乐鑫esp8266学习rtos3.0笔记:分享在 esp8266 C SDK实现冷暖光色温平滑调节的封装,轻松集成到您的项目去。(附带Demo)

    本系列博客学习由非官方人员 半颗心脏 潜心所力所写,不做开发板.仅仅做个人技术交流分享,不做任何商业用途.如有不对之处,请留言,本人及时更改. 基于C SDK的ESP8266开发技术全系列笔记 一.N ...

  5. 如何打造项目级硬核简历,成为一名合格的大厂工程师(必看)

    小提醒:文末有精心整理的免费提供的纯干货资料哟,大厂非刚需!技术是刚需 又一年的秋招大戏要开始了.小部这段时间被问到最多的就是求职相关的问题.怎样才能进大厂?能不能帮忙内推?如何在短时间内增加简历含金 ...

  6. Eclipse轻松玩转SmartFramework

    2019独角兽企业重金招聘Python工程师标准>>>        SmartFramework框架和 SmartSample都是使用Maven构建,使用IDEA开发的.对于像我这 ...

  7. 实时监控 轻松玩转IT运维

    日常IT运维遇到的问题       前段时间刚好和运营商网络运维中心的几位工程师进行了一次沟通,无意中聊到了平时是如何进行日常运维工作的话题,他们一致的感觉是又累又繁琐.便觉得很纳闷,经过了解才明白由 ...

  8. 轻松玩转“项目管理” 群硕软件PMS正式发布

    2019年12月13日,群硕软件PMS项目管理系统正式发布!它是一个让项目管理化繁为简的团队协作工具,通过协作创新解决以上种种问题,让细节跃然于纸上. PMS项目管理系统 目前我国中小微企业存在众多问 ...

  9. Android 智能手机企业项目

    原创作品:http://write.blog.csdn.net/postedit/7956383 欢迎大家一起交流学习,知识在与分享. 希望结交一些志同道和之士 QQ: 474530676 longg ...

最新文章

  1. 深圳杯---垃圾焚烧厂的经济补偿问题
  2. Vue单文件组件基础模板
  3. hdu-4510 小Q系列故事——为什么时光不能倒流(比赛被虐的一道水题)
  4. 基于FPGA的AM信号调制与解调详细步骤
  5. centos7.3 防火墙设置
  6. 蓝桥杯试题java_java蓝桥杯试题
  7. 数据挖掘之数据仓库详述
  8. 东莞芯钰科运动控制卡实战记录-硬件篇
  9. 大数据之 Kafka API 从入门到放弃 (第四章)
  10. 用计算机打元宵节快乐,2019元宵节祝福语大全简短 祝大家元宵节快乐
  11. 微信小程序使用本地背景图无法渲染的解决办法
  12. 关于链接出现 unauthenticated user 用户问题研究
  13. java excel导入校验_excel导入前校验
  14. JS查询日出日落时间和太阳月亮位置
  15. vue实现横向无限滚动
  16. “三高”即通常所说的高血压、高血脂(血脂异常)和高血糖三种病症的总称...
  17. KindEditor编辑器结合EasyUi
  18. modbus tcp主站和从站_Modbus-RTU 一主多从PLC无线通讯经典案例
  19. php获得客户端ip地址范例
  20. 第一周:线性规划、整数规划、非线性规划、二次规划

热门文章

  1. 2.2、物理层下面的传输媒体
  2. 微软免费杀毒软件Morro开始测试 征求定名
  3. stm32关定时器_【菜鸟必看】stm32定时器的妙用
  4. 单片机串口时序与TTL电平
  5. JavaFX实验2 石头剪刀布
  6. Unity 第三人称自由视角
  7. 热点连接的设备android,Android获取实时连接热点的设备IP
  8. 大力哥谈 DALI - DALI 设备 GTIN / 序列号
  9. 从零开始理解DM368的H264视频编码过程(下)
  10. 李开复:人工智能可能会让一半人失业