[Rcpp-devel] split the c++ code in several files

Romain Francois romain at r-enthusiasts.com
Thu Sep 16 19:36:36 CEST 2010


Le 16/09/10 18:32, baptiste auguie a écrit :
> Hi,
>
> Thanks for the valuable information and advice. Some comments / questions below.
>
> On 16 September 2010 15:49, Romain Francois<romain at r-enthusiasts.com>  wrote:
>> Le 16/09/10 15:24, baptiste auguie a écrit :
>>>
>>> Dear list,
>>>
>>>
>>> This is probably not specific to Rcpp but I couldn't find any advice
>>> in the R-exts manual. I am using RcppArmadillo in a package to do some
>>> linear algebra. The C++ code is getting a bit too large to manage in
>>> one file only, I would like to split its content in several files.
>>> It seems possible, but I'm not sure how to deal with the scoping
>>> rules: if a function requires a subroutine defined in another file it
>>> seems to have a scoping problem (the compilation fails with message
>>> "error: ‘xxxx’ was not declared in this scope)". Currently my cpp file
>>> looks like this,
>>>
>>> ///////////////////////////////////////////////////
>>> #include "cda.h"
>>> #include<RcppArmadillo.h>
>>> #include<iostream>
>>>
>>> using namespace Rcpp ;
>>> using namespace RcppArmadillo ;
>>>
>>> using namespace std;
>>>
>>> extern "C" {
>>>
>>>    arma::mat foo(const arma::mat&    R) {
>>>      return(R);
>>>     }
>>>
>>>    // R wrapper
>>>    RCPP_FUNCTION_1(NumericMatrix, test, NumericMatrix IR)
>>>    {
>>>     arma::mat R = Rcpp::as<    arma::mat>(IR);
>>>     return wrap( foo(R) );
>>>    }
>>>   // other routines
>>> }
>>> ///////////////////////////////////////////////////
>>>
>>> (The actual file is here:
>>>
>>> https://r-forge.r-project.org/scm/viewvc.php/pkg/cda/src/cda.cpp?diff_format=h&root=photonics&view=log)
>>>
>>>
>>> Are there workarounds / rules to split the content in several files?
>>>
>>> Best regards,
>>>
>>> baptiste
>>
>> Hello,
>>
>> The usual thing is to declare functions in header files, and include these
>> headers from each .cpp file. You then define the functions in .cpp files in
>> any order you like. As long as it is declared, the compiler knows it is
>> coming.
>
> In principle I understand, but in practice I'm a bit stuck with this.
> In my previous header file I only declared RcppExport functions, such
> as
>
> //////////////
> #ifndef _cda2_CDA2_H
> #define _cda2_CDA2_H
>
> #include<RcppArmadillo.h>
>
> /* void progress_bar(double x, double N); */
> RcppExport SEXP rotation(SEXP phi, SEXP theta, SEXP psi);
>
> #endif
>
> //////////////
>
> When I also add internal C++ routines (uncommenting progress_bar
> above) I get errors such as,
>
> ** testing if installed package can be loaded
> Error in dyn.load(file, DLLpath = DLLpath, ...) :
>    unable to load shared library
> '/Library/Frameworks/R.framework/Resources/library/cda2/libs/x86_64/cda2.so':
>    dlopen(/Library/Frameworks/R.framework/Resources/library/cda2/libs/x86_64/cda2.so,
> 6): Symbol not found: __Z12progress_bardd
>    Referenced from:
> /Library/Frameworks/R.framework/Resources/library/cda2/libs/x86_64/cda2.so
>    Expected in: flat namespace
>   in /Library/Frameworks/R.framework/Resources/library/cda2/libs/x86_64/cda2.so
> ERROR: loading failed

This is because those are not the same since you enclose everything (bad 
practice) into a extern "C" in your .cpp file.

If you split things like this, the only place where you need extern "C" 
(or RcppExport which is an alias) is in the header

>> I think you should use RCPP_FUNCTION_* outside of the extern "C" block.

Actually I think you should not have an extern "C" block at all (see 
above).

> OK, thanks.
>
>>
>>
>> However, I believe modules now do a better job than the RCPP_* macros, and
>> for example I think you don't need this wrapper:
>>
>>   // R level wrapper
>>   RCPP_FUNCTION_3(NumericMatrix, rotation, double phi,
>>                   double theta, double psi) {
>>     return wrap(euler(phi, theta, psi));
>>   }
>>
>> You would simply make a module liks this:
>>
>> RCPP_MODULE(aladdin){
>>         using namespace Rcpp ;
>>
>>         function( "rotation",&euler ) ;
>>         function( "interaction_matrix",&interactionA ) ;
>> }
>>
>> and then on the R side, you grab the module :
>>
>> jasmine<- Module( "aladdin" )
>> jasmine$rotation( 1, 2, 3 )
>> jasmine$interaction_matrix( ... )
>>
>
> It works brilliantly, thanks! It's so much cleaner.

The rules are:
- for the input, anything Rcpp::as can handle is fine
- for the output, anything Rcpp::wrap can handle is fine

>> Also note that from the most recent version of RcppArmadillo, you don't need
>> the Rcpp::as anymore to convert a NumericMatrix to an arma::mat, you can
>> just do (I think):
>>
>> arma::mat R = IR ;
>>
>
> A quick test failed, but I'll try again with something more minimal to
> report.

I think I know what this is. I don't have the right fix right now, and 
I'll spare the details, but this will work "in the future".

> Truth be told, I got lost in the recent discussions on the
> best way to pass a real (complex) matrix from R to Armadillo and I've
> been meaning to go back to this question.

Sorry for the confusion. I think Rcpp::as is fine. I need a bit more 
work in RcppArmadillo for the interchangeability between ComplexVector 
and cx_mat.

Perhaps at the next iteration of updating the package.

> Thanks,
>
> baptiste
>
>
>> Romain

-- 
Romain Francois
Professional R Enthusiast
+33(0) 6 28 91 30 30
http://romainfrancois.blog.free.fr
|- http://bit.ly/cCmbgg : Rcpp 0.8.6
|- http://bit.ly/bzoWrs : Rcpp svn revision 2000
`- http://bit.ly/b8VNE2 : Rcpp at LondonR, oct 5th




More information about the Rcpp-devel mailing list