# multi-sdk-java-packages **Repository Path**: src-oerv/multi-sdk-java-packages ## Basic Information - **Project Name**: multi-sdk-java-packages - **Description**: No description available - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 1 - **Created**: 2025-04-27 - **Last Updated**: 2025-10-31 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # hello-java-macros > **OBS/RPM 环境下的 Java 多 JDK 打包宏与脚本** > 一套宏 + 少量脚本,让 Maven / Gradle / 纯 Java 项目在不改主 spec 主要逻辑的前提下,按所选 JDK(如 `1.8.0`、`17`、`21`)构建出多个变体子包(如 `-jdk1.8.0`、`-jdk17`、`-jdk21`)。 --- ## 目录 * [功能特性](#功能特性) * [快速开始](#快速开始) * [Maven / Gradle / 纯Java 用法](#maven--gradle--纯java-用法) * [prjconf 钩子](#prjconf-钩子) * [探测机制(%_java_probe)](#探测机制_java_probe) * [JDK 版本归一化策略](#jdk-版本归一化策略) * [目录规范与产物](#目录规范与产物) * [故障排查](#故障排查) * [FAQ](#faq) * [最佳实践:README 与 LICENSE 打包](#最佳实践readme-与-license-打包) * [兼容性与要求](#兼容性与要求) * [变更记录](#变更记录) * [许可](#许可) --- ## 功能特性 * **多 JDK 子包**:一次构建,按 JDK 版本自动生成 `-jdk` 子包,文件隔离、清单独立。 * **三种策略自动分发**:Maven / Gradle / 纯 Java 自动探测;也可手动强制。 * **JDK 版本归一化**:内部统一用主版本(`1.8.0 → 8`)收集产物;对外仍保留原始版本号用于子包命名和安装路径。 * **UNKNOWN 兜底**:即便无法判定项目类型,也能稳妥生成空 `files-jdk*.list`,避免 `%files` 失败。 * **日志统一**:`>>> [info] [PHASE=build_pre|install_pre][TYPE=...]` 前缀,便于 grep/排障。 宏与脚本: * 宏文件(安装到 `/usr/lib/rpm/macros.d/`):`macros.java-multi` * 入口:`%java_build_pre` / `%java_install_pre` * 探测:`%_java_probe` * 构建:`%_build_maven` / `%_build_gradle` / `%_build_java` * 安装/映射:`%_map_maven` / `%_install_gradle` / `%_install_java` * 工具:`%_copy_filelists` / `%_emit_empty_files` / `%_java_major` / `%_mvn_compiler_opts` * 脚本(安装到 `/usr/bin/`): * `build-java-multi.sh`、`find-java-multi.sh`(纯 Java) * `build-gradle-multi.sh`、`find-gradle-multi.sh`(Gradle) * *Maven 路径不走脚本*,仅在宏层调用 `%mvn_*`。 --- ## 快速开始 目标包 `*.spec`(最小示例): ```spec # 开关:是否启用多 JDK 子包(默认开);可用 --without multi_jdk 禁用 %bcond_without multi_jdk %if %{with multi_jdk} BuildRequires: hello-java-macros BuildRequires: java-1.8.0-openjdk-devel BuildRequires: java-17-openjdk-devel BuildRequires: java-21-openjdk-devel # 需要构建的 JDK 列表(可在 prjconf 或 spec 覆盖) %global java_package_versions 1.8.0 17 21 # Maven 项目建议至少设置 artifactId(短坐标模式) %global mvn_artifact mylib # 生成子包模板 + 启用 __java_package(供 prjconf 钩子触发) %java_package %endif %install # 主包安装逻辑... # 若是 Maven 项目,这里只需要执行一次(不是每个 JDK 各跑一次) %mvn_install ``` > **提示**:请在 OBS 的 prjconf 中挂载 build/install 前置钩子(见下节)。 --- ## Maven / Gradle / 纯Java 用法 ### Maven * 构建:宏层调用 `%mvn_build`,并可通过 `build-helper:attach-artifact` 动态附加 `classifier=jdk`(默认注释,按需启用)。 * 映射:`%mvn_package` / `%mvn_file`。 * **短坐标(默认)**:`:%{mvn_artifact}::jdk17`(从 POM 解析 G/A/packaging)。 * **全坐标**:设置 ```spec %global __use_short_coords 0 %global mvn_group com.acme %global mvn_artifact mylib %global mvn_packaging jar ``` * 安装:主 spec 中 `%mvn_install` **只需执行一次**。 ### Gradle * 构建:每个 JDK 执行 `./gradlew -x test clean assemble`(或 `gradle`)。 * 多模块工程会递归收集 `**/build/libs/*.jar`。 * 安装:将产物安装到 `/usr/share/java/%{name}/jdk/`,并生成 `files-jdk.list`。 ### 纯 Java * 构建:每个 JDK 设置 `JAVA_HOME`,使用 `javac` + `jar`; * JDK8 用 `-source/-target 1.8`,JDK≥9 用 `--release `。 * 安装:与 Gradle 类似,路径与清单一致。 --- ## prjconf 钩子 在 OBS 项目的 **Project Config (prjconf)** 中添加(示例): ```spec # build 前置:调用 %java_build_pre %__spec_build_pre %{___build_pre} \ echo ">>> %name build_pre is running!" \ %{?__java_package:%{java_build_pre}} \ %{nil} # install 前置:调用 %java_install_pre %__spec_install_pre %{___build_pre} \ [ "$RPM_BUILD_ROOT" != "/" ] && rm -rf "$RPM_BUILD_ROOT" ; \ mkdir -p "$RPM_BUILD_ROOT" ; \ echo ">>> %name install_pre is running!" \ %{?__java_package:%{java_install_pre}} \ %{nil} ``` > 说明:`%java_package` 定义了内部开关 `__java_package`;钩子通过该开关判断是否注入多 JDK 流程。 --- ## 探测机制(%_java_probe) * **目标**:推断源码根目录(`SRCROOT`)与项目类型(`MAVEN` / `GRADLE` / `JAVA` / `UNKNOWN`),并选择 `FILESDIR`(`%files -f` 清单落点)。 * **判定规则(简化)**: * `pom.xml` → MAVEN * `build.gradle` / `settings.gradle` / `gradlew` → GRADLE * 递归存在 `*.java` 或 `src/main/java` → JAVA * 否则 → UNKNOWN * **稳健性**:使用 `test -d/-e` 进行目录/存在性检测,避免 `os.rename()` 等不稳定判断造成误判。 * **FILESDIR 优先策略**:优先将 `FILESDIR` 设为 `BUILD/%{name}-%{version}`,不存在时才回退 `SRCROOT`,避免清单被拷到 `BUILD/` 根导致 `%files` 找不到。 **强制覆盖**(必要时): ```spec # 在 spec 顶部强制类型或源码子目录 %global java_project_type JAVA|MAVEN|GRADLE|UNKNOWN %global java_srcroot_rel my-src-dir ``` --- ## JDK 版本归一化策略 * 入参可为 `1.8.0` / `8` / `17` / `21` 等任意形式; * **查找产物**(`dist-jdk` / `artifacts-jdk.list`)一律使用 **主版本**:`1.8.0 → 8`; * **安装路径与子包命名**保留 **原始入参**,如: * 安装:`/usr/share/java/%{name}/jdk1.8.0/…` * `%files -f files-jdk1.8.0.list` * 这样既能兼容已有命名,又能保证不同写法(`8` vs `1.8.0`)不会造成找不到构建产物。 --- ## 目录规范与产物 * **中间产物(构建阶段生成)**:`%{_builddir}/.%{name}.dist/` * `dist-jdk/`:某 JDK 的 jar 输出目录(非 Maven 路径) * `artifacts-jdk.list`:产物清单(非 Maven 路径) * **文件清单(install_pre 阶段生成)**:`%{_builddir}/.%{name}.filelists/files-jdk.list` * **安装路径(默认模板)**:`/usr/share/java/%{name}/jdk/…` > `%_copy_filelists` 会将 `files-jdk*.list` 复制到 `BUILD/%{name}-%{version}/`,供 `%files -f` 使用。即便 `UNKNOWN`,也会写入最小占位,确保 `%files` 不报错。 --- ## 故障排查 * **进了 UNKNOWN 分支** * 看日志 `PROBE:` 行。若 `SRCROOT/FILESDIR=BUILD` 根,说明候选目录未被识别; * 常见原因:源码解包目录不匹配 `%{name}-%{version}` 且顶层目录名不包含 `%{name}`; * 处理:设置 `%global java_srcroot_rel ...`,或修正 prjconf/宏到包含稳定的目录检测。 * **`%files -f files-jdk*.list` 找不到清单** * 确认 `files-jdk*.list` 最终被复制到了 `BUILD/%{name}-%{version}/`; * 若出现在 `BUILD/` 根,多半是旧版本宏没有 `FILESDIR` 优先策略。升级宏或手动复制到正确目录。 * **Maven 在脚本里调用 `%mvn_*` 失败** * `%mvn_*` 只能在宏中使用;Maven 路径已完全放在宏层,请不要在外部脚本里调用。 * **JDK 不存在** * 日志会打印某版本 JDK 跳过;请确保安装相应 `java--openjdk-devel`。 --- ## FAQ **Q:能只打 `-jdk17` 吗?** A:可以。把 `%global java_package_versions 17` 即可。 **Q:Maven 的 `%mvn_install` 要执行几次?** A:一次。变体映射已在 `install_pre` 阶段登记。 **Q:多模块 Maven 怎么办?** A:目前按主模块 `artifactId=%{mvn_artifact}` 映射;后续会增加“自动遍历子模块”增强。 **Q:Gradle 多模块 jar 会漏吗?** A:脚本使用 `globstar` 递归收集 `**/build/libs/*.jar`,覆盖多模块。 --- ## 最佳实践:README 与 LICENSE 打包 * **LICENSE**:强烈建议随包安装(`%license`);发行版审计/合规通常要求。 * **README**:建议以 `%doc` 安装,方便下游查看宏用法与排障指引。 **在宏包(本包)`hello-java-macros.spec` 中示例**: ```spec # 声明源文件(放到 SOURCES/) Source5: README.md Source6: LICENSE %files %license %{SOURCE6} %doc %{SOURCE5} /usr/lib/rpm/macros.d/macros.java-multi /usr/bin/build-java-multi.sh /usr/bin/build-gradle-multi.sh /usr/bin/find-java-multi.sh /usr/bin/find-gradle-multi.sh ``` > 注意:`%files` 段 **不要** 使用 shell 重定向/管道(如 `2>/dev/null`),也不要写无意义占位符。 --- ## 兼容性与要求 * `rpmbuild`、OBS(Open Build Service) * 目标 Maven 包:在其 spec 中声明 `BuildRequires: xmvn, maven` * 目标 Gradle/Java 包:安装相应 `java--openjdk-devel`;Gradle 可用系统 `gradle` 或项目自带 `gradlew` --- ## 变更记录 * **2025-09-26** * 初始化 --- ## 许可 本项目采用 **MIT License**。