目录
- 前言
- 项目背景
- 问题一:struct option 重复定义
- 问题二:gengetopt 工具路径配置
- 问题三:gengen 工具缺失
- 问题四:gengen 与现代 C++ 编译器的兼容性
- 问题五:config.h 宏定义错误
- 问题六:构建路径配置
- 问题七:文档构建问题
- 完整的构建脚本修复
- 构建结果
- 经验总结
- 参考资源
- 附录:gengen 安装完整脚本
前言
在将 gengetopt 命令行工具适配到 HarmonyOS PC 平台的过程中,遇到了多个构建错误。本文记录了完整的问题诊断和解决过程,希望能为遇到类似问题的开发者提供参考。
项目背景
gengetopt 是一个用于生成命令行参数解析代码的工具,使用 autotools 构建系统。在 HarmonyOS 交叉编译环境中构建时,遇到了以下主要问题:
struct option重复定义错误gengetopt工具路径配置问题gengen工具缺失gengen与现代 C++ 编译器的兼容性问题config.h宏定义错误- 构建路径配置问题
问题一:struct option 重复定义
错误现象
./getopt.h:194:8: error: redefinition of 'option'
struct option
^
/Users/jianguo/Desktop/ohosdk/native/sysroot/usr/include/getopt.h:12:8: note: previous definition is here
struct option {
^
问题分析
gengetopt 项目使用 gnulib 提供的 getopt 实现。当 HAVE_GETOPT_H 被定义为 1 时,getopt.h 会使用 include_next 包含系统的 getopt.h,导致 struct option 被重复定义。
解决方案
需要将 HAVE_GETOPT_H 设置为 0,让 gengetopt 使用自己的 getopt 实现,避免与系统头文件冲突。
修复步骤:
- 修复
config.h:
sed -i '' 's/^#define HAVE_GETOPT_H 1$/#undef HAVE_GETOPT_H/' config.h
- 修复
Makefile(用于生成getopt.h):
sed -i '' 's/^HAVE_GETOPT_H = 1$/HAVE_GETOPT_H = 0/' gl/Makefile
- 清理并重新生成
getopt.h:
rm -f gl/getopt.h
make -C gl getopt.h
验证:
检查生成的 getopt.h 文件,确认 #if 0 块(不会包含系统的 getopt.h):
#if 0
# define _GL_SYSTEM_GETOPT
# include_next <getopt.h>
# undef _GL_SYSTEM_GETOPT
#endif
问题二:gengetopt 工具路径配置
错误现象
/Users/jianguo/HarmonyOSPC/build/code/gengetopt/gengetopt --input cmdline.ggo
make[2]: /Users/jianguo/HarmonyOSPC/build/code/gengetopt/gengetopt: No such file or directory
问题分析
构建脚本检测到系统的 gengetopt 工具(/opt/homebrew/bin/gengetopt),但在更新 Makefile 时,路径计算错误,将 GENGETOPT 设置为不存在的路径。
解决方案
使用 command -v gengetopt 直接获取完整路径,而不是先设置为命令名再计算路径。
修复代码:
# 检查 gengetopt 工具是否可用
GENGETOPT_TOOL=""
ABS_GENGETOPT_TOOL=""
if command -v gengetopt >/dev/null 2>&1; then
# 使用系统的 gengetopt,获取完整路径
ABS_GENGETOPT_TOOL=$(command -v gengetopt)
GENGETOPT_TOOL="${ABS_GENGETOPT_TOOL}"
echo "Using system gengetopt: ${ABS_GENGETOPT_TOOL}"
# 更新 Makefile 中的 GENGETOPT 变量
for makefile in $(find . -name "Makefile" 2>/dev/null); do
if grep -q "^GENGETOPT = " "$makefile" 2>/dev/null; then
sed -i '' "s|^GENGETOPT = .*|GENGETOPT = ${ABS_GENGETOPT_TOOL}|" "$makefile" 2>/dev/null || \
sed -i.bak "s|^GENGETOPT = .*|GENGETOPT = ${ABS_GENGETOPT_TOOL}|" "$makefile"
rm -f "${makefile}.bak"
fi
done
else
echo "Error: gengetopt tool is required but not found"
exit 1
fi
问题三:gengen 工具缺失
错误现象
gengen -i c_source.h_skel -F c_source.h -f c_source
make[4]: gengen: No such file or directory
问题分析
gengen 是 gengetopt 构建过程中必需的代码生成工具,用于从 .skel 模板文件生成 .h 和 .cc 文件。该工具在 macOS 的包管理器(Homebrew、MacPorts)中不可用。
解决方案
需要从源代码构建 gengen。最新版本是 gengen-1.4.2(2009年发布)。
安装步骤:
cd /tmp
curl -O https://ftp.gnu.org/gnu/gengen/gengen-1.4.2.tar.gz
tar xzf gengen-1.4.2.tar.gz
cd gengen-1.4.2
./configure && make && sudo make install
问题四:gengen 与现代 C++ 编译器的兼容性
错误现象
构建 gengen 时遇到多个错误:
- config.h 文件未找到
getopt.c:23:11: fatal error: 'config.h' file not found
- struct option 重复定义
./getopt.h:194:8: error: redefinition of 'option'
- 旧版 C++ 头文件问题
fatal error: 'iostream.h' file not found
fatal error: 'streambuf.h' file not found
- C++ 标准库兼容性问题
error: no matching constructor for initialization of 'streambuf'
error: reference to 'stringbuf' is ambiguous
解决方案
4.1 创建 config.h
config.status 报告创建了 config.h,但文件实际上不存在。手动创建:
sed -e 's/@[A-Z_][A-Z0-9_]*@/1/g' config.h.in > config.h
4.2 修复 HAVE_GETOPT_H
与 gengetopt 相同的问题:
sed -i '' 's/^#define HAVE_GETOPT_H 1$/#undef HAVE_GETOPT_H/' config.h
sed -i '' 's/^HAVE_GETOPT_H = 1$/HAVE_GETOPT_H = 0/' lib/Makefile
rm -f lib/getopt.h
4.3 启用标准库的 sstream
gengen 的代码检查 HAVE_SSTREAM,如果未定义则使用自定义的 sstream 实现。现代 C++ 编译器都支持 <sstream>,应该使用标准库版本:
echo "#define HAVE_SSTREAM 1" >> config.h
4.4 修复 PACKAGE 和 VERSION 定义
config.h 中的 PACKAGE 和 VERSION 被错误定义为数字,需要改为字符串:
sed -i '' \
-e 's/^#undef PACKAGE$/#define PACKAGE "gengen"/' \
-e 's/^#undef VERSION$/#define VERSION "1.4.2"/' \
config.h
4.5 跳过文档构建
gengen 的文档构建需要 makeinfo 工具,且文档不是构建可执行文件的必需部分:
make -C src gengen
完整的 gengen 修复脚本:
#!/bin/bash
cd /tmp/gengen-1.4.2
# 1. 创建 config.h
if [ ! -f config.h ]; then
sed -e 's/@[A-Z_][A-Z0-9_]*@/1/g' config.h.in > config.h
fi
# 2. 修复 HAVE_GETOPT_H
sed -i '' 's/^#define HAVE_GETOPT_H 1$/#undef HAVE_GETOPT_H/' config.h
sed -i '' 's/^HAVE_GETOPT_H = 1$/HAVE_GETOPT_H = 0/' lib/Makefile
rm -f lib/getopt.h
# 3. 启用标准库 sstream
if ! grep -q "^#define HAVE_SSTREAM 1" config.h; then
echo "#define HAVE_SSTREAM 1" >> config.h
fi
# 4. 修复 PACKAGE 和 VERSION
sed -i '' \
-e 's/^#undef PACKAGE$/#define PACKAGE "gengen"/' \
-e 's/^#undef VERSION$/#define VERSION "1.4.2"/' \
config.h
# 5. 构建 gengen(跳过文档)
make -C src gengen
# 6. 安装到用户目录
mkdir -p ~/bin
cp src/gengen ~/bin/gengen
chmod +x ~/bin/gengen
export PATH="$HOME/bin:$PATH"
问题五:config.h 宏定义错误
错误现象
cmdline.c:342:43: error: pointer/integer type mismatch
(strlen(CMDLINE_PARSER_PACKAGE_NAME) ? CMDLINE_PARSER_PACKAGE_NAME : CMDLINE_PARSER_PACKAGE),
问题分析
gengetopt 的 config.h 中,PACKAGE、VERSION 等宏被错误定义为数字 1,而不是字符串。这是因为之前使用 sed 替换 @VAR@ 模板时,将所有变量都替换为了 1。
解决方案
需要将这些宏正确定义为字符串:
sed -i '' \
-e 's/^#define PACKAGE 1$/#define PACKAGE "gengetopt"/' \
-e 's/^#define PACKAGE_NAME 1$/#define PACKAGE_NAME "gengetopt"/' \
-e 's/^#define PACKAGE_TARNAME 1$/#define PACKAGE_TARNAME "gengetopt"/' \
-e 's/^#define PACKAGE_VERSION 1$/#define PACKAGE_VERSION "2.23.1"/' \
-e 's/^#define PACKAGE_STRING 1$/#define PACKAGE_STRING "gengetopt 2.23.1"/' \
-e 's/^#define PACKAGE_BUGREPORT 1$/#define PACKAGE_BUGREPORT "bug-gengetopt@gnu.org"/' \
-e 's/^#define VERSION 1$/#define VERSION "2.23.1"/' \
config.h
问题六:构建路径配置
错误现象
make[4]: *** No rule to make target `/libgen.la', needed by `libgengetopt.la'. Stop.
问题分析
src/Makefile 中 libgengetopt_la_DEPENDENCIES 包含了错误的路径 /libgen.la(绝对路径),应该是相对路径 skels/libgen.la。
解决方案
修复 Makefile 中的路径:
sed -i '' 's|/libgen\.la|skels/libgen.la|g' src/Makefile
问题七:文档构建问题
错误现象
../src/gengetopt: ../src/gengetopt: cannot execute binary file
问题分析
doc 目录的构建需要使用 gengetopt 工具生成文档,但构建的是交叉编译的二进制文件(针对 HarmonyOS aarch64),无法在 macOS 上执行。
解决方案
跳过文档构建,因为文档不是运行时必需的:
sed -i '' 's/ doc//g' Makefile
或者使用主机的 gengetopt 工具(如果可用)。
完整的构建脚本修复
以下是修复后的 build_ohos.sh 关键部分:
#!/bin/bash
# ... 前面的配置代码 ...
# 修复 config.h 中的 HAVE_GETOPT_H
if grep -q "^#define HAVE_GETOPT_H 1" config.h 2>/dev/null; then
echo "Fixing HAVE_GETOPT_H in config.h..."
sed -i '' 's/^#define HAVE_GETOPT_H 1$/#undef HAVE_GETOPT_H/' config.h
fi
# 修复 Makefile 中的 HAVE_GETOPT_H
for makefile in $(find . -name "Makefile" 2>/dev/null); do
if grep -q "^HAVE_GETOPT_H = 1" "$makefile" 2>/dev/null; then
sed -i '' 's/^HAVE_GETOPT_H = 1$/HAVE_GETOPT_H = 0/' "$makefile"
fi
done
# 清理并重新生成 getopt.h
if [ -f "gl/getopt.h" ]; then
rm -f gl/getopt.h
fi
# 检查 gengetopt 工具
if command -v gengetopt >/dev/null 2>&1; then
ABS_GENGETOPT_TOOL=$(command -v gengetopt)
echo "Using system gengetopt: ${ABS_GENGETOPT_TOOL}"
# 更新 Makefile
for makefile in $(find . -name "Makefile" 2>/dev/null); do
if grep -q "^GENGETOPT = " "$makefile" 2>/dev/null; then
sed -i '' "s|^GENGETOPT = .*|GENGETOPT = ${ABS_GENGETOPT_TOOL}|" "$makefile"
fi
done
fi
# 检查 gengen 工具
if command -v gengen >/dev/null 2>&1; then
ABS_GENGEN_TOOL=$(command -v gengen)
echo "Using system gengen: ${ABS_GENGEN_TOOL}"
# 更新 Makefile
for makefile in $(find . -name "Makefile" 2>/dev/null); do
if grep -q "^GENGEN = " "$makefile" 2>/dev/null; then
sed -i '' "s|^GENGEN = .*|GENGEN = ${ABS_GENGEN_TOOL}|" "$makefile"
fi
done
else
echo "Error: gengen tool is required but not found"
echo "Please install gengen first (see installation guide)"
exit 1
fi
# 修复 config.h 中的宏定义
sed -i '' \
-e 's/^#define PACKAGE 1$/#define PACKAGE "gengetopt"/' \
-e 's/^#define PACKAGE_NAME 1$/#define PACKAGE_NAME "gengetopt"/' \
-e 's/^#define PACKAGE_TARNAME 1$/#define PACKAGE_TARNAME "gengetopt"/' \
-e 's/^#define PACKAGE_VERSION 1$/#define PACKAGE_VERSION "2.23.1"/' \
-e 's/^#define PACKAGE_STRING 1$/#define PACKAGE_STRING "gengetopt 2.23.1"/' \
-e 's/^#define PACKAGE_BUGREPORT 1$/#define PACKAGE_BUGREPORT "bug-gengetopt@gnu.org"/' \
-e 's/^#define VERSION 1$/#define VERSION "2.23.1"/' \
config.h
# 修复 libgen.la 路径
sed -i '' 's|/libgen\.la|skels/libgen.la|g' src/Makefile
# 跳过文档构建
sed -i '' 's/ doc//g' Makefile
# 清理并构建
make clean || true
make VERBOSE=1
make install
# ... 后续的打包代码 ...
构建结果
成功构建后,生成以下文件:
output/gengetopt.hnp- HarmonyOS HNP 格式包(253KB)output/ohos_gengetopt_2.23.1.tar.gz- 传统 tar.gz 压缩包(250KB)
经验总结
-
交叉编译环境下的工具依赖:构建工具(如
gengetopt、gengen)需要在主机系统上可用,而不是交叉编译的目标。 -
autotools 配置文件的修复:当
config.h生成不正确时,需要手动修复关键宏定义。 -
旧版软件的兼容性:
gengen-1.4.2是 2009 年的版本,与现代 C++ 编译器存在兼容性问题,需要启用标准库特性(如HAVE_SSTREAM)。 -
路径配置的重要性:确保
Makefile中的路径配置正确,避免绝对路径错误。 -
构建顺序:某些目录(如
doc)的构建可能依赖交叉编译的二进制文件,需要跳过或使用主机工具。
参考资源
附录:gengen 安装完整脚本
#!/bin/bash
# gengen 1.4.2 安装脚本(适用于 macOS)
set -e
GENGEN_VERSION="1.4.2"
INSTALL_DIR="$HOME/bin"
echo "Downloading gengen ${GENGEN_VERSION}..."
cd /tmp
curl -O "https://ftp.gnu.org/gnu/gengen/gengen-${GENGEN_VERSION}.tar.gz"
tar xzf "gengen-${GENGEN_VERSION}.tar.gz"
cd "gengen-${GENGEN_VERSION}"
echo "Configuring..."
./configure
echo "Applying compatibility fixes..."
# 1. 创建 config.h
if [ ! -f config.h ]; then
sed -e 's/@[A-Z_][A-Z0-9_]*@/1/g' config.h.in > config.h
fi
# 2. 修复 HAVE_GETOPT_H
sed -i '' 's/^#define HAVE_GETOPT_H 1$/#undef HAVE_GETOPT_H/' config.h 2>/dev/null || \
sed -i.bak 's/^#define HAVE_GETOPT_H 1$/#undef HAVE_GETOPT_H/' config.h
sed -i '' 's/^HAVE_GETOPT_H = 1$/HAVE_GETOPT_H = 0/' lib/Makefile 2>/dev/null || \
sed -i.bak 's/^HAVE_GETOPT_H = 1$/HAVE_GETOPT_H = 0/' lib/Makefile
rm -f lib/getopt.h
# 3. 启用标准库 sstream
if ! grep -q "^#define HAVE_SSTREAM 1" config.h; then
echo "#define HAVE_SSTREAM 1" >> config.h
fi
# 4. 修复 PACKAGE 和 VERSION
sed -i '' \
-e 's/^#undef PACKAGE$/#define PACKAGE "gengen"/' \
-e 's/^#undef VERSION$/#define VERSION "1.4.2"/' \
config.h 2>/dev/null || \
sed -i.bak \
-e 's/^#undef PACKAGE$/#define PACKAGE "gengen"/' \
-e 's/^#undef VERSION$/#define VERSION "1.4.2"/' \
config.h
echo "Building gengen..."
make -C src gengen
echo "Installing to ${INSTALL_DIR}..."
mkdir -p "${INSTALL_DIR}"
cp src/gengen "${INSTALL_DIR}/gengen"
chmod +x "${INSTALL_DIR}/gengen"
# 添加到 PATH
if ! echo "$PATH" | grep -q "${INSTALL_DIR}"; then
echo "Adding ${INSTALL_DIR} to PATH..."
echo 'export PATH="$HOME/bin:$PATH"' >> ~/.zshrc
export PATH="${INSTALL_DIR}:${PATH}"
fi
echo "gengen installed successfully!"
echo "Location: ${INSTALL_DIR}/gengen"
which gengen
gengen --version
相关链接
作者: 坚果
3470

被折叠的 条评论
为什么被折叠?



