核心内容摘要
《Nature Aging》新发文:解锁运动防治阿尔茨海默病新密码
文章目录
核心原理
完整示例Linux 平台
动态库源码mylib.c
C 封装层dlwrapper.c
Fortran 主程序main.f
编译与运行
Windows 平台适配要点
关键
注意事项
高级技巧直接使用 libdl无需 C 封装
适用场景在 Fortran 中动态加载动态库.so或.dll需借助C 互操作性ISO_C_BINDING调用操作系统原生 API如dlopen/dlsym或LoadLibrary/GetProcAddress。
Fortran 标准本身不提供动态加载接口但可通过 C 绑定桥接实现。
以下分步骤说明并提供完整示例。
核心原理步骤说明
编写动态库用 C 编写使用extern C避免 C 名称修饰Fortran 需通过 ISO_C_BINDING 声明接口
动态加载通过 C 函数封装dlopen/LoadLibraryFortran 调用该封装函数
获取符号通过 C 函数封装dlsym/GetProcAddress返回函数指针或变量地址
类型转换使用c_funptr/c_fptr在 C 函数指针与 Fortran 过程指针间转换⚠️关键点Fortran 无法直接操作void*必须通过 C 封装层中转。
完整示例Linux 平台
动态库源码mylib.c// mylib.c - 编译为 libmylib.so#includestdio.h// 全局变量doubleglobal_value
14159;// C 函数无名称修饰doublecompute(doublex,doubley){returnx*yglobal_value;}// 辅助函数返回变量地址避免 Fortran 直接处理 void*double*get_global_value_ptr(){returnglobal_value;}编译动态库gcc -shared -fPIC -o libmylib.so mylib.c
C 封装层dlwrapper.c// dlwrapper.c - 封装 dlopen/dlsym#define_GNU_SOURCE#includedlfcn.h#includestdint.h// 返回句柄转换为 intptr_t 供 Fortran 使用intptr_topen_library(constchar*path){return(intptr_t)dlopen(path,RTLD_LAZY|RTLD_GLOBAL);}// 获取函数符号void*get_function(intptr_thandle,constchar*name){returndlsym((void*)handle,name);}// 获取变量地址void*get_variable(intptr_thandle,constchar*name){returndlsym((void*)handle,name);}// 关闭库voidclose_library(intptr_thandle){dlclose((void*)handle);}编译为静态库供 Fortran 链接gcc -c -fPIC dlwrapper.c -o dlwrapper.o ar rcs libdlwrapper.a dlwrapper.o
Fortran 主程序main.f90program dynamic_load_example use, intrinsic :: iso_c_binding implicit none ! 接口声明 interface function open_library(path) bind(c, nameopen_library) import :: c_char, c_intptr_t character(kindc_char), intent(in) :: path(*) integer(c_intptr_t) :: open_library end function function get_function(handle, name) bind(c, nameget_function) import :: c_intptr_t, c_funptr integer(c_intptr_t), value :: handle character(kindc_char), intent(in) :: name(*) type(c_funptr) :: get_function end function function get_variable(handle, name) bind(c, nameget_variable) import :: c_intptr_t, c_ptr integer(c_intptr_t), value :: handle character(kindc_char), intent(in) :: name(*) type(c_ptr) :: get_variable end function subroutine close_library(handle) bind(c, nameclose_library) import :: c_intptr_t integer(c_intptr_t), value :: handle end subroutine end interface ! 目标函数类型声明 abstract interface function compute_func(x, y) bind(c) import :: c_double real(c_double), value :: x, y real(c_double) :: compute_func end function end interface ! 变量 integer(c_intptr_t) :: lib_handle type(c_funptr) :: func_ptr type(c_ptr) :: var_ptr procedure(compute_func), pointer :: compute_fptr null() real(c_double), pointer :: global_value_ptr null() real(c_double) :: result !
加载库 lib_handle open_library(libmylib.so // c_null_char) if (lib_handle
then print *, Error: Failed to load library stop end if print *, Library loaded successfully !
获取函数 func_ptr get_function(lib_handle, compute // c_null_char) if (.not. c_associated(func_ptr)) then print *, Error: Failed to get function compute call close_library(lib_handle) stop end if call c_f_procpointer(func_ptr, compute_fptr) !
获取变量 var_ptr get_variable(lib_handle, global_value // c_null_char) if (.not. c_associated(var_ptr)) then print *, Error: Failed to get variable global_value call close_library(lib_handle) stop end if call c_f_pointer(var_ptr, global_value_ptr) !
调用函数 访问变量 result compute_fptr(
0_c_double,
0_c_double) print *, compute(
0,
3.
, result print *, global_value , global_value_ptr !
修改变量通过指针 global_value_ptr
71828_c_double result compute_fptr(
0_c_double,
0_c_double) print *, After modification: compute(
0,
1.
, result !
卸载库 call close_library(lib_handle) print *, Library unloaded end program dynamic_load_example
编译与运行# 编译 Fortran 程序链接 libdlgfortran -o main main.f90 libdlwrapper.a -ldl# 运行确保 libmylib.so 在 LD_LIBRARY_PATH 中exportLD_LIBRARY_PATH.:$LD_LIBRARY_PATH./main输出示例Library loaded successfully compute(
0,
3.
0)
1415900000000003 global_value
1415900000000001 After modification: compute(
0,
1.
0)