背景
本文基于Starrocks 4.x
在机器 Apple M5 MacOS Tahoe 26 系统上进行编译,
对于Starrocks来说是不支持直接在 mac上进行编译的,如果你直接进行build的话,你就会遇到意想不到的问题。
所以我们转换一种思路,那就是本地下载starrocks源码,之后挂载源码到docker中,在容器中,用linux进行编译。也就是Compile StarRocks with Docker 这里所说的。
这里说到了两个linux系统,一种是Ubuntu 一种 是CentOS,分别用这两个系统来操作的话,也是会有区别的,这里我们来实操一下
基于centos
按照官网所说的,我们我们 checkout branch-4.1 分支,以及用挂载的方式去运行一个容器:
docker run -it -v /Users/ljh/github/starrocks/.m2:/root/.m2 \
-v /Users/ljh/github/starrocks:/root/starrocks \
--name branch-4.1 -d starrocks/dev-env-centos7:4.1-latest
之后用docker exec -it进入容器,运行如下命令
cd /root/starrocks
./build.sh
运行一段时间后你会发现,你就会发现遇到类似这样的错误(由于branch和镜像的变动,问题细节可能不一样):
root/starrocks/be/src/util/thrift_util.cpp: In function 'void starrocks::init_thrift_logging()':
/root/starrocks/be/src/util/thrift_util.cpp:105:30: error: 'instance' is not a member of 'apache::thrift::TOutput'
105 | apache::thrift::TOutput::instance().setOutputFunction(thrift_output_function);
| ^~~~~~~~
/root/starrocks/be/src/util/thrift_util.cpp: At global scope:
/root/starrocks/be/src/util/thrift_util.cpp:100:13: warning: 'void starrocks::thrift_output_function(const char*)' defined but not used [-Wunused-function]
100 | static void thrift_output_function(const char* output) {
| ^~~~~~~~~~~~~~~~~~~~~~
make[2]: *** [src/util/CMakeFiles/Util.dir/thrift_util.cpp.o] Error 1
make[1]: *** [src/util/CMakeFiles/Util.dir/all] Error 2
make[1]: *** Waiting for unfinished jobs....
这种问题的根因就是项目中的thrift 版本和 docker容器中/var/local/thirdparty/installed/thrift的版本不一样,这就导致了版本不一致导致的类不存在的问题。
这个时候,如果你能够把这些版本弄一致了(通过cherry-pick或者revert),你可以继续往下编译。
编译一段时间你就会发现,另一个问题:
g++: fatal error: Killed signal terminated program cc1plus
compilation terminated.
这种表示,编译的时候的内存不足,这个时候就要调整容器的内存,我这里调整到了16GB。继续编译,编译到99%的时候,就差临门一脚了,你发现又一个问题出现了:
[ 99%] Linking CXX executable /root/starrocks/be/output/lib/starrocks_be
collect2: fatal error: ld terminated with signal 9 [Killed]
compilation terminated.
这个问题,你再编译多少次,都会绕不过,所以我们这里选择参考使用lld,lld相比ld有速度和节约内存的优势。所以我们这里去下载lld,
[root@8f94d38faa24 installed]# yum install epel-release
[root@8f94d38faa24 installed]# yum install lld
Loaded plugins: fastestmirror, ovl
Loading mirror speeds from cached hostfile
* base: mirrors.aliyun.com
* epel: ftp.iij.ad.jp
* extras: mirrors.aliyun.com
* updates: mirrors.aliyun.com
No package lld available.
Error: Nothing to do
搜索以后发现centos已经已经全面停止维护(EOL),官方技术支持已于 2024年6月30日 结束。所以基于这点考虑,我们重新用Ubuntu 继续进行编译。
ubuntu编译
由于前面branch-4.1的分支和镜像的第三方包中thrift版本的不一致问题,这次我们checkout branch-4.0:
docker run -it -v /Users/ljh/github/starrocks/.m2:/root/.m2 \
-v /Users/ljh/github/starrocks:/root/starrocks \
--name branch-4.0 -d starrocks/dev-env-ubuntu:4.0-latest
之后用docker exec -it进入容器,这里的thrift的版本就是0.20.0(和项目的thrift的版本一致)
而且为了避免centos编译过程中的内存不足问题,所以这里我们采用了lld链接器.而且我们用了clang来做编译:
apt update
apt install clang
最终运行如下命令:
cd /root/starrocks
CC=clang CXX=clang++ STARROCKS_LINKER=lld ./build.sh --clean --be
这里运行一段时间后,又会出现如下问题:
/root/starrocks/be/src/exprs/arithmetic_expr.cpp:47:35: error: unused function 'eliminate_trivial_cast_for_decimal_mul' [-Werror,-Wunused-function]
之后我们使用export STARROCKS_CXX_COMMON_FLAGS="-Wno-unused-function"这种方式去规避,也还是不行。
这个问题出现的原因就是: Clang 把"未使用的 static 函数"当成错误(-Werror,-Wunused-function)导致的,根因是 条件编译不一致。
eliminate_trivial_cast_for_decimal_mul 只在 evaluate_decimal_fast_mul 里被调用,而后者又只在下面这段条件里被用到:
arithmetic_expr.cpp
Lines 106-113
#if defined(__x86_64__) && defined(__GNUC__)
if constexpr (is_mul_op<OP> && lt_is_decimal<Type>) {
ASSIGN_OR_RETURN(auto opt_result, evaluate_decimal_fast_mul(context, ptr));
if (opt_result != nullptr) {
return opt_result;
}
}
#endif
但 函数定义本身没有包在同样的 #if 里:
arithmetic_expr.cpp
Lines 47-64
static std::optional<LogicalType> eliminate_trivial_cast_for_decimal_mul(const Expr* e) {
...
}
因为我这边uname -m出来的是aarch64,因为这里的条件编译是x86_64, 所以会导致这个问题。
注意:aarch64,x86_64是两种完全不同底层的CPU架构。
最终我们修改源码去规避这个问题,修改如下:
iff --git a/be/src/exprs/arithmetic_expr.cpp b/be/src/exprs/arithmetic_expr.cpp
index 9de00c34e1..7caf5303d2 100644
--- a/be/src/exprs/arithmetic_expr.cpp
+++ b/be/src/exprs/arithmetic_expr.cpp
@@ -44,6 +44,7 @@ namespace starrocks {
\
virtual Expr* clone(ObjectPool* pool) const override { return pool->add(new CLASS_NAME(*this)); }
+#if defined(__x86_64__) && defined(__GNUC__)
static std::optional<LogicalType> eliminate_trivial_cast_for_decimal_mul(const Expr* e) {
DIAGNOSTIC_PUSH
#if defined(__GNUC__) && !defined(__clang__)
@@ -62,12 +63,14 @@ static std::optional<LogicalType> eliminate_trivial_cast_for_decimal_mul(const E
}
DIAGNOSTIC_POP
}
+#endif
template <LogicalType Type, typename OP>
class VectorizedArithmeticExpr final : public Expr {
public:
DEFINE_CLASS_CONSTRUCTOR(VectorizedArithmeticExpr);
+#if defined(__x86_64__) && defined(__GNUC__)
StatusOr<ColumnPtr> evaluate_decimal_fast_mul(ExprContext* context, Chunk* chunk) {
auto lhs_lt_opt = eliminate_trivial_cast_for_decimal_mul(_children[0]);
auto rhs_lt_opt = eliminate_trivial_cast_for_decimal_mul(_children[1]);
@@ -101,6 +104,7 @@ public:
}
return nullptr;
}
+#endif
StatusOr<ColumnPtr> evaluate_checked(ExprContext* context, Chunk* ptr) override {
#if defined(__x86_64__) && defined(__GNUC__)
diff --git a/be/src/storage/rowset/binary_plain_page.cpp b/be/src/storage/rowset/binary_plain_page.cpp
index d54669167e..615a4e3b98 100644
--- a/be/src/storage/rowset/binary_plain_page.cpp
+++ b/be/src/storage/rowset/binary_plain_page.cpp
@@ -157,9 +157,9 @@ template <LogicalType Type>
void BinaryPlainPageDecoder<Type>::batch_string_at_index(Slice* dst, const int32_t* idx, size_t size) const {
if (_parsed_datas.has_value()) {
const std::vector<Slice>& parsed_data = *_parsed_datas;
+#ifdef __SSE4_2__
const Slice* parsed_data_ptr = parsed_data.data();
static_assert(sizeof(Slice) == sizeof(__int128));
-#ifdef __SSE4_2__
#pragma GCC unroll 2
for (int i = 0; i < size; ++i) {
DCHECK_LT(idx[i], parsed_data.size());
最终保险起见,我们还是使用默认的gcc编译器:
STARROCKS_LINKER=lld ./build.sh
最终成功了。
总结
所以这一路下来还是挺波折的。因为BE的编译本来就消耗时间,而且中间还遇到很多的问题,前前后后花了2天时间才真正的编译成功。