Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. Fortran and C++ Linking in Qt Creator
Forum Updated to NodeBB v4.3 + New Features

Fortran and C++ Linking in Qt Creator

Scheduled Pinned Locked Moved Solved General and Desktop
5 Posts 4 Posters 673 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • M Offline
    M Offline
    mwillis72
    wrote on 29 Jan 2024, 17:29 last edited by
    #1

    Hello,

    I am totally new to Qt and C++. I have engineering experience with Fortran, so please be easy on me. I am using Qt 6.6.1 with MinGW 11.2.0 64 bit.

    Using this link as a go-by, I created the sum.f90 file, created the fortranlink.h header file, and included the header file in the main.cpp as follows:

    ! sum.f90
    integer function addup (b, c)
    implicit none
      integer b, c
    addup = b + c
      return
    end
    
    // fortranlink.h
    extern "C"
    {
    extern int addup_(int*,int*);
    }
    
    // main.cpp
    #include "mainwindow.h"
    #include "fortranlink.h"
    #include <QApplication>
    
    int main(int argc, char *argv[])
    {
        QApplication a(argc, argv);
        int b=2;
        int c=3;
        int result=addup_(&b, &c);
        return result;
        MainWindow w;
        w.show();
        return a.exec();
    }
    

    I added LIBS +=-lgfortran to the current configuration in the cmake build settings.
    5abd31d0-89e3-4cef-b4fe-d88d1977ae3c-image.png

    I receive the following errors upon running. c6137fd1-9485-44a7-ac6d-ce4c8a4f839a-image.png

    What am I doing wrong!?

    Thank you!

    J J 2 Replies Last reply 29 Jan 2024, 18:18
    0
    • M mwillis72
      29 Jan 2024, 17:29

      Hello,

      I am totally new to Qt and C++. I have engineering experience with Fortran, so please be easy on me. I am using Qt 6.6.1 with MinGW 11.2.0 64 bit.

      Using this link as a go-by, I created the sum.f90 file, created the fortranlink.h header file, and included the header file in the main.cpp as follows:

      ! sum.f90
      integer function addup (b, c)
      implicit none
        integer b, c
      addup = b + c
        return
      end
      
      // fortranlink.h
      extern "C"
      {
      extern int addup_(int*,int*);
      }
      
      // main.cpp
      #include "mainwindow.h"
      #include "fortranlink.h"
      #include <QApplication>
      
      int main(int argc, char *argv[])
      {
          QApplication a(argc, argv);
          int b=2;
          int c=3;
          int result=addup_(&b, &c);
          return result;
          MainWindow w;
          w.show();
          return a.exec();
      }
      

      I added LIBS +=-lgfortran to the current configuration in the cmake build settings.
      5abd31d0-89e3-4cef-b4fe-d88d1977ae3c-image.png

      I receive the following errors upon running. c6137fd1-9485-44a7-ac6d-ce4c8a4f839a-image.png

      What am I doing wrong!?

      Thank you!

      J Offline
      J Offline
      JonB
      wrote on 29 Jan 2024, 18:18 last edited by JonB
      #2

      @mwillis72
      If you do not get a better answer....

      The messages you get would appear if it is not linking with some sum.o or fortranlink.o file which presumably is supposed to be generated by running fortran compiler on sum.f90 to produce it. [Btw those instructions also reference forsum.f90, I'm not sure what the file names should be.]

      I know little about Fortran, Qt6 or cmake. But those instructions were from 10 years ago and would have used qmake. I read that you can still use qmake with Qt6 projects, what about trying that to see whether it still works that way?

      M 1 Reply Last reply 29 Jan 2024, 23:32
      1
      • M mwillis72
        29 Jan 2024, 17:29

        Hello,

        I am totally new to Qt and C++. I have engineering experience with Fortran, so please be easy on me. I am using Qt 6.6.1 with MinGW 11.2.0 64 bit.

        Using this link as a go-by, I created the sum.f90 file, created the fortranlink.h header file, and included the header file in the main.cpp as follows:

        ! sum.f90
        integer function addup (b, c)
        implicit none
          integer b, c
        addup = b + c
          return
        end
        
        // fortranlink.h
        extern "C"
        {
        extern int addup_(int*,int*);
        }
        
        // main.cpp
        #include "mainwindow.h"
        #include "fortranlink.h"
        #include <QApplication>
        
        int main(int argc, char *argv[])
        {
            QApplication a(argc, argv);
            int b=2;
            int c=3;
            int result=addup_(&b, &c);
            return result;
            MainWindow w;
            w.show();
            return a.exec();
        }
        

        I added LIBS +=-lgfortran to the current configuration in the cmake build settings.
        5abd31d0-89e3-4cef-b4fe-d88d1977ae3c-image.png

        I receive the following errors upon running. c6137fd1-9485-44a7-ac6d-ce4c8a4f839a-image.png

        What am I doing wrong!?

        Thank you!

        J Offline
        J Offline
        JoeCFD
        wrote on 29 Jan 2024, 19:01 last edited by
        #3

        @mwillis72 I guess your fortran souce code is not built. Check here out
        https://stackoverflow.com/questions/65868506/can-not-set-the-compiler-flags-for-fortran-using-cmake

        1 Reply Last reply
        1
        • J JonB
          29 Jan 2024, 18:18

          @mwillis72
          If you do not get a better answer....

          The messages you get would appear if it is not linking with some sum.o or fortranlink.o file which presumably is supposed to be generated by running fortran compiler on sum.f90 to produce it. [Btw those instructions also reference forsum.f90, I'm not sure what the file names should be.]

          I know little about Fortran, Qt6 or cmake. But those instructions were from 10 years ago and would have used qmake. I read that you can still use qmake with Qt6 projects, what about trying that to see whether it still works that way?

          M Offline
          M Offline
          mwillis72
          wrote on 29 Jan 2024, 23:32 last edited by mwillis72
          #4

          @JonB

          Thank you, Jon!! Yes - I restarted the project with QMAKE instead. For those who need the help in the future, here are the changes I made to make this work!

          ***** Restarted the project and used QMAKE in lieu of CMAKE.****

          ***** Changed my fortranlink.h file to the C++ syntax as below:****

          #ifndef FORTRANLINK_H
          #define FORTRANLINK_H
          extern "C"
          {
          extern int addup_(int*,int*);
          }
          #endif // FORTRANLINK_H
          

          ***** Modified the .pro file to include the sum.f90 file in sources and added -lgfortran to LIBS as so (note this is the entire file not just the part I modified):****

          QT       += core gui
          
          greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
          
          CONFIG += c++17
          
          # You can make your code fail to compile if it uses deprecated APIs.
          # In order to do so, uncomment the following line.
          #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0
          
          SOURCES += \
              main.cpp \
              mainwindow.cpp \
              sum.f90
          
          HEADERS += \
              fortranlink.h \
              mainwindow.h
          
          FORMS += \
              mainwindow.ui
          
          LIBS += \
              -lgfortran
          
          
          # Default rules for deployment.
          qnx: target.path = /tmp/$${TARGET}/bin
          else: unix:!android: target.path = /opt/$${TARGET}/bin
          !isEmpty(target.path): INSTALLS += target
          

          I also found this website helpful (https://blog.joey-dumont.ca/fortran-c-and-qmake/).

          @JoeCFD, I believe those compile instructions on the link you sent are for compiling a .dll perhaps. I went ahead and bookmarked that page as well for future use. Thanks for your time!

          1 Reply Last reply
          1
          • M mwillis72 has marked this topic as solved on 29 Jan 2024, 23:47
          • S Offline
            S Offline
            SimonSchroeder
            wrote on 31 Jan 2024, 08:36 last edited by
            #5

            I'd like to add something to Fortran/C interoperability. Names of Fortran functions are different on different platforms (and you have to know the rules). Fortunately, there is a standard way to define the names in Fortran:

            ! sum.f90
            integer function addup (b, c) bind(c, name="addup")
              use iso_c_binding
              implicit none
              integer(kind=c_int), value, intent(in) :: b
              integer(kind=c_int), value, intent(in) :: c
              addup = b + c
              return
            end function addup ! I like to be more specific in this place -> sometimes catches bugs
            
            // fortranlink.h
            extern "C"
            {
            int addup(int,int);
            }
            

            The important part is use iso_c_binding which allows to add the bind(c). The name specifies the function name as it can be found by the C linker. The advantage is that now in C you can also use the name addup and it is the same on all operating systems.

            I changed a few more things that make it a little nicer in C or are just modern Fortran. Writing integer :: b is just the modern syntax (I am not sure if it is absolutely required for the other additions I did). integer*4 would also be written better as integer(kind=4). In the context of interoperability with C, I chose kind=c_int (c_int is imported from the iso_c_binding module). At least with the Intel Fortran compiler the default width of integers can be specified as compiler flag and thus does not have to be the same for Fortran and C. Therefore it is better to specify c_int. Or you could use integer(kind=4)/integer*4 in Fortran and int32_t in C/C++ to make them match explicitly. It is also now common to specify the intent of the function parameters: in (i.e. read-only), out (i.e. write-only), and inout. Since you are only reading the values, I specified value as well. Now, you are passing parameters by value instead of by reference (the technical term for the pointers in this context). In this case it makes it much easier to use in C. These are all suggestions, but they can help.

            If you want use the same functions (addup in your case) in Fortran as well, the easiest option is to introduce modules:

            module sum
              use iso_c_binding
              implicit none
            
              contains
                integer function addup (b, c) bind(c, name="addup")
                  use iso_c_binding
                  implicit none
                  integer(kind=c_int), value, intent(in) :: b
                  integer(kind=c_int), value, intent(in) :: c
                  addup = b + c
                  return
                end function addup
            end module sum
            

            To use this in other Fortran functions just add use sum (has to be place even before implicit none inside the functions/subroutines). It is a little annoying that you need dependencies to the modules which is a little cumbersome with current build systems (I don't know how qmake would handle this). For small projects it is still reasonable to add the dependencies to modules by hand. (CMake will properly solve this problem because of C++ modules. It is basically the same dependency problem.)

            We also use modules to put C functions into Fortran:

            module cpp_bridge
              use iso_c_binding
              implicit none
            
              interface
                subroutine foo(x), bind(c, name="foo")
                  integer(kind=c_int),value,intent(in) :: x
                end subroutine foo
            
                ! more subroutines/functions
              end interface
            end module cpp_bridge
            

            It is nice to have the exact same function names both in C and Fortran. In this way you can use any C function in Fortran as you can now have pass-by-value.

            PS: I showed you some modern Fortran. Don't overdo it with modern Fortran. For example, using object oriented programming in Fortran will slow things down (up to a factor of 100). In contrast to C++, Fortran does not have the zero-overhead principle (the only zero-cost is not using some modern features). You only need to learn some modern Fortran: the few features I have showed plus maybe pointers and allocatables (yes, you can allocate in modern Fortran). Haven't had a need to use any other modern Fortran features.

            1 Reply Last reply
            1

            1/5

            29 Jan 2024, 17:29

            • Login

            • Login or register to search.
            1 out of 5
            • First post
              1/5
              Last post
            0
            • Categories
            • Recent
            • Tags
            • Popular
            • Users
            • Groups
            • Search
            • Get Qt Extensions
            • Unsolved