Skip to content

Commit 4d9af22

Browse files
committed
Simplify R CMD config lookups
1 parent 926cd57 commit 4d9af22

6 files changed

Lines changed: 84 additions & 145 deletions

File tree

R/aaa-utils.R

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,43 @@ NULL
66

77
`%||%` <- function(x, y) if (is.null(x)) y else x
88

9+
quickr_r_cmd <- function(
10+
os_type = .Platform$OS.type,
11+
r_home = R.home,
12+
file_exists = file.exists
13+
) {
14+
r_cmd <- r_home("bin/R")
15+
if (identical(os_type, "windows") && !file_exists(r_cmd)) {
16+
r_cmd <- paste0(r_cmd, ".exe")
17+
}
18+
r_cmd
19+
}
20+
21+
quickr_r_cmd_config_value <- function(
22+
name,
23+
r_cmd = quickr_r_cmd(),
24+
system2 = system2
25+
) {
26+
out <- tryCatch(
27+
suppressWarnings(system2(
28+
r_cmd,
29+
c("CMD", "config", name),
30+
stdout = TRUE,
31+
stderr = TRUE
32+
)),
33+
error = function(e) character()
34+
)
35+
status <- attr(out, "status")
36+
if (!is.null(status)) {
37+
return("")
38+
}
39+
value <- trimws(paste(out, collapse = " "))
40+
if (!nzchar(value) || grepl("^ERROR:", value)) {
41+
return("")
42+
}
43+
value
44+
}
45+
946

1047
# @export
1148
# This will be exported by S7 next release.

R/parallel.R

Lines changed: 4 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -138,37 +138,17 @@ openmp_directives <- function(parallel, private = NULL) {
138138
openmp_config_value <- local({
139139
cached <- NULL
140140

141-
function(name) {
141+
function(name, config_value = quickr_r_cmd_config_value) {
142142
if (is.null(cached)) {
143143
cached <<- list()
144144
}
145145
cached_value <- cached[[name]]
146146
if (!is.null(cached_value)) {
147147
return(cached_value)
148148
}
149-
150-
r_cmd <- R.home("bin/R")
151-
if (identical(.Platform$OS.type, "windows") && !file.exists(r_cmd)) {
152-
r_cmd <- paste0(r_cmd, ".exe")
153-
}
154-
out <- tryCatch(
155-
suppressWarnings(system2(
156-
r_cmd,
157-
c("CMD", "config", name),
158-
stdout = TRUE,
159-
stderr = TRUE
160-
)),
161-
error = function(e) character()
162-
)
163-
status <- attr(out, "status")
164-
if (!is.null(status)) {
165-
cached[[name]] <<- ""
166-
return("")
167-
}
168-
value <- trimws(paste(out, collapse = " "))
169-
if (!nzchar(value) || grepl("^ERROR:", value)) {
170-
cached[[name]] <<- ""
171-
return("")
149+
value <- config_value(name)
150+
if (!nzchar(value)) {
151+
value <- ""
172152
}
173153
cached[[name]] <<- value
174154
value

R/quick.R

Lines changed: 21 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -210,25 +210,7 @@ compile <- function(fsub, build_dir = tempfile(paste0(fsub@name, "-build-"))) {
210210

211211
# Link against the same BLAS/LAPACK/Fortran libs as the running R
212212
# to support generated calls to vendor BLAS (e.g., dgemm, dgesv).
213-
cfg <- function(var) {
214-
r_cmd <- R.home("bin/R")
215-
if (identical(.Platform$OS.type, "windows") && !file.exists(r_cmd)) {
216-
r_cmd <- paste0(r_cmd, ".exe")
217-
}
218-
tryCatch(
219-
{
220-
out <- system2(
221-
r_cmd,
222-
c("CMD", "config", var),
223-
stdout = TRUE,
224-
stderr = FALSE
225-
)
226-
paste(out, collapse = " ")
227-
},
228-
error = function(e) ""
229-
)
230-
}
231-
213+
cfg <- quickr_r_cmd_config_value
232214
BLAS_LIBS <- strsplit(cfg("BLAS_LIBS"), "[[:space:]]+")[[1]]
233215
LAPACK_LIBS <- strsplit(cfg("LAPACK_LIBS"), "[[:space:]]+")[[1]]
234216
FLIBS <- strsplit(cfg("FLIBS"), "[[:space:]]+")[[1]]
@@ -237,8 +219,8 @@ compile <- function(fsub, build_dir = tempfile(paste0(fsub@name, "-build-"))) {
237219
FLIBS <- FLIBS[nzchar(FLIBS)]
238220
link_flags <- c(LAPACK_LIBS, BLAS_LIBS, FLIBS)
239221

222+
use_openmp <- isTRUE(attr(fsub@scope, "uses_openmp", exact = TRUE))
240223
suppressWarnings({
241-
use_openmp <- isTRUE(attr(fsub@scope, "uses_openmp", exact = TRUE))
242224
env <- quickr_fcompiler_env(
243225
build_dir = build_dir,
244226
use_openmp = use_openmp,
@@ -261,42 +243,37 @@ compile <- function(fsub, build_dir = tempfile(paste0(fsub@name, "-build-"))) {
261243
stderr = TRUE,
262244
env = env
263245
)
264-
if (!is.null(attr(result, "status")) && length(env)) {
265-
if (use_openmp) {
266-
attr(result, "quickr_openmp_failed") <- TRUE
246+
if (!is.null(attr(result, "status")) && length(env) && !use_openmp) {
247+
result2 <- system2(
248+
R.home("bin/R"),
249+
r_args_libs,
250+
stdout = TRUE,
251+
stderr = TRUE
252+
)
253+
if (is.null(attr(result2, "status"))) {
254+
result <- result2
267255
} else {
268-
result2 <- system2(
269-
R.home("bin/R"),
270-
r_args_libs,
271-
stdout = TRUE,
272-
stderr = TRUE
256+
# Prefer to show the flang attempt first, then the fallback attempt.
257+
result <- c(
258+
"--- flang attempt ---",
259+
result,
260+
"",
261+
"--- fallback attempt ---",
262+
result2
273263
)
274-
if (is.null(attr(result2, "status"))) {
275-
result <- result2
276-
} else {
277-
# Prefer to show the flang attempt first, then the fallback attempt.
278-
result <- c(
279-
"--- flang attempt ---",
280-
result,
281-
"",
282-
"--- fallback attempt ---",
283-
result2
284-
)
285-
attr(result, "status") <- attr(result2, "status")
286-
}
264+
attr(result, "status") <- attr(result2, "status")
287265
}
288266
}
289267
})
290268

291269
status <- attr(result, "status")
292-
openmp_failed <- isTRUE(attr(result, "quickr_openmp_failed"))
293270
if (!is.null(status)) {
294271
# Adjust the compiler error so RStudio console formatter doesn't mangle
295272
# the actual error message https://github.com/rstudio/rstudio/issues/16365
296273
result <- gsub("Error: ", "Compiler Error: ", result, fixed = TRUE)
297274
writeLines(result, stderr())
298275
cat("---\nCompiler exit status:", status, "\n", file = stderr())
299-
if (openmp_failed) {
276+
if (use_openmp) {
300277
openmp_abort(
301278
paste(
302279
"OpenMP was requested but compilation with OpenMP flags failed.",
@@ -340,7 +317,7 @@ compile <- function(fsub, build_dir = tempfile(paste0(fsub@name, "-build-"))) {
340317
quickr_windows_add_dll_paths <- function(
341318
flags,
342319
os_type = .Platform$OS.type,
343-
config_value = openmp_config_value,
320+
config_value = quickr_r_cmd_config_value,
344321
which = Sys.which
345322
) {
346323
if (!identical(os_type, "windows")) {

tests/testthat/helper.R

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -75,17 +75,23 @@ openmp_supported_or_skip <- local({
7575
skip_on_cran()
7676
skip_if_not_installed("pkgload")
7777
if (is.null(supported)) {
78-
supported <<- {
79-
quick(function(x) {
80-
declare(type(x = double(1)))
81-
declare(parallel())
82-
for (i in seq_len(1L)) {
83-
x[i] <- x[i] + 1
84-
}
85-
x
86-
})
87-
TRUE
88-
}
78+
supported <<- tryCatch(
79+
{
80+
quick(function(x) {
81+
declare(type(x = double(1)))
82+
declare(parallel())
83+
for (i in seq_len(1L)) {
84+
x[i] <- x[i] + 1
85+
}
86+
x
87+
})
88+
TRUE
89+
},
90+
quickr_openmp_unavailable = function(e) FALSE
91+
)
92+
}
93+
if (!isTRUE(supported)) {
94+
skip("OpenMP toolchain not available")
8995
}
9096
}
9197
})

tests/testthat/test-compiler.R

Lines changed: 0 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -75,67 +75,6 @@ test_that("quickr_fcompiler_env writes Makevars when flang is usable", {
7575
expect_true(file.exists(sub("R_MAKEVARS_USER=", "", env, fixed = TRUE)))
7676
})
7777

78-
test_that("quickr_windows_add_dll_paths updates PATH for Windows-style runs", {
79-
temp <- withr::local_tempdir()
80-
lib_dir <- file.path(temp, "lib")
81-
bin_dir <- file.path(temp, "bin")
82-
dir.create(lib_dir, recursive = TRUE)
83-
dir.create(bin_dir, recursive = TRUE)
84-
85-
withr::local_envvar(PATH = "C:\\Existing")
86-
expect_true(quickr:::quickr_windows_add_dll_paths(
87-
flags = paste0("-L", lib_dir),
88-
os_type = "windows",
89-
config_value = function(...) "",
90-
which = function(...) ""
91-
))
92-
93-
path <- strsplit(Sys.getenv("PATH"), ";", fixed = TRUE)[[1]]
94-
path_norm <- tolower(normalizePath(path, winslash = "\\", mustWork = FALSE))
95-
lib_norm <- tolower(normalizePath(lib_dir, winslash = "\\", mustWork = FALSE))
96-
bin_norm <- tolower(normalizePath(bin_dir, winslash = "\\", mustWork = FALSE))
97-
98-
expect_true(lib_norm %in% path_norm)
99-
expect_true(bin_norm %in% path_norm)
100-
expect_false(quickr:::quickr_windows_add_dll_paths(
101-
flags = paste0("-L", lib_dir),
102-
os_type = "windows",
103-
config_value = function(...) "",
104-
which = function(...) ""
105-
))
106-
})
107-
108-
test_that("quickr_windows_add_dll_paths is a no-op outside Windows", {
109-
withr::local_envvar(PATH = "C:\\Existing")
110-
expect_false(quickr:::quickr_windows_add_dll_paths(
111-
flags = "-Lfoo",
112-
os_type = "unix",
113-
config_value = function(...) "",
114-
which = function(...) ""
115-
))
116-
})
117-
118-
test_that("quickr_windows_add_dll_paths uses BINPREF from config", {
119-
temp <- withr::local_tempdir()
120-
bin_dir <- file.path(temp, "bin")
121-
dir.create(bin_dir, recursive = TRUE)
122-
binpref <- file.path(bin_dir, "x86_64-w64-mingw32-")
123-
124-
withr::local_envvar(PATH = "C:\\Existing")
125-
expect_true(quickr:::quickr_windows_add_dll_paths(
126-
flags = character(),
127-
os_type = "windows",
128-
config_value = function(key) if (key == "BINPREF") binpref else "",
129-
which = function(...) ""
130-
))
131-
132-
path <- strsplit(Sys.getenv("PATH"), ";", fixed = TRUE)[[1]]
133-
path_norm <- tolower(normalizePath(path, winslash = "\\", mustWork = FALSE))
134-
bin_norm <- tolower(normalizePath(bin_dir, winslash = "\\", mustWork = FALSE))
135-
136-
expect_true(bin_norm %in% path_norm)
137-
})
138-
13978
test_that("compile cleans existing build directories and reports failures", {
14079
fsub <- r2f(function(x) {
14180
declare(type(x = double(1)))

tests/testthat/test-openmp-utils.R

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -40,19 +40,19 @@ test_that("openmp_makevars_lines errors when linker flags are missing", {
4040
test_that("openmp_config_value caches toolchain lookups", {
4141
cache_env <- environment(quickr:::openmp_config_value)
4242
old_cache <- cache_env$cached
43-
old_system2 <- cache_env$system2
43+
old_config <- cache_env$quickr_r_cmd_config_value
4444
withr::defer(cache_env$cached <- old_cache)
4545
withr::defer({
46-
if (is.null(old_system2)) {
47-
rm(system2, envir = cache_env)
46+
if (is.null(old_config)) {
47+
rm(quickr_r_cmd_config_value, envir = cache_env)
4848
} else {
49-
cache_env$system2 <- old_system2
49+
cache_env$quickr_r_cmd_config_value <- old_config
5050
}
5151
})
5252
cache_env$cached <- NULL
5353

5454
calls <- 0
55-
cache_env$system2 <- function(...) {
55+
cache_env$quickr_r_cmd_config_value <- function(...) {
5656
calls <<- calls + 1
5757
"value"
5858
}

0 commit comments

Comments
 (0)