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.
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.
My end goal is to call some C++ functions from within R, here is a MNWE of where I'm hitting a roadblock. If I'm reading the room correctly, I seem to get a segfault when I call my function with .Call but when I call it with .C everything works fine.
Here is my short C++ function
// test.cpp
#include <iostream>
extern "C" void fnTest() {
std::cout << "Hello" << std::endl;
}
Which I then compiled with
R CMD SHLIB -o test.so test.cpp
Which gave the following output:
g++ -std=gnu++11 -shared -L/usr/lib64/R/lib -Wl,-O1,--sort-common,--as-needed,-z,relro,-z,now -o te
st.so test.o -L/usr/lib64/R/lib -lR
Now within R I did
> dyn.load("test.so")
> .C("fnTest")
Hello
list()
> .Call("fnTest")
Hello
*** caught segfault ***
address 0x30, cause 'memory not mapped'
Possible actions:
1: abort (with core dump, if enabled)
2: normal R exit
3: exit R without saving workspace
4: exit R saving workspace
Selection:
The documentation that I read for these two functions is here and didn't seem to indicate much of a difference in the calling format of the two functions.
I tried several other variations (e.g. I was was able to pass arguments successfully to .C but not .Call) and didn't have any success.
What is the proper way to .Call a C++ function from within R?
Some notes on my eventual use case beyond this minimal example, hopefully this is not an XY problem:
I have a project with many complicated dependencies which I know how to build with CMake but not directly from g++. I was able to build a shared library from this project that I could then link into an "R compatible" shared library (R CMD SHLIB -o test.so test.cpp -L/path/to/my/lib/ -l my_lib_name) which I was able to dyn.load() into my R environment. At that point I then ran into the above .C vs. .Call issue.
From reading some additional documentation (that I should have found on the first pass), I believe that you cannot .Call a function that has a return type of void.
I could not find an explicit mention of this, but no example in the documentation (e.g. this section) listed a return type other than SEXP and at one point the documentation states that:
All the R objects you will deal with will be handled with the type SEXP
On the other hand, as documented in the Interface functions .C and .Fortran section, any function that you .C must have a return type of void:
Note that the compiled code should not return anything except through its arguments: C functions should be of type void and Fortran subprograms should be subroutines.
Here are some examples that can be compiled as in the OP. It didn't seem like there was a default "null" return type for .Call'ed functions, but allocVector(REALSXP, 0) R_NilValue seemed to work well.
// test.cpp
#include <R.h>
#include <Rinternals.h>
extern "C" void fnPrintC() {
Rprintf("Hello world!\n");
}
extern "C" SEXP fnPrintCall() {
Rprintf("Hello world!\n");
// return allocVector(REALSXP, 0);
return R_NilValue;
}
extern "C" SEXP fnAddCall(SEXP a, SEXP b) {
double* xa = REAL(a);
double* xb = REAL(b);
SEXP ans = allocVector(REALSXP, 2);
REAL(ans)[0] = *xa + *xb;
REAL(ans)[1] = *xa - *xb;
return ans;
}
Here they are called from R. Note we can send the (void) output to the dummy variable x if we don't want to see it.
> dyn.load("test.so")
> x <- .C("fnPrintC")
> Hello world!
> x <- .Call("fnPrintCall")
> Hello world!
> .Call("fnAddCall", 4, 3)
> [1] 7 1
In general, the documentation linked above was pretty helpful, I recommend starting there for anyone with a similar question, I certainly wish I'd read it more thoroughly earlier on.
I'm trying to build a write of software with the Tensor module provided as unsupported from eigen3. I've written a simple piece of code that will build with a simple application of VectorXd (just printing it to stdout), and will also build with an analogous application of Tensor in place of the VectorXd, but WILL NOT build when I do not throw an optimization flag (-On). Note that my build is from within a conda enviromnent that is using conda-forge compilers, so the g++ in what follows is the g++ obtained from conda forge for ubuntu. It says its name in the error messages following, if that is perceived to be the issue.
I have a feeling this is not about the program I'm trying to write, but just in case I've included an mwe.cpp that seems to produce the error. The code follows:
#include <eigen3/Eigen/Dense>
#include <eigen3/unsupported/Eigen/CXX11/Tensor>
#include <iostream>
using namespace Eigen;
using namespace std;
int main(int argc, char const *argv[])
{
VectorXd v(6);
v << 1, 2, 3, 4, 5, 6;
cout << v.cwiseSqrt() << "\n";
Tensor<double, 1> t(6);
for (auto i=0; i<v.size(); i++){
t(i) = v(i);
}
cout << "\n";
for (auto i=0; i<t.size(); i++){
cout << t(i) << " ";
}
cout << "\n";
return 0;
}
If the above code is compiled without any optimizations, like:
g++ -I ~/miniconda3/envs/myenv/include/ mwe.cpp -o mwe
I get the following compiler error:
/home/myname/miniconda3/envs/myenv/bin/../lib/gcc/x86_64-conda_cos6-linux-gnu/7.3.0/../../../../x86_64-conda_cos6-linux-gnu/bin/ld: /tmp/cc2q8gj4.o: in function `Eigen::internal::(anonymous namespace)::get_random_seed()':
mwe.cpp:(.text+0x15): undefined reference to `clock_gettime'
collect2: error: ld returned 1 exit status
If instead I ask for 'n' optimization level, like the following:
g++ -I ~/miniconda3/envs/loos/include/ -On mwe.cpp -o mwe
The program builds without complaint and I get expected output:
$ ./mwe
1
1.41421
1.73205
2
2.23607
2.44949
1 2 3 4 5 6
I have no clue why this little program, or the real program I'm trying to write, would be trying to get a random seed for anything. Any advice would be appreciated. The reason why I would like to build without optimization is so that debugging is easier. I actually thought all this was being caused by debug flags, but I realized that my build tool's debug setting didn't ask for optimization and narrowed that down to the apparent cause. If I throw -g -O1 I do not see the error.
Obviously, if one were to comment out all the code that has to do with the Tensor module, that is everthing in main above 'return' and below the cwiseSqrt() line, and also the include statement, the code builds and produces expected output.
Technically, this is a linker error (g++ calls the compiler as well as the linker, depending on the command line arguments). And you get linker-errors if an externally defined function is called from somewhere, even if the code is never reached.
When compiling with optimizations enabled, g++ will optimize away uncalled functions (outside the global namespace), thus you get no linker errors. You may want to try -Og instead of -O1 for better debugging experience.
The following code should produce similar behavior:
int foo(); // externally defined
namespace { // anonymous namespace
// defined inside this module, but never called
int bar() {
return foo();
}
}
int main() {
// if you un-comment this line, the
// optimized version will fail as well:
// ::bar();
}
According to man clock_gettime you need to link with -lrt if your glibc version is older than 2.17 -- maybe that is the case for your setup:
g++ -I ~/miniconda3/envs/myenv/include/ mwe.cpp -o mwe -lrt
I'm trying to wrap a c++ function called i_receive() by following this tutorial, I first created a wrap.c file, the content of this file is like this:
int i_receive(const uint32_t *f, int32_t t){
static int (*real_i_receive)(const uint32_t *, int32_t)=NULL;
printf("hello world");
return real_i_receive;
}
I compiled this file with gcc -fPIC -shared -o wrap.so wrap.c -ldl, when I used the LD_PRELOAD to run some C++ code with LD_PRELOAD=/full/path/to/wrap.so ./mycppcode I got this message:
ERROR: ld.so: object '/full/path/to/wrap.so' from LD_PRELOAD cannot be preloaded: ignored`.
I was guessing the reason might be that the wrap file is a C file, and I'm using it with C++ code, am I right?
I changed the file to wrap.cc with the same content, when compiling in the same way as before, I got:
ERROR: invalid conversion from 'int (*)(const uint32_t*, int32_t)' to 'int'
First of all, your 2nd error your are getting becase you are returning a Pointer to function type instead of a int type.
If you want to return an int, call the function from the code :
return real_i_receive(f,t);
Notice the "()" which means a function call.
Regarding your guess : it doesn't matter if you are using C or C++ code, the libaries are all assembly code.
One difference between exporting C functions and C++ functions is the name mangling. You would rather export a function as a C function to be able to access it inside your library through unmagled name.
To export a function without name mangling it, you can use extern "C" .
Replace
return real_i_receive;
with
return real_i_receive(f, t);
As it is, the return type of your function is int but you're returning a function pointer.
I'trying to compile the c code with mex for MATLAB 2013a 64 under win7 64
http://www.cs.cornell.edu/People/tj/svm%5Flight/svm_perf.html
According to info from this site the SVMPerf MATLAB interface was done by O Luaces
but only for Linux and MACos and it don't compile under windows
http://www.aic.uniovi.es/~oluaces/Oscars_Home_Page/Personal.html
for this i installed gnumex to have access to gcc for MATLAB and this is ok.
then I compiled with mex and created object files for all involved c programs according
to make file from SVMPerf.
I also compiled mex_interface.cpp file which was used for MATLAB interface under LINUX.
However when I try to link all files I'm getting following error related to my_malloc
svm_learn_main.obj:svm_learn_main.c:(.text+0x470): first defined here
svm_struct_main.obj:svm_struct_main.c:(.text.startup+0x0): multiple definition of
`main'
svm_learn_main.obj:svm_learn_main.c:(.text.startup+0x0): first defined here
Cannot export mexFunction: symbol not defined
mex_interface.obj:mex_interface.cpp:(.text+0x94): undefined reference to
`my_malloc(unsigned long long)'
mex_interface.obj:mex_interface.cpp:(.text+0x218): undefined reference to
`my_malloc(unsigned long long)'
C:/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/4.9.0/../../../../x86_64-w64-mingw32
/bin/ld.exe: mex_interface.obj: bad reloc address 0x0 in section `.pdata'
collect2.exe: error: ld returned 1 exit status
link command: gcc -shared C:\Users\KRZYSZ~1\AppData\Roaming\MATHWO~1\MATLAB\R2013a
\gnumex\mex.def -o svm_perf_classify.mexw64 -LC:\Users\KRZYSZ~1\AppData\Roaming
\MATHWO~1\MATLAB\R2013a\gnumex -s mex_interface.obj my_malloc.obj svm_learn_main.obj
svm_learn.obj svm_common.obj svm_hideo.obj svm_struct_learn.obj
svm_struct_classify.obj svm_struct_common.obj svm_struct_main.obj svm_struct_api.obj
svm_struct_classify.obj svm_struct_common.obj svm_struct_main.obj -llibmx -llibmex
-llibmat
I believe it points to this code. my_malloc compiles OK. Any idea ??
void create_argc_argv(const mxArray *options,int *argc,char **argv[]) {
// convert the matlab string of options into a CLI-like input (argc and argv)
*argc=1;
mwSize buflen = mxGetN(options)*sizeof(mxChar)+1;
char *buf = mxMalloc(buflen);
// Copy the string data into buf
mxGetString(options, buf, buflen);
// and separate in argv[]
char **ap, **argv_ptr=(char **)my_malloc(MAX_ARGVS*sizeof(char *));
argv_ptr[0]="OLR";
for (ap = (argv_ptr+1); (*ap = strsep(&buf, " \t")) != NULL;)
if (**ap != '\0') {
(*argc)++;
if (++ap >= &argv_ptr[MAX_ARGVS])
break;
}
// 'buf' shouldn't be freed, since it is converted to the different 'argv[i]'
// by setting to '\0' the tabs and white spaces between options
// (this trick was taken from the 'strsep' man page)
// so, we don't make mxFree(buf);
*argv=argv_ptr;
}
my mex command looks like this
mex -largeArrayDims -DWIN -output svm_perf_classify mex_interface.cpp
svm_learn_main.obj svm_learn.obj svm_common.obj svm_hideo.obj svm_struct_learn.obj
svm_struct_classify.obj svm_struct_common.obj svm_struct_main.obj svm_struct_api.obj
svm_struct_classify.obj svm_struct_common.obj svm_struct_main.obj
It looks like the issue you have isn't MEX related, as the main function is declared more than once. Which makes it hard for the compiler to know where to start running the code. If you have public functions you want to use in svm_learn_main or svm_struct_main, you'll want to separate those from the files containing the main function.
mex -largeArrayDims -DWIN -output svm_perf_classify mex_interface.cpp
svm_perf_classify does not have a source file extension(.c or .cpp or other), so it's considered a executable by compiler.