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.
Related
I have the program which needs v2xmvtest.so. When i try to build it via make i get undefined reference to *
Seems like that function from libssl1.0. (If i install it, it's built fine)
But i do not see the place where these function are used. More than that, when i try ldd v2xmvtest.so it does show only libvssl1.1 dependency.
Summary:
Is there a way to find out where those finctions from libvssl1.0 are used in the program ? (i have source code of the v2xmvtest.so and try to search, but there no any of these)
I need a description why ldd does not show me libssl1.0 dependency, but during linkning it's needed
Thank you!
Libraries are not required to fully define used symbols. For instance you can have lib.cpp:
int foo();
int bar(int x)
{
return x + foo();
}
and it compiles even foo is actually not defined yet:
g++ lib.cpp -shared -o lib.so
Then you can have main.cpp:
#include <iostream>
int bar(int);
int foo()
{
return 10;
}
int main()
{
std::cout << bar(42) << std::endl;
}
which defines foo and compiles successfully with lib.so:
g++ main.cpp lib.so -o main
The foo function in lib.so is expected just to be provided when the application is linked and is not specified where exactly from, even not necessary from a library.
You can check for undefined symbols in a library using nm tool:
nm -C -u lib.so
w _ITM_deregisterTMCloneTable
w _ITM_registerTMCloneTable
U foo()
w __cxa_finalize##GLIBC_2.17
w __gmon_start__
And finally you can force gcc to ensure no undefined symbols are used by the object files by compiling with -Wl,-z,defs linker flag:
g++ lib.cpp -shared -Wl,-z,defs -o lib.so
...
lib.cpp:(.text+0x24): undefined reference to `foo()'
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 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.
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 run an up to date debian testing (with kernel 4.19).
Helpers are not found on my system (but they exist in the header, Qt jumps to them)
#include "bpf/bpf.h"
int main (){
int r = bpf_create_map(BPF_MAP_TYPE_ARRAY,1,1,1,0);
return 0;
}
Compilation results in
undefined reference to `bpf_create_map(bpf_map_type, int, int, int, unsigned int)'
compiled with
g++ -c -pipe -g -std=gnu++1z -Wall -W -fPIC -DQT_QML_DEBUG -I. -I../../Qt/5.13.0/gcc_64/mkspecs/linux-g++ -o main.o main.cpp
g++ -lbpf -o server main.o
Same result with
g++ main.cpp -lbpf -o out
I have the libbpf-dev installed as well and i have the associated libraries (a and so).
What is wrong?
Update
even the following code won't work
#include <linux/bpf.h>
int main (){
//int r = bpf_create_map(BPF_MAP_TYPE_ARRAY,1,1,1,0);
bpf_attr attr = {};
attr.map_type = BPF_MAP_TYPE_ARRAY;
attr.key_size = 1;
attr.value_size = 1;
attr.max_entries = 1;
bpf(BPF_MAP_CREATE, &attr, sizeof(attr));
return 0;
}
results in
error: 'bpf' was not declared in this scope
Update2:
BTW, key size is mandated to be 4 and not 1; but it is a point aside, that was unrelated to my problem here.
Namespace issue due to compiling in C++, you probably want:
extern "C" {
#include "bpf/bpf.h"
}
int main()...
Regarding your second error (error: 'bpf' was not declared in this scope), this is not directly related to libbpf, this is because there is no function simply called bpf() to actually perform the syscall. Instead you have to use the syscall number. For example, libbpf defines the following:
static inline int sys_bpf(enum bpf_cmd cmd, union bpf_attr *attr,
unsigned int size)
{
return syscall(__NR_bpf, cmd, attr, size);
}
... and uses sys_bpf() after that, the same way you try to call bpf() in your sample.
For the record, “BPF helpers” often designates BPF functions that you call from within a BPF program, which is not the case here. Hence some confusion in the comments, I believe.