首页 > 其他分享 >轻松玩转Makefile | 企业项目级Makefile实例

轻松玩转Makefile | 企业项目级Makefile实例

时间:2023-03-04 14:57:34浏览次数:37  
标签:code .. Makefile echo 实例 玩转 OBJFILE fun TARGETNAME

前言

本文展示了一个比较完整的企业项目级别的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_DEF
    printf("macro definition enable!\n");
#endif


#ifdef COMPILER_IS_ARM_LINUX_GCC
    printf("The compilation target is arm!\n");
#endif

#ifdef COMPILER_IS_LINUX_GCC
    printf("The compilation target is linux!\n");
#endif

	printf("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 -c

RM := 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 clean

arm:$(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 ok


start  ../code/src/com/main.c ......compiling
created  ../code/src/com/main.o
end    ../code/src/com/main.c ......compiled ok


all files have been compiled , now begin to link every obj for excutable file

linking............
../code/src/func/fun.o ../code/src/com/main.o

linked ok, app has been created

Fri_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
endif

CURCMPLMACRO   := $(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 -c

RM := 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 $@


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

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

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

标签:code,..,Makefile,echo,实例,玩转,OBJFILE,fun,TARGETNAME
From: https://www.cnblogs.com/Wayne123/p/17178278.html

相关文章

  • 埃斯顿机器人编程实例 (取板机械手)
    1,变量定义(此处都定义为全局变量)    2,以下内容为具体程序  ①主程序Start://初始化CALLrInitalWHILE(true)DOCALLrPick1CALLrPla......
  • Winform中在Program.cs中初始化的变量(Sqlite连接实例)等再Form1.cs中访问
    场景部分场景下需要在Winform启动时执行一些初始化的操作。比如这里的执行创建Sqlte数据库和表的操作,为了操作数据库封装了工具类,这个工具类实例怎样在其他页面比如Form......
  • 轻松玩转makefile | 函数的使用
    前言在上一篇文章中,尽管使用了变量和模式,但还是有不够好的地方,在Makefile中要指明每一个源文件,我们接下来利用函数对其进行优化,并介绍其他常用的一些函数。依旧是以fun.c......
  • 我们软件与钉钉集成调用的实例测试效果
    我们的软件已经完成阿里钉钉的接口集成工作。下面是调用接口获取到的查询结果图示:......
  • Web安全入门与靶场实战二(2)- 实例解释HTTP状态码
    在HTTP响应头中有一部分非常重要的信息就是响应行中的状态码。状态码都是由三位数字组成,比如状态码200表示请求成功。状态码主要分为5个大类: 1xx:100-101,指示信息。这种状......
  • 玩转GaussDB 中的SET操作符
    摘要:关系数据库中提供了一个关于集合的运算符SET操作符,其中包括以下操作:UNION/UNIONALL并集、INTERSECT交集、MINUS差集。本文分享自华为云社区《GaussDB中的SET操作......
  • Android图像处理实例解析
    一、概述本篇文章介绍的是关于Android图像处理相关的,主要有动态修改图像的色相、饱和度及亮度,颜色矩阵,图像像素点调整、图像矩阵实现图像的平移缩放等,Xfermode相关知识点,......
  • 轻松玩转makefile | 变量与模式
    前言本文通过简单的几个示例,以及对同一个Makefile进行几个版本的迭代,帮助快速的理解变量和模式规则的使用。1、回顾在上一篇文章中,我们使用Makefile编译fun.c和main.c这......
  • makefile
    makefile一、gccgcc是用来编译代码的编译器编译完后有一些常见的输出文件.a 静态库(文档).c 需要预处理的C语言源代码.h C语言源代码的头文件.i 经过预处理......
  • jmeter性能测试实例2解析--linux环境
    压测准备本地开发环境⽣成脚本,上传压测机器 (修改参数化文件路径、请求地址)内⽹环境,⾮GUI下压测停⽌其他⽆关资源进程压测机和被压测机器隔离(避免资源争夺:内存、CPU、......