资讯动态

Linux下OpenCV+C++程序静态打包实战:解决so依赖缺失问题

发布时间:2026/10/17 14:31:19 来源:尧图企业网站定制
1. 项目概述为什么打包OpenCVC程序比写代码还让人头疼“Linux打包opencv和C可执行程序”——这行字我见过太多次了几乎每个刚从Windows转到Linux做视觉开发的工程师、高校实验室的研究生、甚至某公司嵌入式组的新同事第一次想把本地跑通的detect_face.cpp发给测试同事时都会卡在这一步。不是编译不过是编译过了一拷到另一台机器就报错“error while loading shared libraries: libopencv_core.so.4.5: cannot open shared object file”。更扎心的是对方连apt install opencv-dev都不让装理由很现实系统环境要锁定、依赖不能污染、部署必须零配置。这个问题的本质从来不是OpenCV难用而是Linux下动态链接库的加载机制和发行版生态之间的天然张力。你本地g -o demo demo.cpp $(pkg-config --cflags --libs opencv4)能跑是因为你的开发机上既有/usr/lib/x86_64-linux-gnu/libopencv_core.so.4.5又有/etc/ld.so.conf.d/opencv.conf里配好的路径还有LD_LIBRARY_PATH临时兜底。但目标机器上什么都没有——它只认/lib、/usr/lib、/usr/local/lib这几个白名单路径且默认不扫描子目录。OpenCV官方预编译包又习惯把so文件塞进/usr/lib/x86_64-linux-gnu/这种带架构后缀的目录里而这个路径在多数发行版的默认ldconfig缓存中并不生效。结果就是你的程序在开发机上春风得意一挪地方就成哑巴。所以“打包”在这里不是简单地tar.gz源码而是要做三件事第一把所有运行时真正需要的so文件精准拎出来第二让程序启动时能不靠系统全局配置就找到它们第三确保这些so之间没有版本冲突或符号缺失。这不是脚本自动化能一键解决的事它考验的是对ldd输出的解读能力、对patchelf重写rpath的胆量、对chrpath修改runpath的耐心以及对objdump -T查符号表的熟练度。我试过用linuxdeployqt硬套失败也试过cpack配CPACK_DEBIAN_PACKAGE_DEPENDS结果部署机没apt源最后发现最稳的方案反而是“手工外科手术式打包”——先用工具定位再用命令改写最后用脚本封装。这篇文章就是我把过去三年在五六个不同Linux发行版Ubuntu 20.04/22.04、CentOS 7/8、Debian 11、openSUSE Leap 15上打包OpenCV程序踩过的坑、验证过的参数、实测有效的命令全部摊开讲透。不讲虚的原理只说你复制粘贴就能跑通的步骤不堆砌选项每个patchelf --set-rpath后面的路径都告诉你为什么这么写不回避坑点比如libglib-2.0.so.0和libgthread-2.0.so.0这种OpenCV间接依赖的幽灵库我会直接给你ldd过滤命令和补全方案。如果你正被“程序拷过去就炸”折磨这篇就是为你写的。2. 打包核心思路拆解为什么拒绝“全量拷贝”坚持“最小依赖集”很多人第一反应是既然缺so那就把整个/usr/lib/x86_64-linux-gnu/目录下的opencv相关so全拷过去不就完了我明确告诉你这条路走不通而且会越走越偏。原因有三层每层都直击Linux打包的底层逻辑。第一层是路径污染与加载优先级混乱。OpenCV的so命名规则是libopencv_core.so.4.5.5而系统通常只认libopencv_core.so.4.5这样的soname。当你把一堆带完整版本号的so扔进程序同目录ld-linux-x86-64.so.2加载器会按DT_RPATH或DT_RUNPATH里的路径顺序搜索一旦遇到libopencv_core.so.4.5.5它就会尝试加载这个具体文件。但如果这个文件内部又依赖libglib-2.0.so.0而你没把libglib一起拷或者拷了但版本不对比如你拷的是libglib-2.0.so.0.7000.0而程序需要0.6600.0整个链就断了。更糟的是如果目标机上恰好有旧版libglib-2.0.so.0在/usr/lib里加载器可能优先选系统自带的旧版导致OpenCV初始化失败——这种问题调试起来极其隐蔽ldd看不出来strace要筛几千行。第二层是发行版差异带来的ABI陷阱。Ubuntu 22.04用的是glibc 2.35CentOS 7用的是glibc 2.17两者ABI不兼容。你用Ubuntu编译的程序即使把所有so打包过去在CentOS 7上运行时libstdc.so.6这个基础库就可能报GLIBCXX_3.4.29 not found。这不是OpenCV的问题是C标准库的ABI墙。所以“打包”的前提是你得先确认目标机的glibc版本。我常用这条命令快速探底getconf GNU_LIBC_VERSION。如果目标机是CentOS 7glibc 2.17那你开发机最好也用CentOS 7容器编译或者至少用-static-libstdc静态链接C标准库——但注意-static-libgcc也要加否则libgcc_s.so.1还会动态依赖。第三层是OpenCV自身模块的隐式依赖链。你以为只用了cv::imread就只需要libopencv_imgcodecs.so错。imread内部会调用libjpeg.so.8、libpng16.so.16、libtiff.so.5而这些库又各自依赖libz.so.1、liblzma.so.5。更麻烦的是OpenCV的dnn模块如果启用了CUDA后端还会拖进来libcudart.so.11.0、libnvinfer.so.7这种重量级依赖体积动辄几百MB。所以真正的打包策略必须是“按需抽取”先用ldd扫出直接依赖再用ldd递归扫出间接依赖最后用readelf -d确认每个so的NEEDED条目剔除掉目标机已有的基础库如libc.so.6、libm.so.6、libpthread.so.0只保留OpenCV及其生态链上的“非标”库。我统计过一个只用coreimgprocimgcodecs的简单程序实际需要打包的so通常只有12~15个而不是网上教程说的30个。因此我的打包流程严格遵循“三步过滤法”初筛用ldd ./myapp | grep not found\| /usr定位所有不在/lib或/usr/lib下的so深挖对初筛出的每个so再执行ldd /path/to/so | grep not found\| /usr把它的依赖也拉进来精裁用file命令检查每个so是否为ELF 64-bit LSB pie executable即PIE可执行文件如果是说明它可能被strip过符号表不全要换用未strip的版本同时用objdump -T /path/to/so | grep U \|UND查未定义符号确保没有漏掉libglib这类“影子依赖”。这个思路看似笨重但实测下来打包成功率从不到50%提升到98%以上。因为它是基于真实加载行为的逆向工程而不是靠猜。3. 核心细节解析与实操要点从ldd到patchelf的完整链路现在进入最硬核的部分如何把上面说的思路变成一行行可执行的命令。这里不讲概念只讲你马上能用的操作细节、参数含义和避坑点。我以一个真实案例演示假设你的程序叫face_detector编译命令是g -O2 -o face_detector face_detector.cpp $(pkg-config --cflags --libs opencv4)目标部署机是Ubuntu 20.04glibc 2.31你需要把它打包成一个独立目录里面包含程序和所有依赖so。3.1 第一步精准定位依赖库ldd不是万能的但它是起点先别急着拷文件打开终端cd到程序所在目录执行ldd ./face_detector你会看到类似这样的输出我简化了路径实际会很长linux-vdso.so.1 (0x00007ffc12345000) libopencv_core.so.4.5 /usr/lib/x86_64-linux-gnu/libopencv_core.so.4.5 (0x00007f8b12345000) libopencv_imgproc.so.4.5 /usr/lib/x86_64-linux-gnu/libopencv_imgproc.so.4.5 (0x00007f8b12345000) libopencv_imgcodecs.so.4.5 /usr/lib/x86_64-linux-gnu/libopencv_imgcodecs.so.4.5 (0x00007f8b12345000) libstdc.so.6 /usr/lib/x86_64-linux-gnu/libstdc.so.6 (0x00007f8b12345000) libgcc_s.so.1 /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f8b12345000) libc.so.6 /lib/x86_64-linux-gnu/libc.so.6 (0x00007f8b12345000) libm.so.6 /lib/x86_64-linux-gnu/libm.so.6 (0x00007f8b12345000) /lib64/ld-linux-x86-64.so.2 (0x00007f8b12345000)关键来了只关注箭头右边路径不在/lib或/usr/lib开头的行。上面例子中libopencv_*都在/usr/lib/x86_64-linux-gnu/这个路径不属于默认搜索路径必须打包而libstdc.so.6、libc.so.6等都在/usr/lib/x86_64-linux-gnu/或/lib/x86_64-linux-gnu/但注意/lib/x86_64-linux-gnu/其实是/lib的符号链接/usr/lib/x86_64-linux-gnu/则不是。所以libstdc.so.6的路径/usr/lib/x86_64-linux-gnu/libstdc.so.6必须打包而libc.so.6的路径/lib/x86_64-linux-gnu/libc.so.6可以不打——因为/lib/x86_64-linux-gnu/是/lib的子目录ldconfig默认扫描/lib时会递归进去。提示用这条命令快速提取所有需打包的so路径排除系统基础库ldd ./face_detector | awk {print $3} | grep -v ^$ | grep -v /lib/x86_64-linux-gnu/ | grep -v /lib64/ | grep -v /lib/ | grep -v /usr/lib/ | sort -u它会过滤掉/lib/x86_64-linux-gnu/系统自带、/lib64/64位基础、/lib/核心库下的路径只留下/usr/lib/x86_64-linux-gnu/这类“非标”路径。3.2 第二步递归挖掘间接依赖别信“只拷opencv.so”这种话假设上一步得到libopencv_core.so.4.5你以为拷它就够了执行ldd /usr/lib/x86_64-linux-gnu/libopencv_core.so.4.5你会发现它依赖libglib-2.0.so.0、libgthread-2.0.so.0、libgobject-2.0.so.0而这些库的路径又是/usr/lib/x86_64-linux-gnu/所以必须把它们也加进打包列表。更狠的是libglib-2.0.so.0又依赖libpcre.so.3libpcre.so.3又依赖libz.so.1…… 这个链能拉出七八层。我的做法是写个简单脚本自动递归#!/bin/bash # save as find_deps.sh, chmod x TARGET$1 DEPS() while IFS read -r line; do if [[ $line ~ [[:space:]]/usr/lib/x86_64-linux-gnu/ ]]; then so_path$(echo $line | awk {print $3}) if [[ ! ${DEPS[]} ~ ${so_path} ]]; then DEPS($so_path) # 递归查这个so的依赖 ldd $so_path 2/dev/null | while IFS read -r dep_line; do if [[ $dep_line ~ [[:space:]]/usr/lib/x86_64-linux-gnu/ ]]; then dep_so$(echo $dep_line | awk {print $3}) if [[ ! ${DEPS[]} ~ ${dep_so} ]]; then DEPS($dep_so) fi fi done fi fi done (ldd $TARGET 2/dev/null) # 去重并输出 printf %s\n ${DEPS[]} | sort -u运行./find_deps.sh ./face_detector它会吐出所有需要打包的so绝对路径。注意这个脚本只处理/usr/lib/x86_64-linux-gnu/下的依赖不碰/lib或/usr/lib因为那些是系统保障的。3.3 第三步创建打包目录并拷贝文件结构决定成败别直接把so扔到程序同目录这是新手最大误区。正确结构必须是face_detector_bundle/ ├── face_detector # 你的可执行程序 ├── lib/ # 所有依赖so放这里 │ ├── libopencv_core.so.4.5 │ ├── libopencv_imgproc.so.4.5 │ ├── libglib-2.0.so.0 │ └── ... └── run.sh # 启动脚本可选但强烈推荐为什么因为patchelf修改rpath时路径是相对于可执行程序的。如果你把so和程序放同一级rpath就得设成$ORIGIN即当前目录如果so放在lib/子目录rpath就设成$ORIGIN/lib。后者更清晰也方便后续扩展比如加个plugins/目录。创建目录并拷贝mkdir -p face_detector_bundle/lib cp ./face_detector face_detector_bundle/ # 拷贝所有deps假设deps.txt里存了find_deps.sh的输出 while IFS read -r so; do cp $so face_detector_bundle/lib/ done deps.txt注意cp时务必用绝对路径避免cp: cannot stat libopencv_core.so.4.5: No such file or directory这种低级错误。deps.txt里的路径必须是/usr/lib/x86_64-linux-gnu/libopencv_core.so.4.5这种完整路径。3.4 第四步用patchelf重写rpath最关键的一步90%失败源于此现在face_detector还在找/usr/lib/x86_64-linux-gnu/必须让它改口。patchelf是唯一可靠工具chrpath功能太弱不支持$ORIGIN。执行patchelf --set-rpath $ORIGIN/lib face_detector_bundle/face_detector注意单引号双引号会让shell提前展开$ORIGIN成空字符串导致写入失败。$ORIGIN是ld加载器的特殊变量代表可执行程序自身的目录。所以$ORIGIN/lib就是face_detector_bundle/lib。验证是否成功patchelf --print-rpath face_detector_bundle/face_detector # 应该输出$ORIGIN/lib再验证so的依赖是否被正确解析ldd face_detector_bundle/face_detector此时所有libopencv_*的路径应该显示为 not found因为还没把so放进lib/目录等等我们刚拷过去了——不如果显示not found说明patchelf没生效或者lib/目录下so名字不匹配。常见原因是libopencv_core.so.4.5在lib/目录下但face_detector的NEEDED条目里写的是libopencv_core.so.4.5.5完整版本号。这时要用patchelf强制改名# 先看face_detector需要哪个名字 readelf -d face_detector_bundle/face_detector | grep NEEDED # 输出类似 0x0000000000000001 (NEEDED) Shared library: [libopencv_core.so.4.5.5] # 把lib/下的so软链接成需要的名字 cd face_detector_bundle/lib ln -sf libopencv_core.so.4.5 libopencv_core.so.4.5.5 # 或者用patchelf直接改NEEDED更彻底 patchelf --replace-needed libopencv_core.so.4.5.5 libopencv_core.so.4.5 face_detector_bundle/face_detector实操心得我习惯在打包前先用strip --strip-unneeded瘦身so文件能减少30%体积且不影响运行。命令strip --strip-unneeded face_detector_bundle/lib/*.so*。但注意strip会删掉调试符号如果后续要gdb调试就跳过这步。4. 实操过程与核心环节实现从零开始打包一个可运行的Bundle现在我们把前面所有步骤串起来做成一个可复用的、带错误检查的完整流程。以下是一个经过20次实测验证的打包脚本build_bundle.sh你可以直接复制使用。我以Ubuntu 22.04为例目标程序是face_detector它用到了OpenCV的core、imgproc、imgcodecs、dnn四个模块。4.1 准备工作确认环境与工具链首先确保开发机装齐必要工具sudo apt update sudo apt install -y build-essential pkg-config libopencv-dev patchelf binutils # 验证patchelf版本必须0.12 patchelf --version # 输出应为patchelf 0.12或更高然后编译你的程序关键参数不能少# 编译时加-fPIE -pie生成位置无关可执行文件兼容性更好 g -O2 -fPIE -pie -o face_detector face_detector.cpp $(pkg-config --cflags --libs opencv4) # 检查编译产物是否为PIE file face_detector # 应输出face_detector: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 3.2.0, BuildID[sha1]..., stripped4.2 执行打包全流程逐行解释创建build_bundle.sh#!/bin/bash # build_bundle.sh - OpenCV C程序Linux打包脚本 # 用法./build_bundle.sh ./face_detector bundle_name if [ $# -ne 2 ]; then echo 用法$0 可执行程序路径 打包目录名 exit 1 fi APP_PATH$1 BUNDLE_NAME$2 # 步骤1创建bundle目录结构 echo [1/5] 创建打包目录 $BUNDLE_NAME mkdir -p $BUNDLE_NAME/lib # 步骤2拷贝主程序 echo [2/5] 拷贝主程序 cp $APP_PATH $BUNDLE_NAME/ # 步骤3递归收集所有/usr/lib/x86_64-linux-gnu/下的依赖 echo [3/5] 递归收集依赖库... DEP_LIST() # 初筛 while IFS read -r line; do if [[ $line ~ [[:space:]]/usr/lib/x86_64-linux-gnu/ ]]; then so_path$(echo $line | awk {print $3}) if [[ -n $so_path -f $so_path ]]; then DEP_LIST($so_path) fi fi done (ldd $APP_PATH 2/dev/null) # 深挖每一层 for so in ${DEP_LIST[]}; do while IFS read -r dep_line; do if [[ $dep_line ~ [[:space:]]/usr/lib/x86_64-linux-gnu/ ]]; then dep_so$(echo $dep_line | awk {print $3}) if [[ -n $dep_so -f $dep_so ]]; then # 去重 if [[ ! ${DEP_LIST[]} ~ ${dep_so} ]]; then DEP_LIST($dep_so) fi fi fi done (ldd $so 2/dev/null) done # 去重并排序 DEP_LIST($(printf %s\n ${DEP_LIST[]} | sort -u)) # 步骤4拷贝所有依赖so到lib/目录 echo [4/5] 拷贝 ${#DEP_LIST[]} 个依赖库到 $BUNDLE_NAME/lib/ for so in ${DEP_LIST[]}; do cp $so $BUNDLE_NAME/lib/ # 为每个so创建指向soname的软链接解决NEEDED名字不匹配 soname$(objdump -p $so | grep SONAME | awk {print $2}) if [[ -n $soname ]]; then cd $BUNDLE_NAME/lib ln -sf $(basename $so) $soname cd - /dev/null fi done # 步骤5用patchelf重写rpath并验证 echo [5/5] 重写rpath并验证... patchelf --set-rpath $ORIGIN/lib $BUNDLE_NAME/face_detector # 验证ldd应显示所有so路径为lib/下的相对路径 echo 验证结果 ldd $BUNDLE_NAME/face_detector | grep not found\| | head -10 echo 打包完成Bundle目录$BUNDLE_NAME echo 测试命令cd $BUNDLE_NAME ./face_detector赋予执行权限并运行chmod x build_bundle.sh ./build_bundle.sh ./face_detector face_detector_bundle脚本执行完你会看到类似输出[1/5] 创建打包目录 face_detector_bundle [2/5] 拷贝主程序 [3/5] 递归收集依赖库... [4/5] 拷贝 14 个依赖库到 face_detector_bundle/lib/ [5/5] 重写rpath并验证... 验证结果 linux-vdso.so.1 (0x00007ffd12345000) libopencv_core.so.4.5 /home/user/face_detector_bundle/lib/libopencv_core.so.4.5 (0x00007f8b12345000) libopencv_imgproc.so.4.5 /home/user/face_detector_bundle/lib/libopencv_imgproc.so.4.5 (0x00007f8b12345000) ... 打包完成Bundle目录face_detector_bundle 测试命令cd face_detector_bundle ./face_detector4.3 测试与调试在目标机上零配置运行把整个face_detector_bundle目录压缩tar -czf face_detector_bundle.tar.gz face_detector_bundle拷到目标机Ubuntu 20.04解压后直接运行tar -xzf face_detector_bundle.tar.gz cd face_detector_bundle ./face_detector如果一切顺利程序应该正常启动。如果报错按以下顺序排查./face_detector: No such file or directory这不是文件不存在而是/lib64/ld-linux-x86-64.so.2找不到。说明目标机glibc版本太低。用getconf GNU_LIBC_VERSION对比若目标机是glibc 2.28而开发机是2.31就必须降级编译或静态链接libc不推荐太复杂。error while loading shared libraries: libglib-2.0.so.0: cannot open shared object file说明libglib-2.0.so.0没拷全或者lib/下软链接没建对。进lib/目录ls -l看libglib-2.0.so.0是否指向一个真实存在的so文件。如果不是手动ln -sf libglib-2.0.so.0.7000.0 libglib-2.0.so.0。程序启动但OpenCV初始化失败如cv::dnn::Net::readFromModelOptimizer报错可能是libinference_engine.so这类Intel OpenVINO依赖没打包。用ldd face_detector | grep inference确认若有按同样流程加入DEP_LIST。实操心得我每次打包后必做三件事在目标机上用strace -e traceopenat,openat64 ./face_detector 21 | grep -i no such抓取所有open失败的路径精准定位漏掉的so用readelf -d ./face_detector | grep RUNPATH确认RUNPATH值是$ORIGIN/lib不是空或错误路径用objdump -T ./face_detector | grep U \|UND查未定义符号确保没有U g_malloc这类来自glib的符号报Uundefined如果有说明libglib没链接上。5. 常见问题与排查技巧实录那些文档里不会写的坑打包OpenCV程序90%的问题都出在“以为自己懂了其实没懂”的细节上。下面是我整理的高频问题速查表每一条都来自真实翻车现场附带一针见血的解决方案。5.1 问题速查表问题现象根本原因快速诊断命令解决方案./app: error while loading shared libraries: libopencv_core.so.4.5: cannot open shared object filerpath未设置或设置错误程序仍在找系统路径patchelf --print-rpath ./apppatchelf --set-rpath $ORIGIN/lib ./app确认输出为$ORIGIN/lib./app: /lib/x86_64-linux-gnu/libc.so.6: version GLIBC_2.33 not found目标机glibc版本低于开发机getconf GNU_LIBC_VERSION开发机和目标机都执行开发机切到目标机同版本容器编译或加-static-libgcc -static-libstdc仅限C库ldd ./app显示libglib-2.0.so.0 not found但lib/下明明有这个文件lib/下so的soname与NEEDED条目不匹配如NEEDED要libglib-2.0.so.0.7000.0而你只拷了libglib-2.0.so.0readelf -d ./app | grep NEEDED和objdump -p libglib-2.0.so.0 | grep SONAME在lib/下建软链接ln -sf libglib-2.0.so.0.7000.0 libglib-2.0.so.0程序能启动但cv::imread返回空Mat无报错libjpeg.so.8、libpng16.so.16等图像解码库缺失或版本不兼容ldd ./app | grep -E (jpeg|png|tiff)按同样流程把libjpeg.so.8、libpng16.so.16、libtiff.so.5加入打包列表patchelf: failed to load program: Exec format errorpatchelf版本太低不支持新格式ELFpatchelf --version需≥0.12sudo apt install patchelf或从源码编译最新版打包后体积过大200MB错误打包了libopencv_dnn.so及其CUDA/NVIDIA依赖ldd ./app | grep -i cuda|nv若不用GPU推理编译OpenCV时加-D WITH_CUDAOFF -D WITH_CUDNNOFF5.2 独家避坑技巧技巧1用lddtree替代ldd看清依赖树全貌ldd只能看一层lddtree来自pax-utils包能画出完整的依赖树。安装sudo apt install pax-utils。使用lddtree ./face_detector输出类似./face_detector ├── libopencv_core.so.4.5 /usr/lib/x86_64-linux-gnu/libopencv_core.so.4.5 │ ├── libglib-2.0.so.0 /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0 │ │ ├── libpcre.so.3 /usr/lib/x86_64-linux-gnu/libpcre.so.3 │ │ └── libz.so.1 /lib/x86_64-linux-gnu/libz.so.1 │ └── libgthread-2.0.so.0 /usr/lib/x86_64-linux-gnu/libgthread-2.0.so.0 ├── libopencv_imgproc.so.4.5 /usr/lib/x86_64-linux-gnu/libopencv_imgproc.so.4.5 ...一眼就能看出libpcre.so.3和libz.so.1是否在/lib/x86_64-linux-gnu/可不打还是/usr/lib/x86_64-linux-gnu/必须打。技巧2patchelf的--shrink-rpath是银弹但慎用patchelf --shrink-rpath ./app会自动删除rpath中所有不存在的路径只保留有效的。但它有个致命缺陷如果rpath里有多个路径如$ORIGIN/lib:$ORIGIN/../lib它会全删掉只剩一个。所以我的建议是先用--set-rpath设好再用--shrink-rpath清理冗余而不是依赖它自动生成。技巧3OpenCV的cv::dnn模块永远检查libinference_engine.so很多教程忽略这点。只要你用了cv::dnn::readNetFromONNX就一定依赖Intel OpenVINO的libinference_engine.so。它不在pkg-config --libs opencv4里ldd却会暴露它。解决方案要么打包libinference_engine.so体积大要么编译OpenCV时禁用DNN后端-D OPENCV_DNN_BACKENDOPENCV -D OPENCV_DNN_TARGETCPU。技巧4终极验证——用chroot模拟目标环境最狠的验证方式用debootstrap在本地建一个目标机最小系统然后把bundle拷进去跑。命令# 创建Ubuntu 20.04 chroot sudo debootstrap focal /tmp/focal-chroot http://archive.ubuntu.com/ubuntu/ # 拷bundle进去 sudo cp -r face_detector_bundle /tmp/focal-chroot/root/ # 进chroot sudo chroot /tmp/focal-chroot cd /root/face_detector_bundle ./face_detector如果chroot里能跑那在真实目标机上100%能跑。这是我交付前必做的最后一道关卡。6. 工具选型与参数详解为什么是patchelf而不是chrpath或ldd在打包工具的选择上我见过太多人绕弯路。有人

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑