Introduction
This article is for R package developers who want to use the HDF5 C
library in their own package. hdf5lib makes this easy by
providing a reliable, self-contained HDF5 build that you can link to
without requiring your users to install any system dependencies.
We will walk through the three main steps to link your package to
hdf5lib and then demonstrate a complete example using
Rcpp.
The 3 Steps to Link Your Package
To use hdf5lib in your package, you need to:
- Declare the dependency in your
DESCRIPTIONfile. - Tell the compiler where to find the
hdf5libheaders and libraries in asrc/Makevarsfile. - Include the HDF5 headers in your C/C++ code.
Step 1: Update DESCRIPTION
Add hdf5lib to the LinkingTo field in your
DESCRIPTION file. This tells R that your package needs to
access header files from hdf5lib.
(We’ve also added Rcpp because we’ll use it in our
example below.)
Step 2: Create src/Makevars
Create a file named Makevars inside your package’s
src/ directory. This file provides instructions to the
compiler. hdf5lib provides two helper functions,
c_flags() and ld_flags(), that output the
exact strings needed.
Add the following lines to src/Makevars:
# Get compiler flags (e.g., -I/path/to/headers)
PKG_CPPFLAGS = `$(R_HOME)/bin/Rscript -e "cat(hdf5lib::c_flags(api = 200))"`
# Get linker flags (e.g., -L/path/to/libs -lhdf5)
PKG_LIBS = `$(R_HOME)/bin/Rscript -e "cat(hdf5lib::ld_flags(api = 200))"`The api argument shown here offers a powerful stability
feature. By locking your package to a specific HDF5 API version (e.g.,
api = 200), you ensure that future updates to
hdf5lib will not introduce breaking changes. This gives you
control over when to adopt newer HDF5 features. For a detailed
explanation of API versioning, see the API
Versioning article.
Example: Creating a Package with Rcpp
Let’s create a minimal R package that uses Rcpp to
provide one function: get_hdf5_version(), which calls the
HDF5 C library and returns its version string.
Package Structure
First, create a new package. You can use
Rcpp::Rcpp.package.skeleton("myhdf5package") as a starting
point. The file structure will look like this:
myhdf5package/
├── DESCRIPTION
├── NAMESPACE
├── R/
│ └── RcppExports.R
├── src/
│ ├── Makevars
│ ├── RcppExports.cpp
│ └── hdf5_helpers.cpp // Our new C++ file
└── man/
C++ Source Code (src/hdf5_helpers.cpp)
This file contains the C++ function that will be callable from R. It
uses H5get_libversion to query the library version and
returns it as a string.
#include <Rcpp.h>
#include <hdf5.h>
#include <string>
#include <vector>
//' Get the version of the linked HDF5 library
//'
//' This function calls the HDF5 C API to retrieve the library version
//' and returns it as a character string (e.g., "2.0.0").
//' @export
// [[Rcpp::export]]
Rcpp::String get_hdf5_version() {
unsigned int majnum, minnum, relnum;
// Call the HDF5 C function
herr_t status = H5get_libversion(&majnum, &minnum, &relnum);
if (status < 0) {
Rcpp::stop("Failed to get HDF5 library version.");
}
// Format the version string
std::vector<char> version_str(20);
snprintf(version_str.data(), version_str.size(), "%u.%u.%u", majnum, minnum, relnum);
return Rcpp::String(version_str.data());
}Build and Run
- Run
Rcpp::compileAttributes()to generate the Rcpp export files (R/RcppExports.Randsrc/RcppExports.cpp). - Build and install your package using
devtools::install()or by building a source tarball.
Now, you can use your new function from R:
library(myhdf5package)
get_hdf5_version()
#> "2.0.0"This simple example demonstrates that your package is successfully
linking to hdf5lib and can call its functions. You can now
build more complex functionality by expanding on this foundation.
