MacOS下使用Ada运行时库时缺失libgnat-2020.dylib的问题求助
macOS下Ada动态库移动后无法加载的问题分析与解决
问题现象
用Ada构建FCS Middleware动态库供Flight Control Software主项目调用,库与主项目编译正常,在原目录可正常运行主程序。但将包含可执行文件和动态库的FlightControlSoftware/dist文件夹移动到其他位置(如下载文件夹)后,主程序启动报错:
dyld[15596]: Library not loaded: @rpath/libgnat-2020.dylib Referenced from: <9DD7BB9F-4BC0-3F80-9642-36D5228B5867> /Users/robert/Downloads/dist/fcs_software Reason: tried: '/Users/robert/Downloads/dist//lib/libgnat-2020.dylib' (no such file), '/Users/robert/Downloads//.obj/libgnat-2020.dylib' (no such file), '/Users/../../..//opt/gnat/2020/lib/gcc/x86_64-apple-darwin17.7.0/8.4.1/adalib/libgnat-2020.dylib' (no such file), '/Users/../../..//opt/gnat/2020/lib/libgnat-2020.dylib' (no such file), '/Users/robert/Downloads/dist//lib/libgnat-2020.dylib' (no such file), '/Users/robert/Downloads//.obj/libgnat-2020.dylib' (no such file), '/Users/../../..//opt/gnat/2020/lib/gcc/x86_64-apple-darwin17.7.0/8.4.1/adalib/libgnat-2020.dylib' (no such file), '/Users/../../..//opt/gnat/2020/lib/libgnat-2020.dylib' (no such file), '/usr/local/lib/libgnat-2020.dylib' (no such file), '/usr/lib/libgnat-2020.dylib' (no such file, not in dyld cache) zsh: abort ./fcs_software
项目配置详情
1. 项目结构
. ├── FCS_Middleware │ ├── dist │ │ ├── fcsm-math.ads │ │ ├── fcsm-math.ali │ │ ├── fcsm.ads │ │ ├── fcsm.ali │ │ └── libfcs_middleware.dylib │ ├── fcs_middleware.gpr │ └── src │ ├── fcsm │ │ ├── fcsm-math.adb │ │ ├── hidden_package.adb │ │ └── hidden_package.ads │ ├── fcsm-math.ads │ └── fcsm.ads └── FlightControlSoftware ├── dist │ ├── fcs_software **executable** │ └── lib │ ├── fcsm-math.ali │ ├── fcsm.ali │ └── libfcs_middleware.dylib ├── fcs_middleware.gpr ├── flight_control_software.gpr ├── include │ ├── fcsm-math.ads │ └── fcsm.ads └── src └── main.adb
2. FCS_Middleware主项目文件
project FCS_Middleware is for Source_Dirs use ("src/**"); for Object_Dir use ".obj"; for Library_Dir use "dist"; for Library_Src_Dir use "dist"; for Library_Name use "fcs_middleware"; for Library_Kind use "dynamic"; for Library_Interface use ("FCSM", "FCSM.Math"); end FCS_Middleware;
3. Flight Control Software项目文件
with "fcs_middleware.gpr"; project Flight_Control_Software is for Source_Dirs use ("src/**"); for Object_Dir use ".obj"; for Exec_Dir use "dist"; for Main use ("main.adb"); package Binder is for Switches ("ada") use ("-Es"); end Binder; package Builder is for Executable ("main.adb") use "fcs_software"; end Builder; end Flight_Control_Software;
4. FlightControlSoftware内的FCS_Middleware项目文件
project FCS_Middleware is for Source_Dirs use ("include"); for Library_Name use "fcs_middleware"; for Library_Dir use "dist/lib"; for Library_Kind use "dynamic"; for Externally_Built use "true"; end FCS_Middleware;
问题原因
这不是macOS的Bug,核心原因是依赖的GNAT运行时库libgnat-2020.dylib的查找路径配置错误:
- 编译时生成的rpath包含了相对于原编译目录的路径,移动dist文件夹后这些相对路径失效
- 可执行文件和动态库未配置基于自身位置的相对查找路径,导致dyld无法在新位置定位到
libgnat-2020.dylib - 报错信息显示,dyld尝试的路径要么是原编译目录的残留相对路径,要么是系统默认路径,均找不到目标库
解决方案
方案一:修改项目配置,配置相对rpath
通过在项目文件中添加链接器参数,设置基于自身位置的rpath,确保移动后能正确查找依赖:
- 更新
FCS_Middleware.gpr:
project FCS_Middleware is for Source_Dirs use ("src/**"); for Object_Dir use ".obj"; for Library_Dir use "dist"; for Library_Src_Dir use "dist"; for Library_Name use "fcs_middleware"; for Library_Kind use "dynamic"; for Library_Interface use ("FCSM", "FCSM.Math"); -- 添加链接器配置 package Linker is for Switches ("ada") use ("-Wl,-rpath,@loader_path/../lib"); end Linker; end FCS_Middleware;
- 更新
Flight_Control_Software.gpr:
with "fcs_middleware.gpr"; project Flight_Control_Software is for Source_Dirs use ("src/**"); for Object_Dir use ".obj"; for Exec_Dir use "dist"; for Main use ("main.adb"); package Binder is for Switches ("ada") use ("-Es"); end Binder; package Builder is for Executable ("main.adb") use "fcs_software"; end Builder; -- 添加链接器配置 package Linker is for Switches ("ada") use ("-Wl,-rpath,@loader_path/lib"); end Linker; end Flight_Control_Software;
@loader_path是macOS dyld的特殊变量,代表当前可执行文件/动态库所在目录- 配置后,可执行文件会从自身目录的
lib子目录查找动态库,动态库会从上级目录的lib子目录查找依赖
方案二:打包GNAT运行时库并修改依赖路径
将GNAT运行时库复制到dist目录,再修改可执行文件和动态库的依赖路径:
- 找到
libgnat-2020.dylib的位置,通常在/opt/gnat/2020/lib/下,将其复制到FlightControlSoftware/dist/lib目录 - 执行以下命令修改依赖路径:
# 修改可执行文件的libgnat依赖路径 install_name_tool -change @rpath/libgnat-2020.dylib @loader_path/lib/libgnat-2020.dylib ./dist/fcs_software # 修改动态库的libgnat依赖路径 install_name_tool -change @rpath/libgnat-2020.dylib @loader_path/../lib/libgnat-2020.dylib ./dist/lib/libfcs_middleware.dylib
移动dist目录后,dyld会从dist/lib目录找到所需的运行时库
方案三:静态编译(彻底消除动态依赖)
如果不需要动态库的特性,可改为静态编译,将所有依赖打包进可执行文件:
- 修改
FCS_Middleware.gpr中的库类型:
for Library_Kind use "static";
- 更新
Flight_Control_Software.gpr的链接器配置:
package Linker is for Switches ("ada") use ("-static"); end Linker;
静态编译后的可执行文件可在任意位置直接运行,无需依赖外部动态库
内容的提问来源于stack exchange,提问作者Robert
相关产品推荐
相关产品推荐

