Ubuntu 上的 Fortran 嵌入式开发实践指南
一、场景与总体思路
- 面向ARM/Linux 单板机(如树莓派、RK1808、NVIDIA Jetson 等):在 Ubuntu 主机使用交叉编译工具链生成目标机可执行文件或静态库,通过SSH/NFS/SD 卡部署运行。
- 面向裸机/RTOS/微控制器:Fortran 几乎不直接适用,工程上通常用 C/C++/Rust 编写底层,Fortran 仅以计算库形式被调用(通过 C 接口或 F2C 转换)。
- 面向Android:官方 NDK 默认不含 Fortran,需使用第三方支持 Fortran 的交叉工具链或改用 C/C++ 实现数值内核。
二、环境与工具链准备
-
主机基础环境
- 安装 GNU Fortran 与构建工具:
- sudo apt update && sudo apt install -y gfortran build-essential cmake
- 验证:gfortran --version
- 可选:安装 Fortran 项目工具 fpm(Fortran Package Manager),用于模块化开发与依赖管理:
- 下载 fpm 可执行文件,加入 PATH 后执行 fpm new、fpm run 等命令。
-
交叉编译工具链选择与获取
- ARM/Linux 通用:安装 gcc-aarch64-linux-gnu、g+±aarch64-linux-gnu、gfortran-aarch64-linux-gnu(或 32 位 arm-linux-gnueabihf 系列)。
- 厂商 SDK:如 RK1808/ZLG 等提供 aarch64-linux-gnu 工具链,解压后将其 bin 目录加入 PATH 即可使用(示例:aarch64-linux-gnu-gcc/gfortran)。
- 树莓派等:可从源码构建或使用社区工具链;注意目标机的 glibc 版本要与交叉工具链匹配,避免运行时符号不兼容。
-
Android NDK 的特殊情况
- 官方 NDK 不支持 Fortran。若必须使用,可考虑社区补丁版 NDK(如支持到 NDK r13b 的 android-gfortran),并用 CMake 指定 Fortran 编译器为 aarch64-linux-android-gfortran 进行交叉构建;但该方案版本较旧,维护成本高,生产更推荐以 C/C++ 重写热点数值例程。
三、交叉编译与部署流程
-
最小示例与交叉构建
- 源码(main.f90):
- program main
implicit none
print *, “Hello, embedded Fortran”
end program main
- 交叉编译(ARM64 示例):
- aarch64-linux-gnu-gfortran -O2 -static main.f90 -o main_arm64
- 说明:-static 可减少目标机依赖,便于在精简系统上运行。
- 部署与运行:
- 拷贝到目标机:scp main_arm64 user@192.0.2.10:/tmp
- 运行:ssh user@192.0.2.10 “chmod +x /tmp/main_arm64 && /tmp/main_arm64”
-
使用 CMake 的交叉构建(推荐)
- 工具链文件(aarch64-linux-gnu.toolchain.cmake):
- set(CMAKE_SYSTEM_NAME Linux)
- set(CMAKE_SYSTEM_PROCESSOR aarch64)
- set(CMAKE_C_COMPILER aarch64-linux-gnu-gcc)
- set(CMAKE_CXX_COMPILER aarch64-linux-gnu-g++)
- set(CMAKE_Fortran_COMPILER aarch64-linux-gnu-gfortran)
- set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
- set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
- set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
- set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
- 构建:
- mkdir build && cd build
- cmake -DCMAKE_TOOLCHAIN_FILE=…/aarch64-linux-gnu.toolchain.cmake -DCMAKE_BUILD_TYPE=Release …
- make
- 如需链接厂商库(如多媒体/硬件驱动 SDK),在 CMake 中设置 CMAKE_EXE_LINKER_FLAGS 或 target_link_libraries 指向对应的 .a/.so 与目标 sysroot。
-
库与依赖管理
- 数值库(如 BLAS/LAPACK)可在主机交叉编译为 静态库(.a) 后随应用链接;若库本身包含 Fortran 代码,需确保使用相同目标架构的交叉编译器与一致的 ABI/浮点模型构建。
- 使用 fpm 管理多文件/多依赖项目,便于在主机上编译与在目标机上联调(fpm 支持设置编译器与编译选项,适合作为开发与集成入口)。
四、调试与常见问题
-
运行时错误与 glibc 不匹配
- 现象:Illegal instruction、undefined reference to GLIBC_xx 等。
- 处理:让交叉工具链的 glibc 版本与目标机一致;必要时为目标机编译或挑选合适版本的 GCC/glibc 组合,再重建应用。
-
依赖与路径问题
- 动态库未找到:优先使用 -static 或将 .so 放入目标机的 /usr/lib 或 LD_LIBRARY_PATH 指定路径;交叉构建时用 CMAKE_FIND_ROOT_PATH 精确指向目标 sysroot。
-
并行与加速
- OpenMP:主机与目标机均需 libomp 支持,编译时添加 -fopenmp;目标机运行前确认内核已启用多核与调度策略。
- MPI:嵌入式 Linux 上可用 MPICH/OpenMPI 的交叉版本;编译用 mpif90,运行用 mpiexec/mpirun 指定进程数与主机列表。
-
Android 场景
- 若无法使用第三方 Fortran 工具链,建议将计算密集部分用 C/C++/Rust 重写,通过 ISO_C_BINDING 或 C 接口从 Fortran 调用,以获得更好的兼容性与维护性。