跳到主要内容

Linux环境编译三方库

一、环境准备

1、准备Ubuntu虚拟机

  • 推荐Ubuntu 20.04
  • 设置共享文件夹,用于传递文件 image-20231117161428858
  • 虚拟机重启后,要重新挂载一下共享文件夹

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使用说明
      llvmclang 编译器
      sysroot编译器的 sysroot 目录,存放 SDK 内部的已经包含的库和对应的头文件
      oh-uni-package.json为 SDK 信息描述,如版本
      NOTICE.txt注意事项,内容多为 SDK 的详细描述
      ndk_system_capability.json记录 SDK 提供的能力
      nativeapi_syscap_config.json记录 SDK 提供的能力对应的头文件

二、构建前准备

三、构建三方库

1、打包须知

2、【案例一】cJSON(CMake方式)

  • 参考:https://gitee.com/han_jin_fei/lycium/blob/master/doc/ohos_use_sdk/OHOS_SDK-Usage.md#%E7%BC%96%E8%AF%91cmake%E6%9E%84%E5%BB%BA%E7%9A%84%E5%BA%93

  • 下载源码

  • 以方法一为例,解压代码压缩包,然后进入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
  • 下载源码:
    • 官网下载压缩包 image-20231117163514082
  • 设置环境变量
    • 为什么要设置变量:需要让构建工具使用 OH_SDK 自带的工具链

    • 关于C/C++的编译过程,可以结合4.4章节一起看 image-20231117163558748

    • 设置 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 项目构建

5、【案例四】Lua(NDK适配)

1)NDK方式适配说明

# 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适配)

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