Fortran and C++ Linking in Qt Creator
-
wrote on 29 Jan 2024, 17:29 last edited by
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.
I receive the following errors upon running.
What am I doing wrong!?
Thank you!
-
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.
I receive the following errors upon running.
What am I doing wrong!?
Thank you!
wrote on 29 Jan 2024, 18:18 last edited by JonB@mwillis72
If you do not get a better answer....The messages you get would appear if it is not linking with some
sum.o
orfortranlink.o
file which presumably is supposed to be generated by running fortran compiler onsum.f90
to produce it. [Btw those instructions also referenceforsum.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?
-
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.
I receive the following errors upon running.
What am I doing wrong!?
Thank you!
wrote on 29 Jan 2024, 19:01 last edited by@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 -
@mwillis72
If you do not get a better answer....The messages you get would appear if it is not linking with some
sum.o
orfortranlink.o
file which presumably is supposed to be generated by running fortran compiler onsum.f90
to produce it. [Btw those instructions also referenceforsum.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?
wrote on 29 Jan 2024, 23:32 last edited by mwillis72Thank 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!
-
-
wrote on 31 Jan 2024, 08:36 last edited by
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 thebind(c)
. Thename
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 nameaddup
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 asinteger(kind=4)
. In the context of interoperability with C, I chosekind=c_int
(c_int
is imported from theiso_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 specifyc_int
. Or you could useinteger(kind=4)
/integer*4
in Fortran andint32_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), andinout
. Since you are only reading the values, I specifiedvalue
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 beforeimplicit 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/5