-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathgeneratePredefinedCpp.R
187 lines (174 loc) · 8.58 KB
/
generatePredefinedCpp.R
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
## Newer predefined system (as of 3/15/22).
# How to to create a new predefined class:
# 1. Enter the class definition in a file in the R directory.
# Some are in zzz_NC_predefined.R but they can be anywhere after nClass has been defined.
#
# 2. Include a classname in the nClass call, so it is not randomly generated.
# Include a argument like predefined="my_predefined_local" in the nClass call,
# with a character value that is different from classname.
# Be sure the nClass is an exported R object in the package (usually).
# The class name will be used for the C++ code that will be generated each time you use the nClass.
# The predefined name will be used for permanent files of generated C++ that you will copy to package source code and modify.
# The example here will be my_predefined <- nClass(classname = "my_predefined", predefined = "my_predefined_pkg", ...)
#
# 3. build nCompiler again with the new nClass included.
#
# 4. Load nCompiler and do nCompile(my_predefined, control = list(generate_predefined = TRUE)).
# Be sure you know where code is being generated (default is tempdir(), can be changed by dir argument to nCompile).
# Note that the results from nCompile(my_predefined, control = list(generate_predefined = TRUE)) will not result in
# usable objects right in the current R session. That is because the generated code will lack the interface calls such as
# get_value, set_value, and call_method. The reason is that these must only be created once in any compilation,
# and when the predefined nClass is used later, it should not be the place where those functions are defined.
# If you want to test the predefined class, include some other nFunction or nClass in the call to nCompile.
# Since that will not be predefined, it will trigger inclusion of the interface functions.
# See test-predefined.R for examples.
#
# 5. Copy my_predefined.h (or my_predefined_c_.h) to my_predefined_pkg.h in package source code (i.e. inst/include/nCompiler).
#
# 6. Copy the cpp file, which will have an automatically generated name like "nCompiler_units_1.cpp", to
# my_predfined_pkg.cpp in the package source code. (Note these names match the predefined argument in the nClass class.)
#
# 7. (DEPRECATED - DO NOT DO THIS. LEAVING IT HERE FOR NOTES)
# In my_predefined.cpp, there will be a line like
# #include "my_predefined.h"
# Change that to
# #include "my_predefined_pkg.h"
# i.e. replace the classname with the predefined name.
#
# 8. In my_predefined.h and my_predefined.cpp, there will be #ifndef protections against
# multiple #includes. They will look like
# #ifndef __test_predefined_H
# #define __test_predefined_H
# and
# #ifndef __test_predefined_CPP
# #define __test_predefined_CPP
#
# Change each of these to have a unique name in some way, e.g.
# #ifndef __test_predefined_H_PREDEF
# #define __test_predefined_H_PREDEF
# and similarly for the CPP one
#
# 8. If any other files (which must be included from nCompiler_Eigen_fxns.h)
# in inst/include/nCompiler that need to use my_predefined,
# put the code using my_predefined inside a code block like this:
# #ifdef PREDEFINED_my_predefined
# #include PREDEFINED_HEADER(PREDEFINED_test_predefined)
# <rest of your code>
# #endif
#
# (The C++ pre-processor variable PREDEFINED_my_predefined will be set by generated code
# automatically when you use the predefined class later. In this case it will be 'my_predefined_pkg')
#
# Note that it will not work to put such code just anywhere. It needs to be in one of the files that
# will be arranged to be included after the predefined header, so that
# PREDEFINED_my_predefined has been defined for the C++ preprocessor
# Currently the only file included at that time is nCompiler_Eigen_fxns.h, which is simply a set
# of other include statements. So it should be possible to add to those as needed (and possibly rename).
#
# 9. build nCompiler again so that the package includes the new .h and .cpp files.
#
# 10. You should now be able to use my_predefined as a type in nClasses and nFunctions.
#
# 11. When calling nCompile with code that uses my_predefined, include my_predefined as a compilation unit
# (i.e. an input) to nCompile. Otherwise it will not be used and there will be an error.
#
# Note: It is still possible to set control = list(generate_predefined = TRUE) and use
# locally generated versions of the predefined classes, not the versions that you have
# copied into package sources and installed. However, other functions that uses the classes
# will not work.
#
# Note: During experimental work, in steps 5 and 6 you can copy the files directly to the installed directory
# and then not need to rebuild and resintall the package in order to try them.
################################
### OLDER SYSTEM (as of 3/15/22)
## This script:
## 1. Reads files in nCompiler/R that have predefined nClass definitions.
## 2. Generates the .cpp and .h content in inst
library(nCompiler)
#set_nOption("use_nCompLocal", TRUE)
## if(!("generatePredefinedCpp.R" %in% list.files()))
## stop("You need source generatePredefinedCpp.R with its directory as your working directory.")
## predefined_filebase <- "predefined"
## clear_predefined_files <- function(compileAttributes = TRUE) {
## dir1 = file.path("nCompiler","src")
## dir2 = file.path("nCompiler","inst","include","nCompiler")
## for(dir in c(dir1, dir2)) {
## for(file in paste0(predefined_filebase, c(".h", ".cpp"))) {
## dirfile <- file.path(dir, file)
## if(file.exists(dirfile))
## file.remove(dirfile)
## }
## }
## if(compileAttributes)
## compileAttributes("nCompiler")
## }
## predefFiles <- c("zzz_NC_Predefined.R")
## sourceDir <- file.path("nCompiler", "R")
## predefinedNames <- character()
## predefinedRcppPackets <- list()
## getRcppPacket <- function(parsed, className) {
## env <- new.env()
## eval(parsed, envir = env)
## RcppPacket <- nCompile_nClass(env[[className]],
## control = list(endStage = 'writeCpp',
## filename = predefined_filebase))
## RcppPacket
## }
## for(pF in predefFiles) {
## ## pF <- predefFiles[1]
## pathedFile <- file.path(sourceDir, pF)
## parsed <- parse(file = pathedFile)
## for(iP in seq_along(parsed)) {
## ##iP <- 1;
## thisParsed <- parsed[[iP]]
## if(is.call(thisParsed)) {
## if(deparse(thisParsed[[1]]) == "<-") {
## if(is.call(thisParsed[[3]])) {
## if(deparse(thisParsed[[3]][[1]]) == "nClass") {
## className <- deparse(thisParsed[[2]])
## predefinedNames <- append(predefinedNames, className)
## predefinedRcppPackets <- c(predefinedRcppPackets,
## list(getRcppPacket(thisParsed, className)))
## }
## }
## }
## }
## }
## }
## sepContents <- function(x, element, label)
## c("//--------------------------------------",
## "//--------------------------------------",
## paste0("// ", label),
## "//--------------------------------------",
## x[[element]]
## )
## combinedPacket <- nCompiler:::Rcpp_nCompilerPacket(
## cppContent = c("//GENERATED BY generatedPredefinedCpp.R. DO NOT EDIT BY HAND",
## unlist(mapply(sepContents,
## x = predefinedRcppPackets,
## label = predefinedNames,
## MoreArgs = list(element = "cppContent"),
## SIMPLIFY=FALSE,
## USE.NAMES = FALSE))),
## hContent = c("//GENERATED BY generatedPredefinedCpp.R. DO NOT EDIT BY HAND",
## unlist(mapply(sepContents,
## x = predefinedRcppPackets,
## label = predefinedNames,
## MoreArgs = list(element = "hContent"),
## SIMPLIFY=FALSE,
## USE.NAMES = FALSE))),
## filebase = predefined_filebase
## )
## # Remove "// [[Rcpp::depends(nCompiler)]]"
## # This should occur once per cppDef in cppContent
## removeBool <- combinedPacket$cppContent == "// [[Rcpp::depends(nCompiler)]]"
## combinedPacket$cppContent[removeBool] <- ""
## # This should not occur in hContent, but we can defensively check anyway
## removeBool <- combinedPacket$hContent == "// [[Rcpp::depends(nCompiler)]]"
## combinedPacket$hContent[removeBool] <- ""
## ## remove any old files
## clear_predefined_files(compileAttributes = FALSE)
## nCompiler:::writeCpp_nCompiler(combinedPacket, dir = file.path("nCompiler","inst","include","nCompiler"))
## nCompiler:::writeCpp_nCompiler(combinedPacket, dir = file.path("nCompiler","src"))
## require(Rcpp)
## compileAttributes("nCompiler")