How to run a Fortran program within GNU Octave?

岁酱吖の 提交于 2021-02-05 07:45:12

问题


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?


回答1:


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.



来源:https://stackoverflow.com/questions/62702342/how-to-run-a-fortran-program-within-gnu-octave

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!