From bb4c7c1910bd2499a1af10dffd9977058cbe583e Mon Sep 17 00:00:00 2001 From: Christopher Paciorek Date: Thu, 12 Mar 2026 12:33:59 -0700 Subject: [PATCH 1/3] Add info to Rcpp plugins to support TBB when creating packages (issue #127) --- nCompiler/R/Rcpp_nCompiler_plugin.R | 22 ++++++++++++++++++---- nCompiler/R/cppDefs_nClass.R | 4 ++-- nCompiler/R/cppDefs_nFunction.R | 4 ++-- nCompiler/R/nCompile.R | 4 +++- 4 files changed, 25 insertions(+), 9 deletions(-) diff --git a/nCompiler/R/Rcpp_nCompiler_plugin.R b/nCompiler/R/Rcpp_nCompiler_plugin.R index e585bace..ab065ac4 100644 --- a/nCompiler/R/Rcpp_nCompiler_plugin.R +++ b/nCompiler/R/Rcpp_nCompiler_plugin.R @@ -15,7 +15,7 @@ inlineCxxPlugin <- function(...) { uses_nC_inter <- !isFALSE(inlineCxxPlugin_env$uses_nC_inter) uses_nList <- !isFALSE(inlineCxxPlugin_env$uses_nList) uses_cereal <- !isFALSE(inlineCxxPlugin_env$uses_cereal) - uses_TBB <- FALSE # !isFALSE(inlineCxxPlugin_env$uses_TBB) # including here causes error due to #defining FALSE + uses_TBB <- !isFALSE(inlineCxxPlugin_env$uses_TBB) include.before <- character() if(uses_eigen) include.before <- paste0(include.before, "#define NCOMPILER_USES_EIGEN\n") if(uses_nC_inter) include.before <- paste0(include.before, "#define NCOMPILER_USES_NCLASS_INTERFACE\n") @@ -37,9 +37,9 @@ nCompiler_pluginEnv <- new.env() make_nCompiler_plugin <- function(nCompiler_pluginEnv) { RcppDefaultPlugin <- Rcpp:::Rcpp.plugin.maker() force(nCompiler_pluginEnv) - ans <- function(...) { + ans <- function(...) { result <- RcppDefaultPlugin(...) - result$env$PKG_CPPFLAGS <- c(result$env$PKG_CPPFLAGS, + result$env$PKG_CPPFLAGS <- paste(result$env$PKG_CPPFLAGS, if(length(nCompiler_pluginEnv$includePaths) > 0) paste0( "-I", @@ -50,6 +50,8 @@ make_nCompiler_plugin <- function(nCompiler_pluginEnv) { result$env$PKG_LIBS <- get_nCompLocal_PKG_LIBS_entry() ## Makevars doesn't work ## result$Makevars <- "CXX_STD=CXX11" does not seem to work + if(!isFALSE(inlineCxxPlugin_env$uses_TBB)) + result$env <- setEnvTBB(result$env) result } ans @@ -74,13 +76,15 @@ make_nCompiler_Eigen_plugin <- function(nCompiler_pluginEnv) { "") # result$env$PKG_CXXFLAGS <- "-std=c++11" result$env$PKG_LIBS <- get_nCompLocal_PKG_LIBS_entry() + if(!isFALSE(inlineCxxPlugin_env$uses_TBB)) + result$env <- setEnvTBB(result$env) if(isTRUE(get_nOption('compilerOptions')$throwEigenErrors)) { # replace include directives to enable Eigen errors #preamble = system.file(file.path('include', 'nCompiler', # 'nCompiler_Eigen_EnableErrors.h'), # package = 'nCompiler') #result$includes = readChar(preamble, file.info(preamble)$size) - result$includes = "#define NCOMPILER_HANDLE_EIGEN_ERRORS" + result$includes = c("#define NCOMPILER_HANDLE_EIGEN_ERRORS") } if(isTRUE(get_nOption('compilerOptions')$cppStacktrace)) { # add include directives to add stack basic traces @@ -95,3 +99,13 @@ make_nCompiler_Eigen_plugin <- function(nCompiler_pluginEnv) { } nCompiler_Eigen_plugin <- make_nCompiler_Eigen_plugin(nCompiler_pluginEnv) + +setEnvTBB <- function(env) { + if(.Platform$OS.type == "windows") { + env$PKG_CPPFLAGS <- paste(env$PKG_CPPFLAGS, '-DRCPP_PARALLEL_USE_TBB=1') + env$PKG_LIBS <- paste(env$PKG_LIBS, + '$(shell "${R_HOME}/bin${R_ARCH_BIN}/Rscript.exe"-e "RcppParallel::RcppParallelLibs()")') + } else env$PKG_LIBS <- paste(env$PKG_LIBS, + '$(shell ${R_HOME}/bin/Rscript -e "RcppParallel::RcppParallelLibs()")') + return(env) +} diff --git a/nCompiler/R/cppDefs_nClass.R b/nCompiler/R/cppDefs_nClass.R index c1f8d61e..ec815d0a 100644 --- a/nCompiler/R/cppDefs_nClass.R +++ b/nCompiler/R/cppDefs_nClass.R @@ -11,13 +11,13 @@ nClassBaseClass_init_impl <- function(cppDef) { cppDef$Hpreamble <- pluginIncludes cppDef$Hpreamble <- c(cppDef$Hpreamble, "#define NCOMPILER_USES_EIGEN", - "// #define NCOMPILER_USES_TBB", + "#define NCOMPILER_USES_TBB", "#define NCOMPILER_USES_NLIST", "#define USES_NCOMPILER") cppDef$CPPpreamble <- pluginIncludes cppDef$CPPpreamble <- c(cppDef$CPPpreamble, "#define NCOMPILER_USES_EIGEN", - "// #define NCOMPILER_USES_TBB", + "#define NCOMPILER_USES_TBB", "#define NCOMPILER_USES_NLIST", "#define USES_NCOMPILER") diff --git a/nCompiler/R/cppDefs_nFunction.R b/nCompiler/R/cppDefs_nFunction.R index ff4fbc20..6bd56703 100644 --- a/nCompiler/R/cppDefs_nFunction.R +++ b/nCompiler/R/cppDefs_nFunction.R @@ -8,7 +8,7 @@ cpp_nFunctionClass_init_impl <- function(cppDef) { cppDef$Hpreamble <- pluginIncludes cppDef$Hpreamble <- c(cppDef$Hpreamble, "#define NCOMPILER_USES_EIGEN", - "// #define NCOMPILER_USES_TBB", + "#define NCOMPILER_USES_TBB", "#define NCOMPILER_USES_NLIST", "#define USES_NCOMPILER") ## handler nList in labelAbstractTypes does record in auxEnv if an @@ -19,7 +19,7 @@ cpp_nFunctionClass_init_impl <- function(cppDef) { cppDef$CPPpreamble <- pluginIncludes cppDef$CPPpreamble <- c(cppDef$CPPpreamble, "#define NCOMPILER_USES_EIGEN", - "// #define NCOMPILER_USES_TBB", + "#define NCOMPILER_USES_TBB", "#define NCOMPILER_USES_NLIST", "#define USES_NCOMPILER") cppDef$Hincludes <- c(cppDef$Hincludes)#, diff --git a/nCompiler/R/nCompile.R b/nCompiler/R/nCompile.R index cf4d3d54..49ab08ea 100644 --- a/nCompiler/R/nCompile.R +++ b/nCompiler/R/nCompile.R @@ -1268,7 +1268,9 @@ WP_write_DESCRIPTION_NAMESPACE <- function(units, unitTypes, interfaces, createF # DESCRIPTION[1, "Collate"] <- paste(Rfilepath, collapse = ", ") write.dcf(DESCRIPTION, DESCfile) NAMESPACE <- c(paste0("useDynLib(", pkgName, ", .registration=TRUE)"), - "importFrom(Rcpp, evalCpp)"# , # required at package loading + "importFrom(Rcpp, evalCpp)", # required at package loading + if(!isFALSE(inlineCxxPlugin_env$uses_TBB)) + "importFrom(RcppParallel, RcppParallelLibs)" else NULL # "export(nComp_serialize_)", # "export(nComp_deserialize_)", # "export(call_method)", From a5ffc0834c81def87e0462dded7e305240bd6fef Mon Sep 17 00:00:00 2001 From: Christopher Paciorek Date: Fri, 15 May 2026 17:41:07 -0700 Subject: [PATCH 2/3] Handle TBB in preamble via conditional in cppDef processing, not via Rcpp plugin. --- nCompiler/R/Rcpp_nCompiler_plugin.R | 2 -- nCompiler/R/compile_finalTransformations.R | 2 +- nCompiler/R/compile_labelAbstractTypes.R | 4 ++++ nCompiler/R/cppDefs_nClass.R | 9 +++++++-- nCompiler/R/cppDefs_nFunction.R | 6 ++---- 5 files changed, 14 insertions(+), 9 deletions(-) diff --git a/nCompiler/R/Rcpp_nCompiler_plugin.R b/nCompiler/R/Rcpp_nCompiler_plugin.R index ab065ac4..4c7f6181 100644 --- a/nCompiler/R/Rcpp_nCompiler_plugin.R +++ b/nCompiler/R/Rcpp_nCompiler_plugin.R @@ -15,13 +15,11 @@ inlineCxxPlugin <- function(...) { uses_nC_inter <- !isFALSE(inlineCxxPlugin_env$uses_nC_inter) uses_nList <- !isFALSE(inlineCxxPlugin_env$uses_nList) uses_cereal <- !isFALSE(inlineCxxPlugin_env$uses_cereal) - uses_TBB <- !isFALSE(inlineCxxPlugin_env$uses_TBB) include.before <- character() if(uses_eigen) include.before <- paste0(include.before, "#define NCOMPILER_USES_EIGEN\n") if(uses_nC_inter) include.before <- paste0(include.before, "#define NCOMPILER_USES_NCLASS_INTERFACE\n") if(uses_nList) include.before <- paste0(include.before, "#define NCOMPILER_USES_NLIST\n") if(uses_cereal) include.before <- paste0(include.before, "#define NCOMPILER_USES_CEREAL\n") - if(uses_TBB) include.before <- paste0(include.before, "#define NCOMPILER_USES_TBB\n") include.before <- paste0(include.before, "#include ") ans <- Rcpp::Rcpp.plugin.maker(include.before=include.before)() ans diff --git a/nCompiler/R/compile_finalTransformations.R b/nCompiler/R/compile_finalTransformations.R index a82da612..5ecf424f 100644 --- a/nCompiler/R/compile_finalTransformations.R +++ b/nCompiler/R/compile_finalTransformations.R @@ -104,7 +104,7 @@ inFinalTransformationsEnv( ## shareVars <- replace_nameSubList(shareVars, auxEnv$nameSubList) ## code$args[[4]] <- copyVars ## This is no longer an exprClass ## code$args[[5]] <- shareVars ## Ditto - + ## remove the vector and initial value arg and save for later vector_arg <- removeArg(code, 2) ## TODO: don't remove the init arg unless isTRUE(code$caller$isAssign) diff --git a/nCompiler/R/compile_labelAbstractTypes.R b/nCompiler/R/compile_labelAbstractTypes.R index 15d69c3b..34b16ac8 100644 --- a/nCompiler/R/compile_labelAbstractTypes.R +++ b/nCompiler/R/compile_labelAbstractTypes.R @@ -760,6 +760,8 @@ inLabelAbstractTypesEnv( ## Now the 3rd arg, the body of the loop, can be processed inserts <- c(inserts, compile_labelAbstractTypes(code$args[[3]], symTab, auxEnv)) + + auxEnv$uses_TBB <- TRUE ## I think there shouldn't be any inserts returned since the body should be a bracket expression. return(if (length(inserts) == 0) invisible(NULL) else inserts) } @@ -816,6 +818,8 @@ inLabelAbstractTypesEnv( call. = FALSE) code$type <- symbolBasic$new(name = code$name, nDim = 0, type = code$args[[3]]$type$type) + + auxEnv$uses_TBB <- TRUE return(if (length(inserts) == 0) invisible(NULL) else inserts) } ) diff --git a/nCompiler/R/cppDefs_nClass.R b/nCompiler/R/cppDefs_nClass.R index ec815d0a..10803971 100644 --- a/nCompiler/R/cppDefs_nClass.R +++ b/nCompiler/R/cppDefs_nClass.R @@ -11,13 +11,11 @@ nClassBaseClass_init_impl <- function(cppDef) { cppDef$Hpreamble <- pluginIncludes cppDef$Hpreamble <- c(cppDef$Hpreamble, "#define NCOMPILER_USES_EIGEN", - "#define NCOMPILER_USES_TBB", "#define NCOMPILER_USES_NLIST", "#define USES_NCOMPILER") cppDef$CPPpreamble <- pluginIncludes cppDef$CPPpreamble <- c(cppDef$CPPpreamble, "#define NCOMPILER_USES_EIGEN", - "#define NCOMPILER_USES_TBB", "#define NCOMPILER_USES_NLIST", "#define USES_NCOMPILER") @@ -114,6 +112,13 @@ cpp_nClassBaseClass <- R6::R6Class( cpp_include_needed_nClasses(self, Compiler$symbolTable) symbolTable <<- symbolTable2cppSymbolTable(Compiler$symbolTable) # variableNamesForInterface <<- symbolTable$getSymbolNames() + uses_TBB <- any(sapply(Compiler$NFcompilers, function(x) isTRUE(x$auxEnv$uses_TBB))) + if(uses_TBB) { + self$Hpreamble <- c(self$Hpreamble, + "#define NCOMPILER_USES_TBB") + self$CPPpreamble <- c(self$CPPpreamble, + "#define NCOMPILER_USES_TBB") + } }, buildAll = function(where = where) { buildDefaultSEXPgenerator <- !isFALSE(self$compileInfo$createFromR) diff --git a/nCompiler/R/cppDefs_nFunction.R b/nCompiler/R/cppDefs_nFunction.R index 6bd56703..50a01079 100644 --- a/nCompiler/R/cppDefs_nFunction.R +++ b/nCompiler/R/cppDefs_nFunction.R @@ -8,8 +8,7 @@ cpp_nFunctionClass_init_impl <- function(cppDef) { cppDef$Hpreamble <- pluginIncludes cppDef$Hpreamble <- c(cppDef$Hpreamble, "#define NCOMPILER_USES_EIGEN", - "#define NCOMPILER_USES_TBB", - "#define NCOMPILER_USES_NLIST", + "#define NCOMPILER_USES_NLIST", "#define USES_NCOMPILER") ## handler nList in labelAbstractTypes does record in auxEnv if an ## explicit call to nList() was uses. That is the beginning of a smarter @@ -19,8 +18,7 @@ cpp_nFunctionClass_init_impl <- function(cppDef) { cppDef$CPPpreamble <- pluginIncludes cppDef$CPPpreamble <- c(cppDef$CPPpreamble, "#define NCOMPILER_USES_EIGEN", - "#define NCOMPILER_USES_TBB", - "#define NCOMPILER_USES_NLIST", + "#define NCOMPILER_USES_NLIST", "#define USES_NCOMPILER") cppDef$Hincludes <- c(cppDef$Hincludes)#, ## nCompilerIncludeFile("nCompiler_omnibus_first_h.h")) From b387b284199f8d46f328cb38040eb566efd4e543 Mon Sep 17 00:00:00 2001 From: Christopher Paciorek Date: Sun, 17 May 2026 09:05:44 -0700 Subject: [PATCH 3/3] Update plugins in relation to TBB. --- nCompiler/R/Rcpp_nCompiler_plugin.R | 4 ++-- nCompiler/R/compile_labelAbstractTypes.R | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/nCompiler/R/Rcpp_nCompiler_plugin.R b/nCompiler/R/Rcpp_nCompiler_plugin.R index 4c7f6181..549f0e76 100644 --- a/nCompiler/R/Rcpp_nCompiler_plugin.R +++ b/nCompiler/R/Rcpp_nCompiler_plugin.R @@ -48,7 +48,7 @@ make_nCompiler_plugin <- function(nCompiler_pluginEnv) { result$env$PKG_LIBS <- get_nCompLocal_PKG_LIBS_entry() ## Makevars doesn't work ## result$Makevars <- "CXX_STD=CXX11" does not seem to work - if(!isFALSE(inlineCxxPlugin_env$uses_TBB)) + if(isTRUE(nCompiler_pluginEnv$uses_TBB)) result$env <- setEnvTBB(result$env) result } @@ -103,7 +103,7 @@ setEnvTBB <- function(env) { env$PKG_CPPFLAGS <- paste(env$PKG_CPPFLAGS, '-DRCPP_PARALLEL_USE_TBB=1') env$PKG_LIBS <- paste(env$PKG_LIBS, '$(shell "${R_HOME}/bin${R_ARCH_BIN}/Rscript.exe"-e "RcppParallel::RcppParallelLibs()")') - } else env$PKG_LIBS <- paste(env$PKG_LIBS, + } else env$PKG_LIBS <- paste(env$PKG_LIBS, '$(shell ${R_HOME}/bin/Rscript -e "RcppParallel::RcppParallelLibs()")') return(env) } diff --git a/nCompiler/R/compile_labelAbstractTypes.R b/nCompiler/R/compile_labelAbstractTypes.R index 34b16ac8..7c9c9d0d 100644 --- a/nCompiler/R/compile_labelAbstractTypes.R +++ b/nCompiler/R/compile_labelAbstractTypes.R @@ -762,6 +762,7 @@ inLabelAbstractTypesEnv( inserts <- c(inserts, compile_labelAbstractTypes(code$args[[3]], symTab, auxEnv)) auxEnv$uses_TBB <- TRUE + nCompiler_pluginEnv$uses_TBB <- TRUE ## I think there shouldn't be any inserts returned since the body should be a bracket expression. return(if (length(inserts) == 0) invisible(NULL) else inserts) } @@ -820,6 +821,7 @@ inLabelAbstractTypesEnv( type = code$args[[3]]$type$type) auxEnv$uses_TBB <- TRUE + nCompiler_pluginEnv$uses_TBB <- TRUE return(if (length(inserts) == 0) invisible(NULL) else inserts) } )