前言
本文展现了一个比拟残缺的企业我的项目级别的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_GCCelseCOMPILEMACRO += COMPILER_IS_LINUX_GCC MACRO_DEFendif#循环获取源文件和中间件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 := gccCFLAGS := -Wall -cRM := rmRMFLAGS := -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 ......compilingcreated ../code/src/func/fun.oend ../code/src/func/fun.c ......compiled okstart ../code/src/com/main.c ......compilingcreated ../code/src/com/main.oend ../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_GCCelseCOMPILEMACRO += COMPILER_IS_LINUX_GCC MACRO_DEFendifCURCMPLMACRO := $(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/libsLIBFILE := -lmylib$(TARGETNAME):$(OBJFILE) @$(CC) -o $(OUTPUTDIR)/$(TARGETNAME).$(APPVERSION) $(OBJFILE) -L$(LIBFILEDIRS) $(LIBFILE)
将库文件的名字和寄存门路独自用变量示意
4.8 编译选项
CC := gccCFLAGS := -Wall -cRM := rmRMFLAGS := -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 $@
———————————————————————————————
码字不易,点个赞再走吧!
欢送关注我的同名公众号,这里有更多好料等着你哦!