Skip to content

Commit ffabb43

Browse files
authored
Provide access to TileDB shared libraries in downstream packages (#782)
New helper function to provide access to `libtiledb` used by tiledb-r for downstream packages. This builds off the prototype code @LTLA provided New functions provided: - `.pkg_config()`: provide compiler flags for linking to the version of `libtiledb` that tiledb-r either vendors or links to at the system level - `.core_info()`: provides a vector with the `libtiledb` version and install type (eg. `"vendored"`, `"system"`) - `.core_hash()`: provides the same information as `.core_info()`, but as an MD5 hash Also includes a mini-test suite for CI that tests this functionality with both a system install and vendored install of `libtiledb` [SC-59185](https://app.shortcut.com/tiledb-inc/story/59185/) resolves #780 * Update windows install to include libtiledb source * Clean up comments * Better Windows support * Add tests for .pkg_config() * Add utility functions to check version of libtiledb a package was built with vs version package is loaded with * Rename `R/Init.R` to `R/zzz.R` * Add quoting for Windows * Update changelog Bump develop version
1 parent de4f684 commit ffabb43

File tree

14 files changed

+504
-12
lines changed

14 files changed

+504
-12
lines changed

.github/workflows/pkgconfig.yaml

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
on:
2+
push:
3+
pull_request:
4+
5+
name: pkgconfig
6+
7+
permissions: read-all
8+
9+
jobs:
10+
pkgconfig:
11+
runs-on: ${{ matrix.os }}
12+
name: ${{ matrix.os }} (r-${{ matrix.r }}) (${{ matrix.vendored }} libtiledb)
13+
14+
strategy:
15+
fail-fast: false
16+
matrix:
17+
os:
18+
- ubuntu-latest
19+
r:
20+
- release
21+
# - devel
22+
vendored:
23+
- 'vendored'
24+
- 'system'
25+
include:
26+
- os: ubuntu-latest
27+
use-public-rspm: true
28+
# - os: ubuntu-latest
29+
# r: devel
30+
# http-user-agent: 'release'
31+
exclude:
32+
- os: macos-latest
33+
r: devel
34+
35+
env:
36+
GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }}
37+
R_KEEP_PKG_SOURCE: yes
38+
_R_CHECK_FORCE_SUGGESTS_: "FALSE"
39+
_R_TILEDB_LIBTILEDB_: ${{ matrix.vendored }}
40+
41+
steps:
42+
- uses: actions/checkout@v4
43+
44+
- uses: r-lib/actions/setup-pandoc@v2
45+
46+
- uses: r-lib/actions/setup-r@v2
47+
with:
48+
r-version: ${{ matrix.r }}
49+
http-user-agent: ${{ matrix.http-user-agent }}
50+
use-public-rspm: ${{ matrix.use-public-rspm }}
51+
52+
- name: Setup libtiledb
53+
if: ${{ matrix.vendored == 'system' }}
54+
run: |
55+
VERSION=$(grep version tools/tiledbVersion.txt | cut -f 2 -d ':' | tr -d '[:space:]')
56+
SHA=$(grep sha tools/tiledbVersion.txt | cut -f 2 -d ':' | tr -d '[:space:]')
57+
URL="https://github.com/TileDB-Inc/TileDB/releases/download/${VERSION}/tiledb-linux-x86_64-${VERSION}-${SHA}.tar.gz"
58+
mkdir -vp libtiledb
59+
cd libtiledb
60+
wget -O libtiledb.tar.gz ${URL}
61+
tar -xvzf libtiledb.tar.gz
62+
/usr/bin/sudo cp -Rv include/* /usr/local/include/
63+
/usr/bin/sudo cp -Rv lib/* /usr/local/lib/
64+
cd ..
65+
rm -rfv libtiledb
66+
sudo ldconfig
67+
68+
- uses: r-lib/actions/setup-r-dependencies@v2
69+
with:
70+
extra-packages: local::.
71+
72+
- name: Test tiledb::.pkg_config()
73+
run: Rscript tests/pkgconfig-test.R

DESCRIPTION

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
Package: tiledb
22
Type: Package
3-
Version: 0.30.2.3
3+
Version: 0.30.2.4
44
Title: Modern Database Engine for Complex Data Based on Multi-Dimensional Arrays
55
Authors@R: c(
66
person("TileDB, Inc.", role = c("aut", "cph")),
@@ -24,7 +24,13 @@ SystemRequirements: A C++17 compiler is required; on macOS compilation version 1
2424
build selected); on x86_64 and M1 platforms pre-built TileDB Embedded libraries
2525
are available at GitHub and are used if no TileDB installation is detected, and
2626
no other option to build or download was specified by the user.
27-
Imports: methods, Rcpp (>= 1.0.8), nanotime, spdl, nanoarrow
27+
Imports:
28+
methods,
29+
Rcpp (>= 1.0.8),
30+
nanotime,
31+
spdl,
32+
nanoarrow,
33+
tools
2834
LinkingTo: Rcpp, RcppInt64, nanoarrow
2935
Suggests: tinytest, simplermarkdown, curl, bit64, Matrix, palmerpenguins, nycflights13, data.table, tibble, arrow
3036
VignetteBuilder: simplermarkdown

NAMESPACE

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@ export("return_as<-")
2424
export("selected_points<-")
2525
export("selected_ranges<-")
2626
export("strings_as_factors<-")
27+
export(.core_hash)
28+
export(.core_info)
29+
export(.pkg_config)
2730
export(allows_dups)
2831
export(array_consolidate)
2932
export(array_vacuum)

NEWS.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
* Support parentheses in query conditions
77
* memory alloc: Accomodate zero buffer size estimate v2
88
* Apply `styler::style_pkg()`
9+
* Expose include/linking flags for re-using `libtiledb` in downstream packages
910

1011
# tiledb 0.30.2
1112

R/Version.R

Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,3 +41,170 @@ tiledb_version <- function(compact = FALSE) {
4141
libtiledb_version()
4242
}
4343
}
44+
45+
#' \code{libtiledb} Information
46+
#'
47+
#' Get version and install information of the core \code{libtiledb} install
48+
#'
49+
#' @section Checking the \code{libtiledb} information in downstream packages:
50+
#' These functions are designed to make it easy to test if the core
51+
#' \code{libtiledb} install has changed. This is accomplished by adding a
52+
#' build-time constant to cache the version of \code{libtiledb} was built with.
53+
#' For example, in \code{zzz.R}, put the following line to cache the
54+
#' \code{libtiledb} information during package build
55+
#' \preformatted{
56+
#' .built_with <- list(libtiledb = tiledb::.core_hash())
57+
#' }
58+
#' Then, in the \link[base:ns-hooks]{load hook}, add the following check
59+
#' \preformatted{
60+
#' .onLoad <- function(libname, pkgname) {
61+
#' if (.built_with$libtiledb != tiledb::.core_hash()) {
62+
#' warning("Core libtiledb has changed, please reinstall ", pkgname)
63+
#' }
64+
#' }
65+
#' }
66+
#' This will throw a warning if \pkg{tiledb}, and therefore \code{libtiledb},
67+
#' has changed between downstream package install and load
68+
#'
69+
#' @return \code{.core_info()}: A named character vector with the following entries:
70+
#' \itemize{
71+
#' \item \dQuote{\code{version}}: \code{libtiledb} version
72+
#' \item \dQuote{\code{libtype}}: type of \code{libtiledb} install; will be one
73+
#' of \dQuote{\code{vendored}}, \dQuote{\code{system}}, or \dQuote{\code{unknown}}
74+
#' }
75+
#'
76+
#' @keywords internal
77+
#'
78+
#' @export
79+
#'
80+
#' @examples
81+
#' .core_info()
82+
#'
83+
.core_info <- function() {
84+
info <- c(
85+
version = as.character(tiledb_version(TRUE)),
86+
libtype = character(1L)
87+
)
88+
lib <- system.file(
89+
"tiledb",
90+
package = .pkgenv$pkgname,
91+
lib.loc = .pkgenv$libname
92+
)
93+
if (nzchar(lib)) {
94+
info['libtype'] <- 'vendored'
95+
return(info)
96+
}
97+
if (nzchar(pkgconfig <- Sys.which("pkg-config"))) {
98+
if (!system2(pkgconfig, args = c("--exists", "tiledb"))) {
99+
info['libtype'] <- 'system'
100+
return(info)
101+
}
102+
}
103+
info['libtype'] <- 'unknown'
104+
return(info)
105+
}
106+
107+
#' @return \code{.core_hash()}: The \link[tools:md5sum]{MD5 hash} of the core info
108+
#'
109+
#' @rdname dot-core_info
110+
#'
111+
#' @export
112+
#'
113+
#' @examples
114+
#' .core_hash()
115+
#'
116+
.core_hash <- function() {
117+
tmp <- tempfile()
118+
on.exit(file.remove(tmp), add = TRUE, after = FALSE)
119+
info <- .core_info()
120+
writeLines(paste(names(info), info, sep = ':\t', collapse = '\n'), con = tmp)
121+
return(unname(tools::md5sum(tmp)))
122+
}
123+
124+
#' Compiler Arguments for Using \code{libtiledb}
125+
#'
126+
#' Get compiler flags for using the core \code{libtiledb} install
127+
#' used by \pkg{tiledb}
128+
#'
129+
#' @param opt A single character value with the package configuration variable
130+
#' to fetch; choose from
131+
#' \itemize{
132+
#' \item \dQuote{\code{PKG_CXX_FLAGS}}: compiler flags for \code{libtiledb}
133+
#' \item \dQuote{\code{PKG_CXX_LIBS}}: linking flags for \code{libtiledb}
134+
#' }
135+
#'
136+
#' @return A single string containing either the include directories or linking
137+
#' directories for \code{libtiledb}
138+
#'
139+
#' @keywords internal
140+
#'
141+
#' @export
142+
#'
143+
#' @examples
144+
#' .pkg_config()
145+
#' .pkg_config("PKG_CXX_LIBS")
146+
#'
147+
.pkg_config <- function(opt = c("PKG_CXX_FLAGS", "PKG_CXX_LIBS")) {
148+
opt <- match.arg(opt)
149+
lib <- system.file(
150+
"tiledb",
151+
package = .pkgenv$pkgname,
152+
lib.loc = .pkgenv$libname
153+
)
154+
if (nzchar(lib)) {
155+
pkgdir <- system.file(package = .pkgenv$pkgname, lib.loc = .pkgenv$libname)
156+
return(switch(
157+
EXPR = opt,
158+
PKG_CXX_FLAGS = switch(
159+
EXPR = .Platform$OS.type,
160+
# Adapted from Makevars.win, which includes libdir/include/tiledb in
161+
# addition to libdir/include and pkgdir/include
162+
windows = sprintf(
163+
"-I%s/include -I%s/include -I%s/include/tiledb",
164+
shQuote(pkgdir, type = "cmd"),
165+
shQuote(lib, type = "cmd"),
166+
shQuote(lib, type = "cmd")
167+
),
168+
sprintf("-I%s/include -I%s/include", pkgdir, lib)
169+
),
170+
PKG_CXX_LIBS = switch(
171+
EXPR = .Platform$OS.type,
172+
# rwinlib-tiledb is structured slightly differently than libtiledb for
173+
# Unix-alikes; R 4.2 and higher require ucrt
174+
windows = {
175+
arch <- .Platform$r_arch
176+
libs <- as.vector(vapply(
177+
c(pkgdir, lib),
178+
FUN = \(x) c(
179+
sprintf("%s/lib/%s", shQuote(x, type = "cmd"), arch),
180+
ifelse(
181+
test = getRversion() > '4.2.0',
182+
yes = sprintf("%s/lib/%s-ucrt", shQuote(x, type = "cmd"), arch),
183+
no = ""
184+
)
185+
),
186+
FUN.VALUE = character(2L),
187+
USE.NAMES = FALSE
188+
))
189+
paste('-ltiledb', paste0('-L', Filter(dir.exists, libs), collapse = ' '))
190+
},
191+
sprintf("-ltiledb -L%s/lib -L%s/lib", pkgdir, lib)
192+
)
193+
))
194+
}
195+
if (nzchar(pkgconfig <- Sys.which("pkg-config"))) {
196+
if (!system2(pkgconfig, args = c("--exists", "tiledb"))) {
197+
flag <- switch(
198+
EXPR = opt,
199+
PKG_CXX_FLAGS = "--cflags",
200+
PKG_CXX_LIBS = "--libs"
201+
)
202+
return(trimws(system2(pkgconfig, args = c(flag, "tiledb"), stdout = TRUE)))
203+
}
204+
}
205+
return(switch(
206+
EXPR = opt,
207+
PKG_CXX_FLAGS = "",
208+
PKG_CXX_LIBS = "-ltiledb"
209+
))
210+
}

R/Init.R renamed to R/zzz.R

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,10 @@
5353
## set a preference for allocation size defaults
5454
.pkgenv[["allocation_size"]] <- load_allocation_size_preference()
5555

56+
# cache package name and path
57+
.pkgenv[["pkgname"]] <- pkgname
58+
.pkgenv[["libname"]] <- libname
59+
5660
## call setter for Rcpp plugin support
5761
.set_compile_link_options()
5862

@@ -121,7 +125,6 @@ inlineCxxPlugin <- function(...) {
121125
}
122126
}
123127

124-
125128
#' @importFrom utils read.table
126129
.getLinuxFlavor <- function() {
127130
res <- NA_character_

TileDB-R.Rproj

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@ Encoding: UTF-8
1212
RnwWeave: Sweave
1313
LaTeX: pdfLaTeX
1414

15+
AutoAppendNewline: Yes
16+
StripTrailingWhitespace: Yes
17+
1518
BuildType: Package
1619
PackageUseDevtools: Yes
1720
PackageInstallArgs: --no-multiarch --with-keep.source --install-tests
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
2+
if (!at_home()) {
3+
exit_file("'.pkg_config()' tests run at home")
4+
}
5+
6+
libtype <- Sys.getenv("_R_TILEDB_LIBTILEDB_")
7+
if (nzchar(libtype)) {
8+
expect_true(
9+
libtype %in% c("system", "vendored"),
10+
info = "`Sys.getenv('_R_TILEDB_LIBTILEDB_')` must be 'system' or 'vendored'"
11+
)
12+
}
13+
14+
# Check .core_info()
15+
expect_inherits(
16+
info <- .core_info(),
17+
class = "character",
18+
info = "'.core_info()' returns a character vector"
19+
)
20+
expect_length(info, length = 2L, info = "'.core_info()' returns a two-length vector")
21+
expect_identical(
22+
names(info),
23+
target = c("version", "libtype"),
24+
info = "'.core_info()' returns a named vector with names of 'version' and 'libtype'"
25+
)
26+
expect_identical(
27+
info[["version"]],
28+
target = as.character(tiledb_version(compact = TRUE)),
29+
info = "'.core_info()' returns the correct core version"
30+
)
31+
libtarget <- ifelse(nzchar(libtype), yes = libtype, no = "unknown")
32+
expect_identical(
33+
info[["libtype"]],
34+
target = libtarget,
35+
info = sprintf("'.core_info()' returns the correct libtype ('%s')", libtarget)
36+
)
37+
38+
# Check .core_hash()
39+
tmpfile <- tempfile(tmpdir = tempdir(check = TRUE))
40+
writeLines(
41+
sprintf(
42+
"version:\t%s\nlibtype:\t%s",
43+
as.character(tiledb_version(compact = TRUE)),
44+
ifelse(nzchar(libtype), yes = libtype, no = "unknown")
45+
),
46+
con = tmpfile
47+
)
48+
target <- unname(tools::md5sum(tmpfile))
49+
hash <- .core_hash()
50+
expect_inherits(
51+
hash,
52+
class = "character",
53+
info = "'.core_hash()' returns a character value"
54+
)
55+
expect_length(hash, length = 1L, info = "'.core_hash()' returns a single value")
56+
expect_null(names(hash), info = "'.core_hash()' returns an unnamed value")
57+
expect_identical(
58+
hash,
59+
target = target,
60+
info = "'.core_hash()' returns the correct hash value"
61+
)

0 commit comments

Comments
 (0)