构建工程化:多种不同的工程体系如何编写MakeFile

源码分析

核心MakeFile

这个 Makefile 是一个复杂的构建脚本,用于管理和构建一个大型项目。它包括多个目标、条件判断和递归调用 make 命令来处理多个子项目和子目录。让我们逐部分进行详细解析。

伪目标和变量定义

makefile 复制代码
.PHONY: all clean install build test init
  • .PHONY 目标声明了 allcleaninstallbuildtestinit 是伪目标,不对应实际文件。
makefile 复制代码
PLATDIRS = newbuild so fantom share party www update var SIP-INSTALLROOT linux
CLEANDIRS = $(PLATDIRS) apps
  • PLATDIRSCLEANDIRS 是目录列表变量,用于后续的构建和清理操作。

模式规则

makefile 复制代码
%.all :
	cd $* && $(MAKE)
%.clean :
	cd $* && $(MAKE) clean
%.build :
	cd $* && $(MAKE) build
  • 这三条规则定义了通用目标规则,对于目录列表中的每个目录,会进入该目录并执行相应的 make 目标(allcleanbuild)。

clean 目标

makefile 复制代码
clean:
	rm -rf $(BUILD)/fantom
	make $(patsubst %, %.clean, $(CLEANDIRS))
  • clean 目标删除 $(BUILD)/fantom 目录,并调用 make 命令清理 CLEANDIRS 列表中的每个目录。

平台预构建目标

makefile 复制代码
build_plat_pre:
	@chmod +x $(ROOT)/update/setbaseversion	
	@if [ ! -d $(BUILDROOT) ]; then mkdir -p $(BUILDROOT) ; fi
	@if [ ! -d $(BUILDROOT)/newbuild ]; then mkdir -p $(BUILDROOT)/newbuild ; fi
	@if [ ! -d $(BUILDROOT)/apps ]; then mkdir -p $(BUILDROOT)/apps ; fi
	@if [ ! -d $(BUILDROOT)/bin ]; then mkdir -p $(BUILDROOT)/bin ; fi
	@if [ ! -d $(BUILDROOT)/party ]; then mkdir -p $(BUILDROOT)/party ; fi
	@if [ ! -d $(BUILDROOT)/share/lib ]; then mkdir -p $(BUILDROOT)/share/lib ; fi
	@if [ ! -d $(BUILDROOT)/share/Python-2.7/lib ]; then mkdir -p $(BUILDROOT)/share/Python-2.7/lib ; fi
  • build_plat_pre 目标进行了一些预构建任务,包括设置文件权限和创建所需目录。

应用列表和目标

makefile 复制代码
sis_apps_list = accessskeleton coengine dnsdetect ngfw saas secvisual server_anomaly super \
			wskiller update secdetect dgadetect httpdetector scandetect beforehanddetect \
			cloud_report webshelldetect wxscandetect brutedetect dosdetect netflow_forensic smbdetect \
			mailector secevent sec_dnsdetect sec_httpdetect sec_maildetect sec_netdetect sec_secdetect \
			sec_smbdetect sec_tidnsdetect sec_tihttpdetect sec_tiipdetect sec_thirdparty infoshare monitor \
			sec_filedetect sec_threatdetect documents agent
ifndef NO_SECLIB
sis_apps_list += seclib
endif
SISAPPS = $(patsubst %, apps/%, $(sis_apps_list))
  • sis_apps_list 定义了一个应用列表,包含多个应用名。
  • 如果未定义 NO_SECLIB,则将 seclib 添加到应用列表中。
  • SISAPPSsis_apps_list 转换为带有 apps/ 前缀的格式。

平台打包前置任务

makefile 复制代码
plat_sis_pre:
	@python $(ROOT)/apps/super/plat/plat.py $(ROOT)/apps/super/plat/sis/plugins.conf
  • plat_sis_pre 目标运行一个 Python 脚本,用于配置或预处理。

平台打包

makefile 复制代码
plat_sis: plat_sis_pre plat_fantom $(SISAPPS:=.build)
  • plat_sis 目标依赖于 plat_sis_preplat_fantom 和所有 SISAPPS.build 目标。

云平台应用列表和目标

makefile 复制代码
cloud_apps_list = super cloud_report
CLOUDAPPS = $(patsubst %, apps/%, $(cloud_apps_list))
  • cloud_apps_list 定义了云平台的应用列表。
  • CLOUDAPPScloud_apps_list 转换为带有 apps/ 前缀的格式。
makefile 复制代码
plat_cloud_pre:
	@python $(ROOT)/apps/super/plat/plat.py $(ROOT)/apps/super/plat/cloud/plugins.conf
  • plat_cloud_pre 目标运行一个 Python 脚本,用于云平台的预处理。
makefile 复制代码
plat_cloud: plat_cloud_pre plat_fantom $(CLOUDAPPS:=.build)
  • plat_cloud 目标依赖于 plat_cloud_preplat_fantom 和所有 CLOUDAPPS.build 目标。

平台基础内容打包

makefile 复制代码
plat_fantom: build_plat_pre $(PLATDIRS:=.build)
	@cd $(BUILD) && tar -czf fantom.tar.gz fantom
  • plat_fantom 目标依赖于 build_plat_pre 和所有 PLATDIRS.build 目标。
  • 它会进入 $(BUILD) 目录并将 fantom 目录打包成 fantom.tar.gz

应用打包预处理

makefile 复制代码
build_apps_pre:
	@if [ ! -d "$(BUILDROOT)/apps" ]; then mkdir -p "$(BUILDROOT)/apps" ; fi
  • build_apps_pre 目标确保 $(BUILDROOT)/apps 目录存在。

应用打包

makefile 复制代码
plat_apps: build_apps_pre
ifdef NAME
	@if [ -d $(ROOT)/apps/$(NAME) ]; then \
		cd "$(ROOT)/apps/$(NAME)" && make build; 	\
		cd "$(ROOT)/update" && make build; 	\
		cd $(BUILD)/fantom/apps/ && tar -czf $(NAME).tar.gz $(NAME);	\
		mv $(NAME).tar.gz $(BUILD);\
	else \
		echo "App $(NAME) not exists";	\
	fi
else
endif
  • plat_apps 目标依赖于 build_apps_pre

  • 如果定义了 NAME 变量并且 $(ROOT)/apps/$(NAME) 目录存在,则

    • 进入 $(ROOT)/apps/$(NAME) 并执行 make build
    • 进入 $(ROOT)/update 并执行 make build
    • $(BUILD)/fantom/apps/$(NAME) 目录打包成 $(NAME).tar.gz,并移动到 $(BUILD) 目录。
  • 如果 $(ROOT)/apps/$(NAME) 目录不存在,则输出错误信息。

总结

这个 Makefile 用于构建和打包一个复杂的项目,包含多个应用和平台组件。它通过定义变量和模式规则来管理不同的构建任务,并使用条件判断和递归调用 make 命令来处理各个子目录和应用的构建过程。

php

makefile 复制代码
TYPE = dir

ifdef NO_SECLIB
dirs := $(shell find . -maxdepth 1 -path ./seclib -prune -o -type d -print)
else
dirs := $(shell find . -maxdepth 1 -type d)
endif

dirs := $(basename $(patsubst ./%,%,$(dirs)))

SUBDIRS = $(dirs)

include $(MAKEFILEDIR)/Makefile.$(TYPE)

这个 Makefile 代码片段通过使用条件和 shell 命令来动态生成子目录列表,并根据一个特定的类型包含相应的 Makefile。让我们逐行解析这个 Makefile 片段

代码解析

makefile 复制代码
TYPE = dir
  • 这行定义了一个变量 TYPE,其值为 dir。这个变量在后续的 include 语句中被使用。
makefile 复制代码
ifdef NO_SECLIB
dirs := $(shell find . -maxdepth 1 -path ./seclib -prune -o -type d -print)
else
dirs := $(shell find . -maxdepth 1 -type d)
endif
  • 这里使用了条件判断 ifdef 来检测是否定义了 NO_SECLIB 变量。

  • 如果定义了 NO_SECLIB,则执行第一条命令

    makefile 复制代码
    dirs := $(shell find . -maxdepth 1 -path ./seclib -prune -o -type d -print)
    • 这条命令使用 find 命令查找当前目录(不包括子目录)的所有目录,但排除了 ./seclib 目录。
    • -maxdepth 1 限制查找深度为当前目录。
    • -path ./seclib -prune 用于排除 ./seclib 目录。
    • -o -type d -print 查找类型为目录并打印路径。
  • 否则(如果未定义 NO_SECLIB),则执行第二条命令

    makefile 复制代码
    dirs := $(shell find . -maxdepth 1 -type d)
    • 这条命令使用 find 命令查找当前目录(不包括子目录)的所有目录。
makefile 复制代码
dirs := $(basename $(patsubst ./%,%,$(dirs)))
  • 这行代码使用了 patsubstbasename 函数对 dirs 变量进行处理

    • $(patsubst ./%,%,$(dirs)) 移除每个目录路径前面的 ./ 前缀。
    • $(basename $(patsubst ./%,%,$(dirs))) 进一步处理每个目录路径,只保留目录名称。
makefile 复制代码
SUBDIRS = $(dirs)
  • 将处理后的目录列表赋值给变量 SUBDIRS
makefile 复制代码
include $(MAKEFILEDIR)/Makefile.$(TYPE)
  • 包含另一个 Makefile 文件。文件的路径和名称由 $(MAKEFILEDIR)/Makefile.$(TYPE) 决定。
    • $(MAKEFILEDIR) 是另一个变量,通常在其他地方定义,用于指定 Makefile 文件所在的目录。
    • $(TYPE) 变量的值为 dir,所以这行等价于 include $(MAKEFILEDIR)/Makefile.dir

总结

这个 Makefile 片段的目的是

  • 动态生成当前目录下的子目录列表,并处理排除某些特定目录(如 seclib)。
  • 处理目录路径,将它们标准化为不带 ./ 前缀的格式。
  • 将处理后的目录列表赋值给 SUBDIRS 变量。
  • 根据 TYPE 变量的值,包含另一个 Makefile 文件,便于分层和模块化管理构建过程。

通过这种方式,可以根据不同的条件动态调整构建过程,灵活应对各种需求和依赖关系。

python

makefile 复制代码
TYPE = app

SUBDIRS =

.PHONY: build clean

appversion=`date "+%Y%m%d/%H:%M:%S"`

build:
	@find ./appserver -name .svn | xargs rm -rf
	@find ./bin -name .svn | xargs rm -rf
	@find ./default -name .svn | xargs rm -rf
	@find ./lib -name .svn | xargs rm -rf
	@find ./local -name .svn | xargs rm -rf
	@find ./var -name .svn | xargs rm -rf
	@find ./meta-info -name .svn | xargs rm -rf
	
	@rwini -w -s info -k version -f libinfo -v $(appversion)
	
	@mkdir -p ./patch0/$(notdir $(CURDIR))
	@mv -f ./appserver ./patch0/$(notdir $(CURDIR))/appserver
	@mv -f ./bin ./patch0/$(notdir $(CURDIR))/bin
	@mv -f ./default ./patch0/$(notdir $(CURDIR))/default
	@mv -f ./lib ./patch0/$(notdir $(CURDIR))/lib
	@mv -f ./local ./patch0/$(notdir $(CURDIR))/local
	@mv -f ./var ./patch0/$(notdir $(CURDIR))/var
	@cp -rf ./libinfo ./patch0/$(notdir $(CURDIR))/libinfo
	@cp -rf ./meta-info/update ./patch0
	@cp -rf ./meta-info ./patch0/$(notdir $(CURDIR))/meta-info
	
	@zip -r -q $(notdir $(CURDIR)).zip patch0 libinfo meta-info
	@rm -rf ./libinfo
	@rm -rf ./meta-info
	@rm -rf ./patch0
	
	@if [ ! -d "$(BUILDROOT)/apps/$(notdir $(CURDIR))" ]; then mkdir -p "$(BUILDROOT)/apps/$(notdir $(CURDIR))" ; fi
	@rsync -r . "$(BUILDROOT)/apps/$(notdir $(CURDIR))" --exclude="Makefile" --exclude='.svn/'
clean:
	@rm -f $(notdir $(CURDIR)).zip

这个 Makefile 定义了两个主要目标
buildclean。它主要用于清理项目目录中的 .svn 文件夹、更新版本信息、组织项目文件,并将其打包成压缩文件。下面是对每一部分的详细解析

变量和伪目标

makefile 复制代码
TYPE = app
SUBDIRS =
.PHONY: build clean
  • TYPE = app
    定义了一个变量 TYPE,其值为 app。虽然在这个 Makefile 中没有进一步使用,但它可以用来在包含的其他 Makefile 中使用。
  • SUBDIRS =
    定义了一个空的 SUBDIRS 变量。在这个 Makefile 中没有实际使用。
  • .PHONY: build clean
    声明了两个伪目标 buildclean,这表示这些目标不是实际的文件名,而是任务名称。

版本信息

makefile 复制代码
appversion=`date "+%Y%m%d/%H:%M:%S"`
  • appversion 变量用来保存当前的日期和时间,格式为 YYYYMMDD/HH:MM:SS。这个变量会用于更新版本信息。

build 目标

makefile 复制代码
build:
	@find ./appserver -name .svn | xargs rm -rf
	@find ./bin -name .svn | xargs rm -rf
	@find ./default -name .svn | xargs rm -rf
	@find ./lib -name .svn | xargs rm -rf
	@find ./local -name .svn | xargs rm -rf
	@find ./var -name .svn | xargs rm -rf
	@find ./meta-info -name .svn | xargs rm -rf
	@rwini -w -s info -k version -f libinfo -v $(appversion)
	@mkdir -p ./patch0/$(notdir $(CURDIR))
	@mv -f ./appserver ./patch0/$(notdir $(CURDIR))/appserver
	@mv -f ./bin ./patch0/$(notdir $(CURDIR))/bin
	@mv -f ./default ./patch0/$(notdir $(CURDIR))/default
	@mv -f ./lib ./patch0/$(notdir $(CURDIR))/lib
	@mv -f ./local ./patch0/$(notdir $(CURDIR))/local
	@mv -f ./var ./patch0/$(notdir $(CURDIR))/var
	@cp -rf ./libinfo ./patch0/$(notdir $(CURDIR))/libinfo
	@cp -rf ./meta-info/update ./patch0
	@cp -rf ./meta-info ./patch0/$(notdir $(CURDIR))/meta-info
	@zip -r -q $(notdir $(CURDIR)).zip patch0 libinfo meta-info
	@rm -rf ./libinfo
	@rm -rf ./meta-info
	@rm -rf ./patch0
	@if [ ! -d "$(BUILDROOT)/apps/$(notdir $(CURDIR))" ]; then mkdir -p "$(BUILDROOT)/apps/$(notdir $(CURDIR))" ; fi
	@rsync -r . "$(BUILDROOT)/apps/$(notdir $(CURDIR))" --exclude="Makefile" --exclude='.svn/'
清理 .svn 文件夹
  • 使用 find 命令查找并删除各个目录下的 .svn 文件夹,这些文件夹是 Subversion (SVN) 版本控制系统的目录,不需要打包到最终的发布版本中。
更新版本信息
  • 使用 rwini 命令更新 libinfo 文件中的版本信息,rwini 是一个假设的工具,用于写入 INI 文件格式中的值。具体操作是设置 [info] 节点中的 version 键为当前时间。
组织项目文件
  • 创建一个名为 patch0 的目录,并将各个子目录(如 appserverbindefaultliblocalvar)移动到 patch0/$(notdir $(CURDIR)) 中。
    • $(notdir $(CURDIR)) 获取当前目录的名称(不包括路径),例如,如果当前目录是 /home/user/project,则 $(notdir $(CURDIR)) 会得到 project
复制和压缩文件
  • libinfometa-info 目录复制到 patch0 下的相应位置。
  • 使用 zip 命令将 patch0libinfometa-info 压缩成一个 zip 文件,名称为当前目录名称加 .zip(例如 project.zip)。
  • 删除 libinfometa-infopatch0 目录。
同步文件
  • 如果 $(BUILDROOT)/apps/$(notdir $(CURDIR)) 目录不存在,则创建它。
  • 使用 rsync 命令将当前目录的内容(除了 Makefile.svn 文件夹)同步到 $(BUILDROOT)/apps/$(notdir $(CURDIR)) 目录。

clean 目标

makefile 复制代码
clean:
	@rm -f $(notdir $(CURDIR)).zip
  • 删除以当前目录名称命名的 zip 文件(例如 project.zip)。

总结

  • 这个 Makefile 主要用于清理项目目录中的 .svn 文件夹,更新版本信息,组织和打包项目文件,并将其同步到一个特定的构建目录。
  • build 目标执行了所有这些步骤,而 clean 目标仅删除生成的 zip 文件。
  • 使用了 shell 命令和 rwini 工具来处理文件和目录,动态生成版本信息,并打包和同步项目文件。
相关推荐
wuk9988 分钟前
基于MATLAB编制的锂离子电池伪二维模型
linux·windows·github
DuelCode24 分钟前
Windows VMWare Centos Docker部署Springboot 应用实现文件上传返回文件http链接
java·spring boot·mysql·nginx·docker·centos·mybatis
优创学社229 分钟前
基于springboot的社区生鲜团购系统
java·spring boot·后端
幽络源小助理36 分钟前
SpringBoot基于Mysql的商业辅助决策系统设计与实现
java·vue.js·spring boot·后端·mysql·spring
猴哥源码37 分钟前
基于Java+springboot 的车险理赔信息管理系统
java·spring boot
YuTaoShao1 小时前
【LeetCode 热题 100】48. 旋转图像——转置+水平翻转
java·算法·leetcode·职场和发展
Dcs2 小时前
超强推理不止“大”——手把手教你部署 Mistral Small 3.2 24B 大模型
java
东阳马生架构2 小时前
订单初版—1.分布式订单系统的简要设计文档
java
Code blocks2 小时前
使用Jenkins完成springboot项目快速更新
java·运维·spring boot·后端·jenkins
荔枝吻3 小时前
【沉浸式解决问题】idea开发中mapper类中突然找不到对应实体类
java·intellij-idea·mybatis