Linux环境编译三方库
一、环境准备
1、准备Ubuntu虚拟机
- 推荐Ubuntu 20.04
- 设置共享文件夹,用于传递文件

- 虚拟机重启后,要重新挂载一下共享文件夹
2、准备OpenHarmony环境
-
在Command Line Tools For HarmonyOS下载Linux版本相关的即可。里面包含sdk;建议使用 release 版本

-
解压SDK
tar -zxvf version-Master_Version-OpenHarmony_3.2.10.3-20230105_163913-ohos-sdk-full.tar.gz -
进入Linux目录
ohos@ubuntu20:~/tools/OH_SDK$ cd ohos-sdk
ohos@ubuntu20:~/tools/OH_SDK/ohos-sdk$ ls
linux windows
ohos@ubuntu20:~/tools/OH_SDK/ohos-sdk$ cd linux/
ohos@ubuntu20:~/tools/OH_SDK/ohos-sdk/linux$ ls
ets-linux-x64-4.0.1.2-Canary1.zip native-linux-x64-4.0.1.2-Canary1.zip toolchains-linux-x64-4.0.1.2-Canary1.zip
js-linux-x64-4.0.1.2-Canary1.zip previewer-linux-x64-4.0.1.2-Canary1.zip -
解压工具包,得到编译工具链
ohos@ubuntu20:~/tools/OH_SDK/ohos-sdk/linux$ for i in *.zip;do unzip ${i};done
ohos@ubuntu20:~/tools/OH_SDK/ohos-sdk/linux$ ls
ets native toolchains
ets-linux-x64-4.0.1.2-Canary1.zip native-linux-x64-4.0.1.2-Canary1.zip toolchains-linux-x64-4.0.1.2-Canary1.zip
js previewer
js-linux-x64-4.0.1.2-Canary1.zip previewer-linux-x64-4.0.1.2-Canary1.zip -
native目录介绍
ohos@ubuntu20:~/tools/OH_SDK/ohos-sdk/linux$ cd native/
ohos@ubuntu20:~/tools/OH_SDK/ohos-sdk/linux/native$ ls
build docs nativeapi_syscap_config.json NOTICE.txt sysroot
build-tools llvm ndk_system_capability.json oh-uni-package.json-
build和build-tools目录提供构建时的 cmake,ninja,以及 toolchain 依赖
-
llvm 提供编译工具链
-
sysroot 提供 usr 系统资源
目录 功能 build 构建时 cmake 依赖的配置文件 build-tools 构建工具包含 cmake 和 ninja,我们后面采用 make 进行构建 docs 使用说明 llvm clang 编译器 sysroot 编译器的 sysroot 目录,存放 SDK 内部的已经包含的库和对应的头文件 oh-uni-package.json 为 SDK 信息描述,如版本 NOTICE.txt 注意事项,内容多为 SDK 的详细描述 ndk_system_capability.json 记录 SDK 提供的能力 nativeapi_syscap_config.json 记录 SDK 提供的能力对应的头文件
-
二、构建前准备
- 首先了解和学习 CMAKE、Configure&makefile、NDK编译so这三个编译场景,了解 C/C++ 编译链相关知识
- 了解开源项目:
- 该项目目前持续更新已经鸿蒙化的so库,打包前可以先在该项目中查找,若相关的三方库已经鸿蒙化,则可以节省工作量:https://gitee.com/han_jin_fei/lycium/tree/master/main
- 该项目中的三方库构建说明:https://gitee.com/han_jin_fei/lycium/blob/master/README.md
- HPKBUILD 脚本注释说明:https://gitee.com/han_jin_fei/lycium/blob/master/template/HPKBUILD
- 项目构建方式参考3.4章节内容
三、构建三方库
1、打包须知
- 打包分为三种渠道:
- cmake构建: cmake是现如今c/c++开发最流行的编译构建脚本
- 非cmake构建(Configure&Make方式)
- NDK方式构建
- 如果要自己写cmake脚本,可以参考:
- Lycium工程中已经有相当多的so库了,都是鸿蒙化的,使用前可以先查看是否有现成可复用的so
- https://gitee.com/han_jin_fei/lycium/tree/master/main
- 查看前需要关注鸿蒙化so的版本号,
如果遇到大版本有差异,就有可能无法使用,需要重新构建
- 下面的两个例子 cJSON 和 openssl 均来自 Lycium 项目的demo说明
2、【案例一】cJSON(CMake方式)
-
下载源码
- 方法一:
- 去github上搜索并下载,以1.7.15版本为例,打开链接:https://github.com/DaveGamble/cJSON/releases
- 点击下载

- 方法二:
- 虚拟机打开命令行,git 命令下载:git clone https://github.com/DaveGamble/cJSON.git -b v1.7.15
- 如果虚拟机无法访问,则使用方法一下载,然后传输到虚拟机
- 方法一:
-
以方法一为例,解压代码压缩包,然后进入cJSON目录,新建一个文件夹ohos64build,用于存放cmake时创建的构建文件
tar -zxvf cJSON-1.7.15.tar.gz -
使用 OH_SDK 携带的 cmake 进行编辑
ohos@ubuntu20:~/openHarmony/cJSON/ohos64build$ /home/ohos/tools/OH_SDK/ohos-sdk/linux/native/build-tools/cmake/bin/cmake -DCMAKE_TOOLCHAIN_FILE=/home/ohos/tools/OH_SDK/ohos-sdk/linux/native/build/cmake/ohos.toolchain.cmake .. -L
# 如果需要编译静态库则需要设置 cmake 变量 -DBUILD_SHARED_LIBS=OFF
# 可以通过-DCMAKE_INSTALL_PREFIX=xxx 设置库的安装目录
# 编译 arm32 -DOHOS_ARCH=armeabi-v7a
-- The C compiler identification is Clang 12.0.1
-- Check for working C compiler: /home/ohos/tools/OH_SDK/ohos-sdk/linux/native/llvm/bin/clang # 采用sdk内的编译器
-- Check for working C compiler: /home/ohos/tools/OH_SDK/ohos-sdk/linux/native/llvm/bin/clang -- works
# 删除大量 cmake 日志
ENABLE_PUBLIC_SYMBOLS:BOOL=ON
ENABLE_SAFE_STACK:BOOL=OFF
ENABLE_SANITIZERS:BOOL=OFF
ENABLE_TARGET_EXPORT:BOOL=ON
ENABLE_VALGRIND:BOOL=OFF
ohos@ubuntu20:~/openHarmony/cJSON/ohos64build$ -
继续执行make,编译出so文件
ohos@ubuntu20:~/openHarmony/cJSON/ohos64build$ make
Scanning dependencies of target cjson
[ 2%] Building C object CMakeFiles/cjson.dir/cJSON.c.o
clang: warning: argument unused during compilation: '--gcc-toolchain=/home/ohos/tools/OH_SDK/ohos-sdk/linux/native/llvm' [-Wunused-command-line-argument]
# 删除大量 make 日志
[100%] Linking C executable fuzz_main
[100%] Built target fuzz_main
ohos@ubuntu20:~/openHarmony/cJSON/ohos64build$ -
如果需要编译 arm32 的需要在cmake时加上参数 -DOHOS_ARCH=armeabi-v7a
3、【案例二】openssl(configure方式)
- 参考:https://gitee.com/han_jin_fei/lycium/blob/master/doc/ohos_use_sdk/OHOS_SDK-Usage.md#%E7%BC%96%E8%AF%91%E9%9D%9E-cmake-%E6%9E%84%E5%BB%BA%E7%9A%84%E5%BA%93
- 下载源码:
- 官网下载压缩包

- 官网下载压缩包
- 设置环境变量
-
为什么要设置变量:需要让构建工具使用 OH_SDK 自带的工具链
-
关于C/C++的编译过程,可以结合4.4章节一起看

-
设置 ohos 64bit 库编译工具链环境变量
#aarch64-linux-ohos
export OHOS_SDK=/home/ohos/tools/OH_SDK/ohos-sdk/linux # 此处是我的ohos_sdk解压目录,请替换为你自己的解压目录
export AS=${OHOS_SDK}/native/llvm/bin/llvm-as
export CC="${OHOS_SDK}/native/llvm/bin/clang --target=aarch64-linux-ohos"
export CXX="${OHOS_SDK}/native/llvm/bin/clang++ --target=aarch64-linux-ohos"
export LD=${OHOS_SDK}/native/llvm/bin/ld.lld
export STRIP=${OHOS_SDK}/native/llvm/bin/llvm-strip
export RANLIB=${OHOS_SDK}/native/llvm/bin/llvm-ranlib
export OBJDUMP=${OHOS_SDK}/native/llvm/bin/llvm-objdump
export OBJCOPY=${OHOS_SDK}/native/llvm/bin/llvm-objcopy
export NM=${OHOS_SDK}/native/llvm/bin/llvm-nm
export AR=${OHOS_SDK}/native/llvm/bin/llvm-ar
export CFLAGS="-fPIC -D__MUSL__=1"
export CXXFLAGS="-fPIC -D__MUSL__=1" -
设置 ohos 32bit 库编译工具链环境变量
linux-arm
export OHOS_SDK=/home/ohos/tools/OH_SDK/ohos-sdk/linux # 此处是我的ohos_sdk解压目录,请替换为你自己的解压目录
export AS=${OHOS_SDK}/native/llvm/bin/llvm-as
export CC="${OHOS_SDK}/native/llvm/bin/clang --target=arm-linux-ohos"
export CXX="${OHOS_SDK}/native/llvm/bin/clang++ --target=arm-linux-ohos"
export LD=${OHOS_SDK}/native/llvm/bin/ld.lld
export STRIP=${OHOS_SDK}/native/llvm/bin/llvm-strip
export RANLIB=${OHOS_SDK}/native/llvm/bin/llvm-ranlib
export OBJDUMP=${OHOS_SDK}/native/llvm/bin/llvm-objdump
export OBJCOPY=${OHOS_SDK}/native/llvm/bin/llvm-objcopy
export NM=${OHOS_SDK}/native/llvm/bin/llvm-nm
export AR=${OHOS_SDK}/native/llvm/bin/llvm-ar
export CFLAGS="-fPIC -march=armv7a -D__MUSL__=1"
export CXXFLAGS="-fPIC -march=armv7a -D__MUSL__=1" -
检查环境变量
env | grep oh -
打包结束之后,取消设置的环境变量(OH_SDK的变量可以考虑保留)
unset OHOS_SDK AS CC CXX LD STRIP RANLIB OBJDUMP OBJCOPY NM AR CFLAGS CXXFLAGS -
配置好环境变量之后,然后按照正常的Configure流程走就行了
-
- 执行Configure/Make/Make install
-
进入openssl路径,执行命令
./Configure linux-aarch64 --prefix=/home/cocos/test-zhou/openssl-test/openssl_install -
configure命令执行完之后,openssl目录下多出了两个文件
- configdata.pm
- Makefile
-
执行命令
make -
执行命令
make install -
在prefix指定的路径下,得到了对应的文件
ohos@ubuntu20:~/openHarmony/openssl$ cd ../openssl_install/
ohos@ubuntu20:~/openHarmony/openssl_install$ ls
bin include lib share ssl
ohos@ubuntu20:~/openHarmony/openssl_install$ ls bin/
c_rehash openssl
ohos@ubuntu20:~/openHarmony/openssl_install$ ls lib/
engines-1.1 libcrypto.a libcrypto.so libcrypto.so.1.1 libssl.a libssl.so libssl.so.1.1 pkgconfig
ohos@ubuntu20:~/openHarmony/openssl_install$ ls include/
openssl
-
4、【案例三】Lycium 项目构建
- 项目路径:https://gitee.com/han_jin_fei/lycium/tree/master
- 再次提醒,选择已有so库时,注意版本号是否匹配。若不匹配,尤其是跨越了大版本的情况下,可能无法复用,请根据实际情况审视
- 构建项目
-
构建前,请先阅读:https://gitee.com/han_jin_fei/lycium/blob/master/README.md
-
编译环境准备:https://gitee.com/han_jin_fei/lycium/blob/master/Buildtools/README.md
cd lycium/Buildtools
# 校验压缩包
sha512sum -c SHA512SUM
# 输出 toolchain.tar.gz: OK
# 解压拷贝编译工具
tar -zxvf toolchain.tar.gz
cp toolchain/* ${OHOS_SDK}/native/llvm/bin -
如果是全新的设备,还需要处理cmake版本,依旧参考上面的这个markdown
-
在Lycium根目录执行build即可,根据需要,可以选择需要构建的三方库
./build.sh cJSON
-
5、【案例四】Lua(NDK适配)
1)NDK方式适配说明
- NDK方式构建,使用的是Android.mk文件,编译鸿蒙so时,需要将mk先转换成cmake语法,然后编译构建
- 针对mk转换为cmake,可以参考如下文档:
- 推荐方式:先使用自动转换工具,得到一份转换后的cmake文件,再调整语法错误
- TIP:中只提供了Android.mk文件,转换是会提示没有 Application.mk文件,无法生成cmake。此时可以手动写一个简单的Application.mk文件,方便快速生成
# The ARMv7 is significanly faster due to the use of the hardware FPU
APP_ABI := armeabi-v7a arm64-v8a
#安卓平台的名称,比如android-16
# APP_PLATFORM := android-19
#指定使用C++进行编程时所以来的标准库,默认libstdc++
APP_STL := c++_static
#选择GCC编译器版本,64位ABI默认使用版本4.9,32位ABI默认使用版本4.8,要选择Clang的版本,变量定义为clang3.4、clang3.5或clang
NDK_TOOLCHAIN_VERSION := clang
2)Lua构建
- Android.mk如下
LOCAL_PATH := E:\Lua\lua-5.1.5\src
include $(CLEAR_VARS)
LOCAL_MODULE := liblibCore
LOCAL_SRC_FILES := cpp/MemoryManager.cpp lapi.c lauxlib.c lbaselib.c lcode.c ldblib.c ldebug.c ldo.c ldump.c lfunc.c lgc.c linit.c liolib.c llex.c lmathlib.c lmem.c loadlib.c lobject.c lopcodes.c loslib.c lparser.c lstate.c lstring.c lstrlib.c ltable.c ltablib.c ltm.c lundump.c lvm.c lzio.c LKFile/data_table.cpp LKFile/file_system.cpp LKFile/fragment_table.cpp LKFile/index_table.cpp LKFile/ioutil.cpp LKFile/log.cpp fixhelper.c cpp/Fix.cpp cpp/FixConst.cpp cpp/FixMath.cpp
LOCAL_LDLIBS := -lm -llog -lc -lgcc -std=c++11
LOCAL_CFLAGS := -DANDROID -O2
LOCAL_CPPFLAGS += -fexceptions -fvisibility=hidden -O2
include $(BUILD_SHARED_LIBRARY)
- 使用自动转换工具,生成如下文件
cmake_minimum_required(VERSION 3.6)
set(NDK_TOOLCHAIN_VERSION clang)
set(LOCAL_PATHE:\nntgtd\Lua\lua-5.1.5\src)
project(liblibCore)
set(${PROJECT_NAME}_src cpp/MemoryManager.cpp lapi.c lauxlib.c lbaselib.c lcode.c ldblib.c ldebug.c ldo.c ldump.c lfunc.c lgc.c linit.c liolib.c llex.c lmathlib.c lmem.c loadlib.c lobject.c lopcodes.c loslib.c lparser.c lstate.c lstring.c lstrlib.c ltable.c ltablib.c ltm.c lundump.c lvm.c lzio.c LKFile/data_table.cpp LKFile/file_system.cpp LKFile/fragment_table.cpp LKFile/index_table.cpp LKFile/ioutil.cpp LKFile/log.cpp fixhelper.c cpp/Fix.cpp cpp/FixConst.cpp cpp/FixMath.cpp)
add_library(${PROJECT_NAME} SHARED ${${PROJECT_NAME}_src})
target_link_libraries(${PROJECT_NAME} PRIVATE -lm -llog -lc -lgcc -std=c++11)
target_compile_options(${PROJECT_NAME} PRIVATE -DANDROID -O2)
target_compile_options(${PROJECT_NAME} PRIVATE -fexceptions -fvisibility=hidden -O2)
- 调整相关语法错误后,参考案例一,继续构建Makefile,make后得到相关so
- 上述自动转换过程中存在一个错误,Android.mk 文件中指定了CPP文件的编译标记,但是在cmake中直接指定了整个全量的编译标记:
# Android.mk中,指定的是CPP FLAG
LOCAL_CPPFLAGS += -fexceptions -fvisibility=hidden -O2
# 转译后的cmake文件,对应的是target_compile_options
target_compile_options(${PROJECT_NAME} PRIVATE -fexceptions -fvisibility=hidden -O2)
- 所以需要修改cmake文件,仅针对CPP文件可见性进行隐藏,修改如下:
cmake_minimum_required(VERSION
set(LOCAL_PATH src)
project(libCore)
set(${PROJECT_NAME}_src ${LOCAL_PATH}/cpp/MemoryManager.cpp
# 新增如下方法,指定隐藏CPP的可见性
set(CMAKE_CXX_FLAGS "-fvisibility=hidden ${CMAKE_CXX_FLAGS}")
add_library(${PROJECT_NAME} SHARED ${${PROJECT_NAME}_src})
target_link_libraries(${PROJECT_NAME} PRIVATE -lm -lc -std=c++11)
target_compile_options(${PROJECT_NAME} PRIVATE -DANDROID -O2)
# 删除全局hidden参数
target_compile_options(${PROJECT_NAME} PRIVATE -fexceptions -O2)
- 重新打包,验证功能正常
6、【案例五】toLua(NDK适配)
- toLua打包思路和Lua一致,此案例只列举打包中的一些思路
- 源码:https://github.com/topameng/tolua_runtime
1)快速生成cmake
-
toLua源码中,Android路径下只包含了一个 Android.mk文件,使用自动转换cmake工具(工具详见3.5章节内容)时,会提示没有 Application.mk文件,无法生成。此时,可以手动写一个简单的Application.mk文件,方便快速生成,例如:
# The ARMv7 is significanly faster due to the use of the hardware FPU
APP_ABI := armeabi-v7a arm64-v8a
#安卓平台的名称,比如android-16
# APP_PLATFORM := android-19
#指定使用C++进行编程时所以来的标准库,默认libstdc++
APP_STL := c++_static
#选择GCC编译器版本,64位ABI默认使用版本4.9,32位ABI默认使用版本4.8,要选择Clang的版本,变量定义为clang3.4、clang3.5或clang
NDK_TOOLCHAIN_VERSION := clang
2)构建中间件 libLuaJit.a
- 自动生成cmake之后,发现toLua还需要依赖一个静态链接库libluajit
LOCAL_MODULE := libluajit
LOCAL_SRC_FILES := libluajit.a
include $(PREBUILT_STATIC_LIBRARY)
- 如何实现这个静态库的编译,有许多方法,在这里提供一个思路供参考
- 参考3.4章节内容,核心思路是:借鉴Lycium的脚本
- 首先找到Lycium中的luajit路径,查看:https://gitee.com/han_jin_fei/lycium/blob/master/main/LuaJIT/HPKBUILD
- 观察这个脚本,主要查看 prepare 和 build 两个方法:
- 如果遇到部分工具找不到,可以尝试在对应工具目录下查找带“-unknown-”的相同工具,并建立同名软链接使用。例如:aarch64-linux-ohos-clang 找不到,可以查找 aarch64-unknown-linux-ohos-clang 是否存在。
prepare() {
cp -rf $builddir $builddir-$ARCH-build
cd $builddir-$ARCH-build
if [ $ARCH == "armeabi-v7a" ]
then
dynamic_cc=${OHOS_SDK}/native/llvm/bin/arm-linux-ohos-clang
target_ld=${OHOS_SDK}/native/llvm/bin/arm-linux-ohos-clang
host_gcc="gcc -m32"
elif [ $ARCH == "arm64-v8a" ]
then
dynamic_cc=${OHOS_SDK}/native/llvm/bin/aarch64-linux-ohos-clang
target_ld=${OHOS_SDK}/native/llvm/bin/aarch64-linux-ohos-clang
host_gcc="gcc"
else
echo "${ARCH} not support"
return -1
fi
static_cc=${dynamic_cc}
export target_ar="${OHOS_SDK}/native/llvm/bin/llvm-ar rcus 2>/dev/null"
target_strip=${OHOS_SDK}/native/llvm/bin/llvm-strip
cd $OLDPWD
}
build() {
cd $builddir-$ARCH-build
$MAKE HOST_CC="$host_gcc" CFLAGS="-fPIC" DYNAMIC_CC=${dynamic_cc} TARGET_LD=${target_ld} STATIC_CC=${static_cc} TARGET_AR="${target_ar}" TARGET_STRIP=${target_strip} > $buildlog 2>&1
ret=$?
cd $OLDPWD
return $ret
}
- 观察上面的脚本,核心思路就两点:
- 设置make所需的环境变量
- 通过cmake命令编译
- 因此我们只需要照抄11-13行、18-20行和25行,即可得到构建luajit静态库的脚本
# OpenHarmony/ARM64, armeabi-v8a
dynamic_cc=${OHOS_SDK}/native/llvm/bin/aarch64-linux-ohos-clang
target_ld=${OHOS_SDK}/native/llvm/bin/aarch64-linux-ohos-clang
static_cc=${dynamic_cc}
export target_ar="${OHOS_SDK}/native/llvm/bin/llvm-ar rcus 2>/dev/null"
target_strip=${OHOS_SDK}/native/llvm/bin/llvm-strip
make clean
make -j32 HOST_CC="gcc" CFLAGS="-fPIC" DYNAMIC_CC=${dynamic_cc} TARGET_LD=${target_ld} STATIC_CC=${static_cc} TARGET_AR="${target_ar}" TARGET_STRIP=${target_strip}
cp ./libluajit.a ../../openharmony/libluajit.a