Skip to content

Commit bd5d79b

Browse files
authored
Merge branch 'main' into testthat3e
2 parents 127e700 + e62c914 commit bd5d79b

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

72 files changed

+4083
-1584
lines changed

.github/workflows/R-CMD-check.yaml

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,20 +24,21 @@ jobs:
2424
fail-fast: false
2525
matrix:
2626
config:
27+
- {os: macos-13, r: 'oldrel'}
2728
- {os: macos-latest, r: 'release'}
2829

2930
- {os: windows-latest, r: 'release'}
3031
# use 4.1 to check with rtools40's older compiler
3132
- {os: windows-latest, r: '4.1'}
3233

3334
# Use older ubuntu to maximise backward compatibility
34-
- {os: ubuntu-20.04, r: 'devel', http-user-agent: 'release'}
35-
- {os: ubuntu-20.04, r: 'release'}
36-
- {os: ubuntu-20.04, r: 'release', custom: 'no-cpp11test'}
37-
- {os: ubuntu-20.04, r: 'oldrel-1'}
38-
- {os: ubuntu-20.04, r: 'oldrel-2'}
39-
- {os: ubuntu-20.04, r: 'oldrel-3'}
40-
- {os: ubuntu-20.04, r: 'oldrel-4'}
35+
- {os: ubuntu-22.04, r: 'devel', http-user-agent: 'release'}
36+
- {os: ubuntu-22.04, r: 'release'}
37+
- {os: ubuntu-22.04, r: 'release', custom: 'no-cpp11test'}
38+
- {os: ubuntu-22.04, r: 'oldrel-1'}
39+
- {os: ubuntu-22.04, r: 'oldrel-2'}
40+
- {os: ubuntu-22.04, r: 'oldrel-3'}
41+
- {os: ubuntu-22.04, r: 'oldrel-4'}
4142

4243
env:
4344
GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }}

.github/workflows/format.yaml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,15 @@ name: format_check
99

1010
jobs:
1111
format_check:
12-
runs-on: ubuntu-20.04
12+
runs-on: ubuntu-22.04
1313
steps:
1414
- uses: actions/checkout@v2
1515

1616
- name: Install ClangFormat
17-
run: sudo apt-get install -y clang-format-10
17+
run: sudo apt-get install -y clang-format-12
1818

1919
- name: Run ClangFormat
20-
run: make format clang_format=clang-format-10
20+
run: make format clang_format=clang-format-12
2121

2222
- name: Check for a non-empty diff
2323
run: git diff-files -U --exit-code

DESCRIPTION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
Package: cpp11
22
Title: A C++11 Interface for R's C Interface
3-
Version: 0.5.1.9000
3+
Version: 0.6.0.9000
44
Authors@R:
55
c(
66
person("Davis", "Vaughan", email = "[email protected]", role = c("aut", "cre"), comment = c(ORCID = "0000-0003-4777-038X")),

NAMESPACE

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,5 @@ export(cpp_eval)
44
export(cpp_function)
55
export(cpp_register)
66
export(cpp_source)
7+
export(cpp_unvendor)
78
export(cpp_vendor)

NEWS.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
11
# cpp11 (development version)
22

3+
# cpp11 0.5.2
4+
5+
* Fixed an issue related to `-Wdeprecated-literal-operator` (#447, @andrjohns).
6+
37
# cpp11 0.5.1.9000
48

59
* Uses testthat 3e style tests (#402).
610
* Removes the mockery dependence.
711
* The vendoring function accepts a custom path (i.e., to use the GitHub version of the package)
8-
*
12+
913
# cpp11 0.5.1
1014

1115
* cpp11 now requires R >=4.0.0, in line with the

R/register.R

Lines changed: 52 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -77,17 +77,16 @@ cpp_register <- function(path = ".", quiet = !is_interactive(), extension = c(".
7777
cli::cli_alert_success("generated file {.file {basename(r_path)}}")
7878
}
7979

80-
8180
call_entries <- get_call_entries(path, funs$name, package)
8281

8382
cpp_function_registration <- glue::glue_data(funs, ' {{
8483
"_cpp11_{name}", (DL_FUNC) &_{package}_{name}, {n_args}}}, ',
8584
n_args = viapply(funs$args, nrow)
8685
)
8786

88-
cpp_function_registration <- glue::glue_collapse(cpp_function_registration, sep = "\n")
87+
cpp_function_registration <- glue::glue_collapse(cpp_function_registration, sep = "\n")
8988

90-
extra_includes <- character()
89+
extra_includes <- character()
9190
if (pkg_links_to_rcpp(path)) {
9291
extra_includes <- c(extra_includes, "#include <cpp11/R.hpp>", "#include <Rcpp.h>", "using namespace Rcpp;")
9392
}
@@ -215,35 +214,75 @@ generate_init_functions <- function(funs) {
215214
}
216215

217216
generate_r_functions <- function(funs, package = "cpp11", use_package = FALSE) {
218-
funs <- funs[c("name", "return_type", "args")]
217+
funs <- funs[c("name", "return_type", "args", "file", "line", "decoration")]
219218

220219
if (use_package) {
221220
package_call <- glue::glue(', PACKAGE = "{package}"')
222221
package_names <- glue::glue_data(funs, '"_{package}_{name}"')
223222
} else {
224-
package_names <- glue::glue_data(funs, '`_{package}_{name}`')
223+
package_names <- glue::glue_data(funs, "`_{package}_{name}`")
225224
package_call <- ""
226225
}
227226

228-
funs$package <- package
229227
funs$package_call <- package_call
230228
funs$list_params <- vcapply(funs$args, glue_collapse_data, "{name}")
231229
funs$params <- vcapply(funs$list_params, function(x) if (nzchar(x)) paste0(", ", x) else x)
232230
is_void <- funs$return_type == "void"
233231
funs$calls <- ifelse(is_void,
234-
glue::glue_data(funs, 'invisible(.Call({package_names}{params}{package_call}))'),
235-
glue::glue_data(funs, '.Call({package_names}{params}{package_call})')
232+
glue::glue_data(funs, "invisible(.Call({package_names}{params}{package_call}))"),
233+
glue::glue_data(funs, ".Call({package_names}{params}{package_call})")
236234
)
237235

238-
out <- glue::glue_data(funs, '
239-
{name} <- function({list_params}) {{
240-
{calls}
241-
}}
242-
')
236+
# Parse and associate Roxygen comments
237+
funs$roxygen_comment <- mapply(function(file, line) {
238+
if (file.exists(file)) {
239+
comments <- extract_roxygen_comments(file)
240+
matched_comment <- ""
241+
for (comment in comments) {
242+
# Check if the comment directly precedes the function without gaps
243+
if (line == comment$line + 1) {
244+
matched_comment <- comment$text
245+
break
246+
}
247+
}
248+
matched_comment
249+
} else {
250+
""
251+
}
252+
}, funs$file, funs$line, SIMPLIFY = TRUE)
253+
254+
# Generate R functions with or without Roxygen comments
255+
out <- mapply(function(name, list_params, calls, roxygen_comment) {
256+
if (nzchar(roxygen_comment)) {
257+
glue::glue("{roxygen_comment}\n{name} <- function({list_params}) {{\n\t{calls}\n}}")
258+
} else {
259+
glue::glue("{name} <- function({list_params}) {{\n {calls}\n}}")
260+
}
261+
}, funs$name, funs$list_params, funs$calls, funs$roxygen_comment, SIMPLIFY = TRUE)
262+
263+
out <- glue::trim(out)
243264
out <- glue::glue_collapse(out, sep = "\n\n")
244265
unclass(out)
245266
}
246267

268+
extract_roxygen_comments <- function(file) {
269+
lines <- readLines(file)
270+
roxygen_start <- grep("^/\\* roxygen start", lines)
271+
roxygen_end <- grep("roxygen end \\*/$", lines)
272+
273+
if (length(roxygen_start) == 0 || length(roxygen_end) == 0) {
274+
return(list())
275+
}
276+
277+
roxygen_comments <- mapply(function(start, end) {
278+
roxygen_lines <- lines[(start + 1):(end - 1)]
279+
roxygen_lines <- sub("^", "#' ", roxygen_lines)
280+
list(line = end, text = paste(roxygen_lines, collapse = "\n"))
281+
}, roxygen_start, roxygen_end, SIMPLIFY = FALSE)
282+
283+
roxygen_comments
284+
}
285+
247286
wrap_call <- function(name, return_type, args) {
248287
call <- glue::glue('{name}({list_params})', list_params = glue_collapse_data(args, "cpp11::as_cpp<cpp11::decay_t<{type}>>({name})"))
249288
if (return_type == "void") {

R/source.R

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,13 @@
1818
#' uses 'CXX11' if unset.
1919
#' @param dir The directory to store the generated source files. `tempfile()` is
2020
#' used by default. The directory will be removed if `clean` is `TRUE`.
21+
#' @param local Passed to [dyn.load()]. If `TRUE` (the default) the shared
22+
#' library is loaded with local symbols; if `FALSE` symbols are made global
23+
#' (equivalent to `dyn.load(..., local = FALSE)`), which can be required when
24+
#' other shared objects need to see RTTI/vtable symbols from this library.
25+
#' @note See the unit test that demonstrates this usage at
26+
#' \code{tests/testthat/test-source-local.R} (shows how `local = FALSE` exports
27+
#' the necessary symbols so separate shared objects can link against them).
2128
#' @return For [cpp_source()] and `[cpp_function()]` the results of
2229
#' [dyn.load()] (invisibly). For `[cpp_eval()]` the results of the evaluated
2330
#' expression.
@@ -65,7 +72,7 @@
6572
#' }
6673
#'
6774
#' @export
68-
cpp_source <- function(file, code = NULL, env = parent.frame(), clean = TRUE, quiet = TRUE, cxx_std = Sys.getenv("CXX_STD", "CXX11"), dir = tempfile()) {
75+
cpp_source <- function(file, code = NULL, env = parent.frame(), clean = TRUE, quiet = TRUE, cxx_std = Sys.getenv("CXX_STD", "CXX11"), dir = tempfile(), local = TRUE) {
6976
stop_unless_installed(c("brio", "callr", "cli", "decor", "desc", "glue", "tibble", "vctrs"))
7077
if (!missing(file) && !file.exists(file)) {
7178
stop("Can't find `file` at this path:\n", file, "\n", call. = FALSE)
@@ -145,7 +152,7 @@ cpp_source <- function(file, code = NULL, env = parent.frame(), clean = TRUE, qu
145152
brio::write_lines(r_functions, r_path)
146153
source(r_path, local = env)
147154

148-
dyn.load(shared_lib, local = TRUE, now = TRUE)
155+
dyn.load(shared_lib, local = local, now = TRUE)
149156
}
150157

151158
the <- new.env(parent = emptyenv())
@@ -186,7 +193,7 @@ generate_makevars <- function(includes, cxx_std) {
186193

187194
#' @rdname cpp_source
188195
#' @export
189-
cpp_function <- function(code, env = parent.frame(), clean = TRUE, quiet = TRUE, cxx_std = Sys.getenv("CXX_STD", "CXX11")) {
196+
cpp_function <- function(code, env = parent.frame(), clean = TRUE, quiet = TRUE, cxx_std = Sys.getenv("CXX_STD", "CXX11"), local = TRUE) {
190197
cpp_source(code = paste(c('#include "cpp11.hpp"',
191198
"using namespace ::cpp11;",
192199
"namespace writable = ::cpp11::writable;",
@@ -196,15 +203,16 @@ cpp_function <- function(code, env = parent.frame(), clean = TRUE, quiet = TRUE,
196203
env = env,
197204
clean = clean,
198205
quiet = quiet,
199-
cxx_std = cxx_std
206+
cxx_std = cxx_std,
207+
local = local
200208
)
201209
}
202210

203211
utils::globalVariables("f")
204212

205213
#' @rdname cpp_source
206214
#' @export
207-
cpp_eval <- function(code, env = parent.frame(), clean = TRUE, quiet = TRUE, cxx_std = Sys.getenv("CXX_STD", "CXX11")) {
215+
cpp_eval <- function(code, env = parent.frame(), clean = TRUE, quiet = TRUE, cxx_std = Sys.getenv("CXX_STD", "CXX11"), local = TRUE) {
208216
cpp_source(code = paste(c('#include "cpp11.hpp"',
209217
"using namespace ::cpp11;",
210218
"namespace writable = ::cpp11::writable;",
@@ -217,7 +225,8 @@ cpp_eval <- function(code, env = parent.frame(), clean = TRUE, quiet = TRUE, cxx
217225
env = env,
218226
clean = clean,
219227
quiet = quiet,
220-
cxx_std = cxx_std
228+
cxx_std = cxx_std,
229+
local = local
221230
)
222231
f()
223232
}

R/unvendor.R

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
#' Unvendor the cpp11 dependency
2+
#'
3+
#' This function removes the vendored cpp11 headers from your package and
4+
#' restores the `LinkingTo: cpp11` field in the DESCRIPTION file if it was removed.
5+
#'
6+
#' @inheritParams cpp_register
7+
#' @return The file path to the unvendored code (invisibly).
8+
#' @export
9+
#' @examples
10+
#' # create a new directory
11+
#' dir <- tempfile()
12+
#' dir.create(dir)
13+
#'
14+
#' # vendor the cpp11 headers into the directory
15+
#' cpp_vendor(dir)
16+
#'
17+
#' # unvendor the cpp11 headers from the directory
18+
#' cpp_unvendor(dir)
19+
#'
20+
#' list.files(file.path(dir, "inst", "include", "cpp11"))
21+
#'
22+
#' # cleanup
23+
#' unlink(dir, recursive = TRUE)
24+
cpp_unvendor <- function(path = ".") {
25+
new <- file.path(path, "inst", "include", "cpp11")
26+
27+
if (!dir.exists(new)) {
28+
stop("'", new, "' does not exist", call. = FALSE)
29+
}
30+
31+
unlink(new, recursive = TRUE)
32+
33+
cpp11_hpp <- file.path(dirname(new), "cpp11.hpp")
34+
if (file.exists(cpp11_hpp)) {
35+
unlink(cpp11_hpp)
36+
}
37+
38+
invisible(new)
39+
}

R/vendor.R

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,8 @@ cpp_vendor <- function(path = ".", headers = system.file("include", "cpp11", pac
3838
new <- file.path(path, "inst", "include", "cpp11")
3939

4040
if (dir.exists(new)) {
41-
stop("'", new, "' already exists\n * run unlink('", new, "', recursive = TRUE)", call. = FALSE)
41+
message("'", new, "' already exists, removing it")
42+
cpp_unvendor(path)
4243
}
4344

4445
dir.create(new , recursive = TRUE, showWarnings = FALSE)

README.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,3 +78,13 @@ Please note that the cpp11 project is released with a [Contributor Code of Condu
7878

7979
cpp11 would not exist without Rcpp.
8080
Thanks to the Rcpp authors, Dirk Eddelbuettel, Romain Francois, JJ Allaire, Kevin Ushey, Qiang Kou, Nathan Russell, Douglas Bates and John Chambers for their work writing and maintaining Rcpp.
81+
82+
## Clang format
83+
84+
To match GHA, use clang-format-12 to format C++ code. With systems that provide clang-format-14 or newer, you can use Docker:
85+
86+
```bash
87+
docker run --rm -v "$PWD":/work -w /work ubuntu:22.04 bash -lc "\
88+
apt-get update && apt-get install -y clang-format-12 && \
89+
find . -name '*.cpp' -o -name '*.hpp' -o -name '*.h' | xargs -r clang-format-12 -i"
90+
```

0 commit comments

Comments
 (0)