Ответ 1
Я бы предложил, чтобы такие проекты сворачивали ваш код в пакет. Я создал простой пример такого пакета, который я назвал mixedlang
который доступен в этом репо GitHub. Я опишу процесс создания пакета здесь.
Я сделал следующие шаги:
- Настройте структуру пакета из R с помощью
RcppArmadillo::RcppArmadillo.package.skeleton("mixedlang")
(я использовал RcppArmadillo, а не Rcpp, поскольку OP был - нет ничего особенного в этом примере Armadillo) - Добавлены файлы C++ и Fortran, описанные ниже, в папку
src/
- В R запустите
Rcpp::compileAttributes("mixedlang/")
затемdevtools::install("mixedlang/")
Код
Я создал простую функцию C++, единственной целью которой (по существу) было вызов функции Fortran. Функция example принимает числовой вектор, умножает каждый элемент на его индекс и возвращает результат. Сначала рассмотрим код Fortran:
fortranfunction.f90
Эта функция просто берет два удвоения и умножает их, возвращая результат:
REAL*8 FUNCTION MULTIPLY (X, Y)
REAL*8 X, Y
MULTIPLY = X * Y
RETURN
END
test_function.cpp
Теперь нам нужно вызвать этот код Fortran из нашего кода C++. При этом нам нужно учесть несколько вещей:
- Аргументы Fortran передаются по ссылке, а не по значению.
-
Поскольку
MULTIPLY
определен в другом файле, нам нужно объявить его в нашем C++ файле, чтобы компилятор знал аргументы и возвращаемые типы.а. При объявлении функции Fortran для нашего C++ файла мы отбросим случай имени функции и добавим символ подчеркивания, поскольку компилятор Fortran должен сделать это по умолчанию.
б. Мы должны объявить эту функцию в пределах
extern "C"
спецификации связиextern "C"
; Компиляторы C++ обычно не могут использовать имена функций как уникальные идентификаторы, поскольку они позволяют перегружать, но для вызова функций Fortran нам нужно выполнить именно то, что выполняет спецификация связиextern "C"
(см., Например, этот ответ SO).
#include "RcppArmadillo.h"
// [[Rcpp::depends(RcppArmadillo)]]
// First we'll declare the MULTIPLY Fortran function
// as multiply_ in an extern "C" linkage specification
// making sure to have the arguments passed as pointers.
extern "C" {
double multiply_(double *x, double *y);
}
// Now our C++ function
// [[Rcpp::export]]
Rcpp::NumericVector test_function(Rcpp::NumericVector x) {
// Get the size of the vector
int n = x.size();
// Create a new vector for our result
Rcpp::NumericVector result(n);
for ( int i = 0; i < n; ++i ) {
// And for each element of the vector,
// store as doubles the element and the index
double starting_value = x[i], multiplier = (double)i;
// Now we can call the Fortran function,
// being sure to pass the address of the variables
result[i] = multiply_(&starting_value, &multiplier);
}
return result;
}
Пример вывода
После установки пакета я запустил пример
mixedlang::test_function(0:9)
# [1] 0 1 4 9 16 25 36 49 64 81
Вероятные источники исходных проблем с постерами
- При попытке компиляции изначально они не позволяли компилятору узнать, где
RcppArmadillo.h
. - Попытка сделать это с помощью
sourceCpp
простоsourceCpp
неприятностей; на самом деле это не было сделано для обработки нескольких файлов (см., например, этот ответ от Dirk Eddelbuettel), что необходимо при работе с несколькими языками.
Я не уверен, что произошло, когда они попытались перевернуть его в пакет, поэтому я составил этот пример.