Milvus 编译环境演进

2023-01-09 17:03:33 浏览数 (1)

一、手写动态链接

Milvus 代码库分为了 C Go 两个部分,Go 部分负责系统主体架构、分布式系统、存储/查询链路等,C 部分负责查询、索引引擎专注于单机场景下的高性能,两者之间通过 cgo 接口调用。

为了维护两种语言的代码,就需要加入两种语言的生态。Go 作为一个年轻、现代的语言,开箱自带包管理、自动化测试框架和丰富的标准库;而 C 就走向了另一个极端,虽然有极致的性能和可控的内存管理,但生态过于碎片化。幸好在 build system 领域,CMake 有成为事实标准的趋势。

Milvus 很自然地选择 CMake 作为 C 构建系统,通过编写 CMakeLists.txt 描述要生成的 library 和 headers,而 Go 则通过 cgo 接口链接到相应的 library,在早期版本里是这样写的:

代码语言:javascript复制
/*
#cgo CFLAGS: -I${SRCDIR}/../core/output/include
#cgo darwin LDFLAGS: -L${SRCDIR}/../core/output/lib -lmilvus_segcore -Wl,-rpath,"${SRCDIR}/../core/output/lib"
#cgo linux LDFLAGS: -L${SRCDIR}/../core/output/lib -lmilvus_segcore -Wl,-rpath=${SRCDIR}/../core/output/lib
#include "segcore/collection_c.h"
#include "common/type_c.h"
#include "segcore/segment_c.h"
*/
import "C"
import (
        "errors"
        "fmt"
        "unsafe"
        "github.com/milvus-io/milvus/internal/util/cgoconverter"
)

不难发现这样写有几个问题:

1. 不同操作系统需要指定不同的编译参数

2. hard code 库文件路径耦合严重,不利于维护

以上两个问题相对容易解决,在使用第三方 go library 时,问题会更难解决,例如 Milvus 使用了 https://github.com/tecbot/gorocksdb[1] 作为 Go 的 rocksdb 接口。

gorocksdb 需要修改 CGO 的一系列 go env 才能编译成功,究其原因也是因为 gorocksdb 在使用 rocksdb library 时没有指定 library 和 header 的路径,必须在系统路径中才能找到 librocksdb 。

代码语言:javascript复制
package gorocksdb

// #include "stdlib.h"
// #include "rocksdb/c.h"
import "C"
import (
        "reflect"
        "unsafe"
)

这就导致了 Milvus 的编译脚本中需要 hack go env 才能顺利编译:

代码语言:javascript复制
go env -w CGO_CFLAGS="-I${OUTPUT_LIB}/include"
ldflags=""
if [ -f "${OUTPUT_LIB}/lib/librocksdb.a" ]; then
     case "${unameOut}" in
          Linux*)     ldflags="-L${OUTPUT_LIB}/lib -l:librocksdb.a -lstdc   -lm -lz";;
          Darwin*)    ldflags="-L${OUTPUT_LIB}/lib -lrocksdb -stdlib=libc   -lm -lz -lbz2 -ldl";;
          *)          echo "UNKNOWN:${unameOut}"; exit 0;
     esac
else
     case "${unameOut}" in
          Linux*)     ldflags="-L${OUTPUT_LIB}/lib64 -l:librocksdb.a -lstdc   -lm -lz";;
          Darwin*)    ldflags="-L${OUTPUT_LIB}/lib64 -lrocksdb -stdlib=libc   -lm -lz -lbz2 -ldl";;
          *)          echo "UNKNOWN:${unameOut}" ; exit 0;
      esac
fi

if [ "$MSYSTEM" == "MINGW64" ] ; then
  ldflags="-L${OUTPUT_LIB}/lib -lrocksdb -lstdc   -lm -lz -lshlwapi -lrpcrt4"
fi

if [[ $(arch) == 'arm64' ]]; then
  go env -w GOARCH=arm64
fi

go env -w CGO_LDFLAGS="$ldflags" && GO111MODULE=on
go get github.com/tecbot/gorocksdb

二、pkg-config 链接管理

早期的做法也不是不能用

0 人点赞