GNU Libtool 是一个通用的库支持脚本,用于简化在不同平台上构建和使用共享库的过程。本文将详细介绍将 libtool 2.4.10 适配到 HarmonyOS PC 平台的完整过程,特别是遇到的各类问题和解决方案。
# macOS 上安装必需工具
brew install m4 autoconf automake libtool help2man texinfo
# 注意:m4 版本要求
# libtool 的 bootstrap 脚本对 m4 版本有严格要求
# 必须使用 Homebrew 的 m4,而不是系统的 gm4
export M4="/opt/homebrew/opt/m4/bin/m4"
export PATH="/opt/homebrew/opt/m4/bin:${PATH}"export SDK_PATH="/path/to/ohosdk"
export CC="${SDK_PATH}/native/llvm/bin/clang"
export CXX="${SDK_PATH}/native/llvm/bin/clang++"
export SYSROOT="${SDK_PATH}/native/sysroot"问题描述:
libtool 依赖 gnulib(GNU 可移植性库),需要通过 bootstrap 脚本初始化。首次运行 bootstrap 时,出现以下错误:
bootstrap: error: Prerequisite 'help2man' not found.
bootstrap: error: Prerequisite 'makeinfo' not found.根本原因:
bootstrap 脚本会检查 help2man 和 makeinfo 工具是否存在,但这些工具在交叉编译环境中不是必需的,只是用于生成文档。
解决方案:
创建临时的包装脚本来满足 bootstrap 的检查:
# 创建临时目录存放包装脚本
BOOTSTRAP_BIN_DIR="$(pwd)/.bootstrap_bin"
mkdir -p "${BOOTSTRAP_BIN_DIR}"
# 创建 help2man 包装脚本
cat > "${BOOTSTRAP_BIN_DIR}/help2man" << 'EOF'
#!/bin/sh
if [ "$1" = "--version" ]; then
echo "help2man (GNU help2man) 1.49.3"
exit 0
fi
exit 0
EOF
# 创建 makeinfo 包装脚本
cat > "${BOOTSTRAP_BIN_DIR}/makeinfo" << 'EOF'
#!/bin/sh
if [ "$1" = "--version" ]; then
echo "makeinfo (GNU texinfo) 7.0"
exit 0
fi
exit 0
EOF
chmod +x "${BOOTSTRAP_BIN_DIR}/help2man" "${BOOTSTRAP_BIN_DIR}/makeinfo"
export HELP2MAN="${BOOTSTRAP_BIN_DIR}/help2man"
export MAKEINFO="${BOOTSTRAP_BIN_DIR}/makeinfo"
export PATH="${BOOTSTRAP_BIN_DIR}:${PATH}"经验总结:
bootstrap 脚本通常会检查文档生成工具问题描述:
bootstrap 脚本尝试从官方 GNU 服务器下载 gnulib,但网络连接失败或速度很慢:
bootstrap: running: git clone --shallow-since=2019-02-19 'https://git.savannah.gnu.org/git/gnulib' 'gnulib'根本原因:
bootstrap 脚本优先使用 .gitmodules 文件中的 URLGNULIB_URL 或 gnulib_url 的优先级低于 .gitmodules解决方案:
修改 .gitmodules 文件,将 gnulib 的 URL 替换为 GitCode 镜像:
# 设置使用 GitCode 镜像
export gnulib_url="git@gitcode.com:jianguoxu/gnulib.git"
# 修改 .gitmodules 文件(bootstrap 优先使用此文件)
if [ -f ".gitmodules" ]; then
# 替换官方 URL 为 GitCode 镜像
sed -i.bak 's|url = https://git.savannah.gnu.org/git/gnulib|url = git@gitcode.com:jianguoxu/gnulib.git|g' .gitmodules 2>/dev/null || \
sed -i '' 's|url = https://git.savannah.gnu.org/git/gnulib|url = git@gitcode.com:jianguoxu/gnulib.git|g' .gitmodules 2>/dev/null || true
fi经验总结:
.gitmodules 的优先级高于环境变量.gitmodulessed 命令参数不同,需要兼容处理问题描述:
运行 aclocal 时出现错误,提示不支持某些语言:
configure.ac: error: unsupported language: Objective-C
configure.ac: error: unsupported language: Objective-C++
configure.ac: error: unsupported language: Microsoft Macro Assembler根本原因:
configure.ac 中定义了 Objective-C、Objective-C++ 和 Microsoft Macro Assembler 的语言支持,但这些语言在交叉编译到 HarmonyOS 时不被支持。
解决方案:
在运行 aclocal 之前,注释掉这些不支持的语言:
# 必须在运行 aclocal 之前修复
if [ -f "configure.ac" ]; then
# 备份 configure.ac
cp configure.ac configure.ac.bak
# 注释掉不支持的语言
sed -i.bak 's/^LT_LANG(Objective-C)$/# LT_LANG(Objective-C) # Disabled for cross-compilation/' configure.ac
sed -i.bak 's/^LT_LANG(Objective-C++)$/# LT_LANG(Objective-C++) # Disabled for cross-compilation/' configure.ac
sed -i.bak 's/^LT_LANG(Microsoft Macro Assembler)$/# LT_LANG(Microsoft Macro Assembler) # Disabled for cross-compilation/' configure.ac
fi经验总结:
aclocal 运行之前修改 configure.acaclocal.m4 生成,再修改 configure.ac 就无效了问题描述:
运行 make bootstrap-deps 或 automake 时出现错误:
automake: error: cannot open < libltdl/ltdl.mk: No such file or directory
make[1]: *** No rule to make target `libltdl/ltdl.mk', needed by `libltdl/Makefile.am'. Stop.根本原因:
libltdl/ltdl.mk 文件应该由 make bootstrap-deps 生成bootstrap-deps 本身需要这个文件存在才能运行解决方案:
在运行 bootstrap 之前,创建占位文件:
# 创建占位文件 libltdl/ltdl.mk
if [ ! -f "libltdl/ltdl.mk" ]; then
mkdir -p libltdl
cat > libltdl/ltdl.mk << 'EOF'
# Placeholder ltdl.mk file
# This file will be regenerated by make bootstrap-deps
LTDLDIR = libltdl
# DO NOT REMOVE THIS LINE -- make depends on it
EOF
fi关键点:
# DO NOT REMOVE THIS LINE -- make depends on it 这一行Makefile.am 的生成规则会检查这一行bootstrap-deps 过程中被正确生成的文件替换经验总结:
问题描述:
运行 make 时出现错误:
make[2]: *** No rule to make target `m4/ltversion.in', needed by `m4/ltversion.m4'. Stop.根本原因:
m4/ltversion.m4 依赖于 m4/ltversion.inltversion.in 应该由 make bootstrap-deps 生成bootstrap-deps 失败,这个文件就不会被创建解决方案:
在运行 configure 之前和之后,都确保这个文件存在:
# 在 configure 之前创建
if [ ! -f "m4/ltversion.in" ]; then
mkdir -p m4
cat > m4/ltversion.in << 'EOF'
# This file is used by ltversion.m4
m4_define([LT_PACKAGE_VERSION], [@PACKAGE_VERSION@])
m4_define([LT_PACKAGE_REVISION], [@PACKAGE_REVISION@])
EOF
fi
# 在 configure 之后再次检查(可能被 config.status 删除)
if [ ! -f "m4/ltversion.in" ]; then
# 重新创建
fi经验总结:
config.status 可能会删除某些文件问题描述:
bootstrap 阶段创建的包装脚本在 make 时已经不存在,导致构建失败:
/bin/sh: /path/to/.bootstrap_bin/help2man: No such file or directory
make[2]: *** [doc/libtool.1] Error 127根本原因:
bootstrap 完成后,临时目录可能被清理Makefile 中硬编码了 help2man 和 makeinfo 的路径make 阶段仍然需要这些工具来生成文档解决方案:
在运行 make 之前,重新创建包装脚本:
# 在 configure 成功后,make 之前
BOOTSTRAP_BIN_DIR="$(pwd)/.bootstrap_bin"
mkdir -p "${BOOTSTRAP_BIN_DIR}"
# 重新创建 help2man 包装脚本
if [ ! -f "${BOOTSTRAP_BIN_DIR}/help2man" ]; then
cat > "${BOOTSTRAP_BIN_DIR}/help2man" << 'HELP2MAN_EOF'
#!/bin/sh
# ... 完整的包装脚本内容 ...
HELP2MAN_EOF
chmod +x "${BOOTSTRAP_BIN_DIR}/help2man"
fi
# 重新创建 makeinfo 包装脚本
if [ ! -f "${BOOTSTRAP_BIN_DIR}/makeinfo" ]; then
cat > "${BOOTSTRAP_BIN_DIR}/makeinfo" << 'MAKEINFO_EOF'
#!/bin/sh
# ... 完整的包装脚本内容 ...
MAKEINFO_EOF
chmod +x "${BOOTSTRAP_BIN_DIR}/makeinfo"
fi经验总结:
bootstrap 和 make 是两个不同的阶段--version 检查问题描述:
help2man 包装脚本输出了 man 页面内容到终端,但文件没有被创建:
GEN doc/libtool.1
.TH LIBTOOL 1 "2024" "GNU Libtool"
.SH NAME
...
install: ././doc/libtool.1: No such file or directory
make[3]: *** [install-man1] Error 71根本原因:
help2man 的输出被重定向到文件,但包装脚本只输出到 stdout解决方案:
改进 help2man 包装脚本,使其能够检测输出文件并直接写入:
cat > "${BOOTSTRAP_BIN_DIR}/help2man" << 'HELP2MAN_EOF'
#!/bin/sh
# 处理 --version 和 --help
if [ "$1" = "--version" ]; then
echo "help2man (GNU help2man) 1.49.3"
exit 0
fi
# 查找输出文件参数
OUTPUT_FILE=""
for arg in "$@"; do
case "$arg" in
--output=*)
OUTPUT_FILE="${arg#--output=}"
;;
--output)
# 下一个参数是输出文件
PREV_ARG="--output"
continue
;;
*)
if [ "$PREV_ARG" = "--output" ]; then
OUTPUT_FILE="$arg"
fi
PREV_ARG=""
;;
esac
done
# 如果没有找到输出文件,尝试从输入文件名推断
if [ -z "$OUTPUT_FILE" ] && [ -n "$INPUT_BINARY" ]; then
BASE_NAME=$(basename "$INPUT_BINARY")
OUTPUT_FILE="doc/${BASE_NAME}.1"
fi
# 如果找到了输出文件,直接写入
if [ -n "$OUTPUT_FILE" ]; then
mkdir -p "$(dirname "$OUTPUT_FILE")"
cat > "$OUTPUT_FILE" << 'MAN_EOF'
.TH LIBTOOL 1 "2024" "GNU Libtool"
.SH NAME
libtool \- GNU libtool
...
MAN_EOF
exit 0
fi
# 否则输出到 stdout
echo "..."
exit 0
HELP2MAN_EOF经验总结:
问题描述:
运行 configure 时出现错误:
configure: line 32976: GL_INIT: command not found
config.status: error: cannot find input file: 'Makefile.in'根本原因:
GL_INIT 是 gnulib 提供的宏,定义在 m4/gnulib-comp.m4 中aclocal 需要包含 gnulib/m4 目录才能找到这些宏aclocal 没有正确配置,宏就不会被展开解决方案:
确保 aclocal 调用时包含 gnulib/m4 目录:
# 检查 gnulib 是否已初始化
if [ -d "gnulib/m4" ]; then
# 运行 aclocal,包含 gnulib/m4 目录
aclocal -I m4 -I gnulib/m4 || {
echo "Error: aclocal failed"
exit 1
}
else
# 如果 gnulib 未初始化,先运行 bootstrap
./bootstrap
fi经验总结:
aclocal 的 -I 选项用于指定宏搜索路径gnulib/m4 目录才能找到 gnulib 的宏gnulib 未初始化,必须先运行 bootstrap问题描述:
make bootstrap-deps 失败后,构建过程无法继续:
bootstrap: running: make bootstrap-deps ...
make[1]: *** No rule to make target `libltdl/ltdl.mk', needed by `libltdl/Makefile.am'. Stop.
bootstrap: error: make bootstrap-deps failed根本原因:
bootstrap-deps 需要一些文件存在才能运行,但这些文件又应该由它自己生成。
解决方案: 创建所有必需的占位文件,然后重试:
# 创建占位文件
if [ ! -f "libltdl/ltdl.mk" ]; then
mkdir -p libltdl
cat > libltdl/ltdl.mk << 'EOF'
LTDLDIR = libltdl
# DO NOT REMOVE THIS LINE -- make depends on it
EOF
fi
if [ ! -f "build-aux/ltmain.sh" ]; then
mkdir -p build-aux
# 尝试从 ltmain.in 生成,或创建占位文件
if [ -f "build-aux/ltmain.in" ]; then
sed -e "s/@PACKAGE@/libtool/g" build-aux/ltmain.in > build-aux/ltmain.sh
else
echo "#!/bin/sh" > build-aux/ltmain.sh
fi
chmod +x build-aux/ltmain.sh
fi
if [ ! -f "m4/ltversion.in" ]; then
mkdir -p m4
cat > m4/ltversion.in << 'EOF'
m4_define([LT_PACKAGE_VERSION], [@PACKAGE_VERSION@])
m4_define([LT_PACKAGE_REVISION], [@PACKAGE_REVISION@])
EOF
fi
# 重试 bootstrap-deps
make bootstrap-deps经验总结:
问题描述:
configure 运行成功后,某些文件被 config.status 删除,导致后续 make 失败:
config.status: executing libtool commands
automake: error: cannot open < libltdl/ltdl.mk: No such file or directory根本原因:
config.status 在执行 “libtool commands” 时会调用 automake,而 automake 需要 libltdl/ltdl.mk 文件。
解决方案:
在 configure 运行之后,再次检查并创建必需文件:
# 运行 configure
./configure \
--prefix=${LIBTOOL_INSTALL_HNP_PATH} \
--host=aarch64-linux-gnu \
--enable-static \
--disable-shared \
...
# configure 成功后,再次确保必需文件存在
if [ ! -f "libltdl/ltdl.mk" ]; then
echo "Warning: libltdl/ltdl.mk missing after configure, recreating it..."
mkdir -p libltdl
cat > libltdl/ltdl.mk << 'EOF'
LTDLDIR = libltdl
# DO NOT REMOVE THIS LINE -- make depends on it
EOF
fi
if [ ! -f "m4/ltversion.in" ]; then
echo "Warning: m4/ltversion.in missing after configure, recreating it..."
mkdir -p m4
cat > m4/ltversion.in << 'EOF'
m4_define([LT_PACKAGE_VERSION], [@PACKAGE_VERSION@])
m4_define([LT_PACKAGE_REVISION], [@PACKAGE_REVISION@])
EOF
fi经验总结:
config.status 可能会删除某些文件configure 运行后所有文件都存在最终的 build_ohos.sh 脚本结构如下:
#!/bin/bash
# 1. 环境变量设置
export M4="/opt/homebrew/opt/m4/bin/m4"
export CC="${SDK_PATH}/native/llvm/bin/clang"
export CXX="${SDK_PATH}/native/llvm/bin/clang++"
...
# 2. 创建版本文件
echo "2.4.10" > .tarball-version
echo "2.4.10" > .version
# 创建 git-version-gen 占位符
# 3. 修复 configure.ac(注释不支持的语言)
sed -i '' 's/^LT_LANG(Objective-C)$/# .../' configure.ac
# 4. 创建包装脚本目录
mkdir -p .bootstrap_bin
# 创建 help2man 和 makeinfo 包装脚本
# 5. 配置 gnulib URL(GitCode 镜像)
export gnulib_url="git@gitcode.com:jianguoxu/gnulib.git"
# 修改 .gitmodules
# 6. 创建占位文件
# - libltdl/ltdl.mk
# - build-aux/ltmain.sh
# - m4/ltversion.in
# 7. 运行 bootstrap
./bootstrap || {
# 错误恢复逻辑
# 检查 gnulib 是否已初始化
# 创建缺失的占位文件
# 重试 bootstrap
}
# 8. 验证 gnulib 初始化
if [ ! -d "gnulib/m4" ]; then
echo "Error: gnulib not initialized"
exit 1
fi
# 9. 运行 autoreconf(如果需要)
if [ ! -f "configure" ] || [ ! -f "Makefile.in" ]; then
aclocal -I m4 -I gnulib/m4
autoreconf -f
fi
# 10. 运行 configure
./configure \
--prefix=${LIBTOOL_INSTALL_HNP_PATH} \
--host=aarch64-linux-gnu \
--enable-static \
--disable-shared \
...
# 11. configure 后检查并创建必需文件
# - libltdl/ltdl.mk
# - m4/ltversion.in
# - 重新创建 help2man 和 makeinfo 包装脚本
# 12. 运行 make
make -j$(nproc)
# 13. 运行 make install
make install源码 → bootstrap → autoreconf → configure → make → install
↓ ↓ ↓ ↓ ↓ ↓
版本文件 gnulib初始化 生成configure 配置系统 编译 安装Autotools 项目经常有循环依赖问题:
set -x 启用调试输出config.log 了解 configure 失败原因Makefile 中的硬编码路径成功构建 libtool 2.4.10 for HarmonyOS PC,生成以下文件:
libtool - 主程序libtoolize - 初始化脚本libltdl - 动态加载库libtool 的适配过程充满了挑战,主要原因是其复杂的 Autotools 构建系统和 gnulib 依赖。通过创建占位文件、包装脚本和错误恢复逻辑,我们成功解决了所有问题。希望本文能够帮助其他开发者在适配类似项目时少走弯路。