鸿蒙PC生态实践:LAME 音频编码库移植与工程化指南 - 指南
本文详细介绍了如何针对 OpenHarmony PC 平台,使用 CMake 构建系统交叉编译 LAME MP3 编码库。文章聚焦于解决标准库缺失、架构不匹配等核心移植难题,并提供了适配鸿蒙PC开发环境的工程化 CMakeLists.txt 方案。
前言:鸿蒙PC生态的拓展与三方库移植意义
随着 HarmonyOS 正式进军 PC 领域,构建完善的软件生态成为关键。由于鸿蒙 PC 版的底层基于 OpenHarmony 与 Linux 内核的混合架构,现有 Linux/Windows 平台的开源库需要针对鸿蒙 PC 进行交叉编译与系统级适配。本文将以开源音频库 LAME 为例,详细介绍如何在鸿蒙 PC 平台上完成三方库的移植,并提供可复用的工程化方案。
LAME是目前非常优秀的一种MP3编码引擎,在业界,转码成MP3格式的音频文件时,最常用的编码器就是LAME库。当到达320Kbit/s以上时,LAME编码出来的音频质量几乎可以和CD的音质相媲美,并且还能保证整个音频文件的体积非常小,因此若要在移动端平台上编码MP3文件,使用LAME便成为唯一的选择。同时该库也是ffmpeg的依赖库之一。
一、移植工具链环境搭建
鸿蒙 PC 开发需使用专用的交叉编译工具链。关于环境的搭建,参见猫哥的上一篇博文:《鸿蒙PC生态三方软件移植:开发环境搭建及三方库移植指南》。
虽然官方提供了示例项目工程和 build.sh 脚本,但这些方案适合批量构建多个库,不方便单独调试。我们采用更灵活的 exports.sh 脚本来配置独立的开发环境。
- 配置 SDK 路径与基础工具链
在项目目录下创建 exports.sh 文件,声明 SDK 路径与编译工具。
根据你实际的改下配置:
echo "hello exports"
## 你的SDK路径
SDK_PATH="/root/ohos-sdk/linux"
echo "SDK_PATH:$SDK_PATH"
export OHOS_SDK="$SDK_PATH"
export HNP_PERFIX=
export COMPILER_TOOLCHAIN=${OHOS_SDK}/native/llvm/bin/
BUILD_OS=$(uname)
PYTHON=$(python --version)
echo "python : $PYTHON"
export CC=${COMPILER_TOOLCHAIN}clang && echo "CC : ${CC}"
export CXX=${COMPILER_TOOLCHAIN}clang++ && echo "CXX : ${CXX}"
export HOSTCC=${CC} && echo "HOSTCC : ${HOSTCC}"
export HOSTCXX=${CXX} && echo "HOSTCXX : ${HOSTCXX}"
export CPP="${CXX} -E" && echo "CPP : ${CPP}"
export AS=${COMPILER_TOOLCHAIN}llvm-as && echo "AS : ${AS}"
export LD=${COMPILER_TOOLCHAIN}ld.lld && echo "LD : ${LD}"
export STRIP=${COMPILER_TOOLCHAIN}llvm-strip && echo "STRIP : ${STRIP}"
export RANLIB=${COMPILER_TOOLCHAIN}llvm-ranlib && echo "RANLIB : ${RANLIB}"
export OBJDUMP=${COMPILER_TOOLCHAIN}llvm-objdump && echo "OBJDUMP : ${OBJDUMP}"
export OBJCOPY=${COMPILER_TOOLCHAIN}llvm-objcopy && echo "OBJCOPY : ${OBJCOPY}"
export NM=${COMPILER_TOOLCHAIN}llvm-nm && echo "NM : ${NM}"
export AR=${COMPILER_TOOLCHAIN}llvm-ar && echo "AR : ${AR}"
export SYSROOT=${OHOS_SDK}/native/sysroot
export PKG_CONFIG_SYSROOT_DIR=${SYSROOT}/usr/lib/aarch64-linux-ohos
export PKG_CONFIG_PATH=${PKG_CONFIG_SYSROOT_DIR}
export PKG_CONFIG_EXECUTABLE=${PKG_CONFIG_SYSROOT_DIR}
export HNP_TOOL=${OHOS_SDK}/toolchains/hnpcli
export CMAKE=${OHOS_SDK}/native/build-tools/cmake/bin/cmake
export TOOLCHAIN_FILE=${OHOS_SDK}/native/build/cmake/ohos.toolchain.cmake
export WORK_ROOT=${PWD}
export ARCHIVE_PATH=${WORK_ROOT}/output
export COMM_DEP_PATH=${WORK_ROOT}/deps_install
export HNP_PUBLIC_PATH=${HNP_PERFIX}/data/service/hnp/
export MAKE_QUITE_PARAM=" -s "
export CONFIGURE_QUITE_PARAM=" --quiet "
export TARGET_PLATFORM=aarch64-linux-ohos
export CFLAGS="-fPIC -D__MUSL__=1 -D__OHOS__ -fstack-protector-strong --target=${TARGET_PLATFORM} --ld-path=${LD} --sysroot=${SYSROOT}"
export CXXFLAGS="${CFLAGS} "
export LD_LIBRARY_PATH=${SYSROOT}/usr/lib:${LD_LIBRARY_PATH}
export LDFLAGS="${LDFLAGS} --ld-path=${LD} --target=${TARGET_PLATFORM} --sysroot=${SYSROOT}"
export HOST_TYPE="--host=aarch64-linux --build=aarch64-linux"
#export NCURSES_INSTALL_HNP_PATH="${HNP_PUBLIC_PATH}/ncurses.org/ncurses_v6.4"
mkdir -p ${HNP_PUBLIC_PATH}
mkdir -p ${ARCHIVE_PATH}
mkdir -p code
#export PKG_CONFIG_PATH="${CUSTOM_PREFIX}/lib/pkgconfig:$PKG_CONFIG_PATH"
通过执行 source exports.sh 激活环境。
- CMake 工具链配置
鸿蒙 SDK 提供专用的 ohos.toolchain.cmake 文件,用于指导 CMake 的交叉编译行为。该配置已包含在上述 exports.sh 脚本中。
二、LAME 库移植实战
LAME(Lame Aint an MP3 Encoder)是一个高质量的开源 MP3 音频编码器。LAME 原始的构建系统依赖于 configure 脚本生成 config.h 文件和 Makefiles,这在鸿蒙交叉编译环境中容易出现兼容性问题。因此,我们选择使用 CMake 构建系统,并手动解决移植过程中遇到的关键问题。
lame源码地址:https://sourceforge.net/projects/lame/
- 移植遇到的主要问题与解决思路
手动使用 CMake 构建时,跳过了 LAME 原有的 configure 脚本所做的系统类型检查,导致以下错误:
链接错误:cannot find crti.o 或 file in wrong format (EM: 183),通常是由于工具链未正确配置 sysroot 或架构不匹配导致。
编译错误:unknown type name ‘ieee754_float32_t’ 或 undeclared identifier ‘INT_MAX’ 等。
解决思路:
配置 Sysroot:通过 exports.sh 正确设置 CMAKE_SYSROOT 和 TARGET_PLATFORM,确保编译器能找到标准的 C 库头文件。
适配类型定义:在 CMake 中手动定义 ieee754_float32_t 类型别名,模拟 config.h 的功能。 - 核心 CMake 构建脚本 (CMakeLists.txt)
将以下内容保存为 LAME 源码根目录下的 CMakeLists.txt:
控制是否构建前端可执行文件 (lame),默认禁用以简化移植:
option(BUILD_FRONTEND "Build the LAME frontend executable (lame)" OFF)
set(LAME_VERSION_MAJOR 3)
set(LAME_VERSION_MINOR 100)
set(LAME_VERSION "${LAME_VERSION_MAJOR}.${LAME_VERSION_MINOR}")
包含头文件路径
include_directories(
"${CMAKE_CURRENT_SOURCE_DIR}/include"
"${CMAKE_CURRENT_SOURCE_DIR}/libmp3lame"
)
定义源代码文件列表
file(GLOB_RECURSE LAME_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/libmp3lame/*.c")
— 解决编译错误的关键部分 —
- 解决 ‘ieee754_float32_t’ unknown type name 错误,手动定义为 float
add_definitions(-Dieee754_float32_t=float)
注意:此脚本依赖于外部工具链配置(如 exports.sh 中的 --sysroot)来查找标准库头文件。
添加库目标 (构建为动态库 SHARED,适配鸿蒙动态链接机制)
add_library(mp3lame SHARED ${LAME_SOURCES})
set_target_properties(mp3lame PROPERTIES
VERSION ${LAME_VERSION}
SOVERSION ${LAME_VERSION_MAJOR}
PUBLIC_HEADER "${CMAKE_CURRENT_SOURCE_DIR}/include/lame.h"
)
定义安装规则
install(TARGETS mp3lame
RUNTIME DESTINATION bin
LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib
PUBLIC_HEADER DESTINATION include
)
根据选项决定是否编译前端
if(BUILD_FRONTEND)
message(STATUS "Building LAME frontend executable (lame)")
# ... (此处省略前端构建代码) ...
else()
message(STATUS "Frontend executable build disabled by option BUILD_FRONTEND")
endif()
- 开始执行编译
确保您已经按照第一节配置了 exports.sh 并激活环境。 - 激活环境
source exports.sh
- 进入 LAME 源码目录,创建并进入 build 目录
cd /path/to/lame/source
mkdir build
cd build
- 运行 CMake,指定源码目录(…),并使用鸿蒙专用的工具链文件
CMAKE 环境变量已经在 exports.sh 中定义
${CMAKE} .. -DCMAKE_TOOLCHAIN_FILE=${TOOLCHAIN_FILE} -DBUILD_SHARED_LIBS=ON
- 编译
make -j$(nproc)
完整的cmake脚本
CMakeLists.txt文件:
cmake_minimum_required(VERSION 3.12)
project(LAME C)
# --- 添加一个选项来控制是否构建前端 ---
# 默认开启 (ON),如果你想默认禁用,可以改为 OFF
option(BUILD_FRONTEND "Build the LAME frontend executable (lame)" OFF)
set(LAME_VERSION_MAJOR 3)
set(LAME_VERSION_MINOR 100)
set(LAME_VERSION "${LAME_VERSION_MAJOR}.${LAME_VERSION_MINOR}")
# 包含头文件路径
include_directories(
"${CMAKE_CURRENT_SOURCE_DIR}/include"
"${CMAKE_CURRENT_SOURCE_DIR}/libmp3lame"
)
# 定义源代码文件列表
file(GLOB_RECURSE LAME_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/libmp3lame/*.c")
# --- 解决编译错误的关键部分 ---
# 1. 解决 'ieee754_float32_t' unknown type name 错误
add_definitions(-Dieee754_float32_t=float)
# 添加库目标
add_library(mp3lame SHARED ${LAME_SOURCES})
# 将列表中的每个项目作为单独的选项传递
target_compile_options(mp3lame PRIVATE ${LAME_REQUIRED_INCLUDES})
set_target_properties(mp3lame PROPERTIES
VERSION ${LAME_VERSION}
SOVERSION ${LAME_VERSION_MAJOR}
PUBLIC_HEADER "${CMAKE_CURRENT_SOURCE_DIR}/include/lame.h"
)
install(TARGETS mp3lame
RUNTIME DESTINATION bin
LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib
PUBLIC_HEADER DESTINATION include
)
# --- 使用 if 语句根据选项决定是否编译前端 ---
if(BUILD_FRONTEND)
message(STATUS "Building LAME frontend executable (lame)")
file(GLOB_RECURSE FRONTEND_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/frontend/*.c")
add_executable(lame ${FRONTEND_SOURCES})
target_link_libraries(lame mp3lame)
target_compile_options(lame PRIVATE ${LAME_REQUIRED_INCLUDES})
install(TARGETS lame RUNTIME DESTINATION bin)
else()
message(STATUS "Frontend executable build disabled by option BUILD_FRONTEND")
endif()
三、编译注意事项
如果待移植的项目原生支持 CMake,强烈建议直接使用 CMake 进行构建,可以省去大量适配 configure 脚本和 Makefile 的麻烦。如本文所示,通过适配 CMake,可以高效地解决鸿蒙 PC 平台移植中遇到的标准库兼容性和架构配置问题。
build_os.sh脚本:
export LAME_INSTALL_HNP_PATH=${HNP_PUBLIC_PATH}/lame.org/lame_3.100
#make clean
${CMAKE} \
-DCMAKE_TOOLCHAIN_FILE=${TOOLCHAIN_FILE} \
-DCMAKE_BUILD_TYPE=Release \
-DBUILD_SHARED_LIBS=ON \
-DCMAKE_INSTALL_PREFIX=${LAME_INSTALL_HNP_PATH}\
-DCMAKE_SYSROOT="${SYSROOT}"
make VERBOSE=1 -j$(nproc)
make install
cp hnp.json ${LAME_INSTALL_HNP_PATH}/
pushd ${LAME_INSTALL_HNP_PATH}/../
${HNP_TOOL} pack -i ${LAME_INSTALL_HNP_PATH} -o ${ARCHIVE_PATH}/
tar -zvcf ${ARCHIVE_PATH}/ohos_lame_3.100.tar.gz lame_3.100/
popd
编译成功截图:

如果使用原始的configure脚本形式,编译莫名报错,这个报错原因,至今未找到答案。
原来的build_ohos.sh脚本如下:
export LAME_INSTALL_HNP_PATH=${HNP_PUBLIC_PATH}/lame.org/lame_3.100
#make clean
./configure --host=aarch64-linux-musl \
--target=aarch64-linux-musl \
--enable-shared \
--disable-static \
--prefix=${LAME_INSTALL_HNP_PATH}
make VERBOSE=1 -j$(nproc)
make install
cp hnp.json ${LAME_INSTALL_HNP_PATH}/
pushd ${LAME_INSTALL_HNP_PATH}/../
${HNP_TOOL} pack -i ${LAME_INSTALL_HNP_PATH} -o ${ARCHIVE_PATH}/
tar -zvcf ${ARCHIVE_PATH}/ohos_lame_3.100.tar.gz lame_3.100/
popd

最后实在没办法了,给lame库写了个cmake的脚本,使用cmake的方式搞定了。
如果其他小伙伴有使用configure脚本生成makefile形式编译成功的,欢迎留言交流下哈。
浙公网安备 33010602011771号