Skip to content

Instantly share code, notes, and snippets.

@Luthaf
Last active January 6, 2025 17:17
Show Gist options
  • Save Luthaf/4df78ca52b3caf7fbe0e to your computer and use it in GitHub Desktop.
Save Luthaf/4df78ca52b3caf7fbe0e to your computer and use it in GitHub Desktop.

Revisions

  1. Luthaf revised this gist Sep 23, 2016. 1 changed file with 4 additions and 1 deletion.
    5 changes: 4 additions & 1 deletion foo_mod.f90
    Original file line number Diff line number Diff line change
    @@ -13,8 +13,11 @@ module libfoo
    type(c_ptr) :: ptr ! pointer to the Foo class
    contains
    ! We can bind some functions to this type, allowing for a cleaner syntax.
    final :: delete_foo ! Destructor
    #ifdef __GNUC__
    procedure :: delete => delete_foo_polymorph ! Destructor for gfortran
    #else
    final :: delete_foo ! Destructor
    #endif
    ! Function member
    procedure :: bar => foo_bar
    procedure :: baz => foo_baz
  2. Luthaf revised this gist Mar 15, 2015. 7 changed files with 45 additions and 6 deletions.
    7 changes: 5 additions & 2 deletions Foo.cpp
    Original file line number Diff line number Diff line change
    @@ -12,11 +12,14 @@ Foo::~Foo(){
    }

    int Foo::bar(int c) const{
    cout << "C++ side, calling Foo::bar" << endl;
    return a + c;
    }

    double Foo::baz(double d) const{
    cout << "C++ side, calling Foo::bar" << endl;
    return d + b;
    }

    void foo_speaker(string s){
    Foo f(4, 2);
    cout << s << " Foo(4, 2).bar(3) is: " << f.bar(3) << endl;
    }
    4 changes: 4 additions & 0 deletions Foo.hpp
    Original file line number Diff line number Diff line change
    @@ -1,3 +1,5 @@
    #include <string>

    class Foo {
    public:
    Foo(int a, int b);
    @@ -9,3 +11,5 @@ class Foo {
    int a;
    int b;
    };

    void foo_speaker(std::string s);
    2 changes: 2 additions & 0 deletions foo.h
    Original file line number Diff line number Diff line change
    @@ -18,6 +18,8 @@ void delete_foo(FOO* foo);
    int foo_bar(const FOO* foo, int c);
    double foo_baz(const FOO* foo, double d);

    void foo_speaker(const char* s);

    #ifdef __cplusplus
    }
    #endif
    6 changes: 4 additions & 2 deletions foo_capi.cpp
    Original file line number Diff line number Diff line change
    @@ -15,11 +15,13 @@ void delete_foo(FOO* foo){
    }

    int foo_bar(const FOO* foo, int c){
    cout << "C API, foo_bar" << endl;
    return foo->bar(c);
    }

    double foo_baz(const FOO* foo, double d){
    cout << "C API, foo_baz" << endl;
    return foo->baz(d);
    }

    void foo_speaker(const char* s) {
    foo_speaker(string(s));
    }
    7 changes: 7 additions & 0 deletions foo_cdef.f90
    Original file line number Diff line number Diff line change
    @@ -30,4 +30,11 @@ function foo_baz_c(foo, c) bind(C, name="foo_baz")
    type(c_ptr), intent(in), value :: foo
    real(c_double), value :: c
    end function

    ! void functions maps to subroutines
    subroutine foo_speaker_c(str) bind(C, name="foo_speaker")
    use iso_c_binding
    implicit none
    character(len=1, kind=C_CHAR), intent(in) :: str(*)
    end subroutine
    end interface
    18 changes: 17 additions & 1 deletion foo_mod.f90
    Original file line number Diff line number Diff line change
    @@ -2,7 +2,7 @@ module libfoo
    use iso_c_binding

    private
    public :: foo
    public :: foo, foo_speaker

    ! Yes, include is a keyword in Fortran !
    include "foo_cdef.f90"
    @@ -59,4 +59,20 @@ double precision function foo_baz(this, c)
    double precision, intent(in) :: c
    foo_baz = foo_baz_c(this%ptr, c)
    end function

    subroutine foo_speaker(str)
    implicit none
    character(len=*), intent(in) :: str
    character(len=1, kind=C_CHAR) :: c_str(len_trim(str) + 1)
    integer :: N, i

    ! Converting Fortran string to C string
    N = len_trim(str)
    do i = 1, N
    c_str(i) = str(i:i)
    end do
    c_str(N + 1) = C_NULL_CHAR

    call foo_speaker_c(c_str)
    end subroutine
    end module
    7 changes: 6 additions & 1 deletion test.f90
    Original file line number Diff line number Diff line change
    @@ -3,13 +3,18 @@ program test
    implicit none
    type(foo) :: f

    ! Create an object of type foo
    f = foo(3, 4)

    ! Call bound procedures (member functions)
    write(*,*) f%bar(60), " should be ", 63
    write(*,*) f%baz(10d0), " should be ", 14.0d0

    call foo_speaker("From Fortran!")

    ! The destructor should be called automatically here, but this is not yet
    ! implemented in gfortran. So let's do it manually.
    #ifdef __GNUC__
    ! Only needed for gfortran
    call f%delete
    #endif
    end program
  3. Luthaf revised this gist Mar 14, 2015. 2 changed files with 9 additions and 1 deletion.
    8 changes: 7 additions & 1 deletion Makefile
    Original file line number Diff line number Diff line change
    @@ -1,9 +1,15 @@
    FC = gfortran
    CXX = g++

    UNAME := $(shell uname -s)

    FCFLAGS = -Wall -Wextra
    CCFLAGS = -Wall -Wextra
    LDFLAGS = -lstdc++ # use -lc++ on OS X
    ifeq ($(UNAME_S),Darwin)
    LDFLAGS = -lstdc++
    else
    LDFLAGS = -lc++
    endif

    all: test.x
    test.o : foo_mod.o
    2 changes: 2 additions & 0 deletions test.f90
    Original file line number Diff line number Diff line change
    @@ -8,6 +8,8 @@ program test
    write(*,*) f%bar(60), " should be ", 63
    write(*,*) f%baz(10d0), " should be ", 14.0d0

    #ifdef __GNUC__
    ! Only needed for gfortran
    call f%delete
    #endif
    end program
  4. Luthaf revised this gist Mar 14, 2015. 6 changed files with 30 additions and 24 deletions.
    4 changes: 2 additions & 2 deletions Foo.cpp
    Original file line number Diff line number Diff line change
    @@ -11,12 +11,12 @@ Foo::~Foo(){
    cout << "C++ side, destructor" << endl;
    }

    int Foo::bar(int c){
    int Foo::bar(int c) const{
    cout << "C++ side, calling Foo::bar" << endl;
    return a + c;
    }

    double Foo::baz(double d){
    double Foo::baz(double d) const{
    cout << "C++ side, calling Foo::bar" << endl;
    return d + b;
    }
    6 changes: 3 additions & 3 deletions Foo.hpp
    Original file line number Diff line number Diff line change
    @@ -3,9 +3,9 @@ class Foo {
    Foo(int a, int b);
    ~Foo();

    int bar(int c);
    double baz(double d);
    int bar(int c) const;
    double baz(double d) const;
    private:
    int a;
    int b;
    };
    };
    14 changes: 9 additions & 5 deletions foo.h
    Original file line number Diff line number Diff line change
    @@ -1,19 +1,23 @@
    #ifdef __cplusplus
    #ifdef __cplusplus // Are we compiling this with a C++ compiler ?
    extern "C" {
    class Foo;
    typedef Foo FOO;
    #else
    // From the C side, we use an opaque pointer.
    typedef struct FOO FOO;
    #endif

    // Constructor
    FOO* create_foo(int a, int b);

    // Destructor
    void delete_foo(FOO* foo);

    int foo_bar(FOO* foo, int c);

    double foo_baz(FOO* foo, double d);
    // The const qualificators maps from the member function to pointers to the
    // class instances.
    int foo_bar(const FOO* foo, int c);
    double foo_baz(const FOO* foo, double d);

    #ifdef __cplusplus
    }
    #endif
    #endif
    4 changes: 2 additions & 2 deletions foo_capi.cpp
    Original file line number Diff line number Diff line change
    @@ -14,12 +14,12 @@ void delete_foo(FOO* foo){
    delete foo;
    }

    int foo_bar(FOO* foo, int c){
    int foo_bar(const FOO* foo, int c){
    cout << "C API, foo_bar" << endl;
    return foo->bar(c);
    }

    double foo_baz(FOO* foo, double d){
    double foo_baz(const FOO* foo, double d){
    cout << "C API, foo_baz" << endl;
    return foo->baz(d);
    }
    5 changes: 3 additions & 2 deletions foo_cdef.f90
    Original file line number Diff line number Diff line change
    @@ -18,15 +18,16 @@ function foo_bar_c(foo, c) bind(C, name="foo_bar")
    use iso_c_binding
    implicit none
    integer(c_int) :: foo_bar_c
    type(c_ptr), value :: foo
    ! The const qualification is translated into an intent(in)
    type(c_ptr), intent(in), value :: foo
    integer(c_int), value :: c
    end function

    function foo_baz_c(foo, c) bind(C, name="foo_baz")
    use iso_c_binding
    implicit none
    real(c_double) :: foo_baz_c
    type(c_ptr), value :: foo
    type(c_ptr), intent(in), value :: foo
    real(c_double), value :: c
    end function
    end interface
    21 changes: 11 additions & 10 deletions foo_mod.f90
    Original file line number Diff line number Diff line change
    @@ -4,16 +4,18 @@ module libfoo
    private
    public :: foo

    ! Yes, include is a keyword in Fortran !
    include "foo_cdef.f90"

    ! We'll use a Fortan type to represent a C++ class here, in an opaque maner
    type foo
    private
    type(c_ptr) :: ptr
    type(c_ptr) :: ptr ! pointer to the Foo class
    contains
    ! Destructor
    final :: delete_foo
    procedure :: delete => delete_foo_polymorph
    ! We can bind some functions to this type, allowing for a cleaner syntax.
    final :: delete_foo ! Destructor
    procedure :: delete => delete_foo_polymorph ! Destructor for gfortran
    ! Function member
    procedure :: bar => foo_bar
    procedure :: baz => foo_baz
    end type
    @@ -23,7 +25,7 @@ module libfoo
    procedure create_foo
    end interface

    contains
    contains ! Implementation of the functions. We just wrap the C function here.
    function create_foo(a, b)
    implicit none
    type(foo) :: create_foo
    @@ -37,23 +39,22 @@ subroutine delete_foo(this)
    call delete_foo_c(this%ptr)
    end subroutine

    ! Bounds procedure needs to take a polymorphic (class) argument
    subroutine delete_foo_polymorph(this)
    implicit none
    class(foo) :: this
    call delete_foo_c(this%ptr)
    end subroutine

    function foo_bar(this, c)
    integer function foo_bar(this, c)
    implicit none
    integer :: foo_bar
    class(foo), intent(in) :: this
    integer, intent(in) :: c ! intent(in) si const coté C
    integer, intent(in) :: c
    foo_bar = foo_bar_c(this%ptr, c)
    end function

    function foo_baz(this, c)
    double precision function foo_baz(this, c)
    implicit none
    double precision :: foo_baz
    class(foo), intent(in) :: this
    double precision, intent(in) :: c
    foo_baz = foo_baz_c(this%ptr, c)
  5. Luthaf revised this gist Mar 13, 2015. 7 changed files with 184 additions and 0 deletions.
    11 changes: 11 additions & 0 deletions Foo.hpp
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,11 @@
    class Foo {
    public:
    Foo(int a, int b);
    ~Foo();

    int bar(int c);
    double baz(double d);
    private:
    int a;
    int b;
    };
    23 changes: 23 additions & 0 deletions Makefile
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,23 @@
    FC = gfortran
    CXX = g++

    FCFLAGS = -Wall -Wextra
    CCFLAGS = -Wall -Wextra
    LDFLAGS = -lstdc++ # use -lc++ on OS X

    all: test.x
    test.o : foo_mod.o

    %.x : %.o foo_mod.o foo_capi.o Foo.o
    ${FC} $^ -o $@ ${LDFLAGS}

    %.o : %.f90
    ${FC} ${FCFLAGS} -c $< -o $@

    %.o : %.cpp
    ${CXX} ${CCFLAGS} -c $^ -o $@

    .PHONY : clean

    clean :
    ${RM} -rf *.o *.mod test.x
    19 changes: 19 additions & 0 deletions foo.h
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,19 @@
    #ifdef __cplusplus
    extern "C" {
    class Foo;
    typedef Foo FOO;
    #else
    typedef struct FOO FOO;
    #endif

    FOO* create_foo(int a, int b);

    void delete_foo(FOO* foo);

    int foo_bar(FOO* foo, int c);

    double foo_baz(FOO* foo, double d);

    #ifdef __cplusplus
    }
    #endif
    25 changes: 25 additions & 0 deletions foo_capi.cpp
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,25 @@
    #include "foo.h"
    #include "Foo.hpp"

    #include <iostream>
    using namespace std;

    FOO* create_foo(int a, int b){
    cout << "C API, create_foo" << endl;
    return new Foo(a, b);
    }

    void delete_foo(FOO* foo){
    cout << "C API, delete_foo" << endl;
    delete foo;
    }

    int foo_bar(FOO* foo, int c){
    cout << "C API, foo_bar" << endl;
    return foo->bar(c);
    }

    double foo_baz(FOO* foo, double d){
    cout << "C API, foo_baz" << endl;
    return foo->baz(d);
    }
    32 changes: 32 additions & 0 deletions foo_cdef.f90
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,32 @@
    ! C functions declaration
    interface
    function create_foo_c(a, b) bind(C, name="create_foo")
    use iso_c_binding
    implicit none
    type(c_ptr) :: create_foo_c
    integer(c_int), value :: a
    integer(c_int), value :: b
    end function

    subroutine delete_foo_c(foo) bind(C, name="delete_foo")
    use iso_c_binding
    implicit none
    type(c_ptr), value :: foo
    end subroutine

    function foo_bar_c(foo, c) bind(C, name="foo_bar")
    use iso_c_binding
    implicit none
    integer(c_int) :: foo_bar_c
    type(c_ptr), value :: foo
    integer(c_int), value :: c
    end function

    function foo_baz_c(foo, c) bind(C, name="foo_baz")
    use iso_c_binding
    implicit none
    real(c_double) :: foo_baz_c
    type(c_ptr), value :: foo
    real(c_double), value :: c
    end function
    end interface
    61 changes: 61 additions & 0 deletions foo_mod.f90
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,61 @@
    module libfoo
    use iso_c_binding

    private
    public :: foo

    include "foo_cdef.f90"

    ! We'll use a Fortan type to represent a C++ class here, in an opaque maner
    type foo
    private
    type(c_ptr) :: ptr
    contains
    ! Destructor
    final :: delete_foo
    procedure :: delete => delete_foo_polymorph
    procedure :: bar => foo_bar
    procedure :: baz => foo_baz
    end type

    ! This function will act as the constructor for foo type
    interface foo
    procedure create_foo
    end interface

    contains
    function create_foo(a, b)
    implicit none
    type(foo) :: create_foo
    integer, intent(in) :: a, b
    create_foo%ptr = create_foo_c(a, b)
    end function

    subroutine delete_foo(this)
    implicit none
    type(foo) :: this
    call delete_foo_c(this%ptr)
    end subroutine

    subroutine delete_foo_polymorph(this)
    implicit none
    class(foo) :: this
    call delete_foo_c(this%ptr)
    end subroutine

    function foo_bar(this, c)
    implicit none
    integer :: foo_bar
    class(foo), intent(in) :: this
    integer, intent(in) :: c ! intent(in) si const coté C
    foo_bar = foo_bar_c(this%ptr, c)
    end function

    function foo_baz(this, c)
    implicit none
    double precision :: foo_baz
    class(foo), intent(in) :: this
    double precision, intent(in) :: c
    foo_baz = foo_baz_c(this%ptr, c)
    end function
    end module
    13 changes: 13 additions & 0 deletions test.f90
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,13 @@
    program test
    use libfoo
    implicit none
    type(foo) :: f

    f = foo(3, 4)

    write(*,*) f%bar(60), " should be ", 63
    write(*,*) f%baz(10d0), " should be ", 14.0d0

    ! Only needed for gfortran
    call f%delete
    end program
  6. Luthaf created this gist Mar 13, 2015.
    22 changes: 22 additions & 0 deletions Foo.cpp
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,22 @@
    #include "Foo.hpp"
    #include <iostream>
    using namespace std;


    Foo::Foo(int _a, int _b): a(_a), b(_b){
    cout << "C++ side, constructor" << endl;
    }

    Foo::~Foo(){
    cout << "C++ side, destructor" << endl;
    }

    int Foo::bar(int c){
    cout << "C++ side, calling Foo::bar" << endl;
    return a + c;
    }

    double Foo::baz(double d){
    cout << "C++ side, calling Foo::bar" << endl;
    return d + b;
    }