10
10
# ' `R/extendr-wrappers.R`. Afterwards, you will have to re-document and then
11
11
# ' re-install the package for the wrapper functions to take effect.
12
12
# '
13
- # ' @inheritParams pkgload::load_all
14
13
# ' @param path Path from which package root is looked up.
15
14
# ' @param quiet Logical indicating whether any progress messages should be
16
15
# ' generated or not.
17
- # ' @param force_wrappers Logical indicating whether to install a minimal wrapper
18
- # ' file in the cases when generating wrappers by Rust code failed. This might
19
- # ' be needed when the wrapper file is accidentally lost or corrupted.
16
+ # ' @param force Logical indicating whether to force re-generating
17
+ # ' `R/extendr-wrappers.R` even when it doesn't seem to need updated. (By
18
+ # ' default, generation is skipped when it's newer than the DLL).
19
+ # ' @param compile Logical indicating whether to recompile DLLs:
20
+ # ' \describe{
21
+ # ' \item{`TRUE`}{always recompiles}
22
+ # ' \item{`NA`}{recompiles if needed (i.e., any source files or manifest file are newer than the DLL)}
23
+ # ' \item{`FALSE`}{never recompiles}
24
+ # ' }
20
25
# ' @return (Invisibly) Path to the file containing generated wrappers.
21
26
# ' @export
22
- register_extendr <- function (path = " ." , quiet = FALSE , force_wrappers = FALSE , compile = NA ) {
27
+ register_extendr <- function (path = " ." , quiet = FALSE , force = FALSE , compile = NA ) {
23
28
x <- desc :: desc(rprojroot :: find_package_root_file(" DESCRIPTION" , path = path ))
24
29
pkg_name <- x $ get(" Package" )
25
30
@@ -40,29 +45,51 @@ register_extendr <- function(path = ".", quiet = FALSE, force_wrappers = FALSE,
40
45
41
46
outfile <- rprojroot :: find_package_root_file(" R" , " extendr-wrappers.R" , path = path )
42
47
43
- # If force_wrappers is TRUE, use a minimal wrapper file even when
44
- # make_wrappers() fails; since the wrapper generation depends on the compiled
45
- # Rust code, the package needs to be installed before attempting this, but
46
- # it's not always the case (e.g. the package might be corrupted, or not
47
- # installed yet).
48
- if (isTRUE(force_wrappers )) {
49
- error_handle <- function (e ) {
50
- cli :: cli_alert_danger(" Failed to generate wrapper functions: {e$message}." )
51
- cli :: cli_alert_warning(" Falling back to a minimal wrapper file instead." )
52
-
53
- make_example_wrappers(pkg_name , outfile , path = path )
54
- }
55
- } else {
56
- error_handle <- function (e ) {
48
+ path <- rprojroot :: find_package_root_file(path = path )
49
+
50
+ # If compile is NA, compile if the DLL is newer than the source files
51
+ if (isTRUE(is.na(compile ))) {
52
+ compile <- needs_compilation(path , quiet ) || pkgbuild :: needs_compile(path )
53
+ }
54
+
55
+ if (isTRUE(compile )) {
56
+ # This relies on [`pkgbuild::needs_compile()`], which
57
+ # does not know about Rust files modifications.
58
+ # `force = TRUE` enforces compilation.
59
+ pkgbuild :: compile_dll(
60
+ path = path ,
61
+ force = TRUE ,
62
+ quiet = quiet
63
+ )
64
+ }
65
+
66
+ library_path <- get_library_path(path )
67
+
68
+ if (! file.exists(library_path )) {
69
+ msg <- " {library_path} doesn't exist"
70
+ if (isTRUE(compile )) {
71
+ # If it doesn't exist even after compile, we have no idea what happened
72
+ ui_throw(msg )
73
+ } else {
74
+ # If compile wasn't invoked, it might succeed with explicit "compile = TRUE"
57
75
ui_throw(
58
- " Failed to generate wrapper functions." ,
59
- c(
60
- ui_x(e [[" message" ]])
61
- )
76
+ msg ,
77
+ ui_i(" You need to compile first, try `register_rextendr(compile = TRUE)`" )
62
78
)
63
79
}
64
80
}
65
81
82
+ # If the wrapper file is newer than the DLL file, assume it's been generated
83
+ # by the latest DLL, which should mean it doesn't need to be re-generated.
84
+ # This isn't always the case (e.g. when the user accidentally edited the
85
+ # wrapper file by hand) so the user might need to run with `force = TRUE`.
86
+ if (! isTRUE(force ) && length(find_newer_files_than(outfile , library_path )) > 0 ) {
87
+ rel_path <- pretty_rel_path(outfile , path )
88
+ cli :: cli_alert_info(" {.file {rel_path}} is up-to-date. Skip generating wrapper functions." )
89
+
90
+ return (invisible (character (0L )))
91
+ }
92
+
66
93
tryCatch(
67
94
# Call the wrapper generation in a separate R process to avoid the problem
68
95
# of loading and unloading the same name of a DLL (c.f. #64).
@@ -72,10 +99,14 @@ register_extendr <- function(path = ".", quiet = FALSE, force_wrappers = FALSE,
72
99
outfile = outfile ,
73
100
path = path ,
74
101
use_symbols = TRUE ,
75
- quiet = quiet ,
76
- compile = compile
102
+ quiet = quiet
77
103
),
78
- error = error_handle
104
+ error = function (e ) {
105
+ ui_throw(
106
+ " Failed to generate wrapper functions." ,
107
+ ui_x(e [[" message" ]])
108
+ )
109
+ }
79
110
)
80
111
81
112
# Ensures path is absolute
@@ -121,28 +152,15 @@ make_wrappers <- function(module_name, package_name, outfile,
121
152
# '
122
153
# ' Does the same as [`make_wrappers`], but out of process.
123
154
# ' @inheritParams make_wrappers
124
- # ' @param compile Logical indicating whether the library should be recompiled.
125
155
# ' @noRd
126
156
make_wrappers_externally <- function (module_name , package_name , outfile ,
127
- path , use_symbols = FALSE , quiet = FALSE ,
128
- compile = NA ) {
129
- func <- function (path , make_wrappers , compile , quiet ,
157
+ path , use_symbols = FALSE , quiet = FALSE ) {
158
+ func <- function (path , make_wrappers , quiet ,
130
159
module_name , package_name , outfile ,
131
160
use_symbols , ... ) {
132
- if (isTRUE(compile )) {
133
- # This relies on [`pkgbuild::needs_compile()`], which
134
- # does not know about Rust files modifications.
135
- # `force = TRUE` enforces compilation.
136
- pkgbuild :: compile_dll(
137
- path = path ,
138
- force = TRUE ,
139
- quiet = quiet
140
- )
141
- }
142
-
143
- dll_path <- file.path(path , " src" , paste0(package_name , .Platform $ dynlib.ext ))
161
+ library_path <- file.path(path , " src" , paste0(package_name , .Platform $ dynlib.ext ))
144
162
# Loads native library
145
- lib <- dyn.load(dll_path )
163
+ lib <- dyn.load(library_path )
146
164
# Registers library unloading to be invoked at the end of this function
147
165
on.exit(dyn.unload(lib [[" path" ]]), add = TRUE )
148
166
@@ -159,7 +177,6 @@ make_wrappers_externally <- function(module_name, package_name, outfile,
159
177
args <- list (
160
178
path = rprojroot :: find_package_root_file(path = path ),
161
179
make_wrappers = make_wrappers ,
162
- compile = compile ,
163
180
# arguments passed to make_wrappers()
164
181
module_name = module_name ,
165
182
package_name = package_name ,
0 commit comments