[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