0

I have an extensive existing code base in C and Fortran. I want to write an R package that wraps around some of the high-level C functions using RCPP. The nature of most of the C functions I am interested in calling via RCPP is that they again call several C header files, many of which link to Fortran functions.

I have hit a wall when it comes to linking the Fortran functions to the C headers I am including in the cpp function.

A minimal reproducible example is below. It consists of three files, rcpp_script.cpp, c_header.h and fortrancode.f90, which all sit in the /src folder of an RCPP package project created via RStudio. rcpp_script.cpp defines a function rcpp_wrapper(), which is intended to wrap around a C function complicated_c_fun() that is defined in c_header.h. This function complicated_c_fun() calls a function FORTRANCODE() that is defined in fortrancode.f90. When I try installing the package (via RStudio Build -> Check), I receive the following error message:

C:\RBuildTools\4.3\x86_64-w64-mingw32.static.posix\bin/ld.exe: rcpp_script.o:rcpp_script.cp:(.text+0x130): undefined reference to `FORTRANCODE_(double*)' C:\RBuildTools\4.3\x86_64-w64-mingw32.static.posix\bin/ld.exe: rcpp_script.o:rcpp_script.cp:(.text+0x160): undefined reference to `FORTRANCODE_(double*)' collect2.exe: error: ld returned 1 exit status

rcpp_script.cpp:

#include <Rcpp.h>
#include "c_header.h"
using namespace Rcpp;

// [[Rcpp::export]]
double rcpp_wrapper(double p) {
  double z = complicated_c_fun(p);
  return z;
}

c_header.h:

#ifndef C_HEADER_H
#define C_HEADER_H

double complicated_c_fun(double z) {
  double r;
  extern double FORTRANCODE_(double* z);
  r = FORTRANCODE_(&z);
  return (4*r);
}

#endif // C_HEADER_H

fortrancode.f90:

DOUBLE PRECISION FUNCTION FORTRANCODE(P)
  
DOUBLE PRECISION P
  
IF ( P .LT. 1 ) THEN
  FORTRANCODE = 0
ELSE
  FORTRANCODE = 1
ENDIF
  
END FUNCTION FORTRANCODE

How can I properly link the Fortran code to the C header file? Thank you in advance for your help.

Dirk Eddelbuettel
  • 360,940
  • 56
  • 644
  • 725
elmo
  • 325
  • 1
  • 12
  • "many of which link to Fortran functions." -- how do they do that? Understanding how the existing C code calls Fortran might help you figure out how to do it from R. – John Coleman Jun 07 '23 at 12:17
  • There are existing CRAN packages using Fortran. I would have took for one using `f90` but I think that is a solved problem (that has nothing to do with `Rcpp` methinks -- you just have to work out how to tell R to compile and link, this is likely in the [R Installation & Administration](https://rstudio.github.io/r-manuals/r-admin/) and/or in [Writing R Extensions](https://rstudio.github.io/r-manuals/r-exts/). BTW we write it as Rcpp. Capital R, Lowercase cpp. – Dirk Eddelbuettel Jun 07 '23 at 12:28
  • 1
    Why in the world are you putting a function *definition* in your C header? Headers should not contain definitions of external functions, only their declarations. (But fixing this will not itself solve your problem.) – John Bollinger Jun 07 '23 at 12:29
  • Apparently my computer have a package `mixedland` that @JBDuckMayr once set up after I prompted him when he answered a similar question. See [this GH repo](https://github.com/duckmayr/mixedlang). And see [this prior SO answer](https://stackoverflow.com/questions/31396802/integrate-fortran-c-with-r/) (that was not accepted so cannot use to close as duplicate). – Dirk Eddelbuettel Jun 07 '23 at 12:31
  • Fortran does have explicit C interop features, which could enable chosen Fortran functions to be called directly from C++ as well. But I'm not convinced that throwing Rcpp into the mix does anything useful here. – John Bollinger Jun 07 '23 at 12:31
  • @JohnBollinger This is very specifically an _R_ interop question and yes Matilda, we do. C can call Fortran all day long, and billions of compute jobs have done so with eg Fortran based BLAS and LAPACK from C frontends like R, Octave, and many others. – Dirk Eddelbuettel Jun 07 '23 at 12:33
  • @DirkEddelbuettel, I recognize the R context, but as far as the Fortran part is concerned, it seems very much a *C* interop question. Note that the Fortran function is called from `complicated_c_fun()`, not directly from R. I also recognize that the involvement of the C part is probably why the OP turned to Rcpp, but I remain unconvinced of the usefulness of doing so. – John Bollinger Jun 07 '23 at 12:36
  • Thanks a lot for your answers. I have seen the approach in ```mixedlang``` which allows the Fortran function to be called in the Rcpp function and that is very helpful. However, in my case, I need the C code, which I call via Rcpp, to be able to call the Fortran function. The existing C/Fortran code base can be compiled to a dll just fine, but I want to create an R package that wraps around the existing C code. – elmo Jun 07 '23 at 13:00
  • I can only suggest to read e.g. [Writing R Extension](https://rstudio.github.io/r-manuals/r-exts/) (parts about Fortran) very carefully. You are most likely simply instrumenting your tools the wrong way when R itself (as a C program) has _plenty_ of examples doing what you want. You could also ask on the r-package-devel list. As there is zero Rcpp content here I will edit away the tag. Good luck! – Dirk Eddelbuettel Jun 07 '23 at 13:06
  • 1
    @elmo, if the question is specifically about calling the Fortran function from the C function, then the the fact that the C function is itself called from R via C++ seems to be a red herring. C and Fortran (and C++) are compiled languages. All of the details of one of these calling another are set up at compilation time, not at call time, so it does not matter how the front end is called. – John Bollinger Jun 07 '23 at 13:18
  • 1
    As such, I think this is probably a dupe of one or more of the many questions here about calling Fortran from C, such as [Calling a FORTRAN subroutine from C](https://stackoverflow.com/q/8207997/2402272) or [Mixing code in C, C++, and Fortran](https://stackoverflow.com/q/28943465/2402272), among others. Inasmuch as the question seems to have drawn a lot of attention from the R community here, however, I hesitate to dupehammer it. – John Bollinger Jun 07 '23 at 13:28

1 Answers1

1

Thanks to the very helpful comments by @DirkEddelbuettel and @JohnBollinger, I understood that my issue was not related to Rcpp, but rather about how to call Fortran from C++ vs. from C. While the code in my original question works with the original C compiler that was used, when using the g++ compiler, the Fortran function needs to be included as follows:

c_header.h:

#ifndef C_HEADER_H
#define C_HEADER_H

extern "C" {
  double fortrancode_(double* p);
}

double complicated_c_fun(double z) {
  double r;
  r = fortrancode_(&z);
  return (4*r);
}

#endif // C_HEADER_H
elmo
  • 325
  • 1
  • 12