I can't seem to figure out why this isn't working.
/* main.cpp */
#include <stdio.h>
extern "C"
{
int __stdcall inhalf(int *);
}
int main()
{
int toHalf = 2;
int halved = inhalf(&toHalf);
printf("Half of 2 is %d", halved);
return 0;
}
Ok, that looks good.
$ g++ -c main.cpp
No errors.
! functions.f90
function inhalf(i) result(j)
integer, intent(in) :: i
integer :: j
j = i/2
end function inhalf
I'm pretty sure that's right.
$ gfortran -c functions.f90
So far so good...
$ gcc -o testo main.o functions.o
main.o:main.cpp:(.text+0x24): undefined reference to `inhalf#4'
collect2.exe: error: ld returned 1 exit status
I've been looking this up for over an hour, but I couldn't find anything that worked for this case. How should I solve this?
For full C compatibility you can use the bind feature of modern Fortran:
! functions.f90
function inhalf(i) result(j) bind(C,name='inhalf')
integer, intent(in) :: i
integer :: j
j = i/2
end function inhalf
This allows you to give a name to the function that you can use in C (and others) without relying on the naming scheme your compiler uses on its own.
The __stdcall is Win32 only (and the default behavior for linking, see here). You can safely remove it. [Actually it is required for compiling your code in Linux. ]
Related
One colleague did send me a Fortran function to include in my C++ program.
So far, everything in my program is coded in C++.
To keep things simple (especially dependencies and installation) I thought I'll just re-code it in C++.
Unfortunately, the code is very complex with many goto statements and other stuff I'm not very familiar with. (I have never worked with Fortran and this is from an old scientific Fortran 77 program)
Thus, I would like to call the Fortran function directly in C++.
A prerequisite is, that I'm using CMake for my program and everything (like linking) has to be done in the CMake file. Additionally, the CMake file should be as simple as possible since only scientists work and extend the program with no sophisticated programming background.
I found many approaches and solutions on the internet - however, most are very complex dealing with modules and libraries - I only need to call one function, we are not working with libraries or such.
Unfortunately, I get a lot of errors when executing my code:
c:/mingw/bin/../lib/gcc/x86_64-w64-mingw32/9.2.0/../../../../x86_64-w64-mingw32/bin/ld.exe:
skipping incompatible C:/MinGW/lib/gcc/mingw32/6.3.0/libgfortran.dll.a
when searching for -lgfortran
c:/mingw/bin/../lib/gcc/x86_64-w64-mingw32/9.2.0/../../../../x86_64-w64-mingw32/bin/ld.exe:
skipping incompatible C:/MinGW/lib/gcc/mingw32/6.3.0/libgfortran.a
when searching for -lgfortran
c:/mingw/bin/../lib/gcc/x86_64-w64-mingw32/9.2.0/../../../../x86_64-w64-mingw32/bin/ld.exe:
skipping incompatible C:/MinGW/lib/gcc/mingw32/6.3.0\libgfortran.a
when searching for -lgfortran
c:/mingw/bin/../lib/gcc/x86_64-w64-mingw32/9.2.0/../../../../x86_64-w64-mingw32/bin/ld.exe:
skipping incompatible C:/MinGW/lib/gcc/mingw32/6.3.0/libgfortran.dll.a
when searching for -lgfortran
c:/mingw/bin/../lib/gcc/x86_64-w64-mingw32/9.2.0/../../../../x86_64-w64-mingw32/bin/ld.exe:
skipping incompatible C:/MinGW/lib/gcc/mingw32/6.3.0/libgfortran.a
when searching for -lgfortran
c:/mingw/bin/../lib/gcc/x86_64-w64-mingw32/9.2.0/../../../../x86_64-w64-mingw32/bin/ld.exe:
cannot find -lgfortran
My main question is: Are these errors due to a problem in my code or are they related to a problem with my environment?
This is what my code looks like:
main.cpp
#include <iostream>
extern double f_add(double *, double *, double *);
int main() {
double a = 1.;
double b = 2.;
double c;
f_add(&a, &b, &c);
std::cout << c << std::endl;
}
f_add.f
real function f_add(a, b, c)
real a,b,c
c = a+b
end
CMakeLists.txt
cmake_minimum_required(VERSION 3.17)
project(test_cpp)
set(CMAKE_CXX_STANDARD 14)
SET (CMAKE_Fortran_COMPILER gfortran)
ENABLE_LANGUAGE(Fortran)
set(SOURCE_FILES
main.cpp
f_add.f
)
add_executable(test_cpp ${SOURCE_FILES})
I think your C++ code is missing extern "C" and some additional corrections to the Fortran code. For example, the following would work:
#include <iostream>
extern "C" {
double f_add(double, double);
}
int main() {
double a = 1.;
double b = 2.;
double c;
c = f_add(a, b);
std::cout << c << std::endl;
}
and,
function f_add(a, b) result(c) bind(C, name = "f_add")
use iso_c_binding, only: c_double
implicit none ! remove this line if your F77 code has implicitly-declared variables.
real(c_double), intent(in), value :: a, b
real(c_double) :: c
c = a + b
end function f_add
Then compile, link, and run (via MinGW GNU 10.1 that I am using),
gfortran -c f_add.f90
g++ -c main.cpp
g++ *.o -o main.exe
./main.exe
The output is,
3
I do not have CMake installed in MinGW, but setting it up should be straightforward with the above modifications. Your CMake file is fully functional in a Linux environment if that helps.
I am attempting to perform a 2D integral numerically using the quadpack double library. Since this website does not have a Latex engine integrated I attach a picture with the math.
I also attach below my implementation of this operation in the test_module module.
module test_module
use f90_kind ! defines dp
use physconst ! defines pi
use global_variables ! defines the variables for quadpack
use csv_file ! allows me to write to a csv file
implicit none
real(dp) :: a, b, c ! parameters I want to set
contains
real(dp) function multi_val_func(theta)
real(dp), intent(in) :: theta
multi_val_func = exp(theta**2 + c*theta)
end function multi_val_func
real(dp) function theta_integral(phi)
real(dp), intent(in) :: phi
c = phi*(a+b)
! Quadpack variables
epsabs = 1.0E-14_dp
epsrel = 0.0E0_dp
key = 6
ilow = 0.0E0_dp
ihigh = 2.0E0_dp*pi
call dqage(multi_val_func, ilow, ihigh, epsabs, epsrel, key, limit, &
res, abserr, neval, ier, alist, blist, rlist, elist, iord, last)
theta_integral = res
end function theta_integral
subroutine phi_integral(final_result)
real(dp),intent(out) :: final_result
a = 1.0E0_dp
b = 1.0E0_dp
! Quadpack variables
epsabs = 1.0E-14_dp
epsrel = 0.0E0_dp
key = 6
ilow = 0.0E0_dp
ihigh = pi
call dqage(theta_integral, ilow, ihigh, epsabs, epsrel, key, limit, &
res, abserr, neval, ier, alist, blist, rlist, elist, iord, last)
final_result = res
print *, final_result
end subroutine phi_integral
end module test_module
In the main file I define the result variable and thereafter call phi_integral(result). I compile this code using the following makefile
FFLAGS = -O0 -fcheck=all -ffree-line-length-none
debug:
gfortran -c $(FFLAGS) $(srcdir)/f90_kind.f90
gfortran -c $(FFLAGS) $(srcdir)/physconst.f90
gfortran -c $(FFLAGS) $(srcdir)/global_variables.f90
gfortran -c $(FFLAGS) $(extlib_qp)/quadpack_double.f90
gfortran -c $(FFLAGS) $(extlib_csv)/csv_file.f90
gfortran -c $(FFLAGS) $(srcdir)/multi_var_integration.f90
gfortran -c $(FFLAGS) $(srcdir)/main.f90
gfortran *.o -o debug -lblas -llapack
rm -f *.o *.mod
The code compiles but when I run it I receive the following error:
Fortran runtime error: Recursive call to nonrecursive procedure 'dqage'
Error termination. Backtrace:
#0 0x103a28d3d
#1 0x103a299f5
#2 0x103a29fd6
#3 0x1039f94b6
#4 0x1039dee59
#5 0x1039fad68
#6 0x1039f9948
#7 0x1039dec7d
#8 0x1039def61
#9 0x1039defa3
Any suggestion for dealing with this is greatly appreciated.
Not every subroutine or function in Fortran is re-entrant or, as Fortran calls it, "recursive". Before Fortran 2018 a subroutine that can be called, when already inside itself (even if indirectly) must be marked by the recursive attribute.
Even if a subroutine is marked that way, it may not work as expected if it contains static (saved) data or if it uses global (common blocks, module) variables.
I cannot immediately see any such static data used in http://www.netlib.no/netlib/quadpack/dqage.f so it might actually work after adding recursive.
However, as francescalus pointed out, you should be better off with a dedicated 2d quadrature library.
The theta integral can be done via the error function erf. See wolfram alpha.
The result of that is a function of one variable phi which can be evaluated via quadpack. Thus, you don't need a multidimensional integral routine after all.
I want to run a Fortran program within Octave. I would like to do this for automation purposes and use Octave for all the data processing.
Is it possible to run a Fortran program from octave using cygwin, if so, could you provide me some pointers along that direction?
Moreover, I have a gfortran compiler installed in my system, Is there a way I could make use of it to complete my task mentioned above?
Furthermore, I tried to use mex to perform the same:
mckoctfile --mex HelloWorld.f
I got the following error after trying the mex approach:
c:/octave/octave~1.0/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/9.2.0/../../../../x86_64-w64-mingw32/bin/ld.exe: C:\Users\rajan\AppData\Local\Temp/oct-qur1RF.o: in function `hi': C:\Tech Stuff\Fortran Programs/HelloWorld.f:3: undefined reference to `_gfortran_st_write'
c:/octave/octave~1.0/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/9.2.0/../../../../x86_64-w64-mingw32/bin/ld.exe: C:\Tech Stuff\Fortran Programs/HelloWorld.f:3: undefined reference to `_gfortran_transfer_character_write'
c:/octave/octave~1.0/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/9.2.0/../../../../x86_64-w64-mingw32/bin/ld.exe: C:\Tech Stuff\Fortran Programs/HelloWorld.f:3: undefined reference to `_gfortran_st_write_done'
c:/octave/octave~1.0/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/9.2.0/../../../../x86_64-w64-mingw32/bin/ld.exe: C:\Users\rajan\AppData\Local\Temp/oct-qur1RF.o: in function `main':C:\Tech Stuff\Fortran Programs/HelloWorld.f:6: undefined reference to `_gfortran_set_args'
c:/octave/octave~1.0/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/9.2.0/../../../../x86_64-w64-mingw32/bin/ld.exe: C:\Tech Stuff\Fortran Programs/HelloWorld.f:6: undefined reference to `_gfortran_set_options'
collect2.exe: error: ld returned 1 exit status
warning: mkoctfile: building exited with failure sta
How do I resolve this error to move forward?
Obviously your particular use-case may be a lot more complex than this, but here's a simple example to get you started (or to help you decide whether it's worth going down that route at all...)
Let's start with a simple octfile which performs simple integer addition, no fortran involved for now.
// in: simple_addition.cpp
#include <octave/oct.h>
DEFUN_DLD (simple_addition, args, ,"Add two integers via C++")
{
octave_value retval = args(0).int_value() + args(1).int_value();
return retval;
}
Compile:
mkoctfile -c simple_addition.cpp # compiles a simple_addition.o file
mkoctfile -o simple_addition simple_addition.o # links .o file to named output file
In octave:
octave:1> simple_addition(1,2)
ans = 3
Now let's put this aside for a minute, and see how we might call a fortran-defined function from pure c++. First let's create a simple integer addition function:
! in fortran_addition.f90
function fortran_addition(a,b) result(Out)
integer, intent(in) :: a,b ! input
integer :: Out ! output
Out = a + b
end function fortran_addition
and compile it using gfortran:
gfortran -c fortran_addition.f90 # creates fortran_addition.o
You can see (e.g. using nm fortran_addition.o) that the generated object contains a reference to a symbol under the name fortran_addition_ (note the added underscore at the end).
Now let's create a normal (i.e. non-octave-related) c++ wrapper program which calls the function defined via this symbol:
// in generic_fortran_addition_wrapper.cpp
#include <iostream>
extern "C" { int fortran_addition_( int *, int * ); }
int main() {
int a = 1, b = 2, fortran_result;
fortran_result = fortran_addition_( &a, &b );
std::cout << a << " + " << b << " = " << fortran_result << std::endl;
}
compile:
g++ -c generic_fortran_addition_wrapper.cpp
g++ -o addints generic_fortran_addition_wrapper.o fortran_addition.o
./addints # outputs `1 + 2 = 3` on the terminal
Now we have all the ingredients to create an octfile that wraps a fortran function:
// in fortran_addition_wrapper.cpp
#include <octave/oct.h>
extern "C" { int fortran_addition_( int *, int *); }
DEFUN_DLD (fortran_addition_wrapper, args, ,"Add two integers via fortran")
{
int a, b, fortran_result;
a = args(0).int_value();
b = args(1).int_value();
fortran_result = fortran_addition_( &a, &b );
octave_value retval(fortran_result);
return retval;
}
compile with mkoctfile:
mkoctfile -c fortran_addition_wrapper.cpp
mkoctfile -o fortran_addition_wrapper fortran_addition_wrapper.o fortran_addition.o
and then in octave:
octave:1> fortran_addition_wrapper(1,2)
ans = 3
Having said all this, obviously if you have a fully defined fortran program, rather than just linkable functions, and you have a running compiled executable on your system, then you can skip all the above 'formalities' and just call your executable via the system() command from octave. Obviously in this scenario it's up to you to pass the data in an octave-agnostic way ... but presumably if you have a standalone fortran executable, then presumably it already has a way of reading input data from the operating system.
EDIT as per the comments below, I've been reminded that I got side-tracked and answered the question that was asked in the comments to the original question, and forgot to address the error messages in the original question. As mentioned in my comment there, mkoctave is a generic wrapper to the gnu compiler collection. Those messages do not sound specific to octave, but rather that the compiler/linker complains that you're missing the fortran runtime libraries that define these basic functions.
I would like to develop a Fortran Static Library that include a custom subroutine that takes a long time to complete.
This static library will be linked in my C++ application statically too.
My goal is monitoring the current status of this subroutine in my C++ application in real-time.
So, for each step of a "fortran loop", I would like to send the loop index to my C++ application.
I'm new in Fortran world, so I was thinking that this task could be something like this:
My C++ header:
extern "C" void fortran_status(int* value);
My Fortran-90 file:
module my_interfaces
use iso_c_binding
interface
subroutine fortran_status(progress_value) bind(C, name = 'fortran_status')
use, intrinsic :: iso_c_binding
integer(c_int), intent(out) :: progress_value
end subroutine fortran_status
end interface
end module my_interfaces
! My long calc subroutine
subroutine my_long_calc(progress_value) BIND(C, name = 'my_long_calc')
use, intrinsic :: ISO_C_BINDING
use my_interfaces
implicit none
EXTERNAL fortran_status
integer (C_INT), INTENT(INOUT) :: progress_value
integer (C_INT) :: count
do count = 0, 5
progress_value = progress_value + 1
! Send 'progress_value' to a C++ function:
call fortran_status(progress_value)
! Wait 1 second:
call sleep(1)
end do
end subroutine my_long_calc
This Fortran code gives me a compile-time error:
error #6406: Conflicting attributes or multiple declaration of name. [FORTRAN_STATUS] C:\Users\lamar\Desktop\Lib1_interface\Lib1.f90 18
I'm using Microsoft Visual Studio 2019 with Intel Visual Fortran (Windows 10 x64).
How could I monitoring that subroutine status? Or get the fortran loop index in my C++ application?
UPDATE 1:
I removed the EXTERNAL fortran_status and now I got no errors in compile-time of my Fortran code.
Now, I would like to link this static Lib (x86) with my C++ code:
#include <iostream>
extern "C" {
void my_long_calc(void);
void fortran_status(int* value);
}
void fortran_status(int* value)
{
std::cout << "Fortran current status = " << *value << std::endl;
}
int main (void)
{
std::cout << "Monitoring Fortran subroutine..." << std::endl;
my_long_calc();
return 0;
}
I'm trying to compile and link it using MingW:
g++ -Wall -L. .\Lib2.lib -lgfortran .\main.cpp -o app.exe
And I got this linker error:
undefined reference to my_long_calc
How can I link it?
I would like to see in my terminal output:
Monitoring Fortran subroutine...
Fortran current status = 0
Fortran current status = 1
Fortran current status = 2
Fortran current status = 3
Fortran current status = 4
Fortran current status = 5
UPDATE 2
Now this changed Fortran code compiles and it work well ONLY if I'm using MingW g++ (x86).
Fortran code:
module my_interfaces
use iso_c_binding
interface
subroutine fortran_status(progress_value) bind(C, name = 'fortran_status')
use, intrinsic :: iso_c_binding
integer(c_int), intent(out) :: progress_value
end subroutine fortran_status
end interface
end module my_interfaces
! My long calc subroutine
subroutine my_long_calc() BIND(C, name = 'my_long_calc')
use, intrinsic :: ISO_C_BINDING
use my_interfaces
implicit none
integer (C_INT) :: progress_value
integer (C_INT) :: count
progress_value = 0
do count = 0, 5
progress_value = count
! Send 'progress_value' to a C++ function:
call fortran_status(progress_value)
! Wait 1 second:
call sleep(1)
end do
end subroutine my_long_calc
C++ Code:
#include <iostream>
extern "C" {
void my_long_calc(void);
void fortran_status(int* value);
}
void fortran_status(int* value)
{
std::cout << "Fortran current status = " << *value << std::endl;
}
int main (void)
{
std::cout << "Monitoring Fortran subroutine..." << std::endl;
my_long_calc();
return 0;
}
Compile c++: g++ -Wall -c .\main.cpp
Compile fortran: gfortran -c .\gfortran.f90
Link all together: g++ .\main.o .\gfortran.o -o app.exe -lgfortran
The problem now is that I need to use Visual Studio 2019 and Visual Fortran to develop my Fortran Code.
And I would like to compile all Fortran code to a single static library (*.lib) file using Visual Studio.
What I need to change to get to link the *.lib file (from Visual Fortran) using the MingW g++ command?
I was thinking to use something like this:
g++ main.cpp my_lib.lib -o app.exe
But I got this linker error:
undefined reference to my_long_calc
What I need to do?
The code in your "Update 2" is perfectly fine and works with Intel Visual Fortran and Microsoft Visual C++. See also the discussion you started in https://community.intel.com/t5/Intel-Fortran-Compiler/Interoperability-Fortran-to-C/m-p/1144147
I do not recommend mixing Intel Visual Fortran compiled objects/libraries with g++ on Windows. You can get Microsoft Visual Studio Community Edition free if you meet the rather liberal license terms. If you insist on using g++, mix it with gfortran.
I am trying to call a Fortran function from Rust but I am getting this error:
/src/timer.f:4: undefined reference to `_gfortran_cpu_time_4'
I searched through the internet but can't find any solution to this. The Fortran code is:
subroutine timer(ttime)
double precision ttime
temp = sngl(ttime)
call cpu_time(temp)
ttime = dble(temp)
return
end
And the Rust binding is:
use libc::{c_double};
extern "C" {
pub fn timer_(d: *mut c_double);
}
I don't know what I am doing wrong.
As the commenters said, you need to link to libgfortran.
Specifically, in the Rust world, you should use (or create) a *-sys package that details the appropriate linking steps and exposes the base API. Then build higher-level abstractions on top of that.
However, I didn't seem to need to do any of that:
timer.f90
subroutine timer(ttime)
double precision ttime
temp = sngl(ttime)
call cpu_time(temp)
ttime = dble(temp)
return
end
Cargo.toml
[package]
name = "woah"
version = "0.1.0"
authors = ["An Devloper <an.devloper#example.com>"]
build = "build.rs"
[dependencies]
libc = "*"
build.rs
fn main() {
println!("cargo:rustc-link-lib=dylib=timer");
println!("cargo:rustc-link-search=native=/tmp/woah");
}
src/main.rs
extern crate libc;
use libc::{c_double};
extern "C" {
pub fn timer_(d: *mut c_double);
}
fn main() {
let mut value = 0.0;
unsafe { timer_(&mut value); }
println!("The value was: {}", value);
}
And it's put together via
$ gfortran-4.2 -shared -o libtimer.dylib timer.f90
$ cargo run
The value was: 0.0037589999847114086
Which seems to indicate that this shared library either doesn't need libgfortran or it's being automatically included.
If you create a static library instead (and link to it appropriately via cargo:rustc-link-lib=dylib=timer):
$ gfortran-4.2 -c -o timer.o timer.f90
$ ar cr libtimer.a *.o
$ cargo run
note: Undefined symbols for architecture x86_64:
"__gfortran_cpu_time_4", referenced from:
_timer_ in libtimer.a(timer.o)
In this case, adding gfortran allows the code to compile:
println!("cargo:rustc-link-lib=dylib=gfortran");
Disclaimer: I've never compiled Fortran before, so it's very likely I've done something silly.