文前说明
作为码农中的一员,需要不断的学习,我工作之余将一些分析总结和学习笔记写成博客与大家一起交流,也希望采用这种方式记录自己的学习之旅。
本文仅供学习交流使用,侵权必删。
不用于商业目的,转载请注明出处。
分析整理的版本为 Ovirt 3.4.5 版本。
1. 概述
- 一个工程中的源文件不计其数,其按类型、功能、模块分别放在若干个目录中,通过 Makefile 可以定义一系列的规则来指定复杂的功能操作。
- make 命令工具,它可以解释 Makefile 中的指令,这样 Makefile 可以像 shell 脚本一样,执行操作系统的命令。
- Makefile 文件中描述了整个工程所有文件的编译顺序、编译规则。
- Makefile 有自己的书写格式、关键字、函数。
- Makefile 在绝大多数的 IDE 开发环境中都在使用,已经成为一种工程的编译方法。
- Makefile 编写完成,只需要一个 make 命令,整个工程完全自动编译,极大的提高了软件开发的效率。
- make 命令工具最主要也是最基本的功能就是通过 Makefile 文件来描述源程序之间的相互关系并自动维护编译工作。
2. engine Makefile 原理分析
2.1 调试
warning 函数
- $(warning string)函数可以放在 Makefile 中的任何地方,执行该函数时,会将 string 输出,方便定位 make 执行到哪个位置。
命令行选项
- " -n "、" --just-print "、" --dry-run "、" --recon ",不管目标是否更新,把规则和连带规则下的命令打印出来,但不执行。
- " -t "、" --touch ",把目标文件的时间更新,但不更改目标文件,make 假装编译目标,但不是真正的编译目标,只是把目标变成已编译过的状态。
- " -q "、" --question ",如果目标存在,不输出,不执行编译,如果目标不存在,打印出一条出错信息。
- " -W
"、" --what-if= "、" --assume-new= "、" --new-file= ",参数需要指定一个文件。一般是是源文件(或依赖文件),make 会根据规则推导来运行依赖于这个文件的命令,一般来说,可以和 " -n " 参数一同使用,查看这个依赖文件所发生的规则命令。 - 最适合用来调试的命令行选项有。
- --just-print(-n),使 make 读进 Makefile 并且输出它更新工作目标时将会执行的命令,但是不会真的执行。
- --print-database(-p),会运行 Makefile,显示 GNU 版权信息以及 make 所运行的命令,然后输出它的内部数据库。
- --warn-undefined-variables,使得 make 在未定义的变量被扩展时显示警告信息。
--debug 选项
- 当需要知道 make 如何分析依存图时,可以使用 --debug 选项。
- 除了运行调试器,这个选项是获得最详细信息的另一个方法。
- 有五个调试选项以及一个修饰符可用,分别是 basic、verbose、implicit、jobs、all 以及 makefile。
- 调试选项被指定成 --debug,就是进行 basic 调试。
调试 | 说明 |
---|---|
basic | 信息最不详细的基本调试功能。启用时,make 会输出被发现尚未更新的工作目标并更新动作的状态。 |
verbose | 会启用 basic 选项功能,以及提供关于 " 哪些文件被分析、哪些必要条件不需要重建等 " 的额外信息。 |
implicit | 会启用 basic 选项功能,以及提供关于 " 为每个工作目标搜索隐含规则 " 的额外信息。 |
jobs | 会输出被 make 调用的子进程的细节,不会启用 basic 选项的功能。 |
all | 会启用所有选项,当使用 -d 选项时,默认会启用此功能。 |
makefile | 不会启用调试信息,直到 Makefile 被更新。包括更新任何的引入文件。如果使用此修饰符,make 会在重编译 Makefile 以及引入文件的时候,输出被选择的信息。这个选项会启用 basic 选项,all 选项也会启用此选项。 |
2.2 原理
- 通过 ovirt-engine 的 Makefile 文件可以编译整个 engine 的项目代码。
2.2.1 变量的自定义
engine Makefile 中的自定义变量 | 说明 |
---|---|
BUILD_GWT | 是否启用编译前端 GWT,默认值为 1 启用。 |
BUILD_GWT_USERPORTAL | 是否启用编译用户门户,默认值为 1 启用。 |
BUILD_GWT_WEBADMIN | 是否启用编译管理门户,默认值为 1 启用。 |
BUILD_LOCALES | 是否启用本地化处理,默认值为 0 不启用。 |
BUILD_DEV | 是否为开发编译,默认值为 0 不是。 |
BUILD_UT | 是否执行单元测试,默认值为 1 执行。 |
EXTRA_BUILD_FLAGS | 编译额外参数。 |
BUILD_VALIDATION | 是否编译验证,默认值 1 验证。 |
DEV_REBUILD | 重新执行开发编译标记,默认值 1。 |
DEV_BUILD_GWT_DRAFT | 开发编译阶段,是否启用 GWT 编译优化,默认值 0 不启用。 |
DEV_EXTRA_BUILD_FLAGS | 开发编译额外参数。 |
DEV_EXTRA_BUILD_FLAGS_GWT_DEFAULTS | 开发编译额外的 GWT 参数默认值,默认值 -D gwt.userAgent=gecko1_8,只编译火狐浏览器。 |
PACKAGE_NAME | 包名,默认值 ovirt-engine。 |
ENGINE_NAME | 引擎名称,与包名一致。 |
MVN | mvn 命令,Makefile 文件中可用 $(MVN) 调用执行。 |
RPMBUILD | rpmbuild 命令, Makefile 文件中可用 $(RPMBUILD) 调用执行。 |
PYTHON | python 命令,Makefile 文件中可用 $(PYTHON) 调用执行。 |
PYFLAKES | pyflakes 命令,Makefile 文件中可用 $(PYFLAKES) 调用执行,是用于测试 python 源码的工具。 |
PEP8 | pep8 命令,Makefile 文件中可用 $(PEP8) 调用执行,是用于 python 规范格式检查。 |
PREFIX | 编译至目录的前缀,默认值为 /usr/local,编译后的文件放置在 /usr/local 这个目录下。 |
LOCALSTATE_DIR | 本地状态文件目录,默认值 $(PREFIX)/var。 |
BIN_DIR | 执行目录,默认值 $(PREFIX)/bin。 |
PID_DIR | PID 文件目录,默认值 $(LOCALSTATE_DIR)/run。 |
SYSCONF_DIR | 系统配置目录,默认值 $(PREFIX)/etc。 |
DATAROOT_DIR | 数据目录,默认值 $(PREFIX)/share。 |
MAN_DIR | MAN 目录,默认值 $(DATAROOT_DIR)/man。 |
DOC_DIR | 文档目录,默认值 $(DATAROOT_DIR)/doc。 |
DATA_DIR | engine 数据目录,默认值 $(DATAROOT_DIR)/$(ENGINE_NAME)。 |
MAVENPOM_DIR | maven pom 目录,默认值 $(DATAROOT_DIR)/maven-poms。 |
JAVA_DIR | java 目录,默认值 $(DATAROOT_DIR)/java。 |
PKG_SYSCONF_DIR | engine 配置目录,默认值 $(SYSCONF_DIR)/$(ENGINE_NAME)。 |
PKG_PKI_DIR | engine PKI 配置目录,默认值 $(SYSCONF_DIR)/pki/$(ENGINE_NAME)。 |
PKG_DOC_DIR | engine 文档目录,默认值 $(DOC_DIR)/$(ENGINE_NAME)。 |
PKG_EAR_DIR | engine ear 目录,默认值 $(DATA_DIR)/engine.ear。 |
PKG_JBOSS_MODULES | Jboss modules 目录,默认值 $(DATA_DIR)/modules。 |
PKG_CACHE_DIR | 缓存文件目录,默认值 $(LOCALSTATE_DIR)/cache/$(ENGINE_NAME)。 |
PKG_LOG_DIR | 日志目录,默认值 $(LOCALSTATE_DIR)/log/$(ENGINE_NAME)。 |
PKG_STATE_DIR | 状态目录,默认值 $(LOCALSTATE_DIR)/lib/$(ENGINE_NAME)。 |
PKG_TMP_DIR | 临时文件目录,默认值 $(LOCALSTATE_DIR)/tmp/$(ENGINE_NAME)。 |
JBOSS_HOME | Jboss 目录,默认值 /usr/share/jboss-as。 |
JBOSS_RUNTIME | Jboss 运行目录,默认值 $(PKG_STATE_DIR)/jboss_runtime。 |
PYTHON_DIR | $(PYTHON_SYS_DIR) 变量定义的目录。 |
DEV_PYTHON_DIR | 开发编译阶段 python 目录。 |
PKG_USER | 执行用户,默认值 ovirt。 |
PKG_GROUP | 执行组,默认值 ovirt。 |
2.2.2 版本的定义
- 引入版本描述文件。
include version.mak
[test@localhost engine]$ cat version.mak
# Version Information
# Major and minor are taken from pom.xml
# Fix release is manually specified,
# increment after releasing/branching
FIX_RELEASE=5
# Milestone is manually specified,
# example for ordering:
# - master
# - alpha
# - master
# - beta
# - master
# - beta2
# - master
# - rc
# - master
# - rc2
# - master
# -
#
MILESTONE=
# RPM release is manually specified,
# For pre-release:
# RPM_RELEASE=0.N.$(MILESTONE).$(shell date -u +%Y%m%d%H%M%S)
# While N is incremented when milestone is changed.
#
# For release:
# RPM_RELEASE=N
# while N is incremented each re-release
#
RPM_RELEASE=0.0.$(MILESTONE).$(shell date -u +%Y%m%d%H%M%S)
#
# Downstream only release prefix
# Downstream (mead) does not use RPM_RELEASE but internal
# mead versioning.
# Increment the variable bellow after every milestone is
# released.
# Or leave empty to have only mead numbering.
#
DOWNSTREAM_RPM_RELEASE_PREFIX=0.
POM_VERSION
- 获取 pom 文件的版本信息,值为 3.4.5。
# POM_VERSION:=$(shell cat pom.xml | grep '' | sed -e 's/.*>\(.*\)<.*/\1/' -e 's/-SNAPSHOT//')
[test@localhost engine]$ cat pom.xml | grep '' | sed -e 's/.*>\(.*\)<.*/\1/' -e 's/-SNAPSHOT//'
3.4.5
- $(shell
) 可以执行 shell 命令。
赋值运算符 | 说明 |
---|---|
= | 最基本的赋值。 |
:= | 覆盖之前的值。 |
?= | 如果没有被赋值过就赋予等号后面的值。 |
+= | 添加等号后面的值。 |
- " = " 赋值,变量的值将会是整个 Makefile 中最后被指定的值。
x = foo
y = $(x) bar
x = xyz
# y 的值是 xyz bar。
- " := " 赋值,变量的值决定于它在 Makefile 中的位置。
x = foo
y := $(x) bar
x = xyz
# y 的值是 foo bar。
APP_VERSION
- 获取软件版本信息,值为 3.4.5。
# APP_VERSION=$(shell echo $(POM_VERSION) | sed 's/\([^.]*\.[^.]\)\..*/\1/').$(FIX_RELEASE)
[test@localhost engine]$ echo 3.4.5 | sed 's/\([^.]*\.[^.]\)\..*/\1/'
3.4
RPM_VERSION
- RPM 包版本与软件版本信息一致,值为 3.4.5。
RPM_VERSION=$(APP_VERSION)
PACKAGE_VERSION
- 软件包版本。(如果包含里程碑信息,可以追加)
PACKAGE_VERSION=$(APP_VERSION)$(if $(MILESTONE),_$(MILESTONE))
DISPLAY_VERSION
- 显示版本。
DISPLAY_VERSION=$(PACKAGE_VERSION)
2.2.3 编译参数的组装
条件判断
- 条件判断语句只能用于 控制 make 实际执行的语言,但是 不能控制规则中命令的执行过程。
关键字 | 说明 |
---|---|
ifeq | 判断参数是否相等,相等返回 true,否则 false。 |
ifneq | 判断参数是否不相等,不相等返回 true,否则 false。 |
ifdef | 判断变量是否有值,有值为 true,否则 false。 |
ifndef | 判断变量是否没有值,没有值为 true,否则 false。 |
- 条件判断语句之间可以有空格,但不能有 Tab 字符(\t)。
- 条件语句中不能使用自动变量($@,@^,$<)。
- 一条完整的条件语句必须位于同一个 Makefile 中。
- 条件判断类似C语言中的宏,预处理阶段有效,执行阶段无效。
- make 在加载 Makefile 时,首先计算表达式的值(赋值方式不同,计算方式不同),然后根据 判断语句的表达式 决定执行的内容。
开发编译参数的组装
DEV_BUILD_FLAGS:=
ifneq ($(DEV_BUILD_GWT_DRAFT),0)
DEV_BUILD_FLAGS:=$(DEV_BUILD_FLAGS) -P gwtdraft
endif
DEV_BUILD_FLAGS:=$(DEV_BUILD_FLAGS) $(DEV_EXTRA_BUILD_FLAGS_GWT_DEFAULTS)
DEV_BUILD_FLAGS:=$(DEV_BUILD_FLAGS) $(DEV_EXTRA_BUILD_FLAGS)
- 如果开发编译阶段 GWT 优化启用,添加参数 -P gwtdraft。
- 添加开发编译额外的 GWT 默认参数和开发编译额外参数。
编译参数的组装
BUILD_FLAGS:=
ifneq ($(BUILD_GWT),0)
ifneq ($(BUILD_GWT_USERPORTAL),0)
BUILD_FLAGS:=$(BUILD_FLAGS) -P gwt-user
endif
ifneq ($(BUILD_GWT_WEBADMIN),0)
BUILD_FLAGS:=$(BUILD_FLAGS) -P gwt-admin
endif
endif
ifneq ($(BUILD_LOCALES),0)
BUILD_FLAGS:=$(BUILD_FLAGS) -D gwt.locale=en_US,zh_CN
endif
ifeq ($(BUILD_UT),0)
BUILD_FLAGS:=$(BUILD_FLAGS) -D skipTests
endif
ifneq ($(BUILD_DEV),0)
BUILD_FLAGS:=$(BUILD_FLAGS) $(DEV_BUILD_FLAGS)
endif
BUILD_FLAGS:=$(BUILD_FLAGS) $(EXTRA_BUILD_FLAGS)
- 如果开启了 GWT 编译,再判断是否开启用户门户和管理门户的编译,根据开关不同,组装 -P gwt-user 和 -P gwt-admin 的参数。
- 如果开启了本地化编译,组装 -D gwt.locale=en_US,zh_CN,编译中文和英文。
- 如果开启了单元测试,组装 -D skipTests 参数。
- 如果开启了开发编译,组装开发编译的一些参数。
- 最后组装编译的额外参数。
其他组装
PYTHON_SYS_DIR:=$(shell $(PYTHON) -c "from distutils.sysconfig import get_python_lib as f;print(f())")
OUTPUT_RPMBUILD=$(shell pwd -P)/tmp.rpmbuild
OUTPUT_DIR=output
TARBALL=$(PACKAGE_NAME)-$(PACKAGE_VERSION).tar.gz
ARCH=noarch
BUILD_FILE=tmp.built
MAVEN_OUTPUT_DIR=.
BUILD_TARGET=install
- 获取 python 系统命令目录。
[test@localhost engine]$ python -c "from distutils.sysconfig import get_python_lib as f;print(f())"
/usr/lib/python2.7/site-packages
- rpmbuild 输出。
OUTPUT_RPMBUILD=$(shell pwd -P)/tmp.rpmbuild
# /root/rpmbuild/BUILD/ovirt-engine/tmp.rpmbuild
- 输出目录。
OUTPUT_DIR=output
- 打包 Tar 包名称。
TARBALL=$(PACKAGE_NAME)-$(PACKAGE_VERSION).tar.gz
# ovirt-engine-3.4.5.tar.gz
- 软件架构。
ARCH=noarch
- 编译文件。
BUILD_FILE=tmp.built
- maven 输出目录。
MAVEN_OUTPUT_DIR=.
- 编译 Tar 命令。(install 是一个函数)
BUILD_TARGET=install
2.2.4 后缀自定义规则
.SUFFIXES:
.SUFFIXES: .in
.in:
sed \
-e "s|@ENGINE_DEFAULTS@|$(DATA_DIR)/services/ovirt-engine/ovirt-engine.conf|g" \
-e "s|@ENGINE_VARS@|$(PKG_SYSCONF_DIR)/engine.conf|g" \
-e "s|@ENGINE_SETUP_VARS@|$(SYSCONF_DIR)/ovirt-engine-setup.conf|g" \
-e "s|@ENGINE_NOTIFIER_VARS@|$(PKG_SYSCONF_DIR)/notifier/notifier.conf|g" \
-e "s|@ENGINE_WSPROXY_VARS@|$(PKG_SYSCONF_DIR)/ovirt-websocket-proxy.conf|g" \
-e "s|@ENGINE_USER@|$(PKG_USER)|g" \
-e "s|@ENGINE_GROUP@|$(PKG_GROUP)|g" \
-e "s|@ENGINE_ETC@|$(PKG_SYSCONF_DIR)|g" \
-e "s|@ENGINE_PKI@|$(PKG_PKI_DIR)|g" \
-e "s|@ENGINE_LOG@|$(PKG_LOG_DIR)|g" \
-e "s|@ENGINE_TMP@|$(PKG_TMP_DIR)|g" \
-e "s|@ENGINE_USR@|$(DATA_DIR)|g" \
-e "s|@ENGINE_DOC@|$(PKG_DOC_DIR)|g" \
-e "s|@ENGINE_VAR@|$(PKG_STATE_DIR)|g" \
-e "s|@ENGINE_CACHE@|$(PKG_CACHE_DIR)|g" \
-e "s|@ENGINE_PID@|$(PID_DIR)/$(ENGINE_NAME).pid|g" \
-e "s|@DEV_PYTHON_DIR@|$(DEV_PYTHON_DIR)|g" \
-e "s|@RPM_VERSION@|$(RPM_VERSION)|g" \
-e "s|@RPM_RELEASE@|$(RPM_RELEASE)|g" \
-e "s|@PACKAGE_NAME@|$(PACKAGE_NAME)|g" \
-e "s|@PACKAGE_VERSION@|$(PACKAGE_VERSION)|g" \
-e "s|@DISPLAY_VERSION@|$(DISPLAY_VERSION)|g" \
-e "s|@JBOSS_HOME@|$(JBOSS_HOME)|g" \
-e "s|@JBOSS_RUNTIME@|$(JBOSS_RUNTIME)|g" \
-e "s|@PEP8@|$(PEP8)|g" \
-e "s|@PYFLAKES@|$(PYFLAKES)|g" \
-e "s|@DEVMODE@|$(BUILD_DEV)|g" \
$< > $@
符号 | 说明 |
---|---|
$@ | 目标文件。 |
$< | 第一个依赖文件。 |
$^ | 所有的依赖文件。 |
$? | 比目标还要新的依赖文件列表。 |
$% | 仅当目标是函数库文件中,表示规则中的目标成员名。 |
$+ | 所有依赖目标的集合,与 $^ 类似,包含重复。 |
$* | 不包含扩展名的目标文件名称。 |
- 结合上述用例,将变量替换后,根据 .in 文件生成没有 .in 的文件,即 config.py.in 经过变量替换后生成 config.py 文件。
- 通过模板 后缀自定义规则 生成的文件列表。
GENERATED = \
ovirt-engine.spec \
build/python-check.sh \
packaging/bin/engine-prolog.sh \
packaging/bin/ovirt-engine-log-setup-event.sh \
packaging/bin/pki-common.sh \
packaging/etc/engine-manage-domains/engine-manage-domains.conf \
packaging/etc/engine.conf.d/README \
packaging/etc/notifier/log4j.xml \
packaging/etc/notifier/notifier.conf.d/README \
packaging/etc/ovirt-websocket-proxy.conf.d/README \
packaging/pythonlib/ovirt_engine/config.py \
packaging/services/ovirt-engine-notifier/config.py \
packaging/services/ovirt-engine-notifier/ovirt-engine-notifier.conf \
packaging/services/ovirt-engine-notifier/ovirt-engine-notifier.systemd \
packaging/services/ovirt-engine-notifier/ovirt-engine-notifier.sysv \
packaging/services/ovirt-engine/config.py \
packaging/services/ovirt-engine/ovirt-engine.conf \
packaging/services/ovirt-engine/ovirt-engine.systemd \
packaging/services/ovirt-engine/ovirt-engine.sysv \
packaging/services/ovirt-websocket-proxy/config.py \
packaging/services/ovirt-websocket-proxy/ovirt-websocket-proxy.conf \
packaging/services/ovirt-websocket-proxy/ovirt-websocket-proxy.systemd \
packaging/services/ovirt-websocket-proxy/ovirt-websocket-proxy.sysv \
packaging/setup/bin/ovirt-engine-setup.env \
packaging/setup/ovirt_engine_setup/config.py \
packaging/sys-etc/logrotate.d/ovirt-engine \
packaging/sys-etc/logrotate.d/ovirt-engine-notifier \
packaging/sys-etc/logrotate.d/ovirt-engine-setup \
$(NULL)
2.2.5 执行动作
- make 的基本规则。
target ... : prerequisites ...
command
....
....
- target 是目标文件, 可以是 Object File,可以是 可执行文件,还可是 标签。
- prerequisites 生成 target 所需的文件或目标。
- command make 需要执行的命令,可以是任何 shell 命令。
generated-files 标签
- 修改部分文件权限。
generated-files: $(GENERATED)
chmod a+x build/python-check.sh
chmod a+x packaging/services/ovirt-engine/ovirt-engine.sysv
chmod a+x packaging/services/ovirt-engine-notifier/ovirt-engine-notifier.sysv
chmod a+x packaging/services/ovirt-websocket-proxy/ovirt-websocket-proxy.sysv
chmod a+x packaging/bin/ovirt-engine-log-setup-event.sh
validations 标签
- 执行了文件的检查和验证。
validations: generated-files
if [ "$(BUILD_VALIDATION)" != 0 ]; then \
build/shell-check.sh && \
build/python-check.sh && \
build/dbscripts/check_for_duplicate_upgrade_scripts.sh; \
fi
maven 标签
- 执行 mvn 命令,生成 ${BUILD_FILE} 文件。
maven:
export MAVEN_OPTS="${MAVEN_OPTS} -XX:MaxPermSize=512m"
$(MVN) \
$(BUILD_FLAGS) \
$(BUILD_TARGET)
touch "$(BUILD_FILE)"
clean 标签
- 清除 mvn 命令生成的文件。
- 删除临时文件和通过模板后缀自定义规则生成的文件。
clean:
# Clean maven generated stuff:
$(MVN) clean $(EXTRA_BUILD_FLAGS)
rm -rf $(OUTPUT_RPMBUILD) $(OUTPUT_DIR) $(BUILD_FILE) tmp.dev.flist
# Clean files generated from templates:
rm -rf $(GENERATED)
test 标签
- 执行 mvn install 命令(mvn 命令可以查看 Maven 相关整理)。
test:
$(MVN) install $(BUILD_FLAGS) $(EXTRA_BUILD_FLAGS)
$(BUILD_FILE) 标签
# BUILD_FILE=tmp.built
$(BUILD_FILE):
$(MAKE) maven
install 标签
- 执行动作标签 all、install-layout、install_artifacts 和 install_poms。
install: \
all \
install-layout \
install_artifacts \
install_poms \
$(NULL)
all 标签
- 执行动作标签 generated-files、validations 和 $(BUILD_FILE)。
all: \
generated-files \
validations \
$(BUILD_FILE) \
$(NULL)
install-layout 标签
- install 命令的作用是安装或升级软件或备份数据,它的使用权限是所有用户。
- install 允许控制目标文件的属性。
- install 通常用于程序的 makefile,使用它来将程序拷贝到目标(安装)目录。
- 命令格式:install [OPTION]… [-T] SOURCE DEST。
install [OPTION]… -d DIRECTORY…。
参数 | 说明 |
---|---|
-backup[=CONTROL] | 为每个已存在 的目的地文件进行备份。 |
-b | 类似 -backup,但不接受任何参数。 |
-D, -compare | 比较每对源文件和目标文件,如果目的地具有相同的内容和任何指定的所有者,组,权限以及可能的 SELinux 上下文,那么不要修改目的地。 |
-d, -directory | 所有参数都作为目录处理,而且会创建指定目录的所有主目录。 |
-D | 创建 <目的地> 前的所有主目录,然后将 <来源> 复制至 <目的地>。在第一种格式中有用。 |
-g, -group=组 | 自行设定所属组,而不是进程目前的所属组。 |
-m, -mode=模式 | 自行设定权限模式,(像 chmod)。 |
-o, -owner | 自行设定权限所有者(只适用于超级用户)。 |
-p, -preserve-timestamp | 以 <来源> 文件的访问/修改时间作为相应的目的地文件的时间属性。 |
-s, -strip | 用 strip 命令删除 symbol table。 |
-S, -suffix=后缀 | 自定指定备份文件的后缀。 |
-v, -verbose | 处理每个文件/目录时印出名称。 |
-Z CONTEXT, -context=CONTEXT | 设置要用于任何创建的文件和目录的默认。SELinux 安全上下文,如果 SELinux 被禁用,则打印警告并忽略该选项。 |
-help | 显示此帮助信息并离开。 |
-version | 显示版本信息并离开。 |
install-layout: \
install-packaging-files \
$(NULL)
install -d -m 755 "$(DESTDIR)$(BIN_DIR)"
ln -sf "$(DATA_DIR)/setup/bin/ovirt-engine-setup" "$(DESTDIR)$(BIN_DIR)/engine-setup"
ln -sf "$(DATA_DIR)/setup/bin/ovirt-engine-remove" "$(DESTDIR)$(BIN_DIR)/engine-cleanup"
ln -sf "$(DATA_DIR)/setup/bin/ovirt-engine-upgrade-check" "$(DESTDIR)$(BIN_DIR)/engine-upgrade-check"
ln -sf "$(DATA_DIR)/bin/engine-config.sh" "$(DESTDIR)$(BIN_DIR)/engine-config"
ln -sf "$(DATA_DIR)/bin/engine-manage-domains.sh" "$(DESTDIR)$(BIN_DIR)/engine-manage-domains"
ln -sf "$(DATA_DIR)/bin/engine-backup.sh" "$(DESTDIR)$(BIN_DIR)/engine-backup"
install -d -m 755 "$(DESTDIR)$(PKG_PKI_DIR)/certs"
install -d -m 755 "$(DESTDIR)$(PKG_PKI_DIR)/keys"
install -d -m 750 "$(DESTDIR)$(PKG_PKI_DIR)/private"
install -d -m 755 "$(DESTDIR)$(PKG_PKI_DIR)/requests"
install -d -m 755 "$(DESTDIR)$(DATA_DIR)/ui-plugins"
install -d -m 755 "$(DESTDIR)$(PKG_SYSCONF_DIR)/branding"
install -d -m 750 "$(DESTDIR)$(PKG_STATE_DIR)/backups"
install -d -m 0755 "$(DESTDIR)$(DATA_DIR)/uploads"
install -d -m 0755 "$(DESTDIR)$(DATA_DIR)/files"
-rm -f "$(DESTDIR)$(DATA_DIR)/files/usbfilter.txt"
ln -s "$(PKG_SYSCONF_DIR)/usbfilter.txt" "$(DESTDIR)$(DATA_DIR)/files/usbfilter.txt"
-rm -f "$(DESTDIR)$(DATA_DIR)/files/novnc"
ln -s "/usr/share/novnc" "$(DESTDIR)$(DATA_DIR)/files/novnc"
-rm -f "$(DESTDIR)$(DATA_DIR)/files/spice-html5"
ln -s "/usr/share/spice-html5" "$(DESTDIR)$(DATA_DIR)/files/spice-html5"
install -d -m 755 "$(DESTDIR)$(PKG_SYSCONF_DIR)/branding"
-rm -f "$(DESTDIR)$(PKG_SYSCONF_DIR)/branding/00-ovirt.brand"
ln -s "$(DATA_DIR)/branding/ovirt.brand" "$(DESTDIR)$(PKG_SYSCONF_DIR)/branding/00-ovirt.brand"
ln -sf "$(DATA_DIR)/conf/osinfo-defaults.properties" "$(DESTDIR)$(PKG_SYSCONF_DIR)/osinfo.conf.d/00-defaults.properties"
ln -sf "$(DATA_DIR)/conf/osinfo-sdcos.properties" "$(DESTDIR)$(PKG_SYSCONF_DIR)/osinfo.conf.d/01-sdcos.properties"
- 创建目录、建立软链接、删除部分文件等等。
install-packaging-files 标签
install-packaging-files: \
$(GENERATED) \
$(NULL)
$(MAKE) copy-recursive SOURCEDIR=packaging/sys-etc TARGETDIR="$(DESTDIR)$(SYSCONF_DIR)" EXCLUDE_GEN="$(GENERATED)"
$(MAKE) copy-recursive SOURCEDIR=packaging/etc TARGETDIR="$(DESTDIR)$(PKG_SYSCONF_DIR)" EXCLUDE_GEN="$(GENERATED)"
$(MAKE) copy-recursive SOURCEDIR=packaging/pki TARGETDIR="$(DESTDIR)$(PKG_PKI_DIR)" EXCLUDE_GEN="$(GENERATED)"
for d in bin branding conf files firewalld services setup; do \
$(MAKE) copy-recursive SOURCEDIR="packaging/$${d}" TARGETDIR="$(DESTDIR)$(DATA_DIR)/$${d}" EXCLUDE_GEN="$(GENERATED)"; \
done
$(MAKE) copy-recursive SOURCEDIR=packaging/man TARGETDIR="$(DESTDIR)$(MAN_DIR)" EXCLUDE_GEN="$(GENERATED)"
$(MAKE) copy-recursive SOURCEDIR=packaging/pythonlib TARGETDIR="$(DESTDIR)$(PYTHON_DIR)" EXCLUDE_GEN="$(GENERATED)"
# we should avoid make these directories dirty
$(MAKE) copy-recursive SOURCEDIR=packaging/dbscripts TARGETDIR="$(DESTDIR)$(DATA_DIR)/dbscripts" \
EXCLUDE_GEN="$(GENERATED)" \
EXCLUDE="$$(echo $$(find packaging/dbscripts \( -name '*.scripts.md5' -or -name '*.schema' -or -name '*.log' \)))"
copy-recursive 标签
copy-recursive:
( cd "$(SOURCEDIR)" && find . -type d -printf '%P\n' ) | while read d; do \
install -d -m 755 "$(TARGETDIR)/$${d}"; \
done
( \
cd "$(SOURCEDIR)" && find . -type f -printf '%P\n' | \
while read f; do \
exclude=false; \
for x in $(EXCLUDE_GEN); do \
if [ "$(SOURCEDIR)/$${f}" = "$${x}.in" ]; then \
exclude=true; \
break; \
fi; \
done; \
for x in $(EXCLUDE); do \
if [ "$(SOURCEDIR)/$${f}" = "$${x}" ]; then \
exclude=true; \
break; \
fi; \
done; \
$${exclude} || echo "$${f}"; \
done \
) | while read f; do \
src="$(SOURCEDIR)/$${f}"; \
dst="$(TARGETDIR)/$${f}"; \
[ -x "$${src}" ] && MASK=0755 || MASK=0644; \
[ -n "$(DEV_FLIST)" ] && echo "$${dst}" | sed 's#^$(PREFIX)/##' >> "$(DEV_FLIST)"; \
install -T -m "$${MASK}" "$${src}" "$${dst}"; \
done
install_artifacts 标签
- 命令格式:unzip [-Z] [-cflptTuvz[abjnoqsCDKLMUVWX$/:^]] file[.zip] [file(s) ...] [-x xfile(s) ...] [-d exdir]
选项 | 说明 |
---|---|
-f | 更新现有的文件。 |
-l | 显示压缩文件内所包含的文件。 |
-p | 与 -c 参数类似,会将解压缩的结果显示到屏幕上,但不会执行任何的转换。 |
-t | 检查压缩文件是否正确。 |
-u | 与 -f 参数类似,但是除了更新现有的文件外,也会将压缩文件中的其他文件解压缩到目录中。 |
-v | 执行时显示详细的信息。 |
-z | 仅显示压缩文件的备注文字。 |
-a | 对文本文件进行必要的字符转换。 |
-b | 不要对文本文件进行字符转换。 |
-C | 压缩文件中的文件名称区分大小写。 |
-j | 不处理压缩文件中原有的目录路径。 |
-L | 将压缩文件中的全部文件名改为小写。 |
-M | 将输出结果送到 more 命令处理。 |
-n | 解压缩时不要覆盖原有的文件。 |
-o | 不必先询问用户,unzip 执行后覆盖原有的文件。 |
-P<密码> | 使用 zip 的密码选项。 |
-q | 执行时不显示任何信息。 |
-s | 将文件名中的空白字符转换为底线字符。 |
-V | 保留 VMS 的文件版本信息。 |
-X | 解压缩时同时回存文件原来的 UID/GID。 |
-d<目录> | 指定文件解压缩后所要存储的目录。 |
-x<文件> | 指定不要处理 .zip 压缩文件中的哪些文件。 |
-Z | unzip-Z 等于执行 zipinfo 指令。 |
install_artifacts:
# we must exclude tmp.repos directory so we
# won't get artifacts of older branches
# we should use search MAVEN_OUTPUT_DIR as it may contain
# pre-compiled artifacts at different hierarchy.
install -dm 0755 "$(DESTDIR)$(PKG_JBOSS_MODULES)"
find "$(MAVEN_OUTPUT_DIR)" -name '*-modules.zip' | grep -v tmp.repos | xargs -n 1 unzip -q -o -d "$(DESTDIR)$(PKG_JBOSS_MODULES)"
install -dm 0755 "$(DESTDIR)$(PKG_EAR_DIR)"
find "$(MAVEN_OUTPUT_DIR)" -name '*.ear' -type f | grep -v tmp.repos | xargs -n 1 unzip -q -o -d "$(DESTDIR)$(PKG_EAR_DIR)"
# extract embedded artifacts as doc
# no need to relay on source tree for these
install -d -m 755 "$(DESTDIR)$(PKG_DOC_DIR)"
unzip -q -c "$(DESTDIR)$(PKG_JBOSS_MODULES)/org/ovirt/engine/core/dal/main/dal.jar" bundles/AuditLogMessages.properties > \
"$(DESTDIR)$(PKG_DOC_DIR)/AuditLogMessages.properties"
chmod 0644 "$(DESTDIR)$(PKG_DOC_DIR)/AuditLogMessages.properties"
install_poms 标签
- 对个模块的 pom 文件进行处理。
install_poms:
install -dm 755 "$(DESTDIR)$(MAVENPOM_DIR)"
install -m 644 backend/manager/modules/bll/pom.xml "$(DESTDIR)$(MAVENPOM_DIR)/$(PACKAGE_NAME)-bll.pom"
install -m 644 backend/manager/modules/common/pom.xml "$(DESTDIR)$(MAVENPOM_DIR)/$(PACKAGE_NAME)-common.pom"
install -m 644 backend/manager/modules/compat/pom.xml "$(DESTDIR)$(MAVENPOM_DIR)/$(PACKAGE_NAME)-compat.pom"
install -m 644 backend/manager/modules/dal/pom.xml "$(DESTDIR)$(MAVENPOM_DIR)/$(PACKAGE_NAME)-dal.pom"
install -m 644 backend/manager/modules/pom.xml "$(DESTDIR)$(MAVENPOM_DIR)/$(PACKAGE_NAME)-manager-modules.pom"
install -m 644 backend/manager/modules/restapi/interface/common/jaxrs/pom.xml "$(DESTDIR)$(MAVENPOM_DIR)/$(PACKAGE_NAME)-interface-common-jaxrs.pom"
install -m 644 backend/manager/modules/restapi/interface/definition/pom.xml "$(DESTDIR)$(MAVENPOM_DIR)/$(PACKAGE_NAME)-restapi-definition.pom"
install -m 644 backend/manager/modules/restapi/jaxrs/pom.xml "$(DESTDIR)$(MAVENPOM_DIR)/$(PACKAGE_NAME)-restapi-jaxrs.pom"
install -m 644 backend/manager/modules/restapi/pom.xml "$(DESTDIR)$(MAVENPOM_DIR)/$(PACKAGE_NAME)-restapi-parent.pom"
install -m 644 backend/manager/modules/restapi/types/pom.xml "$(DESTDIR)$(MAVENPOM_DIR)/$(PACKAGE_NAME)-restapi-types.pom"
install -m 644 backend/manager/modules/scheduler/pom.xml "$(DESTDIR)$(MAVENPOM_DIR)/$(PACKAGE_NAME)-scheduler.pom"
install -m 644 backend/manager/modules/searchbackend/pom.xml "$(DESTDIR)$(MAVENPOM_DIR)/$(PACKAGE_NAME)-searchbackend.pom"
install -m 644 backend/manager/modules/utils/pom.xml "$(DESTDIR)$(MAVENPOM_DIR)/$(PACKAGE_NAME)-utils.pom"
install -m 644 backend/manager/modules/vdsbroker/pom.xml "$(DESTDIR)$(MAVENPOM_DIR)/$(PACKAGE_NAME)-vdsbroker.pom"
install -m 644 backend/manager/pom.xml "$(DESTDIR)$(MAVENPOM_DIR)/$(PACKAGE_NAME)-manager.pom"
install -m 644 backend/manager/tools/pom.xml "$(DESTDIR)$(MAVENPOM_DIR)/$(PACKAGE_NAME)-tools.pom"
install -m 644 backend/pom.xml "$(DESTDIR)$(MAVENPOM_DIR)/$(PACKAGE_NAME)-backend.pom"
install -m 644 pom.xml "$(DESTDIR)$(MAVENPOM_DIR)/$(PACKAGE_NAME)-root.pom"
gwt-debug 标签
- 前端 GWT debug 模式。
gwt-debug:
[ -n "$(DEBUG_MODULE)" ] || ( echo "Please specify DEBUG_MODULE" && false )
cd "frontend/webadmin/modules/$(DEBUG_MODULE)" && \
$(MVN) \
$(DEV_EXTRA_BUILD_FLAGS_GWT_DEFAULTS) \
$(DEV_EXTRA_BUILD_FLAGS) \
-Dgwt.noserver=true \
-Pgwtdev,gwt-admin,gwt-user \
gwt:debug
install-dev 标签
- 开发编译模式。
install-dev: \
all-dev \
$(NULL)
# remove dbscripts to avoid dups
rm -fr "$(DESTDIR)$(DATA_DIR)/dbscripts"
if [ -f "$(DESTDIR)$(PREFIX)/dev.$(PACKAGE_NAME).flist" ]; then \
cat "$(DESTDIR)$(PREFIX)/dev.$(PACKAGE_NAME).flist" | while read f; do \
rm -f "$(DESTDIR)$(PREFIX)/$${f}"; \
done; \
rm -f "$(DESTDIR)$(PREFIX)/dev.$(PACKAGE_NAME).flist"; \
fi
rm -f tmp.dev.flist
$(MAKE) \
install \
BUILD_DEV=1 \
BUILD_VALIDATION=0 \
PYTHON_DIR="$(PREFIX)$(PYTHON_SYS_DIR)" \
DEV_FLIST=tmp.dev.flist \
$(NULL)
cp tmp.dev.flist "$(DESTDIR)$(PREFIX)/dev.$(PACKAGE_NAME).flist"
install -d "$(DESTDIR)$(PKG_TMP_DIR)"
install -d "$(DESTDIR)$(PKG_CACHE_DIR)"
install -d "$(DESTDIR)$(PKG_STATE_DIR)/content"
install -d "$(DESTDIR)$(PKG_STATE_DIR)/setup/answers"
install -d "$(DESTDIR)$(PKG_LOG_DIR)/host-deploy"
install -d "$(DESTDIR)$(PKG_LOG_DIR)/setup"
install -d "$(DESTDIR)$(PKG_LOG_DIR)/notifier"
install -d "$(DESTDIR)$(PKG_LOG_DIR)/engine-manage-domains"
install -d "$(DESTDIR)$(PKG_LOG_DIR)/dump"
if [ -e "$(DESTDIR)$(PKG_TMP_DIR)/deployments" ]; then \
touch "$(DESTDIR)$(PKG_TMP_DIR)/deployments/engine.ear.deployed"; \
fi
all-dev 标签
- 全编译模式。
all-dev:
[ "$(DEV_REBUILD)" != 0 ] && rm -f "$(BUILD_FILE)" || :
rm -f $(GENERATED)
$(MAKE) \
all \
BUILD_DEV=1 \
DEV_PYTHON_DIR="$(PREFIX)$(PYTHON_SYS_DIR)" \
$(NULL)
- engine spec 文件中的编译步骤,实际执行的就是 make 命令(spec 相关可以查看 【Ovirt 笔记】ovirt-engine.spec 配置分析与整理)。
%global make_common_opts \\\
-j1 \\\
BUILD_GWT=%{ovirt_build_gwt} \\\
BUILD_LOCALES=%{ovirt_build_locales} \\\
BUILD_UT=%{ovirt_build_ut} \\\
BUILD_VALIDATION=0 \\\
PACKAGE_NAME=%{name} \\\
RPM_VERSION=%{version} \\\
RPM_RELEASE=%{release} \\\
DISPLAY_VERSION=%{version}-%{release} \\\
ENGINE_NAME=%{engine_name} \\\
LOCALSTATE_DIR=%{_localstatedir} \\\
PREFIX=%{_prefix} \\\
SYSCONF_DIR=%{_sysconfdir} \\\
BIN_DIR=%{_bindir} \\\
PID_DIR=%{_localstatedir}/run \\\
DATAROOT_DIR=%{_datadir} \\\
MAN_DIR=%{_mandir} \\\
DOC_DIR=%{_docdir} \\\
PYTHON=%{__python} \\\
PYTHON_DIR=%{python_sitelib} \\\
JAVA_DIR=%{_javadir} \\\
MAVENPOM_DIR=%{_mavenpomdir} \\\
PKG_SYSCONF_DIR=%{engine_etc} \\\
PKG_DOC_DIR=%{engine_doc} \\\
PKG_EAR_DIR=%{engine_ear} \\\
PKG_PKI_DIR=%{engine_pki} \\\
PKG_JBOSS_MODULES=%{engine_jboss_modules} \\\
PKG_CACHE_DIR=%{engine_cache} \\\
PKG_LOG_DIR=%{engine_log} \\\
PKG_TMP_DIR=%{engine_tmp} \\\
PKG_STATE_DIR=%{engine_state} \\\
PKG_USER=%{engine_user} \\\
PKG_GROUP=%{engine_group} \\\
JBOSS_HOME=/usr/share/jbossas \\\
MAVEN_OUTPUT_DIR=. \\\
%{?BUILD_FLAGS:BUILD_FLAGS="%{BUILD_FLAGS}"} \\\
%{?EXTRA_BUILD_FLAGS:EXTRA_BUILD_FLAGS="%{EXTRA_BUILD_FLAGS}"}
......
make %{make_common_opts} install DESTDIR="%{buildroot}"
- 开发过程中的本地编译,可以执行。
make clean install-dev PREFIX=<编译至所在路径> DEV_EXTRA_BUILD_FLAGS_GWT_DEFAULTS="-Dgwt.userAgent=gecko1_8 -Dgwt.locale=en_US,zh_CN" BUILD_GWT_WEBADMIN="1" BUILD_GWT_USERPORTAL="0" BUILD_UT="0"
参数 | 说明 |
---|---|
PREFIX | 编译路径地址。 |
-Dgwt.userAgent | 编译浏览器种类火狐。 |
-Dgwt.locale | 编译语言中文、英文。 |
BUILD_GWT_WEBADMIN | 是否编译前端 GWT 管理门户。 |
BUILD_GWT_USERPORTAL | 是否编译前端 GWT 用户门户。 |
BUILD_UT | 是否运行单元测试。 |
- 前端 GWT 调试可以执行。
make gwt-debug DEBUG_MODULE="webadmin" DEV_EXTRA_BUILD_FLAGS_GWT_DEFAULTS="-Dgwt.userAgent=gecko1_8"
- 调试前端 GWT 管理门户。
make gwt-debug DEBUG_MODULE="userportal-gwtp" DEV_EXTRA_BUILD_FLAGS_GWT_DEFAULTS="-Dgwt.userAgent=gecko1_8"
- 调试前端 GWT 用户门户。