summaryrefslogtreecommitdiff
path: root/mrpt-libmath.spec
blob: 52f993bf6aea0ea773adde8a267984a28a3d2d52 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
%define ros_distro humble
%define RosPkgName mrpt-libmath
%define src_version 2.15.20
%define mrpt_version 2.15.21
# mrpt 的 git submodule 内容(GitHub archive tarball 不含),按需手工补:
%define nanoflann_version 1.5.5
%define simpleini_version 4.22

Name:           ros-%{ros_distro}-%{RosPkgName}
Version:        2.15.20
Release:        3%{?dist}
Summary:        Mobile Robot Programming Toolkit (MRPT) libraries (math C++ libraries)
License:        BSD
URL:            https://github.com/MRPT/mrpt_ros.git
Source0:        %{RosPkgName}-%{src_version}.tar.gz
# mrpt upstream source, pre-fetched to avoid ExternalProject git clone at build time
Source1:        https://github.com/MRPT/mrpt/archive/refs/tags/%{mrpt_version}.tar.gz#/mrpt-%{mrpt_version}.tar.gz
# mrpt 的两个 submodule(COPR chroot 无外网,构建期无法下载/克隆,须随 SRPM 携带):
#   nanoflann —— mrpt 强制依赖(script_nanoflann.cmake: FATAL_ERROR if not found;
#                mrpt-math 的 target_link_libraries 也直接链 nanoflann::nanoflann),
#                openEuler 官方源无系统包,只能喂 3rdparty/nanoflann 让内层自建(头文件库)
#   simpleini —— mrpt-config 编译 CConfigFile.cpp 需要 SimpleIni.h(script_simpleini.cmake
#                回退到 3rdparty/simpleini 作为 include 目录)
Source2:        https://github.com/jlblancoc/nanoflann/archive/refs/tags/v%{nanoflann_version}.tar.gz#/nanoflann-%{nanoflann_version}.tar.gz
Source3:        https://github.com/brofield/simpleini/archive/refs/tags/v%{simpleini_version}.tar.gz#/simpleini-%{simpleini_version}.tar.gz

%global debug_package %{nil}
%global __os_install_post %(echo '%{__os_install_post}' | sed -e 's!/usr/lib[^[:space:]]*/brp-python-bytecompile[[:space:]].*$!!g')
%global __provides_exclude_from ^/opt/ros/%{ros_distro}/.*$
%global __requires_exclude_from ^/opt/ros/%{ros_distro}/.*$

# 本包向上依赖 ros-humble-mrpt-libbase:内层 mrpt 里 mrpt-math 直接依赖
# mrpt-serialization / mrpt-random / mrpt-system(见 libs/math/CMakeLists.txt 的
# define_mrpt_lib 参数),这三者由 mrpt-libbase 提供;本包内层 BUILD_mrpt-*=OFF,
# 靠 DeclareMRPTLib.cmake 的 find_package(mrpt-XXX) 分支复用已安装版本。
BuildRequires:  ros-%{ros_distro}-mrpt-libbase
BuildRequires:  assimp-devel
BuildRequires:  eigen3-devel
BuildRequires:  ffmpeg-devel
# openEuler 的 freeglut 只有运行库,头文件/so 链接在 -devel;找不到系统 GLUT 时
# mrpt 会去编内置 freeglut,因 -Werror=implicit-function-declaration 失败
BuildRequires:  freeglut-devel
BuildRequires:  git
BuildRequires:  gtest-devel
BuildRequires:  libXrandr-devel
BuildRequires:  libXxf86vm-devel
BuildRequires:  libglvnd-devel
BuildRequires:  libjpeg-devel
BuildRequires:  libpcap-devel
BuildRequires:  libudev-devel
BuildRequires:  libusbx-devel
BuildRequires:  libzstd-devel
BuildRequires:  mesa-libGL-devel
BuildRequires:  mesa-libGLU-devel
BuildRequires:  opencv
BuildRequires:  pkgconfig
BuildRequires:  pybind11-devel
BuildRequires:  suitesparse-devel
BuildRequires:  tbb-devel
BuildRequires:  tinyxml2-devel
BuildRequires:  zlib-devel
BuildRequires:  cmake

Requires:       ros-%{ros_distro}-ros-workspace
Requires:       ros-%{ros_distro}-mrpt-libbase
Requires:       eigen3-devel
Requires:       suitesparse-devel

Provides:       %{name}-devel = %{version}-%{release}
Provides:       %{name}-doc = %{version}-%{release}
Provides:       %{name}-runtime = %{version}-%{release}

%description
Mobile Robot Programming Toolkit (MRPT) libraries (math C++ libraries).
  This package contains: mrpt-math

%prep
%autosetup -n %{RosPkgName}-%{src_version}
# --- 复用预置 mrpt 源码,避免 ExternalProject 在构建期 git clone -------------
# mrpt_libmath/CMakeLists.txt 用 ExternalProject_Add(mrpt ...) 拉取上游 mrpt,
# 本地复用路径写成 ${CMAKE_BINARY_DIR}/../mrpt_libbase/mrpt-build/...,那是 ROS
# 官方 buildfarm 的目录布局(build 目录 = <ws>/build/mrpt_libmath,故其 .. 即
# <ws>/build)。本 spec 的 CMAKE_BINARY_DIR = <top>/mrpt_libmath/.obj,同一表达式
# 会多出一层 mrpt_libmath(<top>/mrpt_libmath/mrpt_libbase/mrpt-build),EXISTS
# 检查必然失败而退回 git clone;COPR chroot 无外网,clone 100% 失败
# ("Could not resolve host: github.com")。
# 统一改写成相对 CMakeLists.txt 自身目录的 ../mrpt-build,与下面预置的
# <top>/mrpt-build 对齐(EXISTS 检查 / SOURCE_DIR 两处)。
sed -i 's|\${CMAKE_BINARY_DIR}/\.\./mrpt_libbase/mrpt-build|${CMAKE_CURRENT_LIST_DIR}/../mrpt-build|g' \
    mrpt_libmath/CMakeLists.txt
# 去掉 HOME==/home/buildfarm 守卫:该条件只对 buildfarm 屏蔽本地复用,去掉后
# 复用分支在任何构建环境都成立。注意本仓库 mrpt_libmath 的条件是裸 "AND NOT
# ..."(mrpt_libbase 是 "AND (NOT ...)",多一层括号),模式须与之逐字对应。
sed -i 's/ AND NOT "\$ENV{HOME}" STREQUAL "\/home\/buildfarm"//' \
    mrpt_libmath/CMakeLists.txt
# 给内层 mrpt 追加开关(外层 cmake 命令行传的 MRPT_WITH_xxx 落在 ROS 包装工程上,
# 而包装工程只把它们原样忽略——真正生效的是写死在 ExternalProject_Add 里的
# CMAKE_ARGS,必须在此注入):
#   MRPT_HAS_LIBFYAML=OFF  openEuler 无 libfyaml,内置分支要 3rdparty/libfyaml
#                          (submodule 空目录)且会 file(READ .tarball-version) 报错;
#                          该特性只影响 mrpt::containers::yaml,关掉即可(ROS 包
#                          package.xml 里 libfyaml-dev 也被上游注释掉了)
#   MRPT_WITH_KINECT=OFF   libusb 存在时默认开启 Kinect,会去编译空的
#                          3rdparty/libfreenect(openEuler 无 libfreenect-devel)
#   MRPT_HAS_OPENNI2=OFF   无 libopenni2
#   MRPT_BUILD_OCTOMAP=OFF 无系统 octomap 时 ExternalProject 会从 GitHub 下载
#                          octomap(构建期无外网必失败)
#   CMAKE_PREFIX_PATH      内层 mrpt 对 BUILD_mrpt-*=OFF 的兄弟库走
#                          DeclareMRPTLib.cmake 的 find_package(mrpt-XXX) 分支,
#                          必须能搜到 mrpt-libbase 装到 /opt/ros/<distro> 的
#                          mrpt-*-config.cmake;缺了它 mrpt-math 会被静默地
#                          "Disabling compilation of lib mrpt-math" 而产出空包
sed -i 's|^\(\s*-DDISABLE_JSONCPP=ON\)$|\1\n    -DMRPT_HAS_LIBFYAML=OFF\n    -DMRPT_WITH_KINECT=OFF\n    -DMRPT_HAS_OPENNI2=OFF\n    -DMRPT_BUILD_OCTOMAP=OFF\n    -DCMAKE_PREFIX_PATH=/opt/ros/%{ros_distro}|' \
    mrpt_libmath/CMakeLists.txt
# 预置 ExternalProject 的 SOURCE_DIR:<top>/mrpt-build/src/mrpt
mkdir -p mrpt-build/src
tar -xzf %{SOURCE1} -C mrpt-build/src
mv mrpt-build/src/mrpt-%{mrpt_version} mrpt-build/src/mrpt
# GitHub archive tarball 不含 git submodule 内容,而上游 mrpt 顶层 CMakeLists.txt
# 有无条件存在性检查(3rdparty/nanogui/include、3rdparty/rplidar_sdk/sdk/src),
# 缺失即 FATAL_ERROR "git submodules missing!"。补空目录绕过;这两个子项目在内层
# CMAKE_ARGS 里已分别用 -DMRPT_BUILD_nanogui=OFF / -DMRPT_BUILD_rplidar_sdk=OFF
# 关闭,不会被真正编译。
mkdir -p mrpt-build/src/mrpt/3rdparty/nanogui/include \
         mrpt-build/src/mrpt/3rdparty/rplidar_sdk/sdk/src
# 填充 mrpt 的两个必需 submodule(见 Source2/Source3 说明):nanoflann 供内层
# CMake 自建(头文件库,mrpt-math 直接链接),simpleini 仅作为 mrpt-config 的
# include 目录。
rm -rf mrpt-build/src/mrpt/3rdparty/nanoflann mrpt-build/src/mrpt/3rdparty/simpleini
mkdir -p mrpt-build/src/mrpt/3rdparty/nanoflann mrpt-build/src/mrpt/3rdparty/simpleini
tar -xzf %{SOURCE2} -C mrpt-build/src/mrpt/3rdparty/nanoflann --strip-components=1
tar -xzf %{SOURCE3} -C mrpt-build/src/mrpt/3rdparty/simpleini --strip-components=1
# Override the version cmake reads from package.xml to match the pre-fetched source
echo 'set(MRPT_VERSION_TO_DOWNLOAD "%{mrpt_version}")' > override_mrpt_version.cmake

%build
[ -f /opt/ros/%{ros_distro}/setup.sh ] && source /opt/ros/%{ros_distro}/setup.sh || true
export PYTHONPATH=/opt/ros/%{ros_distro}/lib/python%{python3_version}/site-packages${PYTHONPATH:+:$PYTHONPATH}
export PKG_CONFIG_PATH=/opt/ros/%{ros_distro}/lib/pkgconfig${PKG_CONFIG_PATH:+:$PKG_CONFIG_PATH}
cd mrpt_libmath
mkdir -p .obj && cd .obj
%cmake3 \
    -DCMAKE_INSTALL_PREFIX="/opt/ros/%{ros_distro}" \
    -DAMENT_PREFIX_PATH="/opt/ros/%{ros_distro}" \
    -DCMAKE_PREFIX_PATH="/opt/ros/%{ros_distro}" \
    -UINCLUDE_INSTALL_DIR -ULIB_INSTALL_DIR -USYSCONF_INSTALL_DIR -USHARE_INSTALL_PREFIX -ULIB_SUFFIX \
    -DSETUPTOOLS_DEB_LAYOUT=OFF \
    -DBUILD_TESTING=OFF -DTESTING=OFF -DCMAKE_SUPPRESS_REGENERATION=ON \
    -DMRPT_WITH_FREENECT=OFF \
    -DMRPT_WITH_OPENNI2=OFF \
    -DMRPT_WITH_GLFW=OFF \
    -DMRPT_BUILD_wxThings=OFF \
    ..
# 闸门:cmake 生成 mrpt-gitclone.cmake 即表示未复用 %prep 预置的 mrpt 源码,
# 构建期将 git clone(COPR chroot 无外网,必然失败)。这里提前失败并给出明确
# 原因,避免又白烧一轮 COPR 构建。
if [ -e mrpt-build/tmp/mrpt-gitclone.cmake ]; then
    echo "ERROR: cmake 准备 git clone mrpt —— %prep 预置源码未被复用,请检查预置路径" >&2
    exit 1
fi
# --- 并行度与内存:mrpt-math 的模板 TU 是内存杀手 ---------------------------
# 现象(build 112579):4 核 / MemTotal 6.9GiB / 无 swap 的 COPR builder 上
# `make -j4` 编译 libs/math/src/CMatrixFixed.cpp 时 cc1plus 被 OOM killer
# SIGKILL(日志 "c++: fatal error: Killed signal terminated program cc1plus",
# 随后 .s 被截断报 "unknown pseudo-op: `.l'" / "open CFI at the end of file")。
# 该 TU 用 DO_MATFIXED_INSTANTIATION 把 CMatrixFixed 的 5 种尺寸 × 2 种标量
# 类型的全套成员显式实例化,另有 A_/MatrixBase_instantiate_* 一组同量级的
# 实例化 TU,-O2 -g 下单进程峰值内存达 GB 级,4 路并行叠峰即打爆 6.9GiB。
#   (1) 降单进程内存:CMake 会用环境变量 CXXFLAGS/CFLAGS 初始化 CMAKE_<LANG>_FLAGS
#       (build 112579 日志里内层 "C++ flags (active config.)" 就是 rpmbuild 的
#       optflags 透传结果),故在 make 之前覆盖为 -O1 -g0:本包文件头已把
#       debug_package 置空,-g 只烧内存不出产物;-O1 对矩阵运算足够,
#       并保留下游 hardening 项(stack-protector / FORTIFY / GLIBCXX_ASSERTIONS)。
#   (2) 限并行:按“每个 cc1plus 预留 2.5GiB”从 MemTotal 反推 job 数,取
#       min(nproc, 内存上限)、至少 1 路,避免多路 cc1plus 同时叠峰。
#   ★ 本段注释里禁止再出现百分号前缀的宏指令字样(global / define / undefine):
#     rpm 的 scriptlet 解析器会把注释行里的这类文本当宏定义提取,定义之后同一
#     行的残留文本会被丢出来当命令执行 —— build 112584 就是这么挂的
#     ("line 105: command not found" → "Bad exit status from ...",而编译
#     本身已 100% 通过、libmrpt-math.so 已链接)。
export CFLAGS="-O1 -g0 -fstack-protector-strong -Wp,-D_FORTIFY_SOURCE=2 -fasynchronous-unwind-tables"
export CXXFLAGS="-O1 -g0 -fstack-protector-strong -Wp,-D_FORTIFY_SOURCE=2 -Wp,-D_GLIBCXX_ASSERTIONS -fasynchronous-unwind-tables"
JOBS="$(nproc 2>/dev/null || echo 1)"
MEM_KB="$(awk '/^MemTotal:/{print $2; exit}' /proc/meminfo 2>/dev/null)"
case "$MEM_KB" in
    ''|*[!0-9]*) MEM_KB=0 ;;
esac
if [ "$MEM_KB" -gt 0 ]; then
    MEM_JOBS=$(( MEM_KB / 2621440 ))
    if [ "$MEM_JOBS" -lt 1 ]; then MEM_JOBS=1; fi
    if [ "$JOBS" -gt "$MEM_JOBS" ]; then JOBS="$MEM_JOBS"; fi
fi
echo "mrpt-math 构建并行度: -j${JOBS}(nproc=$(nproc 2>/dev/null || echo '?'), MemTotal=${MEM_KB}KiB)"
make -j"$JOBS"

%install
[ -f /opt/ros/%{ros_distro}/setup.sh ] && source /opt/ros/%{ros_distro}/setup.sh || true
export PYTHONPATH=/opt/ros/%{ros_distro}/lib/python%{python3_version}/site-packages${PYTHONPATH:+:$PYTHONPATH}
export PKG_CONFIG_PATH=/opt/ros/%{ros_distro}/lib/pkgconfig${PKG_CONFIG_PATH:+:$PKG_CONFIG_PATH}
cd mrpt_libmath
cd .obj
make install DESTDIR=%{buildroot}

%files
/opt/ros/%{ros_distro}

%changelog
* Tue Sep 22 2026 ai-importer <ai-importer@openeuler.org> - 2.15.20-3
- 修复 build 段注释里的宏指令字样被 rpm 当宏定义提取、行尾残留文本被当命令
  执行(build 112584:编译已 100% 通过、libmrpt-math.so 已链接,随后
  "/var/tmp/rpm-tmp.utF2pB: line 105: command not found" 导致
  "Bad exit status from ... (build 段)")。rpm 的 scriptlet 解析器会把
  注释行里「百分号 + global/define + 名字 + 值」形式的文本提取为宏定义,
  定义之后同一行的剩余文本会被丢出来当脚本体执行——上一轮把 OOM 结论写进
  注释时踩到了这个坑。处置:该注释块改为不含百分号的纯文字(技术结论不变)。
- 本轮构建日志同时确认上一轮的 OOM 治理已生效:-j2 + 内层 -O1 下全部 CXX
  TU(含 CMatrixFixed.cpp 等实例化 TU,41 个)编译完成、libmrpt-math.so
  链接成功,全程无 cc1plus 被杀记录(build 112584)。
* Tue Sep 22 2026 ai-importer <ai-importer@openeuler.org> - 2.15.20-2
- 修复 %build 阶段 cc1plus 被 OOM killer 杀死(build 112579 实测:编译
  libs/math/src/CMatrixFixed.cpp 时 "c++: fatal error: Killed signal
  terminated program cc1plus",随后 .s 被截断报 unknown pseudo-op: `.l')。
  根因:mrpt-math 的定长矩阵实例化 TU 单进程峰值内存达 GB 级,而 COPR
  builder 只有 4 核 / 6.9GiB 内存 / 无 swap(hw_info.log),`make -j4`
  四路 cc1plus 叠峰打爆内存。
  * %build 在 make 前覆盖 CFLAGS/CXXFLAGS 为 -O1 -g0(+ 保留 hardening 项):
    CMake 用环境变量初始化 CMAKE_<LANG>_FLAGS,内层 mrpt 因此以更低优化级别
    编译;本包 debug_package 已 %{nil},去掉 -g 不损失产物内容。
  * %build 用 min(nproc, MemTotal/2.5GiB) 计算并行度(本例得 -j2)替代
    `make %{?_smp_mflags}`,保证至少 1 路,避免再次触发 OOM。
- Release 2(上一版 2.15.20-1 构建失败,无产物)。
* Tue Sep 22 2026 ai-importer <ai-importer@openeuler.org> - 2.15.20-1
- 依赖预检无 provider 修复(7 个缺口全部对齐既有的
  ros-humble-mrpt-libbase-2.15.20-3 处置方式;这些名字在 openEuler 官方源 /
  EPOL / ROS SIG 外挂源均查无 provider):
  * Debian 名修正:libxxf86vm → libXxf86vm-devel。
  * libfreenect-devel / libopenni2-dev / libglfw3-dev / wx-common / wxwidgets /
    nanoflann_vendor 从 BuildRequires 移除,改为关掉内层 mrpt 对应特性:
    -DMRPT_WITH_KINECT=OFF / -DMRPT_HAS_OPENNI2=OFF / -DMRPT_WITH_GLFW=OFF /
    -DMRPT_BUILD_wxThings=OFF;nanoflann 改用 Source2 喂 3rdparty/nanoflann
    (mrpt 的强制依赖,openEuler 无系统包)。这些条目在 mrpt_libmath/package.xml
    里本就自注为 "not actually required by this ROS package, but we need them
    for the mrpt/config.h to reflect we have such feature",只影响 config.h 的
    特性开关,mrpt-math 本体并不使用。
  * 按既有基线补齐 openEuler 实际可用的 devel 包:freeglut → freeglut-devel、
    libjpeg → libjpeg-devel,新增 libglvnd-devel / mesa-libGLU-devel /
    libzstd-devel / tbb-devel / gtest-devel / git。
- 修复构建期 ExternalProject 退回 git clone(COPR chroot 无外网必失败):
  %prep 预置 mrpt 源码到 <top>/mrpt-build/src/mrpt,并把 CMakeLists.txt 的本地
  复用路径改写为 ${CMAKE_CURRENT_LIST_DIR}/../mrpt-build、移除 buildfarm HOME
  守卫;补 3rdparty/nanogui/include 与 3rdparty/rplidar_sdk/sdk/src 空目录绕过
  上游 "git submodules missing!" 致命检查;Source2/Source3 填入 nanoflann 与
  simpleini;%build 增加 gitclone 闸门。
- 内层 mrpt 的 CMAKE_ARGS 注入 -DCMAKE_PREFIX_PATH=/opt/ros/%{ros_distro}:
  mrpt-math 依赖 mrpt-serialization/mrpt-random/mrpt-system,而本包内层
  BUILD_mrpt-*=OFF,靠 DeclareMRPTLib.cmake 的 find_package(mrpt-XXX) 复用
  mrpt-libbase 已安装版本;命中不了时 mrpt-math 会被静默禁用、产出空包。