已开启
feat: 新增 community/inih 三方库适配 #2275
feat: 新增 community/inih 三方库适配 #2275
已开启
STF-Zero创建于 29 天前
共 12 个文件变更+420-0
@@ -0,0 +1,185 @@
1+# Copyright (c) 2026 STF-Zero
2+# Licensed under the Apache License, Version 2.0 (the "License");
3+# you may not use this file except in compliance with the License.
4+# You may obtain a copy of the License at
5+#
6+# http://www.apache.org/licenses/LICENSE-2.0
7+#
8+# Unless required by applicable law or agreed to in writing, software
9+# distributed under the License is distributed on an "AS IS" BASIS,
10+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+# See the License for the specific language governing permissions and
12+# limitations under the License.
13+#
14+# Contributor: STF-Zero <caoningxu@gmail.com>
15+# Maintainer: STF-Zero <caoningxu@gmail.com>
16+# buildtools=meson HPKBUILD 骨架
17+pkgname=inih
18+pkgver=r62
19+pkgrel=0
20+pkgdesc="inih (INI Not Invented Here) is a simple, small, embeddable INI file parser written in C (with an optional C++ INIReader wrapper)"
21+url="https://github.com/benhoyt/inih"
22+license=("BSD-3-Clause")
23+makedepends=()
24+source="https://github.com/benhoyt/inih/archive/refs/tags/r62.tar.gz"
25+archs=("armeabi-v7a" "arm64-v8a" "x86_64")
26+builddir=${pkgname}-${pkgver}
27+buildtools="meson"
28+downloadpackage=true
29+autounpack=false
30+packagename=${pkgname}-${pkgver}.tar.gz
31+patchflag=false
32+depends=()
33+ 
34+prepare() {
35+ cd ${PKGBUILD_ROOT}
36+ extract_archive() {
37+ local _arc="$1" _dst="$2"
38+ cd "$_dst" || return 1
39+ case "$_arc" in
40+ *.tar.gz|*.tgz) tar -xzf "$_arc" ;;
41+ *.tar.bz2) tar -xjf "$_arc" ;;
42+ *.tar.xz) tar -xJf "$_arc" ;;
43+ *.zip) unzip -qo "$_arc" ;;
44+ *) echo "unsupported archive: $_arc"; return 1 ;;
45+ esac
46+ }
47+ if [ ! -d "$builddir" ]; then
48+ extract_archive "${packagename}" "${PKGBUILD_ROOT}" || return 1
49+ fi
50+ # 目录名规范化:解压目录可能与 $builddir 不同名(pkgver 带 v 前缀、
51+ # GitHub 归档含 commit hash),finalize 清源重建时依赖此逻辑
52+ if [ ! -d "$builddir" ]; then
53+ for _d in *; do
54+ if [ -d "$_d" ] && [ "$_d" != "logs" ] && [ "$_d" != "hpkbuild_history" ] && ! echo "$_d" | grep -q -- '-build$'; then
55+ if [ -f "$_d/meson.build" ] || [ -f "$_d/CMakeLists.txt" ] || [ -f "$_d/configure" ] || [ -f "$_d/Makefile" ]; then
56+ mv "$_d" "$builddir" 2>/dev/null && break
57+ fi
58+ fi
59+ done
60+ fi
61+ # 唯一目录兜底:patch 创建构建系统的库在打补丁前无构建标记,唯一普通
62+ # 目录直接规范化(poly1305 真实案例);多个候选时 fail closed。
63+ if [ ! -d "$builddir" ]; then
64+ _candidates=()
65+ for _d in *; do
66+ if [ -d "$_d" ] && [ "$_d" != "logs" ] && [ "$_d" != "hpkbuild_history" ] && [ "${_d:0:1}" != "." ] && ! echo "$_d" | grep -q -- '-build$'; then
67+ _candidates+=("$_d")
68+ fi
69+ done
70+ if [ "${#_candidates[@]}" -eq 1 ]; then
71+ mv "${_candidates[0]}" "$builddir" 2>/dev/null || return 1
72+ fi
73+ fi
74+ [ -d "$builddir" ] || return 1
75+ # 双层嵌套规范化(nspr 实证):归档根 builddir/ 内含唯一源码目录
76+ # (如 builddir/nspr/ 有 configure)时提升到 builddir,否则 build() 在
77+ # 错误目录触发 autoreconf -> "configure.ac is required"。
78+ if [ ! -f "$builddir/configure" ] && [ ! -f "$builddir/configure.ac" ] && [ ! -f "$builddir/CMakeLists.txt" ]; then
79+ _inner=""
80+ for _d in "$builddir"/*/; do
81+ [ -d "${_d%/}" ] || continue
82+ case "${_d%/}" in *-build|*logs*|*hpkbuild_history*) continue;; esac
83+ if [ -f "${_d}configure" ] || [ -f "${_d}configure.ac" ] || [ -f "${_d}configure.in" ] || [ -f "${_d}CMakeLists.txt" ] || [ -f "${_d}Makefile" ] || [ -f "${_d}meson.build" ]; then
84+ if [ -z "$_inner" ]; then _inner="${_d%/}"; else _inner=""; break; fi
85+ fi
86+ done
87+ if [ -n "$_inner" ]; then
88+ mv "$_inner" "${builddir}-__inner"
89+ rm -rf "$builddir"
90+ mv "${builddir}-__inner" "$builddir"
91+ echo "[nest] 双层嵌套源码已提升: $builddir" >> $buildlog
92+ fi
93+ fi
94+ # 【meson 特有】清理 subprojects/ 下的空占位目录:gitee 归档会把 git
95+ # 子模块留成空目录,meson 0.61 见到目录已存在就不再执行 wrap-git 克隆,
96+ # 直接报 "Subproject exists but has no meson.build file"(glib gvdb/
97+ # proxy-libintl 实证)。仅删空目录,agent 手写的 stub meson.build 不受影响。
98+ find "${builddir}/subprojects" -maxdepth 1 -mindepth 1 -type d -empty -exec rmdir {} + 2>/dev/null || true
99+ # patch 应用:H+P 项目 clean rebuild 必须重放补丁(poly1305 真实案例)
100+ if $patchflag; then
101+ cd "$builddir" || return 1
102+ if [ ! -f .oh_patch_applied ]; then
103+ _PATCHED=0
104+ for _pl in 1 0 2; do
105+ patch -N -p${_pl} --batch --forward < "../${pkgname}_oh_pkg.patch" >/dev/null 2>&1
106+ _rc=$?
107+ if [ $_rc -eq 0 ]; then _PATCHED=1; break; fi
108+ _first=$(grep -m1 '^+++' "../${pkgname}_oh_pkg.patch" | sed 's/^+++ //; s/ .*//; s/^[ab]\///')
109+ if [ -n "$_first" ] && [ -f "$_first" ]; then _PATCHED=1; break; fi
110+ done
111+ [ "$_PATCHED" -eq 1 ] || { echo "patch 应用失败(-p1/-p0/-p2 均无效)" >> $buildlog; return 1; }
112+ touch .oh_patch_applied
113+ fi
114+ cd ${PKGBUILD_ROOT}
115+ fi
116+ source envset.sh
117+ # per-ARCH 源码隔离:每次 run_build 从干净源码副本重建
118+ rm -rf ${builddir}-${ARCH}-build
119+ cp -r ${builddir} ${builddir}-${ARCH}-build
120+ return 0
121+}
122+ 
123+build() {
124+ cd ${PKGBUILD_ROOT}/${builddir}-${ARCH}-build || return 1
125+ # 按 ARCH 加载交叉编译环境(source envset.sh 只定义函数,必须调用
126+ # setarm32ENV/setarm64ENV/setx86_64ENV 才会设置 CC/AR/RANLIB——否则 meson 得到空 CC)
127+ source envset.sh 2>/dev/null
128+ case "${ARCH}" in
129+ armeabi-v7a) setarm32ENV; _cpu_family="arm" ;;
130+ arm64-v8a) setarm64ENV; _cpu_family="aarch64" ;;
131+ x86_64) setx86_64ENV; _cpu_family="x86_64" ;;
132+ *) echo "unsupported ARCH: ${ARCH}" >&2; return 1 ;;
133+ esac
134+ export CC AR RANLIB CFLAGS LDFLAGS
135+ # 生成 meson cross-file(CC/CXX 来自 OHOS clang wrapper;SDK 无预置
136+ # ohos.meson.cross,libfuse/glib 实证用自生成 crossfile)
137+ cat > crossfile.txt <<EOF
138+[binaries]
139+c = '${CC}'
140+cpp = '${CXX}'
141+ar = '${AR}'
142+strip = '${STRIP}'
143+pkgconfig = '/usr/bin/pkg-config'
144+ 
145+[properties]
146+c_args = []
147+c_link_args = []
148+ 
149+[host_machine]
150+system = 'linux'
151+cpu_family = '${_cpu_family}'
152+cpu = '${_cpu_family}'
153+endian = 'little'
154+EOF
155+ # 传递依赖 pkgconfig 合并:meson 的 pkg-config 查找需要直接+传递依赖的
156+ # .pc(cairo/pixman 实证:缺 pixman-1.pc → 回退 subproject pixman,其
157+ # wrap revision=master 版本漂移 → 要求 meson>=1.3 而系统 0.61.2)。
158+ for _dep_dir in ${LYCIUM_ROOT}/usr/*/${ARCH}; do
159+ _dep_pkg=$(basename "$(dirname "${_dep_dir}")")
160+ [ "${_dep_pkg}" = "${pkgname}" ] && continue
161+ [ -d "${_dep_dir}/lib/pkgconfig" ] && PKG_CONFIG_LIBDIR="${PKG_CONFIG_LIBDIR:+${PKG_CONFIG_LIBDIR}:}${_dep_dir}/lib/pkgconfig"
162+ done
163+ export PKG_CONFIG_LIBDIR
164+ # 每次 setup 前删除 build 目录:meson 缓存旧配置会导致新参数不生效
165+ rm -rf _build
166+ meson setup _build --cross-file crossfile.txt \
167+ --prefix=${LYCIUM_ROOT}/usr/${pkgname}/${ARCH} \
168+ --buildtype=release >> $buildlog 2>&1 || return 1
169+ ninja -C _build -j${JOB:-4} >> $buildlog 2>&1 || return 1
170+}
171+ 
172+package() {
173+ cd ${PKGBUILD_ROOT}/${builddir}-${ARCH}-build || return 1
174+ ninja -C _build install >> $buildlog 2>&1 || return 1
175+}
176+ 
177+cleanbuild() {
178+ cd ${PKGBUILD_ROOT}
179+ rm -rf ${PWD}/${builddir} ${PWD}/${builddir}-*-build
180+ return 0
181+}
182+ 
183+check() {
184+ echo "The test must be on an OpenHarmony device!"
185+}
@@ -0,0 +1,65 @@
1+#!/bin/sh
2+# Copyright (c) 2026 STF-Zero
3+# Licensed under the Apache License, Version 2.0 (the "License");
4+# you may not use this file except in compliance with the License.
5+# You may obtain a copy of the License at
6+#
7+# http://www.apache.org/licenses/LICENSE-2.0
8+#
9+# Unless required by applicable law or agreed to in writing, software
10+# distributed under the License is distributed on an "AS IS" BASIS,
11+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+# See the License for the specific language governing permissions and
13+# limitations under the License.
14+#
15+# Contributor: STF-Zero <caoningxu@gmail.com>
16+# Maintainer: STF-Zero <caoningxu@gmail.com>
17+# HARNESS_EXPECTED_CASES = 8
18+# HARNESS_TEST_ORIGIN = upstream_test
19+# HARNESS_HPKCHECK_AUTOGENERATED = 1
20+# HARNESS_RUNTIME_FILES = _build/tests/unittest_heap_string _build/tests/unittest_call_handler_on_new_section _build/tests/unittest_heap _build/tests/unittest_multi_max_line _build/tests/unittest_stop_on_first_error _build/tests/unittest_handler_lineno _build/tests/unittest_allow_no_value _build/tests/unittest_alloc
21+# HARNESS_RUNTIME_INSTALL = shared-libraries
22+. ./HPKBUILD >/dev/null 2>&1
23+logfile=${LYCIUM_THIRDPARTY_ROOT}/${pkgname}/${pkgname}_${ARCH}_harness_test.log
24+build_root=${LYCIUM_THIRDPARTY_ROOT}/${pkgname}/${builddir}-${ARCH}-build
25+checkprepare() {
26+ for _d in "${LYCIUM_ROOT}"/usr/*/"${ARCH}"/lib; do
27+ [ -d "$_d" ] && LD_LIBRARY_PATH="${_d}:${LD_LIBRARY_PATH}"
28+ done
29+ export LD_LIBRARY_PATH
30+}
31+run_case() {
32+ case_name=$1
33+ binary_rel=$2
34+ workdir_rel=$3
35+ case_log=${logfile}.${case_name}
36+ binary=${build_root}/${binary_rel}
37+ if [ ! -x "${binary}" ]; then
38+ echo "missing upstream test executable: ${binary}" > "${case_log}"
39+ result=1
40+ else
41+ mkdir -p "${build_root}/${workdir_rel}"
42+ (cd "${build_root}/${workdir_rel}" && "${binary}") > "${case_log}" 2>&1
43+ result=$?
44+ fi
45+ cat "${case_log}" >> "${logfile}"
46+ if [ ${result} -eq 0 ]; then
47+ echo "HARNESS_CASE ${case_name} PASS" | tee -a "${logfile}"
48+ else
49+ echo "HARNESS_CASE ${case_name} FAIL" | tee -a "${logfile}"
50+ fi
51+ return ${result}
52+}
53+openharmonycheck() {
54+ : > "${logfile}"
55+ status=0
56+ run_case build-tests-unittest-heap-string "_build/tests/unittest_heap_string" "_build/tests" || status=1
57+ run_case build-tests-unittest-call-handler-on-new-section "_build/tests/unittest_call_handler_on_new_section" "_build/tests" || status=1
58+ run_case build-tests-unittest-heap "_build/tests/unittest_heap" "_build/tests" || status=1
59+ run_case build-tests-unittest-multi-max-line "_build/tests/unittest_multi_max_line" "_build/tests" || status=1
60+ run_case build-tests-unittest-stop-on-first-error "_build/tests/unittest_stop_on_first_error" "_build/tests" || status=1
61+ run_case build-tests-unittest-handler-lineno "_build/tests/unittest_handler_lineno" "_build/tests" || status=1
62+ run_case build-tests-unittest-allow-no-value "_build/tests/unittest_allow_no_value" "_build/tests" || status=1
63+ run_case build-tests-unittest-alloc "_build/tests/unittest_alloc" "_build/tests" || status=1
64+ return ${status}
65+}
@@ -0,0 +1,16 @@
1+<?xml version="1.0" encoding="UTF-8"?>
2+<configuration>
3+ <oatconfig>
4+ <filefilterlist>
5+ <filefilter name="copyrightPolicyFilter" desc="Filters for compatibility,license header policies">
6+ <filteritem type="filename" name="SHA512SUM" desc="SHA512SUM文件,不添加版权头"/>
7+ </filefilter>
8+ <filefilter name="defaultPolicyFilter" desc="Filters for compatibility,license header policies">
9+ <filteritem type="filename" name="SHA512SUM" desc="SHA512SUM文件,不添加版权头"/>
10+ </filefilter>
11+ <filefilter name="binaryFileTypePolicyFilter" desc="Filters for resources files policies">
12+ <filteritem type="filename" name="*.png" desc="指导文档需要的png图片"/>
13+ </filefilter>
14+ </filefilterlist>
15+ </oatconfig>
16+</configuration>
@@ -0,0 +1,11 @@
1+[
2+ {
3+ "Name": "inih",
4+ "License": "BSD-3-Clause",
5+ "License File": "https://github.com/benhoyt/inih/blob/master/LICENSE.txt",
6+ "Version Number": "r62",
7+ "Owner": "caoningxu@gmail.com",
8+ "Upstream URL": "https://github.com/benhoyt/inih",
9+ "Description": "inih (INI Not Invented Here) is a simple, small, embeddable INI file parser written in C (with an optional C++ INIReader wrapper)"
10+ }
11+]
@@ -0,0 +1,27 @@
1+# inih三方库说明
2+ 
3+## 功能简介
4+ 
5+inih (INI Not Invented Here) is a simple, small, embeddable INI file parser written in C (with an optional C++ INIReader wrapper)
6+ 
7+- 上游地址:https://github.com/benhoyt/inih
8+- 版本:r62
9+- 开源协议:BSD-3-Clause
10+- 支持的架构:armeabi-v7a, arm64-v8a, x86_64
11+- 构建方式:meson
12+ 
13+## 三方库版本
14+ 
15+- r62
16+ 
17+## 已适配功能
18+ 
19+- To use it, just give iniparse() an INI file, and it will call a callback for every name=value pair parsed, giving you strings for the section, name, and value. It's done this way ("SAX style") because it works well on low-memory embedded systems, but also because it makes for a KISS implementation
20+ 
21+## 使用约束
22+ 
23+- [IDE和SDK版本](../../docs/constraint.md)
24+ 
25+## 集成方式
26+ 
27+[应用包hap集成](docs/hap_integrate.md)
@@ -0,0 +1 @@
1+206ddfaa55d29396c3a44f8d1dfcf578c5ebf892e81fe875cd6b4ec2af5cccf400ca13fc6585b6d8232bd122bd8aef7522bfc83898b5609b29c20bad9390ee02 inih-r62.tar.gz
@@ -0,0 +1,115 @@
1+# inih如何集成到应用hap
2+ 
3+本库已基于 OpenHarmony 镜像完成交叉编译与设备端加载验证(版本 r62)。
4+ 
5+实测环境:`arm64-v8a`(QEMU 裁剪镜像(模拟),目标 `127.0.0.1:5855`,`uname -m=aarch64`);`armeabi-v7a`(QEMU 裁剪镜像(模拟),目标 `127.0.0.1:5755`,`uname -m=armv7l`)。
6+ 
7+以上均为**模拟运行环境,不是物理真机**;真机(开发板/手机/平板)验证:**未做**(上方均为模拟环境)。
8+社区标准验证环境为 [润和 RK3568 开发板](https://gitee.com/openharmony-sig/knowledge_demo_temp/tree/master/docs/rk3568_helloworld)(OpenHarmony 3.2 Release 镜像),本库未使用该开发板;验证过程与结果见 `docs/pic/` 截图。
9+ 
10+## 准备应用工程
11+ 
12+### 准备应用开发环境
13+ 
14+- [开发环境准备](../../../docs/hap_integrate_environment.md)
15+ 
16+### 增加构建脚本及配置文件
17+ 
18+本库的构建脚本与配置文件:`HPKBUILD`(交叉编译脚本)、`HPKCHECK`(设备端测试入口)、`OAT.xml`(版权头豁免),详见 [HPKBUILD](../HPKBUILD) 与 [HPKCHECK](../HPKCHECK)。
19+ 
20+应用工程侧,在最外层(cpp 目录下)`CMakeLists.txt` 中添加如下语句:
21+ 
22+```shell
23+ #将三方库加入工程中
24+ target_link_libraries(entry PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/thirdparty/inih/${OHOS_ARCH}/lib/libinih.so)
25+ 
26+ #将三方库的头文件加入工程中
27+ target_include_directories(entry PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/thirdparty/inih/${OHOS_ARCH}/include)
28+```
29+ 
30+### 准备三方库源码
31+ 
32+- 下载本仓库
33+ 
34+ ```shell
35+ git clone https://gitcode.com/CPF-ApplicationTPC/tpc_c_cplusplus.git --depth=1
36+ ```
37+ 
38+- 三方库目录结构
39+ 
40+ ```shell
41+ tpc_c_cplusplus/community/inih #三方库inih的目录结构如下
42+ ├── docs #三方库相关文档的文件夹
43+ ├── HPKBUILD #构建脚本
44+ ├── HPKCHECK #测试脚本
45+ ├── SHA512SUM #三方库校验文件
46+ ├── OAT.xml #OAT开源审查文本文件
47+ ├── README.OpenSource #说明三方库源码的下载地址,版本,license等信息
48+ ├── README_zh.md #三方库简介
49+ ```
50+ 
51+## 应用中使用三方库
52+ 
53+- 在IDE的cpp目录下新增thirdparty目录,将编译产物 `lycium/usr/inih/<abi>/` 下的 `include/` 与 `lib/` 拷贝进去,形成 `cpp/thirdparty/inih/<abi>/{include,lib}`(动态库名字带版本号和不带版本号的都需要;`share/`、`cmake/` 等非头文件/库内容可以不拷),如下图所示:
54+ 
55+ &nbsp;
56+ 
57+ &nbsp;![thirdparty_install_dir](pic/inih_install_dir.png)
58+ 
59+## 编译工程
60+ 
61+- 在lycium目录下编译三方库
62+ 
63+ 编译环境的搭建参考[准备三方库构建环境](../../../lycium/README.md#1编译环境准备)
64+ 
65+ ```shell
66+ cd lycium
67+ ./build.sh inih
68+ ```
69+ 
70+- 三方库头文件及生成的库
71+ 
72+ 在lycium目录下会生成usr目录,该目录下存在已编译完成的32位和64位三方库
73+ 
74+ ```shell
75+ inih/armeabi-v7a inih/arm64-v8a inih/x86_64
76+ ```
77+ 
78+- [测试三方库](#测试三方库)
79+ 
80+## 测试三方库
81+ 
82+- 三方库的测试使用原库自带的测试用例来做测试,[准备三方库测试环境](../../../lycium/README.md#3ci环境准备)
83+ 
84+- 进入到构建目录运行测试用例(`arm64-v8a` 为构建64位的目录,`armeabi-v7a` 为构建32位的目录),执行结果如图所示:
85+ 
86+```shell
87+ cd /data/tpc_c_cplusplus/thirdparty/inih/inih-r62-arm64-v8a-build/
88+ _build/tests/unittest_heap_string
89+ _build/tests/unittest_call_handler_on_new_section
90+ _build/tests/unittest_heap
91+ _build/tests/unittest_multi_max_line
92+ _build/tests/unittest_stop_on_first_error
93+ _build/tests/unittest_handler_lineno
94+ _build/tests/unittest_allow_no_value
95+ _build/tests/unittest_alloc
96+```
97+ 
98+&nbsp;![arm64](pic/arm64.png)
99+&nbsp;![armv7a](pic/armv7a.png)
100+&nbsp;![x86_64](pic/x86_64.png)
101+&nbsp;![screenshot_commands](pic/screenshot_commands.png)
102+ 
103+本库交付的 `HPKCHECK` 已把上述用例固化为设备端一键执行:交叉编译出的测试可执行文件随载荷下发到设备运行(`arm64-v8a`/`armeabi-v7a` 使用 QEMU 镜像,`x86_64` 使用 DevEco Studio 官方模拟器),结果见 `docs/pic/` 截图。
104+ 
105+## 运行效果
106+ 
107+本库已完成设备端加载与用例验证(设备端执行记录见 `docs/pic/` 截图);应用侧(HAP)集成后的运行效果截图后续补充。
108+ 
109+## 参考资料
110+ 
111+- [润和RK3568开发板标准系统快速上手](https://gitee.com/openharmony-sig/knowledge_demo_temp/tree/master/docs/rk3568_helloworld)
112+- [OpenHarmony三方库地址](https://gitee.com/openharmony-tpc)
113+- [OpenHarmony知识体系](https://gitee.com/openharmony-sig/knowledge)
114+- [通过DevEco Studio开发一个NAPI工程](https://gitee.com/openharmony-sig/knowledge_demo_temp/blob/master/docs/napi_study/docs/hello_napi.md)
115+- 上游源码:https://github.com/benhoyt/inih/archive/refs/tags/r62.tar.gz