关于人工智能:轻松玩转Makefile-企业项目级Makefile实例

48次阅读

共计 6061 个字符,预计需要花费 16 分钟才能阅读完成。

前言

本文展现了一个比拟残缺的企业我的项目级别的 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 $@

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

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

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

正文完
 0