You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于ISO_C_BINDING实现Fortran版C结构体malloc/free等效逻辑及dlopen插件机制Hello World组件开发咨询

Fortran Plugin Implementation for dlopen-Based System (Hello World)

Got it, let's build out your Fortran plugin to match the C API exactly, using iso_c_binding to ensure full compatibility with your dlopen-based plugin manager. Here's a complete, working implementation, followed by a breakdown of key details:

Complete Fortran Plugin Code

module f_alg_mod
    use, intrinsic :: iso_c_binding, only : c_int, c_ptr, c_char, c_null_char, c_f_pointer, c_associated
    implicit none (type, external)

    ! Match the C Alg_t struct exactly using C binding
    type, bind(C) :: Alg_t
        type(c_ptr) :: name        ! Corresponds to C's const char*
        type(c_ptr) :: svcLocator  ! Corresponds to C's void*
    end type Alg_t

    ! Declare C standard library functions we need for memory and I/O
    interface
        function c_malloc(size) bind(C, name="malloc")
            import :: c_ptr, c_int
            integer(c_int), intent(in) :: size
            type(c_ptr) :: c_malloc
        end function c_malloc

        subroutine c_free(ptr) bind(C, name="free")
            import :: c_ptr
            type(c_ptr), intent(in) :: ptr
        end subroutine c_free
    end interface

contains

    ! Equivalent to c_alg_new: allocates and initializes the Alg_t struct
    function f_alg_new(name, svcLocator) result(ctx_ptr) bind(C, name="f_alg_new")
        type(c_ptr), intent(in) :: name, svcLocator
        type(c_ptr) :: ctx_ptr
        type(Alg_t), pointer :: ctx

        ! Allocate memory using C's malloc to match the C API's memory model
        ctx_ptr = c_malloc(sizeof(Alg_t, c_int))
        if (.not. c_associated(ctx_ptr)) return

        ! Convert the opaque C pointer to a Fortran pointer for easy field access
        call c_f_pointer(ctx_ptr, ctx)

        ! Assign input values to the struct fields
        ctx%name = name
        ctx%svcLocator = svcLocator
    end function f_alg_new

    ! Equivalent to c_alg_del: frees the allocated struct
    subroutine f_alg_del(self) bind(C, name="f_alg_del")
        type(c_ptr), intent(in) :: self
        call c_free(self)
    end subroutine f_alg_del

    ! Equivalent to c_alg_ini: prints initialization messages
    function f_alg_ini(self) result(err) bind(C, name="f_alg_ini")
        type(c_ptr), intent(in) :: self
        integer(c_int) :: err
        type(Alg_t), pointer :: ctx
        character(len=:), allocatable :: fort_name

        ! Convert the void* pointer back to our Alg_t struct pointer
        call c_f_pointer(self, ctx)

        ! Convert C's null-terminated string to a Fortran allocatable string
        call c_str_to_fortran(ctx%name, fort_name)

        ! Print initialization output (using Fortran's native print for simplicity)
        print '(A, A, A)', ">>> initialize [", trim(fort_name), "]..."
        print '(A, A, A)', ">>> initialize [", trim(fort_name), "]... [done]"

        err = 0  ! Return success code
        deallocate(fort_name)
    end function f_alg_ini

    ! Equivalent to c_alg_exe: prints execution messages
    function f_alg_exe(self) result(err) bind(C, name="f_alg_exe")
        type(c_ptr), intent(in) :: self
        integer(c_int) :: err
        type(Alg_t), pointer :: ctx
        character(len=:), allocatable :: fort_name

        call c_f_pointer(self, ctx)
        call c_str_to_fortran(ctx%name, fort_name)

        print '(A, A, A)', ">>> execute [", trim(fort_name), "]..."
        print '(A, A, A)', ">>> execute [", trim(fort_name), "]... [done]"

        err = 0
        deallocate(fort_name)
    end function f_alg_exe

    ! Equivalent to c_alg_fin: prints finalization messages
    function f_alg_fin(self) result(err) bind(C, name="f_alg_fin")
        type(c_ptr), intent(in) :: self
        integer(c_int) :: err
        type(Alg_t), pointer :: ctx
        character(len=:), allocatable :: fort_name

        call c_f_pointer(self, ctx)
        call c_str_to_fortran(ctx%name, fort_name)

        print '(A, A, A)', ">>> finalize [", trim(fort_name), "]..."
        print '(A, A, A)', ">>> finalize [", trim(fort_name), "]... [done]"

        err = 0
        deallocate(fort_name)
    end function f_alg_fin

    ! Helper: Convert C null-terminated string to Fortran allocatable string
    subroutine c_str_to_fortran(c_str, fort_str)
        type(c_ptr), intent(in) :: c_str
        character(len=:), allocatable, intent(out) :: fort_str
        character(kind=c_char), pointer :: char_ptr(:)
        integer :: str_len

        if (.not. c_associated(c_str)) then
            fort_str = ""
            return
        end if

        ! Calculate length of the C string
        call c_f_pointer(c_str, char_ptr, [huge(0)])
        str_len = 0
        do while (char_ptr(str_len+1) /= c_null_char)
            str_len = str_len + 1
        end do

        ! Allocate and copy the string to Fortran format
        allocate(character(len=str_len) :: fort_str)
        fort_str = transfer(char_ptr(1:str_len), fort_str)
    end subroutine c_str_to_fortran

end module f_alg_mod

! Dummy program unit (required by some Fortran compilers for shared library builds)
program dummy
    use f_alg_mod
    implicit none
end program dummy

Key Details & Explanations

1. Matching the C Struct Layout

Your initial struct used a fixed-length character array for name, which doesn't align with C's const char*. Instead, we use type(c_ptr) to hold the C string pointer directly—this ensures the struct layout is identical to the C version, which is critical for interoperability.

2. Exporting Exact Symbol Names

Every function exposed to the plugin manager uses bind(C, name="f_alg_new") (and similar for other functions). This forces Fortran to use the exact symbol name your plugin manager looks for, avoiding compiler-generated suffixes like _ that would break dlsym lookups.

3. Memory Management Consistency

We bind directly to C's malloc and free to handle memory allocation/deallocation. This ensures the plugin manages its own memory, as required by your system—your plugin manager only needs to pass the opaque pointer between functions.

4. C String Handling

The c_str_to_fortran helper converts C's null-terminated strings to Fortran allocatable strings, making it easy to work with the name field in native Fortran print statements. We avoid using C's fprintf here because Fortran's print is simpler and avoids linking complexities.

5. Compiling the Plugin

To compile this into a shared library compatible with dlopen:

gfortran -shared -fPIC -o libfalg.so f_alg.f90

This generates libfalg.so, which your existing plugin manager code can load directly with dlopen and look up symbols like "f_alg_new" or "f_alg_ini" without modifications.

内容的提问来源于stack exchange,提问作者sbinet

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.30 16:23:17