Skip to content

Commit b7ad4f6

Browse files
authored
Merge pull request #58 from RcppCore/feature/portable-configure
provide portable (works on Windows) configure
2 parents 966b715 + 42c6355 commit b7ad4f6

File tree

6 files changed

+229
-2970
lines changed

6 files changed

+229
-2970
lines changed

DESCRIPTION

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ LinkingTo: BH (>= 1.60.0-1)
2828
SystemRequirements: GNU make, Windows: cmd.exe and cscript.exe, Solaris: g++ is required
2929
License: GPL-2
3030
URL: http://rcppcore.github.io/RcppParallel, https://github.com/RcppCore/RcppParallel
31+
Biarch: TRUE
3132
Collate:
3233
'build.R'
3334
'hooks.R'

R/config/configure.R

Lines changed: 203 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,203 @@
1+
# utils.R ----
2+
3+
#' Configure a File
4+
#'
5+
#' Configure a file, replacing any instances of `@`-delimited variables, e.g.
6+
#' `@VAR@`, with the value of the variable called `VAR` in the associated
7+
#' `config` environment.
8+
#'
9+
#' @param source The file to be configured.
10+
#' @param target The file to be generated.
11+
#' @param config The configuration environment.
12+
#' @param verbose Boolean; report files as they are configured?
13+
#'
14+
#' @export
15+
configure_file <- function(
16+
source,
17+
target = sub("[.]in$", "", source),
18+
config = read_config(),
19+
verbose = getOption("configure.verbose", TRUE))
20+
{
21+
contents <- readLines(source, warn = FALSE)
22+
enumerate(config, function(key, val) {
23+
needle <- paste("@", key, "@", sep = "")
24+
replacement <- val
25+
contents <<- gsub(needle, replacement, contents)
26+
})
27+
28+
ensure_directory(dirname(target))
29+
writeLines(contents, con = target)
30+
31+
if (isTRUE(verbose)) {
32+
fmt <- "** configured file: '%s' => '%s'"
33+
message(sprintf(fmt, source, target))
34+
}
35+
}
36+
37+
#' Read R Configuration for a Package
38+
#'
39+
#' Read the \R configuration, as through `R CMD config --all`.
40+
#'
41+
#' @param package The path to an \R package's sources.
42+
#' @param values The \R configuration values to read (as a character vector).
43+
#' If `NULL` (the default), all values are read (as through `R CMD config --all`).
44+
#' @param verbose Boolean; notify the user as \R configuration is read?
45+
#'
46+
#' @export
47+
read_config <- function(
48+
package = ".",
49+
values = NULL,
50+
verbose = getOption("configure.verbose", TRUE))
51+
{
52+
# move to requested directory
53+
owd <- setwd(package)
54+
on.exit(setwd(owd), add = TRUE)
55+
R <- file.path(R.home("bin"), "R")
56+
57+
if (is.null(values)) {
58+
if (verbose)
59+
message("** executing 'R CMD config --all'")
60+
output <- system2(R, c("CMD", "config", "--all"), stdout = TRUE)
61+
equalsIndex <- regexpr("=", output, fixed = TRUE)
62+
keys <- trim_whitespace(substring(output, 1, equalsIndex - 1))
63+
config <- as.list(trim_whitespace(substring(output, equalsIndex + 1)))
64+
names(config) <- keys
65+
66+
} else {
67+
if (verbose)
68+
message("** executing 'R CMD config'")
69+
config <- lapply(values, function(value) {
70+
system2(R, c("CMD", "config", value), stdout = TRUE)
71+
})
72+
names(config) <- values
73+
}
74+
75+
list2env(config, parent = globalenv())
76+
}
77+
78+
#' Concatenate the Contents of a Set of Files
79+
#'
80+
#' Given a set of files, concatenate their contents into
81+
#' a single file.
82+
#'
83+
#' @param sources An \R list of files
84+
#' @param target The file to use for generation.
85+
#' @param headers Headers to be used for each file copied.
86+
#'
87+
#' @export
88+
concatenate_files <- function(
89+
sources,
90+
target,
91+
headers = sprintf("# %s ----", basename(sources)))
92+
{
93+
pieces <- vapply(seq_along(sources), function(i) {
94+
source <- sources[[i]]
95+
header <- headers[[i]]
96+
contents <- trim_whitespace(read_file(source))
97+
paste(header, contents, "", sep = "\n\n")
98+
}, character(1))
99+
100+
ensure_directory(dirname(target))
101+
writeLines(pieces, con = target)
102+
}
103+
104+
ensure_directory <- function(dir) {
105+
info <- file.info(dir)
106+
107+
# no file exists at this location; try to make it
108+
if (is.na(info$isdir)) {
109+
dir.create(info$isdir, recursive = TRUE, showWarnings = FALSE)
110+
if (!file.exists(dir))
111+
stop("failed to create directory '", dir, "'")
112+
return(TRUE)
113+
}
114+
115+
# a directory already exists
116+
if (isTRUE(info$isdir))
117+
return(TRUE)
118+
119+
# a file exists, but it's not a directory
120+
stop("file already exists at path '", dir, "'")
121+
}
122+
123+
enumerate <- function(x, f, ...) {
124+
nms <- if (is.environment(x)) ls(envir = x) else names(x)
125+
lapply(nms, function(nm) {
126+
f(nm, x[[nm]], ...)
127+
})
128+
}
129+
130+
read_file <- function(path) {
131+
paste(readLines(path, warn = FALSE), collapse = "\n")
132+
}
133+
trim_whitespace <- function(x) {
134+
gsub("^[[:space:]]*|[[:space:]]*$", "", x)
135+
}
136+
137+
138+
# use-configure.R ----
139+
140+
#' Add Configure Infrastructure to an R Package
141+
#'
142+
#' Add the infrastructure needed to configure an R package.
143+
#'
144+
#' @param package The path to the top-level directory of an \R package.
145+
#' @export
146+
use_configure <- function(package = ".") {
147+
148+
# find resources
149+
package <- normalizePath(package, winslash = "/")
150+
resources <- system.file("resources", package = "configure")
151+
152+
# copy into temporary directory
153+
dir <- tempfile("configure-")
154+
on.exit(unlink(dir, recursive = TRUE), add = TRUE)
155+
156+
dir.create(dir)
157+
file.copy(resources, dir, recursive = TRUE)
158+
159+
# rename resources directory
160+
owd <- setwd(dir)
161+
on.exit(setwd(owd), add = TRUE)
162+
file.rename(basename(resources), basename(package))
163+
164+
# now, copy these files back into the target directory
165+
file.copy(basename(package), dirname(package), recursive = TRUE)
166+
}
167+
168+
169+
# run-configure.R ----
170+
171+
# figure out the current package's name
172+
DESCRIPTION <- read.dcf("DESCRIPTION", all = TRUE)
173+
fmt <- "* configuring package '%s' ..."
174+
message(sprintf(fmt, DESCRIPTION$Package))
175+
176+
# overlay user configuration
177+
envir <- new.env(parent = globalenv())
178+
files <- list.files("R/config/scripts", pattern = "[.][rR]$", full.names = TRUE)
179+
for (file in files) {
180+
fmt <- "** sourcing '%s'"
181+
message(sprintf(fmt, file))
182+
source(file, local = envir)
183+
}
184+
185+
# apply configure script (if any)
186+
config <- list()
187+
if (exists("configure", envir = envir, inherits = FALSE)) {
188+
configure <- get("configure", envir = envir, inherits = FALSE)
189+
message("** executing user-defined configure script")
190+
config <- configure()
191+
}
192+
193+
# configure .in files
194+
inputs <- getOption("configure.inputs", default = {
195+
list.files(c("R", "src"), pattern = "[.]in$", full.names = TRUE)
196+
})
197+
for (input in inputs)
198+
configure_file(input, config = config, verbose = TRUE)
199+
200+
fmt <- "* successfully configured package '%s'"
201+
message(sprintf(fmt, DESCRIPTION$Package))
202+
203+

R/config/scripts/variables.R

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
configure <- function() {
2+
3+
if (getRversion() < "3.4.0") {
4+
config <- list(
5+
CC = "$(CC)",
6+
CXX11 = "$(CXX1X)",
7+
CXX11STD = "$(CXX1XSTD)",
8+
CXX11PICFLAGS = "$(CXX1XPICFLAGS)"
9+
)
10+
} else {
11+
config <- list(
12+
CC = "$(CC)",
13+
CXX11 = "$(CXX11)",
14+
CXX11STD = "$(CXX11STD)",
15+
CXX11PICFLAGS = "$(CXX11PICFLAGS)"
16+
)
17+
}
18+
19+
config$STDVER <- "c++11"
20+
21+
config
22+
}

0 commit comments

Comments
 (0)