前往小程序,Get更优阅读体验!
立即前往
发布
社区首页 >专栏 >oceanbase源码分析 build.sh --init 执行过程

oceanbase源码分析 build.sh --init 执行过程

原创
作者头像
程序员小王
修改2025-01-12 18:38:54
修改2025-01-12 18:38:54
6200
代码可运行
举报
文章被收录于专栏:践行笔记
运行总次数:0
代码可运行

OceanBase 数据库源码解读

OceanBase是由蚂蚁集团、阿里巴巴完全自主研发的分布式关系型数据库,始创于2010年。

OceanBase具有数据强一致、高可用、高性能、在线扩展、高度兼容SQL标准和主流关系型数据库、低成本等特点

您能获得什么

通过本系列的源码解读文章,您首先可以了解 OceanBase 数据库的基本原理,学到一个数据库是如何实现的。推而广之,您也可以把 OceanBase 的实现原理应用到其他数据库,这对您学习其他数据库也有帮助。其次,在熟悉了 OceanBase 的代码之后,如果有需要,您可以直接在未来的工作中使用我们的代码,或者为 OceanBase 贡献您的代码

今天 分析:执行过程

代码语言:javascript
代码运行次数:0
复制
bash build.sh debug --init --make


1. build.sh --init 调用 main
2. main 执行 do_init
3. do_init 完成后进入 CMake 配置
4. CMake 加载配置文件
5. 输出配置信息
6. 检查依赖
生成构建系统

1. Get the code, build and run 【先运行】

Check the Install toolchain guide for supported OS, GLIBC version requirement, and how to install the C++ toolcha

https://oceanbase.github.io/oceanbase/toolchain/

CentOS编译

代码语言:javascript
代码运行次数:0
复制
# 1. 初始化依赖
./build.sh --init

# 2. 选择编译模式(debug/release等)
./build.sh debug --make
./build.sh release --make

1. 系统要求

  • CentOS 6及以上版本
  • 支持的CPU架构:x86_64或aarch64

2. 基础编译工具

代码语言:javascript
代码运行次数:0
复制
# 必需的基础软件包
yum install -y \
  gcc \
  gcc-c++ \
  make \
  glibc-devel \
  libstdc++-devel \
  git \
  wget \
  perl \
  tar \
  bzip2 \
  which

3. 编译器版本要求

代码语言:javascript
代码运行次数:0
复制
# GCC版本要求
- 默认支持C++11标准 (代码中 CPP_STANDARD_OPTION=11)
- 如果使用-DCPP_STANDARD_20=ON,则需要支持C++20标准的GCC版本

# 推荐GCC版本
- CentOS 7: GCC 4.8.5及以上
- CentOS 8: GCC 8.x及以上

4. 系统资源要求

代码语言:javascript
代码运行次数:0
复制
# 硬件资源

- CPU: 建议4核及以上(编译会使用所有可用核心 grep -c ^processor /proc/cpuinfo)

- 内存: 建议16GB及以上

- 磁盘空间: 建议50GB及以上(用于源码、依赖和编译输出)

  

# 系统配置

- 最大文件打开数: ulimit -n 65535

- 最大用户进程数: ulimit -u 65535

5. 依赖库要求

代码语言:javascript
代码运行次数:0
复制
# 核心依赖包
yum install -y \
  libaio-devel \
  openssl-devel \
  bzip2-devel \
  zlib-devel \
  ncurses-devel \
  libcurl-devel \
  readline-devel \
  mariadb-devel \
  boost-devel

# 如果使用RPM打包还需要
yum install -y \
  rpm-build \
  rpmlint

6. CMake要求

代码语言:javascript
代码运行次数:0
复制
- 脚本会使用工具目录中的CMake: ${TOOLS_DIR}/bin/cmak

2. build.sh --init 流程图

流程说明:

2.1. 入口流程

代码语言:javascript
代码运行次数:0
复制
./build.sh --init
↓
main "$@" 。//$@ 是一个特殊变量,代表脚本运行时传递的所有命令行参数
↓
parse_args  # 设置NEED_INIT=true
↓
do_init     # 执行初始化

在 Shell 脚本中,main "$@" 是一种常见的用法,用于定义一个 main 函数并传递所有的命令行参数给它。让我们详细了解这部分的含义:

./script.sh arg1 "arg two" arg3"$@" 将解析为 arg1arg twoarg3

  • "$*" 把所有参数拼接成一个字符串处理。
  • "$@" 保留了参数的独立性,每个参数单独处理。

用法示例

示例脚本

代码语言:javascript
代码运行次数:0
复制
#!/bin/bash

main() {
    echo "Number of arguments: $#"
    echo "Arguments:"
    for arg in "$@"; do
        echo "$arg"
    done
}

# Call the main function and pass all command-line arguments
main "$@"
运行示例
代码语言:javascript
代码运行次数:0
复制
./script.sh arg1 "arg two" arg3
输出
代码语言:javascript
代码运行次数:0
复制
Number of arguments: 3
Arguments:
arg1
arg two
arg3

2.2 parse_args

代码语言:javascript
代码运行次数:0
复制
# parse arguments
ALL_ARGS=("$@")  //这个是一个数组
function parse_args
{
    for i in "${ALL_ARGS[@]}"; do//ALL_ARGS[@] 全部元素 {}集合
        if [[ "$i" == "--init" ]]
        then
            NEED_INIT=true
}


#!/bin/bash

# 定义一个数组
ALL_ARGS=("arg1" "arg2" "arg3" "arg with spaces")

# 遍历数组中的每个元素
for i in "${ALL_ARGS[@]}"; do
    echo "Current argument: $i"
done

2.2. do_init

代码语言:javascript
代码运行次数:0
复制
# dep_create
TOPDIR=`readlink -f \`dirname $0\`` 
function do_init
{
    export CPP_STANDARD=${CPP_STANDARD_OPTION} //C++ 标准库的版本 为11
    time1_ms=$(echo $[$(date +%s%N)/1000000]) //脚本开始执行的时间
    (cd $TOPDIR/deps/init && bash dep_create.sh) 
    //$TOPDIR 是一个预定义的环境变量,通常指向项目根目录
    //进入 deps/init 目录并执行 dep_create.sh 脚本
    if [ $? -ne 0 ]; then
      exit $?
    fi
    time2_ms=$(echo $[$(date +%s%N)/1000000]) //脚本开始执行的时间
}

补充:

代码:

代码语言:javascript
代码运行次数:0
复制
TOPDIR=`readlink -f \`dirname $0\``

的作用是获取当前脚本所在的绝对路径,并将其赋值给变量 TOPDIR

详细解析

  1. $0
    • $0 是一个特殊变量,表示脚本的名称或脚本被执行时的路径。
    • 当你运行一个脚本时,$0 会包含该脚本的路径或仅包含文件名,取决于你如何调用脚本。
  2. dirname $0
    • dirname 是一个命令,用于返回给定路径的目录部分。
    • 例如,如果脚本路径是 /home/user/script.shdirname $0 将返回 /home/user
    • 它提取出脚本所在的目录路径。
  3. 反引号(``)
    • 反引号用于命令替换,即先执行反引号内的命令,并将命令的输出结果作为返回值。
    • 在这行代码中,dirname $0 会先被执行,获取脚本的目录路径。
  4. readlink -f
    • readlink -f 命令返回指定路径的绝对路径。如果路径是符号链接,-f 选项会跟踪符号链接,返回最终的实际路径。
    • 它确保你获得的是完整的、规范化的绝对路径。

整体含义

  • dirname $0 获取脚本文件所在的目录路径。
  • readlink -f 将该目录路径转化为绝对路径,解决了相对路径和符号链接的问题。
  • 最终,TOPDIR 变量将存储脚本所在的目录的绝对路径。

举例说明

假设脚本的路径是 /home/user/projects/script.sh,当你运行这行命令时:

  1. dirname $0 会返回 /home/user/projects
  2. readlink -f /home/user/projects 由于已经是绝对路径,结果仍然是 /home/user/projects
  3. TOPDIR 的值将是 /home/user/projects

2.3 Linux初始化逻辑 dep_create.sh

1. 初始化和环境清理

代码语言:javascript
代码运行次数:0
复制
unalias -a
PWD="$(cd $(dirname $0); pwd)"
OS_ARCH="$(uname -m)" || exit 1
OS_RELEASE="0"
AL3_RELEASE="0"
  • unalias -a:清除所有的 alias(别名),避免干扰后续命令。
  • PWD:获取脚本所在的当前绝对路径。
  • OS_ARCH:使用 uname -m 获取系统架构(例如 x86_64)。
  • 初始化 OS_RELEASEAL3_RELEASE0

2. 检查操作系统版本

代码语言:javascript
代码运行次数:0
复制
if [[ ! -f /etc/os-release ]]; then
    echo "[ERROR] os release info not found" 1>&2 && exit 1
fi
source /etc/os-release || exit 1
  • 检查 /etc/os-release 文件是否存在,如果没有该文件,输出错误信息并退出。
  • 读取 /etc/os-release 文件,获取系统的详细信息(例如 NAME, VERSION, ID, VERSION_ID 等),并将其加载到当前 shell 环境中。

3. 操作系统兼容性处理

定义了多个函数来根据不同操作系统(如 CentOS、AlmaLinux、Ubuntu 等)设置适当的版本标识:

代码语言:javascript
代码运行次数:0
复制
function compat_centos9() { ... }
function compat_centos8() { ... }
function compat_centos7() { ... }
function compat_alinux3() { ... }

每个函数会根据系统信息输出相关信息,并设置 OS_RELEASEAL3_RELEASE

4. 获取操作系统版本

代码语言:javascript
代码运行次数:0
复制
function get_os_release() { ... }
get_os_release || exit 1
  • get_os_release 函数检查系统的架构和版本,通过比较操作系统的 ID 和版本来确定操作系统的兼容性,并根据系统架构和版本设置 OS_RELEASEAL3_RELEASE

5. 设置依赖文件路径

代码语言:javascript
代码运行次数:0
复制
DEP_FILE="oceanbase.${OS_TAG}.deps"//oceanbase.el8.x86_64.deps
MD5=`md5sum ${DEP_FILE} | cut -d" " -f1`
  • DEP_FILE 是包含依赖信息的文件,格式为 oceanbase.${OS_TAG}.deps,其中 OS_TAG 基于操作系统和架构动态生成。
  • 计算 DEP_FILE 的 MD5 值,以便后续判断是否使用缓存。

6. 检查依赖目录是否存在

代码语言:javascript
代码运行次数:0
复制
if [ -f ${WORKSAPCE_DEPS_3RD_MD5} ]; then
    ...
fi
  • 检查本地依赖缓存是否已经初始化,若已初始化则跳过下载和安装依赖的过程,否则继续。

7. 依赖缓存共享检查

代码语言:javascript
代码运行次数:0
复制
if [ "x${DEP_CACHE_DIR}" == "x" ]; then
    NEED_SHARE_CACHE=OFF
    echo_log "disable share dep cache due to env DEP_CACHE_DIR not set"
fi
  • 检查是否设置了共享依赖缓存目录 DEP_CACHE_DIR,若未设置,则禁用缓存。

8. 判断是否使用缓存

代码语言:javascript
代码运行次数:0
复制
if [ ${NEED_SHARE_CACHE} == "ON" ]; then
    ...
fi
  • 如果启用缓存,检查缓存目录是否存在,并尝试链接缓存目录。如果缓存目录和依赖文件都存在,则跳过下载过程。

9. 下载和解压依赖包

代码语言:javascript
代码运行次数:0
复制
mkdir -p "${TARGET_DIR_3RD}/pkg"
for sect in "${!packages[@]}"
do
    ...
    wget "$repo/${pkg}" -O "${TARGET_DIR_3RD}/pkg/${TEMP}" &> ${TARGET_DIR_3RD}/pkg/error.log
done
  • 根据 DEP_FILE 中的内容(依赖列表),循环下载每个依赖包。
  • 使用 wget 下载依赖包到 TARGET_DIR_3RD/pkg/ 目录。
  • 下载成功后,使用 rpm2cpiorpmextract.sh 解压依赖包。

10. 依赖缓存目录管理

代码语言:javascript
代码运行次数:0
复制
if [ ${LINK_CHACE_DIRECT}  == "ON" ]; then
    ln -sf ${CACHE_DEPS_DIR_3RD} ${WORKSPACE_DEPS_3RD}
    exit $?
fi
  • 在下载和解压依赖包后,检查是否启用了缓存共享。如果启用了缓存共享,则将下载的依赖软链接到工作目录,避免重复下载。

11. 生成缓存和锁文件

代码语言:javascript
代码运行次数:0
复制
touch ${CACHE_DEPS_LOCKFILE}
chmod 777 ${CACHE_DEPS_LOCKFILE}
echo_log "generate lock file ${CACHE_DEPS_LOCKFILE}"
  • 在成功下载依赖并缓存后,创建锁文件来防止其他进程同时修改缓存。

12. 缓存清理和完成标记

代码语言:javascript
代码运行次数:0
复制
rm -rf ${CACHE_DEPS_LOCKFILE}
echo_log "unlock lock file ${CACHE_DEPS_LOCKFILE}"
touch ${WORKSAPCE_DEPS_3RD_MD5}
touch ${WORKSAPCE_DEPS_3RD_DONE}
touch ${WORKSAPCE_DEPS_3RD_CPP_STANDARD}
  • 删除锁文件,标记依赖已经成功初始化,并生成 .DONE.CPP_STANDARD 文件以标识缓存初始化完成。

总结:

  • 这段脚本主要用于 初始化和管理依赖包,通过获取系统信息来选择适当的操作系统版本,并根据配置文件下载和解压相关的依赖包。
  • 它还包括缓存机制,如果缓存目录存在并且有效,则跳过下载步骤;否则,下载并缓存依赖包。
  • 最终,脚本会完成依赖的初始化,并在必要时更新缓存目录和相关文件。

3. 执行

执行顺序:

build.sh 首先调用 dep_create.sh 安装依赖

dep_create.sh 完成后,CMake使用 env.cmake 配置编译环境

env.cmake 使用 dep_create.sh 创建的环境进行编译配置

依赖关系:

dep_create.sh 负责准备编译环境

env.cmake 负责使用这个环境

两者需要保持配置的一致性执行顺序:

  1. build.sh --init 调用 main
  2. main 执行 do_init
  3. do_init 完成后进入 CMake 配置
  4. CMake 加载配置文件
  5. 输出配置信息
  6. 检查依赖 生成构建系统
代码语言:javascript
代码运行次数:0
复制
# make build directory && cmake && make (if need)
function do_build
{
    if [ ! -f ${TOOLS_DIR}/bin/cmake ]; then
      echo_log "[NOTICE] Your workspace has not initialized dependencies, please append '--init' args to initialize dependencies"
      exit 1
    fi

    TYPE=$1; shift
    prepare_build_dir $TYPE || return
    ${CMAKE_COMMAND} ${TOPDIR} "$@" -DCPP_STANDARD_20=$CPP_STANDARD_20_OPTION
    if [ $? -ne 0 ]; then
      echo_err "Failed to generate Makefile"
      exit 1
    fi
}

4 附:build.sh --init

代码语言:javascript
代码运行次数:0
复制
./build.sh --init
./build.sh --init
[dep_create.sh] [NOTICE] 'Ubuntu 22.04.5 LTS (x86_64)' is compatible with CentOS 9, use el9 dependencies list
[dep_create.sh] oceanbase.el9.x86_64.deps has been initialized due to /workspace/oceanbase/deps/3rd/e9982c3dd04198e4728809c2bf18f7c5, /workspace/oceanbase/deps/3rd/DONE and /workspace/oceanbase/deps/3rd/CPP_11 exists
[build.sh] use dep_create.sh to create deps cost time: 0m0s
-- Using C++11 standard
-- build with pie
-- Using OB_CC compiler: /workspace/oceanbase/deps/3rd/usr/local/oceanbase/devtools/bin/clang
-- Using OB_CXX compiler: /workspace/oceanbase/deps/3rd/usr/local/oceanbase/devtools/bin/clang++
-- ob-compile not found, compile locally.
-- open source build enabled
-- This is BINARY dir /workspace/oceanbase
-- This is SOURCE dir /workspace/oceanbase
-- check deps for libeasy
-- This is BINARY dir /workspace/oceanbase/deps/oblib
-- This is SOURCE dir /workspace/oceanbase/deps/oblib
-- oblib_add_library compress
-- oblib_add_library zstd
-- oblib_add_library zstd_1_3_8
-- oblib_add_library lz4
-- oblib_add_library snappy
-- zlib_lite use qpl
-- oblib_add_library zlib_lite
-- oblib_add_library restore
-- oblib_add_library s3
-- oblib_add_library cos_sdk
-- ob_lib_add_target oblib_lib_simd
-- ob_lib_add_target oblib_lib
-- ob_lib_add_target oblib_lib_bitmap
-- ob_add_new_object_target ob_malloc_object
-- ob_lib_add_target oblib_common
-- ob_lib_add_target oblib_rpc
-- oblib_extra_objects /workspace/oceanbase/deps/oblib/src/lib/compress/zstd/zstd_objs.o;/workspace/oceanbase/deps/oblib/src/lib/compress/zstd_1_3_8/zstd_1_3_8_objs.o;/workspace/oceanbase/deps/oblib/src/lib/compress/lz4/lz4-all.a.o;/workspace/oceanbase/deps/oblib/src/lib/compress/zlib_lite/zlib_lite_objs.o;/workspace/oceanbase/deps/oblib/src/lib/restore/cos/cos_sdk_objs.o
-- /workspace/oceanbase/deps/3rd
-- This is BINARY dir /workspace/oceanbase/src/objit
-- This is SOURCE dir /workspace/oceanbase/src/objit
-- Building with -fPIC
-- ob_add_new_object_target ob_share
-- ob_add_new_object_target ob_sql
-- observer_add_target ob_sql_simd
-- generating /workspace/oceanbase/src/share/inner_table/sys_package/system_package.cpp ...
-- generate /workspace/oceanbase/src/share/inner_table/sys_package/system_package.cpp done
-- observer_add_target ob_pl
-- observer_add_target ob_rootserver
-- observer_add_target ob_logservice
-- ob_add_new_object_target oblogminer_objs
-- ob_add_new_object_target oblogminer_obj_dev
-- ob_add_new_object_target obcdc_objects
-- ob_add_new_object_target obcdc_objects_miner
-- ob_add_new_object_target obcdc_tailf_objects
-- ob_add_new_object_target obcdc_tailf_objects_static
-- ob_add_new_object_target ob_storage
-- observer_add_target ob_storage_simd
-- observer_add_target ob_diagnose_lua
-- observer_add_target ob_server
-- ob_add_new_object_target obtable_base_objects
-- Configuring done (0.5s)
-- Generating done (4.1s)
-- Build files have been written to: /workspace/oceanbase

deps/

├── 3rd/

│ └── usr/

│ └── local/

│ └── oceanbase/

│ ├── deps/

│ │ └── devel/

│ │ ├── openssl -> /usr/local/opt/openssl

│ │ ├── boost -> /usr/local/opt/boost

│ │ └── mariadb -> /usr/local/opt/mariadb-connector-c

│ └── devtools/

│ └── bin/

│ ├── cmake -> /usr/local/opt/cmake/bin/cmake

│ ├── clang -> /usr/local/opt/llvm/bin/clang

│ └── clang++ -> /usr/local/opt/llvm/bin/clang++

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • OceanBase 数据库源码解读
  • 1. Get the code, build and run 【先运行】
    • 1. 系统要求
    • 2. 基础编译工具
    • 3. 编译器版本要求
    • 4. 系统资源要求
    • 5. 依赖库要求
    • 6. CMake要求
  • 2. build.sh --init 流程图
    • 流程说明:
    • 2.1. 入口流程
      • 2.2 parse_args
      • 2.2. do_init
      • 详细解析
      • 整体含义
      • 举例说明
      • 2.3 Linux初始化逻辑 dep_create.sh
      • 1. 初始化和环境清理
      • 2. 检查操作系统版本
      • 3. 操作系统兼容性处理
      • 4. 获取操作系统版本
      • 5. 设置依赖文件路径
      • 6. 检查依赖目录是否存在
      • 7. 依赖缓存共享检查
      • 8. 判断是否使用缓存
      • 9. 下载和解压依赖包
      • 10. 依赖缓存目录管理
      • 11. 生成缓存和锁文件
      • 12. 缓存清理和完成标记
      • 总结:
  • 3. 执行
    • 4 附:build.sh --init
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档