构建程序
构建系统是利用GNU make程序将源代码构建成一组可执行文件和库,用于应用程序的开发。
make程序
make程序以依赖树的形式维护产品和源文件的依赖信息,其中顶层节点(或目标)依赖于几个子目标,随后子目标再向下依赖,依此类推,直到源文件的最后节点(或目标)。make程序能够使用文件系统时间戳和文件“存在”函数跟踪源文件修改和依赖链中的更改,并更新所有依赖于修改后源文件的目标。
构建系统包括两个子系统:
- 项目文件数组:将每个组件描述为项目,定义项目的属性及其依赖关系;
- 一组级联make文件:将项目信息交付给make程序,以便维护所有组件、源代码、头文件和程序的完整依赖树。
这个完整的依赖关系树使make程序能够跟踪和构建SmartEDB的任何部分。
构建操作可以作为一系列构建操作逐步运行,也可以并行运行,以充分利用构建系统的多CPU能力。
makefile
构建系统的项目makefile描述了产品的每个组件,包括定义了组件是什么,如何构建,源代码文件、标志和属性等。
产品中有以下类型项目:
- 可执行文件(分别用于主机端和目标端);
- 库(静态和动态);
- JAVA类和jar文件;
- Python模块;
- 使用的第三方应用。
makefile结构
根目录makefile将SmartEDB的安装位置定义在变量MCO_ROOT
变量中,使用绝对路径。
MCO_ROOT=$(abspath .)
include $(MCO_ROOT)/include/settings.makefile
include $(if $(findstring yes,$(MCO_QUICK_BUILD))
$(findstring on,$(MCO_QUICK_BUILD)),,$(MCO_ROOT)/)makefile.cascade
include $(MCO_ROOT)/include/rules.makefile
子目录makefile的唯一区别在于定义变量MCO_ROOT
为相对路径。
MCO_ROOT=$(abspath ..)
include $(MCO_ROOT)/include/settings.makefile
include $(if $(findstring yes,$(MCO_QUICK_BUILD))
$(findstring on,$(MCO_QUICK_BUILD)),,$(MCO_ROOT)/)makefile.cascade
include $(MCO_ROOT)/include/rules.makefile
注
在大多数情况下,只需将现有的子目录makefile复制到新目录中,并调整变量MCO_ROOT
以生成新的子目录makefile。
makefile有一些根据MCO_QUICK_BUILD
控件工作的逻辑。(参见下面的Make System Control)
makefile.cascade
级联makefiles是一组在所有主要目录中,定义目录层次结构,包含其他下游makefile.cacade
文件和项目makefiles
的一组makefile.cacade
文件。
通常,子目录中makefile.cascade包括其级别以下子目录中的所有makefile.cascade:
-include $(call mco_makefile_file, \
crypt/makefile.cascade \
mcobackup/makefile.cascade \
...
python/makefile.cascade \
feedhandler/makefile.cascade \
)
项目级makefile.cascade包含项目文件,并将项目属性交付给make程序:
MCO_FILE_DIR:=$(dir $(lastword $(MAKEFILE_LIST)))
include $(MCO_FILE_DIR)makefile.project.mcolib
注
最简单创建新子目录或项目makefile.cascade的方法是复制现有文件并调整下游级联和项目文件。
include/settings.makefile
中设置了级联文件中是否包含下游项目的逻辑。
例如:
target/sal/sync/makefile.cascade: include $(call mco_makefile_file,
$(addprefix makefile.project.mcos,$(MCO_TARGET_SYNC_IMPLEMENTATIONS)))
注
一些级联文件在“include”指令前面有一个破折号(“-”)。make实用程序语言的这种构造定义了可选包含,这对于子级make文件的情况很有用。Cascade需要包含(可能存在也可能不存在)在源代码树中,这取决于包中包含的特性。
makefile.project.
项目makefile定义了项目的名称、属性(如源代码文件、数据库、使用的模块或特性等),并将项目绑定到适当的列表中,以使构建系统为项目生成构建过程。
下面是一个库项目makefile的示例:
MCO_PRJ_LIST += mcosql
PRJ_TARGET_LIBRARY_DPTR_STATIC += mcosql
PRJ_TARGET_LIBRARY_DPTR_DYNAMIC += mcosql
PRJ_TARGET_LIBRARY_OFFS_STATIC += mcosql
PRJ_TARGET_LIBRARY_OFFS_DYNAMIC += mcosql
PRJ_mcosql_TAGS:=target sql malloc
PRJ_mcosql_DIR :=$(call mco_project_dir)
PRJ_mcosql_SRC :=$(call mco_project_file, dbapi.cpp compiler.cpp
sqlc.cpp operators.cpp optimizer.cpp nodes.cpp schema.cpp
sql.cpp utils.cpp exceptions.cpp stub.cpp value.cpp hash.cpp
multisql.cpp mcoapi.cpp mcosql.cpp mcoseq.cpp mcoapic.cpp)
下面是一个可执行项目makefile的示例:
MCO_PRJ_LIST += hasimple-master
PRJ_TARGET_EXECUTABLE_DPTR +=
PRJ_TARGET_EXECUTABLE_OFFS += hasimple-master
PRJ_hasimple-master_TAGS:=sample ha
PRJ_hasimple-master_DIR:=$(call mco_project_dir)
PRJ_hasimple-master_SRC:=$(call mco_project_file, master.c)
$(MCO_SAMPLES_COMMON_DIR)/common.c $(MCO_SAMPLES_COMMON_DIR)/commonha.c
PRJ_hasimple-master_SCHEMAS:=$(call mco_project_file,schema.mco)
PRJ_hasimple-master_DATABASES:=simplemstdb
PRJ_hasimple-master_RUNTIME:=YES
PRJ_hasimple-master_MEMDEV:=PRIVATE
PRJ_hasimple-master_STORAGE:=TRANSIENT
PRJ_hasimple-master_SYNC:=AUTO
PRJ_hasimple-master_TRANSMGR:=MURSIW
PRJ_hasimple-master_F_HA:=TCP
注
项目文件将项目添加到相应的构建系统列表和已定义的项目属性中。有关“属性”的含义,请参阅 Project makefile flags。
make指令
在Unix-Linux软件包安装根目录以及每个示例子目录中,都提供了makefile
。如需重新构建库,可使用GNU生成工具对项目文件和第三方应用进行重构。
all
构建所有二进制文件
make … all …
clean
清理目录树。该命令只删除中间文件,而保留最终产品和构建日志。
make … clean …
distclean
彻底清理。此命令删除所有中间文件和目录,最终文件和构建日志将被清除。
make … distclean …
host
仅生成主机端可执行文件。
target
仅构建目标端实用程序和库。
tools
主机端+目标端组合
samples
此命令将构建所有示例。
make samples
make程序参数
定义以下参数来控制make程序的构建过程。
MCO_BUILD_ROOT
定义脚本放置所有构建活动和中间文件的目录(绝对路径)。默认是与MCO_ROOT
相同的目录。
MCO_PRODUCT_ROOT
定义构建脚本创建产品的目录(绝对路径)。默认值是MCO_BUILD_ROOT
。
提示
可以使用此参数将最终产品与中间文件、源代码树等分开。
MCO_QUICK_BUILD
- no - 默认。
- yes - 脚本将从当前目录启动级联导入,构建过程将仅覆盖当前和所有下游目录,从而使构建过程更快。
MCO_BUILD_LOG
定义如何显示构建过程日志。构建脚本将所有命令和输出放入构建日志中。通常,构建日志的命名与项目的产品名称相同,并带有.build-log
扩展。此外,构建脚本为对象文件生成单独的构建日志,将它们命名为<object-file-name>.o.build-log
。
- on - (默认)只显示简短的进度信息。
- off - 关闭。
- full - 完整设置。立即打印所有输出,并且不维护构建日志。
注
由于该流程的异步特性会导致输出混乱,强烈不建议对并行构建使用full
设置。
MCO_EXTRA_CHECKS
- <no set> - 默认。
- on - 基于gcc的构建启用额外的检查(相当于
-Wall
和-pedantic
选项)。
MCO_ENABLE_EVAL_BINARIES
- <no set> - 默认。
- yes - 在bin目录中生成评估版本(后缀为
.eval
)。
MCO_DISABLE
允许用户从构建过程中排除一组或特定的项目或特性。
此参数值需要以,
或空格分隔的。
注意
禁用参数不仅会导致从构建过程中排除指定的项目,而且还会禁用特性存在的编译定义。
示例:
MCO_DISABLE:=sequences
MCO_DISABLE:=java python lua
MCO_DISABLE:=net,fsystem
MCO_ENABLE
启用被禁用的项目/特性。
示例:
MCO_ENABLE:=wchar
MCO_ENABLE:=rtree
额外参数
参数示例 | 说明 |
---|---|
SHOW_BUILD_LOG=on | 使用MCO_BUILD_LOG=full 。 |
x64=on|off | 构建系统自动检测目标数据总线宽度(在目标编译器的帮助下)。必须指定x64=off以使构建脚本生成32位代码。 |
MCO_SKIP_PERFMON=yes | 跳过性能监视器(perfmon )构建。 |
MCO_SKIP_SEQ_LIB=yes | 禁用序列支持。 |
MCO_SKIP_LUA_UDF=yes | 为Lua禁用UDF。 |
MCO_SKIP_XSQL_BIN=yes | 跳过xSQL构建。 |
JAVA=off | 跳过Java相关代码。 |
PYTHON=off | 跳过Python相关代码。 |
LUA=off | 跳过Lua相关代码。 |
FEEDHANDLER=off | 跳过FeedHandler相关代码。. |
重写参数
以下参数可用于重写gcc/g++编译器名称,以使用替代编译器。
MCO_BUILD_GCC_OVERRIDE=<gcc-executable-name>
MCO_BUILD_GXX_OVERRIDE=<g++-executable-name>
MCO_HOST_GCC_OVERRIDE=<gcc-executable-name>
MCO_HOST_GXX_OVERRIDE=<g++-executable-name>
MCO_TARGET_GCC_OVERRIDE=<gcc-executable-name>
MCO_TARGET_GXX_OVERRIDE=<g++-executable-name>
示例:
MCO_TARGET_GCC_OVERRIDE=gcc456
MCO_TARGET_GXX_OVERRIDE=g++456
MCO_FORCE_OPENSSL
重写OpenSSL包的自动检测。
- auto - (默认)尝试使用由
MCO_OPENSSL_INCLUDE_PATH
环境变量指向的OpenSSL安装,如果它已设置;否则,如果构建体系结构与目标相同并且构建系统具有必要的头文件,则尝试使用构建系统的OpenSSL头文件;最后,使用源树中的OpenSSL包为目标系统构建OpenSSL安装,并使用它来构建SmartEDB。 - envpath - 无条件强制使用
$(MCO_OPENSSL_INCLUDE_PATH)
来查找目标的OpenSSL头文件。 - buildsys - 无条件强制使用构建系统的OpenSSL安装。
- sourcetree - 从
target/sal/net
中的源代码归档文件强制构建特定于目标的OpenSSL包。
示例:
MCO_FORCE_OPENSSL=auto
MCO_FORCE_PYTHON
重写Python 包的自动检测。
- auto - (默认)如果设置了
PYTHONBIN
环境变量,尝试使用它指向的Python安装;否则尝试通过路径找到Python安装。接下来检查Python版本是否足够,是否可运行,体系结构是否匹配并且具有必要的头文件。否则,从源代码树中的包构建Python。 - envpath - 无条件强制使用
$(PYTHONBIN)
来查找Python。 - buildsys - 无条件地强制使用构建系统的Python安装。
- sourcetree - 从
target/python
源代码文件中强制构建Python包。
HOST_COMPILER_FAMILY
TARGET_COMPILER_FAMILY
重写对主机端/目标端操作系统的自动检测编译器。
示例:
TARGET_COMPILER_FAMILY=gcc
HOST_ARCH
TARGET_ARCH
重写对主机端/目标端硬件架构的自动检测编译器。
示例:
TARGET_ARCH=aarch64
HOST_DBUS_WIDTH
TARGET_DBUS_WIDTH
重写对主机端/目标端数据总线宽度的自动检测编译器。
示例:
TARGET_DBUS_WIDTH=32 //16 | 32 | 64
HOST_FLAGS
TARGET_FLAGS
无条件地向编译器/链接器命令行添加参数,用于主机端/目标端代码编译。(参数完全按照它们出现的样子添加—不应用检查。)
示例:
TARGET_FLAGS="--sysroot=/opt/toolchains/arm-unknown-linux/"
第三方应用
SmartEDB代码中使用了一些第三方应用组件(如LUA、Java、Python和OpenSSL),并依赖于组件的API和构建过程。构建脚本通过一些特殊的预防措施确保第三方应用的预安装版本符合SmartEDB要求,支持所需的硬件,存在开发标头等。
- LUA:SmartEDB源代码树中有完整的源代码及补丁。构建系统需要分别为每个目标平台构建LUA代码。
- Java:构建系统依赖Java构建平台的安装,需要为当前构建系统定义
JAVA\_HOME
环境变量。 - Python:SmartEDB源代码树中有Python 2.7.14源代码包(支持Python 2.7.x)。
- 构建脚本将测试Python版本号和头文件。
- 目标端平台需要与构建平台相匹配。
- 如果以上条件中的任何一个失败,构建脚本将构建一个特定于目标端的Python安装,并使用其来生成SmartEDB Python模块。
- 在某些情况下,构建脚本需要构建一个与目标端数据总线匹配,并能够在构建系统上执行的Python安装。
- OpenSSL:构建系统匹配已安装的OpenSSL的版本及其硬件平台,并检查开发头文件。如果这些条件中的任何一个都失败了,脚本就会从SmartEDB源代码树中现有的源代码包中构建特定于目标端的OpenSSL软件安装。
提示
可以使用MCO_FORCE_OPENSSL
和MCO_FORCE_PYTHON
控件覆盖Python和OpenSSL的自动检测。请参阅“创建系统覆盖”。
第三方makefile
make程序用特殊的工程文件封装第三方make程序。这取决于如何处理第三方产品构建过程的细节。
参考:target/sal/net/makefile.project.openssl
或target/python/makefile.project.python
。
构建过程、产品、构建日志和中间文件通过PRJ_CUSTOM
列表处理。
运行提示
以下是一些使用构建系统的提示:
使用
-j
选项运行make命令行来启动并行构建。该选项有参数-j X
,其中X是允许使用的cpu数量。- j 1
意味着在单个CPU上运行。
-j
将使用所有可用的CPU。
- 在多CPU上运行构建系统可能会耗尽系统资源或达到用户限制(配额)。如果在构建过程中,系统变得无响应、提示进程不足,请尝试调整限制或减少所使用的CPU数量。
- 在共享构建系统中,请不要一次耗尽机器的全部功率,服务器上的并行构建可能会影响系统上的其他用户和服务。
MacOS系统用户
确保JAVA_HOME
环境变量有一个有效值。通常初始化变量的方法是在~/.profile
中添加以下行:
export JAVA_HOME=$(/usr/libexec/java_home)
确保账户有足够的可用权限。使用以下命令增加**“每个用户的进程数”**限制:
sudo sysctl -w kern.maxprocperuid=4096
模板
下面是构建系统文件的一些模板,可以用于复制粘贴。
makefile
请将<offset-path-to-the-root-directory>
更改为项目目录或子目录路径。
MCO_ROOT=$(abspath <offset-path-to-the-root-directory>)
include $(MCO_ROOT)/include/settings.makefile
include $(if $(findstring yes,$(MCO_QUICK_BUILD))$(findstring on,$(MCO_QUICK_BUILD)),,
$(MCO_ROOT)/)makefile.cascade
include $(MCO_ROOT)/include/rules.makefile
makefile.cascade
如果在同一个目录中有多个项目,对可选项目,在include
前加-
。
MCO_FILE_DIR:=$(dir $(lastword $(MAKEFILE_LIST)))
include $(MCO_FILE_DIR)makefile.project.<project-name-1>
...
include $(MCO_FILE_DIR)makefile.project.<project-name-N>
替换<directory1>…<directoryN>
为项目子目录。
include $(call mco_makefile_file, \
<directory1>/makefile.cascade \
...
<directoryN>/makefile.cascade \
)
makefile.project.
以下为示例项目的makefile.project.<project-name>
,请替换<project-name>
为项目名。
MCO_PRJ_LIST += <project-name>
PRJ_TARGET_EXECUTABLE_DPTR += <project-name>
PRJ_TARGET_EXECUTABLE_OFFS += <project-name>
PRJ_<project-name>_TAGS:=<project-name> sample core
PRJ_<project-name>_DIR:=$(call mco_project_dir)
PRJ_<project-name>_SRC:=$(call mco_project_file,main.c) $(MCO_SAMPLES_COMMON_DIR)/common.c
PRJ_<project-name>_SCHEMAS:=$(call mco_project_file,schema.mco)
PRJ_<project-name>_DATABASES:=<database-name>
PRJ_<project-name>_RUNTIME:=YES
PRJ_<project-name>_MEMDEV:=PRIVATE
PRJ_<project-name>_STORAGE:=TRANSIENT
PRJ_<project-name>_SYNC:=AUTO
PRJ_<project-name>_TRANSMGR:=MURSIW
库项目目录:
MCO_PRJ_LIST += <project-name>
PRJ_TARGET_LIBRARY_DPTR_STATIC += <project-name>
PRJ_TARGET_LIBRARY_DPTR_DYNAMIC += <project-name>
PRJ_TARGET_LIBRARY_OFFS_STATIC += <project-name>
PRJ_TARGET_LIBRARY_OFFS_DYNAMIC += <project-name>
PRJ_<project-name>_TAGS:=<project-name> target core
PRJ_<project-name>_DIR :=$(call mco_project_dir)
PRJ_<project-name>_SRC :=$(call mco_project_file, mcosrc1.c … mcosrcN.cpp)
问题和诊断
大多数构建问题来自于系统中安装的第三方应用和SmartEDB不兼容性。例如:
- 产品的版本与所需的版本不同;
- 构建系统缺少产品的开发头文件。
通常,问题检测可尝试以下方法:
- 使用
MCO_EXPLAIN=python, openssl
查看构建脚本。
$ make qqq MCO_EXPLAIN=openssl,python
Analyzing build environment...
MCO_FORCE_PYTHON=auto
MCO_BUILD_PYTHON=/usr/bin/python
[X] - OpenSSL 1.1.1 exists on the build system
[ ] - Forced to use MCO_OPENSSL_INCLUDE_PATH env. variable
[ ] - Forced to use build system OpenSSL installation
[ ] - Forced to build and use own OpenSSL installation
[ ] - auto-detection enabled, MCO_OPENSSL_INCLUDE_PATH env. variable is set and development headers are present
[ ] - auto-detection enabled, the build system match to the target system and there are usable development headers in the local OpenSSL installation
[X] - auto-detection enabled, build and use own OpenSSL installation if all above failed
[ ] - Invalid value of MCO_FORCE_OPENSSL detected, build and use own OpenSSL installation
MCO_TARGET_OPENSSL_INCLUDE=/home/x/t1219/SmartEDB/target/sal/net/openssl-Linux-x86_64/include
[X] Python does exist on the build system
[X] Target and build-system arch. signatures are the same [+] or Build system is x86_64 and the target is x86 [+] (python is runnable and good for the target usage)
[X] DBus width match (otherwise not good for target usage)
[X] Build python is 2.7.x (otherwise not good for target/cross usage)
[ ] Dev. headers are present (otherwise not good for target usage)
BUILD_PYTHON =/usr/bin/python
CROSS_PYTHON =/home/x/t1219/SmartEDB/target/python/Python-2.7.14-Linux-x86_64/bin/python2.7
TARGET_PYTHON=/home/x/t1219/SmartEDB/target/python/Python-2.7.14-Linux-x86_64/bin/python2.7
Loading cascade make system...
Setting up the build procedure...
Processing...
make: *** No rule to make target 'qqq'. Stop.
- 运行并启用解释,收集它的输出日志和内部数据库:
$ make MCO_EXPLAIN=openssl,python all -p>issue-log 2>&1
- 对于任何编译问题,最好禁用并行构建并启用详细的日志记录(禁用
-j make
选项)
make MCO_BUILD_LOG=full all