pkgbuild/ 0000755 0001762 0000144 00000000000 14535342146 012062 5 ustar ligges users pkgbuild/NAMESPACE 0000644 0001762 0000144 00000001376 14527147040 013305 0 ustar ligges users # Generated by roxygen2: do not edit by hand
export(build)
export(check_build_tools)
export(check_compiler)
export(check_latex)
export(check_rtools)
export(clean_dll)
export(compile_dll)
export(compiler_flags)
export(find_rtools)
export(has_build_tools)
export(has_compiler)
export(has_devel)
export(has_latex)
export(has_rtools)
export(local_build_tools)
export(needs_compile)
export(pkg_has_src)
export(pkg_links_to_cpp11)
export(pkg_links_to_rcpp)
export(pkgbuild_process)
export(rcmd_build_tools)
export(rtools_needed)
export(rtools_path)
export(setup_rtools)
export(with_build_tools)
export(with_debug)
export(with_latex)
export(without_cache)
export(without_compiler)
export(without_latex)
importFrom(R6,R6Class)
importFrom(utils,head)
importFrom(utils,tail)
pkgbuild/LICENSE 0000644 0001762 0000144 00000000056 14521162745 013070 0 ustar ligges users YEAR: 2023
COPYRIGHT HOLDER: pkgbuild authors
pkgbuild/README.md 0000644 0001762 0000144 00000010622 14442272563 013344 0 ustar ligges users # pkgbuild
[](https://github.com/r-lib/pkgbuild/actions/workflows/R-CMD-check.yaml)
[](https://app.codecov.io/gh/r-lib/pkgbuild?branch=main)
The goal of pkgbuild is to make it easy to build packages with compiled code. It provides tools to configure your R session, and check that everything is working ok. If you are using RStudio, it also helps you trigger automatic install of the build tools.
## Installation
Install the released version from CRAN
```r
install.packages("pkgbuild")
```
Or install the development version from GitHub:
```r
# install.packages("pak")
pak::pak("r-lib/pkgbuild")
```
## Example
``` r
# Check that you have the build tools installed
pkgbuild::check_build_tools(debug = TRUE)
# Build a package
pkgbuild::build("/path/to/my/package")
# Run your own code in an environment guaranteed to
# have build tools available
pkgbuild::with_build_tools(my_code)
```
## Configuration
### `DESCRIPTION` entries
* `Config/build/clean-inst-doc` can be set to `FALSE` to avoid cleaning up
`inst/doc` when building a source package. Set it to `TRUE` to force a
cleanup. See the `clean_doc` argument of `build()` as well.
* `Config/build/copy-method` can be used to avoid copying large directories
in `R CMD build`. It works by copying (or linking) the files of the
package to a temporary directory, leaving out the (possibly large) files
that are not part of the package. Possible values:
- `none`: pkgbuild does not copy the package tree. This is the default.
- `copy`: the package files are copied to a temporary directory before
` R CMD build`.
- `link`: the package files are symbolic linked to a temporary directory
before `R CMD build`. Windows does not have symbolic links, so on Windows
this is equivalent to `copy`.
You can also use the `pkg.build_copy_method` option or the
`PKG_BUILD_COPY_METHOD` environment variable to set the copy method.
The option is consulted first, then the `DESCRIPTION` entry, then the
environment variable.
* `Config/build/extra-sources` can be used to define extra source files for
pkgbuild to decide whether a package DLL needs to be recompiled in
`needs_compile()`. The syntax is a comma separated list of file names,
or globs. (See `?utils::glob2rx()`.) E.g. `src/rust/src/*.rs` or `configure*`.
### Options
* `pkg.build_copy_method`: use this option to avoid copying large directories
when building a package. See possible values above, at the
`Config/build/copy-method` `DESCRIPTION` entry.
* `pkg.build_extra_flags`: set this to `FALSE` to to opt out from adding
debug compiler flags in `compile_dll()`. Takes precedence over the
`PKG_BUILD_EXTRA_FLAGS` environment variable. Possible values:
- `TRUE`: add extra flags,
- `FALSE`: do not add extra flags,
- `"missing"`: add extra flags if the user does not have a
`$HOME/.R/Makevars` file.
* `pkg.build_stop_for_warnings`: if it is set to `TRUE`, then pkgbuild will stop
for `R CMD build` errors. It takes precedence over the
`PKG_BUILD_STOP_FOR_WARNINGS` environment variable.
### Environment variables
* `PKG_BUILD_COLOR_DIAGNOSTICS`: set it to `false` to opt out of colored
compiler diagnostics. Set it to `true` to force colored compiler
diagnostics.
* `PKG_BUILD_COPY_METHOD`: use this environment variable to avoid copying
large directories when building a package. See possible values above,
at the `Config/build/copy-method` `DESCRIPTION` entry.
* `PKG_BUILD_EXTRA_FLAGS`: set this to `false` to to opt out from adding
debug compiler flags in `compile_dll()`. The `pkg.build_extra_flags` option
takes precedence over this environment variable. Possible values:
- `"true"`: add extra flags,
- `"false"`: do not add extra flags,
- `"missing"`: add extra flags if the user does not have a
`$HOME/.R/Makevars` file.
* `PKG_BUILD_STOP_FOR_WARNINGS`: if it is set to `true`, then pkgbuild will stop
for `R CMD build` errors. The `pkg.build_stop_for_warnings` option takes
precedence over this environment variable.
## Code of Conduct
Please note that the pkgbuild project is released with a
[Contributor Code of Conduct](https://pkgbuild.r-lib.org/CODE_OF_CONDUCT.html).
By contributing to this project, you agree to abide by its terms.
pkgbuild/man/ 0000755 0001762 0000144 00000000000 14535333212 012627 5 ustar ligges users pkgbuild/man/pkg_links_to_rcpp.Rd 0000644 0001762 0000144 00000000675 14152340747 016643 0 ustar ligges users % Generated by roxygen2: do not edit by hand
% Please edit documentation in R/c-registration.R
\name{pkg_links_to_rcpp}
\alias{pkg_links_to_rcpp}
\alias{pkg_links_to_cpp11}
\title{Test if a package path is linking to Rcpp or cpp11}
\usage{
pkg_links_to_rcpp(path)
pkg_links_to_cpp11(path)
}
\arguments{
\item{path}{Path to a package, or within a package.}
}
\description{
Test if a package path is linking to Rcpp or cpp11
}
\keyword{internal}
pkgbuild/man/pkgbuild-package.Rd 0000644 0001762 0000144 00000001560 14426741134 016317 0 ustar ligges users % Generated by roxygen2: do not edit by hand
% Please edit documentation in R/pkgbuild-package.R
\docType{package}
\name{pkgbuild-package}
\alias{pkgbuild}
\alias{pkgbuild-package}
\title{pkgbuild: Find Tools Needed to Build R Packages}
\description{
Provides functions used to build R packages. Locates compilers needed to build R packages on various platforms and ensures the PATH is configured appropriately so R can use them.
}
\seealso{
Useful links:
\itemize{
\item \url{https://github.com/r-lib/pkgbuild}
\item \url{https://pkgbuild.r-lib.org}
\item Report bugs at \url{https://github.com/r-lib/pkgbuild/issues}
}
}
\author{
\strong{Maintainer}: Gábor Csárdi \email{csardi.gabor@gmail.com}
Authors:
\itemize{
\item Hadley Wickham
\item Jim Hester
}
Other contributors:
\itemize{
\item Posit Software, PBC [copyright holder, funder]
}
}
\keyword{internal}
pkgbuild/man/has_build_tools.Rd 0000644 0001762 0000144 00000004147 14426741134 016303 0 ustar ligges users % Generated by roxygen2: do not edit by hand
% Please edit documentation in R/build-tools.R
\name{has_build_tools}
\alias{has_build_tools}
\alias{check_build_tools}
\alias{with_build_tools}
\alias{local_build_tools}
\title{Are build tools are available?}
\usage{
has_build_tools(debug = FALSE)
check_build_tools(debug = FALSE, quiet = FALSE)
with_build_tools(code, debug = FALSE, required = TRUE)
local_build_tools(
debug = FALSE,
required = TRUE,
.local_envir = parent.frame()
)
}
\arguments{
\item{debug}{If \code{TRUE}, will print out extra information useful for
debugging. If \code{FALSE}, it will use result cached from a previous run.}
\item{quiet}{if \code{TRUE} suppresses output from this function.}
\item{code}{Code to rerun in environment where build tools are guaranteed to
exist.}
\item{required}{If \code{TRUE}, and build tools are not available,
will throw an error. Otherwise will attempt to run \code{code} without
them.}
\item{.local_envir}{The environment to use for scoping.}
}
\description{
\code{has_build_tools} returns a logical, \code{check_build_tools} throws
an error. \code{with_build_tools} checks that build tools are available,
then runs \code{code} in an correctly staged environment.
If run interactively from RStudio, and the build tools are not
available these functions will trigger an automated install.
}
\details{
Errors like \verb{running command '"C:/PROGRA~1/R/R-34~1.2/bin/x64/R" CMD config CC' had status 127}
indicate the code expected Rtools to be on the system PATH. You can
then verify you have rtools installed with \code{has_build_tools()} and
temporarily add Rtools to the PATH \code{with_build_tools({ code })}.
It is possible to add Rtools to your system PATH manually; you can use
\code{\link[=rtools_path]{rtools_path()}} to show the installed location. However because this
requires manual updating when a new version of Rtools is installed and the
binaries in Rtools may conflict with existing binaries elsewhere on the PATH it
is better practice to use \code{with_build_tools()} as needed.
}
\examples{
has_build_tools(debug = TRUE)
check_build_tools()
}
\seealso{
has_rtools
}
pkgbuild/man/pkg_has_src.Rd 0000644 0001762 0000144 00000000542 14152340747 015410 0 ustar ligges users % Generated by roxygen2: do not edit by hand
% Please edit documentation in R/has_src.R
\name{pkg_has_src}
\alias{pkg_has_src}
\title{Does a source package have \verb{src/} directory?}
\usage{
pkg_has_src(path = ".")
}
\arguments{
\item{path}{Path to package (or directory within package).}
}
\description{
If it does, you definitely need build tools.
}
pkgbuild/man/without_compiler.Rd 0000644 0001762 0000144 00000001136 14152340747 016522 0 ustar ligges users % Generated by roxygen2: do not edit by hand
% Please edit documentation in R/with-debug.R
\name{without_compiler}
\alias{without_compiler}
\alias{without_cache}
\alias{without_latex}
\alias{with_latex}
\title{Tools for testing pkgbuild}
\usage{
without_compiler(code)
without_cache(code)
without_latex(code)
with_latex(code)
}
\arguments{
\item{code}{Code to execute with broken compilers}
}
\description{
\code{with_compiler} temporarily disables code compilation by setting
\code{CC}, \code{CXX}, makevars to \code{test}. \code{without_cache}
resets the cache before and after running \code{code}.
}
pkgbuild/man/has_latex.Rd 0000644 0001762 0000144 00000000407 14152340747 015075 0 ustar ligges users % Generated by roxygen2: do not edit by hand
% Please edit documentation in R/latex.R
\name{has_latex}
\alias{has_latex}
\alias{check_latex}
\title{Is latex installed?}
\usage{
has_latex()
check_latex()
}
\description{
Checks for presence of pdflatex on path.
}
pkgbuild/man/needs_compile.Rd 0000644 0001762 0000144 00000000725 14152340747 015736 0 ustar ligges users % Generated by roxygen2: do not edit by hand
% Please edit documentation in R/compile-dll.R
\name{needs_compile}
\alias{needs_compile}
\title{Does the package need recompiling?
(i.e. is there a source or header file newer than the dll)}
\usage{
needs_compile(path = ".")
}
\arguments{
\item{path}{Path to a package, or within a package.}
}
\description{
Does the package need recompiling?
(i.e. is there a source or header file newer than the dll)
}
\keyword{internal}
pkgbuild/man/compile_dll.Rd 0000644 0001762 0000144 00000005617 14340630410 015404 0 ustar ligges users % Generated by roxygen2: do not edit by hand
% Please edit documentation in R/compile-dll.R
\name{compile_dll}
\alias{compile_dll}
\title{Compile a .dll/.so from source.}
\usage{
compile_dll(
path = ".",
force = FALSE,
compile_attributes = pkg_links_to_cpp11(path) || pkg_links_to_rcpp(path),
register_routines = FALSE,
quiet = FALSE,
debug = TRUE
)
}
\arguments{
\item{path}{Path to a package, or within a package.}
\item{force}{If \code{TRUE}, for compilation even if \code{\link[=needs_compile]{needs_compile()}} is
\code{FALSE}.}
\item{compile_attributes}{if \code{TRUE} and the package uses Rcpp, call
\code{\link[Rcpp:compileAttributes]{Rcpp::compileAttributes()}} before building the package. It is ignored
if package does not need compilation.}
\item{register_routines}{if \code{TRUE} and the package does not use Rcpp, call
register routines with
\code{tools::package_native_routine_registration_skeleton()} before building
the package. It is ignored if package does not need compilation.}
\item{quiet}{if \code{TRUE} suppresses output from this function.}
\item{debug}{If \code{TRUE}, and if no user Makevars is found, then the build
runs without optimisation (\code{-O0}) and with debug symbols (\code{-g}). See
\code{\link[=compiler_flags]{compiler_flags()}} for details. If you have a user Makevars (e.g.,
\verb{~/.R/Makevars}) then this argument is ignored.}
}
\description{
\code{compile_dll} performs a fake R CMD install so code that
works here should work with a regular install (and vice versa).
During compilation, debug flags are set with
\code{\link{compiler_flags}(TRUE)}.
}
\details{
Invisibly returns the names of the DLL.
\subsection{Configuration}{
\subsection{Options}{
\itemize{
\item \code{pkg.build_extra_flags}: set this to \code{FALSE} to to opt out from adding
debug compiler flags in \code{compile_dll()}. Takes precedence over the
\code{PKG_BUILD_EXTRA_FLAGS} environment variable. Possible values:
\itemize{
\item \code{TRUE}: add extra flags,
\item \code{FALSE}: do not add extra flags,
\item \code{"missing"}: add extra flags if the user does not have a
\verb{$HOME/.R/Makevars} file.
}
}
}
\subsection{Environment variables}{
\itemize{
\item \code{PKG_BUILD_EXTRA_FLAGS}: set this to \code{false} to to opt out from adding
debug compiler flags in \code{compile_dll()}. The \code{pkg.build_extra_flags} option
takes precedence over this environment variable. Possible values:
\itemize{
\item \code{"true"}: add extra flags,
\item \code{"false"}: do not add extra flags,
\item \code{"missing"}: add extra flags if the user does not have a
\verb{$HOME/.R/Makevars} file.
}
}
}
}
}
\note{
If this is used to compile code that uses Rcpp, you will need to
add the following line to your \code{Makevars} file so that it
knows where to find the Rcpp headers:
\verb{PKG_CPPFLAGS=}$(R_HOME)/bin/Rscript -e 'Rcpp:::CxxFlags()'``
}
\seealso{
\code{\link[=clean_dll]{clean_dll()}} to delete the compiled files.
}
pkgbuild/man/has_compiler.Rd 0000644 0001762 0000144 00000002356 14323725614 015577 0 ustar ligges users % Generated by roxygen2: do not edit by hand
% Please edit documentation in R/compiler.R
\name{has_compiler}
\alias{has_compiler}
\alias{check_compiler}
\alias{has_devel}
\title{Is a compiler available?}
\usage{
has_compiler(debug = FALSE)
check_compiler(debug = FALSE)
}
\arguments{
\item{debug}{If \code{TRUE}, will print out extra information useful for
debugging. If \code{FALSE}, it will use result cached from a previous run.}
}
\description{
These functions check if a small C file can be compiled, linked, loaded
and executed.
\code{has_compiler()} and \code{has_devel()} return \code{TRUE} or \code{FALSE}.
\code{check_compiler()} and \code{check_devel()}
throw an error if you don't have developer tools installed.
If the \code{"pkgbuild.has_compiler"} option is set to \code{TRUE} or \code{FALSE},
no check is carried out, and the value of the option is used.
The implementation is based on a suggestion by Simon Urbanek.
End-users (particularly those on Windows) should generally run
\code{\link[=check_build_tools]{check_build_tools()}} rather than \code{\link[=check_compiler]{check_compiler()}}.
}
\examples{
has_compiler()
check_compiler()
with_build_tools(has_compiler())
}
\seealso{
\code{\link[=check_build_tools]{check_build_tools()}}
}
pkgbuild/man/clean_dll.Rd 0000644 0001762 0000144 00000000617 14152340747 015045 0 ustar ligges users % Generated by roxygen2: do not edit by hand
% Please edit documentation in R/compile-dll.R
\name{clean_dll}
\alias{clean_dll}
\title{Remove compiled objects from /src/ directory}
\usage{
clean_dll(path = ".")
}
\arguments{
\item{path}{Path to a package, or within a package.}
}
\description{
Invisibly returns the names of the deleted files.
}
\seealso{
\code{\link[=compile_dll]{compile_dll()}}
}
pkgbuild/man/build.Rd 0000644 0001762 0000144 00000013306 14366011511 014215 0 ustar ligges users % Generated by roxygen2: do not edit by hand
% Please edit documentation in R/build.R
\name{build}
\alias{build}
\title{Build package}
\usage{
build(
path = ".",
dest_path = NULL,
binary = FALSE,
vignettes = TRUE,
manual = FALSE,
clean_doc = NULL,
args = NULL,
quiet = FALSE,
needs_compilation = pkg_has_src(path),
compile_attributes = FALSE,
register_routines = FALSE
)
}
\arguments{
\item{path}{Path to a package, or within a package.}
\item{dest_path}{path in which to produce package. If it is an existing
directory, then the output file is placed in \code{dest_path} and named
according to the current R conversions (e.g. \code{.zip} for Windows binary
packages, \code{.tgz} for macOS binary packages, etc).
If it is an existing file, then it will be overwritten.
If \code{dest_path} does not exist, then it is used as a file name.
If \code{NULL}, it defaults to the parent directory of the package.}
\item{binary}{Produce a binary (\code{--binary}) or source (
\code{--no-manual --no-resave-data}) version of the package.}
\item{vignettes, manual}{For source packages: if \code{FALSE}, don't build PDF
vignettes (\code{--no-build-vignettes}) or manual (\code{--no-manual}).}
\item{clean_doc}{If \code{TRUE}, clean the files in \code{inst/doc} before building
the package. If \code{NULL} and the \code{Config/build/clean-inst-doc} entry is
present in \code{DESCRIPTION}, then that is used. Otherwise, if \code{NULL},
and interactive, ask to remove the files prior to cleaning. In most
cases cleaning the files is the correct behavior to avoid stale
vignette outputs in the built package.}
\item{args}{An optional character vector of additional command
line arguments to be passed to \verb{R CMD build} if \code{binary = FALSE},
or \verb{R CMD install} if \code{binary = TRUE}.}
\item{quiet}{if \code{TRUE} suppresses output from this function.}
\item{needs_compilation}{Usually only needed if the packages has
C/C++/Fortran code. By default this is autodetected.}
\item{compile_attributes}{if \code{TRUE} and the package uses Rcpp, call
\code{\link[Rcpp:compileAttributes]{Rcpp::compileAttributes()}} before building the package. It is ignored
if package does not need compilation.}
\item{register_routines}{if \code{TRUE} and the package does not use Rcpp, call
register routines with
\code{tools::package_native_routine_registration_skeleton()} before building
the package. It is ignored if package does not need compilation.}
}
\value{
a string giving the location (including file name) of the built
package
}
\description{
Building converts a package source directory into a single bundled file.
If \code{binary = FALSE} this creates a \code{tar.gz} package that can
be installed on any platform, provided they have a full development
environment (although packages without source code can typically be
installed out of the box). If \code{binary = TRUE}, the package will have
a platform specific extension (e.g. \code{.zip} for windows), and will
only be installable on the current platform, but no development
environment is needed.
}
\details{
\subsection{Configuration}{
\subsection{\code{DESCRIPTION} entries}{
\itemize{
\item \code{Config/build/clean-inst-doc} can be set to \code{FALSE} to avoid cleaning up
\code{inst/doc} when building a source package. Set it to \code{TRUE} to force a
cleanup. See the \code{clean_doc} argument.
\item \code{Config/build/copy-method} can be used to avoid copying large
directories in \verb{R CMD build}. It works by copying (or linking) the
files of the package to a temporary directory, leaving out the
(possibly large) files that are not part of the package. Possible
values:
\itemize{
\item \code{none}: pkgbuild does not copy the package tree. This is the default.
\item \code{copy}: the package files are copied to a temporary directory before
\verb{ R CMD build}.
\item \code{link}: the package files are symbolic linked to a temporary
directory before \verb{R CMD build}. Windows does not have symbolic
links, so on Windows this is equivalent to \code{copy}.
}
You can also use the \code{pkg.build_copy_method} option or the
\code{PKG_BUILD_COPY_METHOD} environment variable to set the copy method.
The option is consulted first, then the \code{DESCRIPTION} entry, then the
environment variable.
\item \code{Config/build/extra-sources} can be used to define extra source files
for pkgbuild to decide whether a package DLL needs to be recompiled in
\code{needs_compile()}. The syntax is a comma separated list of file names,
or globs. (See \code{\link[utils:glob2rx]{utils::glob2rx()}}.) E.g. \verb{src/rust/src/*.rs} or
\verb{configure*}.
\item \code{Config/build/bootstrap} can be set to \code{TRUE} to run
\verb{Rscript bootstrap.R} in the source directory prior to running subsequent
build steps.
}
}
\subsection{Options}{
\itemize{
\item \code{pkg.build_copy_method}: use this option to avoid copying large
directories when building a package. See possible values above, at the
\code{Config/build/copy-method} \code{DESCRIPTION} entry.
\item \code{pkg.build_stop_for_warnings}: if it is set to \code{TRUE}, then pkgbuild
will stop for \verb{R CMD build} errors. It takes precedence over the
\code{PKG_BUILD_STOP_FOR_WARNINGS} environment variable.
}
}
\subsection{Environment variables}{
\itemize{
\item \code{PKG_BUILD_COLOR_DIAGNOSTICS}: set it to \code{false} to opt out of colored
compiler diagnostics. Set it to \code{true} to force colored compiler
diagnostics.
\item \code{PKG_BUILD_COPY_METHOD}: use this environment variable to avoid copying
large directories when building a package. See possible values above,
at the \code{Config/build/copy-method} \code{DESCRIPTION} entry.
}
will stop for \verb{R CMD build} errors. The \code{pkg.build_stop_for_warnings}
option takes precedence over this environment variable.
}
}
}
pkgbuild/man/has_rtools.Rd 0000644 0001762 0000144 00000002556 14152340747 015311 0 ustar ligges users % Generated by roxygen2: do not edit by hand
% Please edit documentation in R/rtools-cache.R, R/rtools.R
\name{rtools_path}
\alias{rtools_path}
\alias{has_rtools}
\alias{find_rtools}
\alias{setup_rtools}
\alias{check_rtools}
\title{Is Rtools installed?}
\usage{
rtools_path()
has_rtools(debug = FALSE)
check_rtools(debug = FALSE)
}
\arguments{
\item{debug}{If \code{TRUE}, will print out extra information useful for
debugging. If \code{FALSE}, it will use result cached from a previous run.}
}
\value{
Either a visible \code{TRUE} if rtools is found, or an invisible
\code{FALSE} with a diagnostic \code{\link[=message]{message()}}.
As a side-effect the internal package variable \code{rtools_path} is
updated to the paths to rtools binaries.
}
\description{
To build binary packages on windows, Rtools (found at
\url{https://CRAN.R-project.org/bin/windows/Rtools/}) needs to be on
the path. The default installation process does not add it, so this
script finds it (looking first on the path, then in the registry).
It also checks that the version of rtools matches the version of R.
\code{has_rtools()} determines if Rtools is installed, caching the results.
Afterward, run \code{rtools_path()} to find out where it's installed.
}
\section{Acknowledgements}{
This code borrows heavily from RStudio's code for finding Rtools.
Thanks JJ!
}
\examples{
has_rtools()
}
\keyword{internal}
pkgbuild/man/compiler_flags.Rd 0000644 0001762 0000144 00000001700 14535333212 016102 0 ustar ligges users % Generated by roxygen2: do not edit by hand
% Please edit documentation in R/compiler-flags.R
\name{compiler_flags}
\alias{compiler_flags}
\title{Default compiler flags used by devtools.}
\usage{
compiler_flags(debug = FALSE)
}
\arguments{
\item{debug}{If \code{TRUE} adds \code{-g -O0} to all flags
(Adding \env{FFLAGS} and \env{FCFLAGS})}
}
\description{
These default flags enforce good coding practice by ensuring that
\env{CFLAGS} and \env{CXXFLAGS} are set to \code{-Wall -pedantic}.
These tests are run by cran and are generally considered to be good practice.
}
\details{
By default \code{\link[=compile_dll]{compile_dll()}} is run with \code{compiler_flags(TRUE)},
and check with \code{compiler_flags(FALSE)}. If you want to avoid the
possible performance penalty from the debug flags, install the package.
}
\examples{
compiler_flags()
compiler_flags(TRUE)
}
\seealso{
Other debugging flags:
\code{\link{with_debug}()}
}
\concept{debugging flags}
pkgbuild/man/rcmd_build_tools.Rd 0000644 0001762 0000144 00000002010 14152340747 016441 0 ustar ligges users % Generated by roxygen2: do not edit by hand
% Please edit documentation in R/rcmd.R
\name{rcmd_build_tools}
\alias{rcmd_build_tools}
\title{Call R CMD 'command' with build tools active}
\usage{
rcmd_build_tools(..., env = character(), required = TRUE, quiet = FALSE)
}
\arguments{
\item{...}{Parameters passed on to \code{rcmd_safe}.}
\item{env}{Additional environment variables to set. The defaults from
\code{callr::rcmd_safe_env()} are always set.}
\item{required}{If \code{TRUE}, and build tools are not available,
will throw an error. Otherwise will attempt to run \code{code} without
them.}
\item{quiet}{if \code{TRUE} suppresses output from this function.}
}
\description{
This is a wrapper around \code{callr::rcmd_safe()} that checks
that you have build tools available, and on Windows, automatically sets
the path to include Rtools.
}
\examples{
# These env vars are always set
callr::rcmd_safe_env()
if (has_build_tools()) {
rcmd_build_tools("CONFIG", "CC")$stdout
rcmd_build_tools("CC", "--version")$stdout
}
}
pkgbuild/man/with_debug.Rd 0000644 0001762 0000144 00000001624 14535333212 015242 0 ustar ligges users % Generated by roxygen2: do not edit by hand
% Please edit documentation in R/with-debug.R
\name{with_debug}
\alias{with_debug}
\title{Temporarily set debugging compilation flags.}
\usage{
with_debug(
code,
CFLAGS = NULL,
CXXFLAGS = NULL,
FFLAGS = NULL,
FCFLAGS = NULL,
debug = TRUE
)
}
\arguments{
\item{code}{to execute.}
\item{CFLAGS}{flags for compiling C code}
\item{CXXFLAGS}{flags for compiling C++ code}
\item{FFLAGS}{flags for compiling Fortran code.}
\item{FCFLAGS}{flags for Fortran 9x code.}
\item{debug}{If \code{TRUE} adds \code{-g -O0} to all flags
(Adding \env{FFLAGS} and \env{FCFLAGS})}
}
\description{
Temporarily set debugging compilation flags.
}
\examples{
flags <- names(compiler_flags(TRUE))
with_debug(Sys.getenv(flags))
\dontrun{
install("mypkg")
with_debug(install("mypkg"))
}
}
\seealso{
Other debugging flags:
\code{\link{compiler_flags}()}
}
\concept{debugging flags}
pkgbuild/man/rtools_needed.Rd 0000644 0001762 0000144 00000000514 14152340747 015752 0 ustar ligges users % Generated by roxygen2: do not edit by hand
% Please edit documentation in R/rtools.R
\name{rtools_needed}
\alias{rtools_needed}
\title{Retrieve a text string with the rtools version needed}
\usage{
rtools_needed(r_version = getRversion())
}
\description{
Retrieve a text string with the rtools version needed
}
\keyword{internal}
pkgbuild/man/pkgbuild_process.Rd 0000644 0001762 0000144 00000002565 14323713030 016460 0 ustar ligges users % Generated by roxygen2: do not edit by hand
% Please edit documentation in R/build-bg.R
\name{pkgbuild_process}
\alias{pkgbuild_process}
\title{Build package in the background}
\description{
This R6 class is a counterpart of the \code{\link[=build]{build()}} function, and
represents a background process that builds an R package.
}
\section{Usage}{
\if{html}{\out{
}}\preformatted{bp <- pkgbuild_process$new(path = ".", dest_path = NULL,
binary = FALSE, vignettes = TRUE, manual = FALSE, args = NULL)
bp$get_dest_path()
}\if{html}{\out{
}}
Other methods are inherited from \link[callr:rcmd_process]{callr::rcmd_process} and
\code{processx::process}.
}
\section{Arguments}{
See the corresponding arguments of \code{\link[=build]{build()}}.
}
\section{Details}{
Most methods are inherited from \link[callr:rcmd_process]{callr::rcmd_process} and
\code{processx::process}.
\code{bp$get_dest_path()} returns the path to the built package.
}
\section{Examples}{
\if{html}{\out{}}\preformatted{## Here we are just waiting, but in a more realistic example, you
## would probably run some other code instead...
bp <- pkgbuild_process$new("mypackage", dest_path = tempdir())
bp$is_alive()
bp$get_pid()
bp$wait()
bp$read_all_output_lines()
bp$read_all_error_lines()
bp$get_exit_status()
bp$get_dest_path()
}\if{html}{\out{
}}
}
pkgbuild/DESCRIPTION 0000644 0001762 0000144 00000002353 14535342146 013573 0 ustar ligges users Package: pkgbuild
Title: Find Tools Needed to Build R Packages
Version: 1.4.3
Authors@R: c(
person("Hadley", "Wickham", role = "aut"),
person("Jim", "Hester", role = "aut"),
person("Gábor", "Csárdi", , "csardi.gabor@gmail.com", role = c("aut", "cre")),
person("Posit Software, PBC", role = c("cph", "fnd"))
)
Description: Provides functions used to build R packages. Locates
compilers needed to build R packages on various platforms and ensures
the PATH is configured appropriately so R can use them.
License: MIT + file LICENSE
URL: https://github.com/r-lib/pkgbuild, https://pkgbuild.r-lib.org
BugReports: https://github.com/r-lib/pkgbuild/issues
Depends: R (>= 3.5)
Imports: callr (>= 3.2.0), cli (>= 3.4.0), desc, processx, R6
Suggests: covr, cpp11, knitr, mockery, Rcpp, rmarkdown, testthat (>=
3.0.0), withr (>= 2.3.0)
Config/Needs/website: tidyverse/tidytemplate
Config/testthat/edition: 3
Encoding: UTF-8
RoxygenNote: 7.2.3
NeedsCompilation: no
Packaged: 2023-12-10 13:32:36 UTC; gaborcsardi
Author: Hadley Wickham [aut],
Jim Hester [aut],
Gábor Csárdi [aut, cre],
Posit Software, PBC [cph, fnd]
Maintainer: Gábor Csárdi
Repository: CRAN
Date/Publication: 2023-12-10 14:00:06 UTC
pkgbuild/tests/ 0000755 0001762 0000144 00000000000 14526624156 013230 5 ustar ligges users pkgbuild/tests/testthat/ 0000755 0001762 0000144 00000000000 14535342146 015064 5 ustar ligges users pkgbuild/tests/testthat/test-withr.R 0000644 0001762 0000144 00000001717 14442273510 017322 0 ustar ligges users
test_that("withr_with_makevars", {
split_lines <- function(x) strsplit(x, "\n\r?")[[1]]
orig <- split_lines(callr::rcmd("config", "CFLAGS")$stdout)
new <- withr_with_makevars(
new = c(CFLAGS = "-DFOO"),
split_lines(callr::rcmd("config", "CFLAGS")$stdout)
)
expect_equal(new, paste(orig, "-DFOO"))
# with our own custom Makevars file
tmp <- tempfile()
on.exit(unlink(tmp), add = TRUE)
writeLines(c(
"CFLAGS=-DTHIS",
"CXXFLAGS+=-DTHAT"
), tmp)
orig <- split_lines(callr::rcmd("config", "CFLAGS")$stdout)
new <- withr_with_makevars(
new = c(CFLAGS = "-DFOO"),
path = tmp,
split_lines(callr::rcmd("config", "CFLAGS")$stdout)
)
expect_equal(new, "-DTHIS -DFOO")
orig <- split_lines(callr::rcmd("config", "CXXFLAGS")$stdout)
new <- withr_with_makevars(
new = c(CXXFLAGS = "-DFOO"),
path = tmp,
split_lines(callr::rcmd("config", "CXXFLAGS")$stdout)
)
expect_equal(new, paste(orig, "-DTHAT -DFOO"))
})
pkgbuild/tests/testthat/testDummy/ 0000755 0001762 0000144 00000000000 14152340747 017057 5 ustar ligges users pkgbuild/tests/testthat/testDummy/NAMESPACE 0000644 0001762 0000144 00000000012 14152340747 020267 0 ustar ligges users export(a)
pkgbuild/tests/testthat/testDummy/DESCRIPTION 0000644 0001762 0000144 00000000270 14152340747 020564 0 ustar ligges users Package: testDummy
Title: Tools to make developing R code easier
License: GPL-2
Description:
Author: Hadley
Maintainer: Hadley
Version: 0.1
pkgbuild/tests/testthat/testDummy/R/ 0000755 0001762 0000144 00000000000 14521162621 017251 5 ustar ligges users pkgbuild/tests/testthat/testDummy/R/a.R 0000644 0001762 0000144 00000000007 14152340747 017620 0 ustar ligges users a <- 1
pkgbuild/tests/testthat/testDummy/R/b.R 0000644 0001762 0000144 00000000007 14152340747 017621 0 ustar ligges users b <- 2
pkgbuild/tests/testthat/fixtures/ 0000755 0001762 0000144 00000000000 14152340747 016735 5 ustar ligges users pkgbuild/tests/testthat/fixtures/xxx.zip 0000644 0001762 0000144 00000000240 14152340747 020304 0 ustar ligges users PK
U8Jgt xxxUT 0XXux xxx
PK
U8Jgt xxxUT 0Xux PK I A pkgbuild/tests/testthat/fixtures/xxx.tar.gz 0000644 0001762 0000144 00000000214 14152340747 020710 0 ustar ligges users 1X A
0F=ay-B87("y߄ݻT5(o"J0!ڠw˪|ϥVs.e_l?%MZpݿ { ( pkgbuild/tests/testthat/fixtures/testWithSrc_0.1.tar.gz 0000644 0001762 0000144 00000001135 14152340747 022725 0 ustar ligges users XQk0^mI$JJ4t65NYMD+Hʶ2';e[ФeB:q;sN0x'Q@8NV="kDPM) Peڅ2cSa:sjWWk6]7B86wSrV],fW :<\%'
õ\Z.+݅,
ͯ_ldjq2YX}Bj]Hb)sv#LxAY{
d"E1O0xH{k?`>?4;bƞTX3?mmG{Jԡ$ RYQn}05 %?oמWJpOew[a.jqh<+Y| (+trS·enGuTc-*l2Lj,*]Kep,JB3`yͭpr>v&nBŭm4'-ǎ3Ovv pkgbuild/tests/testthat/fixtures/xxx.gz 0000644 0001762 0000144 00000000034 14152340747 020123 0 ustar ligges users 0X xxx gt pkgbuild/tests/testthat/fixtures/testDummy_0.1.tar.gz 0000644 0001762 0000144 00000000631 14152340747 022435 0 ustar ligges users N0w8zkI @VFörHi֜õi/|;ְ;waA% anvDk:k419;ԆSR6*L%ۺl:uY#0?;&+Rf9$gr!˄gZpD]zⶹX!̤%_AcV}|4g"2v(L'潨>n|!2VH6Iz
!B8n]]owFfsGA)^XO]He.إzҟGh?:ZàQlCo`X-xf pkgbuild/tests/testthat/test-rtools.R 0000644 0001762 0000144 00000001677 14410345632 017514 0 ustar ligges users
test_that("has_rtools finds rtools", {
skip_if_not(is_windows() && !is.null(scan_path_for_rtools()))
# Rtools path can be looked up by the PATH
without_cache({
expect_true(has_rtools())
expect_true(!is.null(scan_path_for_rtools()))
})
withr::with_path(Sys.getenv("R_HOME"), action = "replace", {
expect_equal(scan_path_for_rtools(), NULL)
})
skip_if_not(!is.null(scan_registry_for_rtools()))
# Rtools path can be looked up from the registery
expect_true(!is.null(scan_registry_for_rtools()))
without_cache(
withr::with_path(Sys.getenv("R_HOME"), action = "replace", {
has_rtools()
expect_true(rtools_path() != "")
})
)
})
test_that("rtools_needed works", {
skip_if_not(is_windows())
# Test only frozen versions
expect_equal(rtools_needed("3.6.3"), "Rtools 3.5")
expect_equal(rtools_needed("2.9"), "Rtools 3.0")
expect_equal(rtools_needed("0.0.0"), "the appropriate version of Rtools")
})
pkgbuild/tests/testthat/test-build.R 0000644 0001762 0000144 00000022673 14410345632 017270 0 ustar ligges users
# Package build setup ----------------------------------------------------
test_that("with*_latex context fixtures force has_latex result", {
expect_true(with_latex(has_latex()))
expect_false(without_latex(has_latex()))
# one of them should be different from default
expect_true({
with_latex(has_latex()) != has_latex() ||
without_latex(has_latex()) != has_latex()
})
})
# expect `manual=TRUE` & empty `args` not to add build --no-manual flag
test_that("source build setup accept args and/or parameterized helpers", {
expect_silent(res <- with_latex({
build_setup_source(
file.path(testthat::test_path(), "testDummy"),
file.path(tempdir(), "testDummyBuild"),
vignettes = FALSE,
manual = TRUE,
clean_doc = FALSE,
args = c(),
needs_compilation = FALSE
)
}))
expect_true(!"--no-manual" %in% res$args)
# expect `manual=FALSE` to affect build --no-manual flag
expect_silent(res <- with_latex({
build_setup_source(
file.path(testthat::test_path(), "testDummy"),
file.path(tempdir(), "testDummyBuild"),
vignettes = FALSE,
manual = FALSE,
clean_doc = FALSE,
args = c(),
needs_compilation = FALSE
)
}))
expect_true("--no-manual" %in% res$args)
# expect `args` "--no-manual" to affect build --no-manual flag
expect_silent(res <- with_latex({
build_setup_source(
file.path(testthat::test_path(), "testDummy"),
file.path(tempdir(), "testDummyBuild"),
vignettes = FALSE,
manual = TRUE,
clean_doc = FALSE,
args = c("--no-manual"),
needs_compilation = FALSE
)
}))
expect_true("--no-manual" %in% res$args)
expect_silent(res <- build_setup_source(
file.path(testthat::test_path(), "testDummy"),
file.path(tempdir(), "testDummyBuild"),
vignettes = TRUE,
manual = FALSE,
clean_doc = FALSE,
args = c(),
needs_compilation = FALSE
))
expect_true(!"--no-build-vignettes" %in% res$args)
# expect `vignettes=FALSE` to affect build --no-build-vignettes flag
expect_silent(res <- build_setup_source(
file.path(testthat::test_path(), "testDummy"),
file.path(tempdir(), "testDummyBuild"),
vignettes = FALSE,
manual = FALSE,
clean_doc = FALSE,
args = c(),
needs_compilation = FALSE
))
expect_true("--no-build-vignettes" %in% res$args)
# expect `arg` `--no-build-vignettes` to produce --no-build-vignettes flag
expect_silent(res <- build_setup_source(
file.path(testthat::test_path(), "testDummy"),
file.path(tempdir(), "testDummyBuild"),
vignettes = TRUE,
manual = FALSE,
clean_doc = FALSE,
args = c("--no-build-vignettes"),
needs_compilation = FALSE
))
expect_true("--no-build-vignettes" %in% res$args)
})
# Package without source code --------------------------------------------
test_that("source builds return correct filenames", {
path <- build("testDummy", dest_path = tempdir(), quiet = TRUE)
on.exit(unlink(path))
expect_true(file.exists(path))
expect_false(is.na(desc::desc(path)$get("Packaged")))
expect_true(is.na(desc::desc(path)$get("Built")))
})
test_that("binary builds return correct filenames", {
path <- build("testDummy", binary = TRUE, dest_path = tempdir(), quiet = TRUE)
on.exit(unlink(path))
expect_true(file.exists(path))
})
test_that("can build package without src without compiler", {
without_compiler({
path <- build("testDummy", binary = TRUE, dest_path = tempdir(), quiet = TRUE)
on.exit(unlink(path))
expect_true(file.exists(path))
})
})
# Package with src code ---------------------------------------------------
test_that("source builds return correct filenames", {
path <- build("testWithSrc", dest_path = tempdir(), quiet = TRUE, register_routines = FALSE)
on.exit(unlink(path))
expect_true(file.exists(path))
})
test_that("build package with src requires compiler", {
without_compiler({
expect_error(
build("testWithSrc", dest_path = tempdir(), quiet = TRUE),
"Could not find tools"
)
})
})
# Package files -----------------------------------------------------------
test_that("package tarball binary build", {
path <- build("testDummy", dest_path = tempdir(), quiet = TRUE)
on.exit(unlink(path), add = TRUE)
path2 <- build(path,
dest_path = tempdir(), quiet = TRUE,
binary = TRUE, needs_compilation = FALSE,
compile_attributes = FALSE
)
on.exit(unlink(path2), add = TRUE)
expect_true(file.exists(path2))
expect_false(is.na(desc::desc(path2)$get("Packaged")))
expect_false(is.na(desc::desc(path2)$get("Built")))
})
test_that("package tarball binary build errors", {
path <- build("testDummy", dest_path = tempdir(), quiet = TRUE)
on.exit(unlink(path), add = TRUE)
expect_error(
build(path, dest_path = tempdir(), quiet = TRUE),
"binary"
)
expect_error(
build(path,
dest_path = tempdir(), quiet = TRUE, binary = TRUE,
needs_compilation = FALSE, compile_attributes = TRUE
),
"compile_attributes"
)
})
test_that("warnings can be turned into errors", {
src <- withr::local_tempdir()
dest <- withr::local_tempdir()
file.copy(test_path("testDummy"), src, recursive = TRUE)
withr::local_options(pkg.build_stop_for_warnings = TRUE)
expect_silent(
build(file.path(src, "testDummy"), dest_path = dest, quiet = TRUE)
)
dir.create(file.path(src, "testDummy", "inst"), recursive = TRUE, showWarnings = FALSE)
saveRDS(1:10, file.path(src, "testDummy", "inst", "testthat-problems.rds"))
# No warning/error on R <= 3.5
if (getRversion() <= "3.6") skip("Needs R 3.5.0")
# Warning looks different on older R
if (getRversion() >= "4.1") {
expect_snapshot(
error = TRUE,
build(file.path(src, "testDummy"), dest_path = dest, quiet = TRUE),
transform = function(x) {
x <- sub("\u2018", "'", x, fixed = TRUE)
x <- sub("\u2019", "'", x, fixed = TRUE)
x <- sub("checking for file '.*'", "checking for file ''", x)
x
}
)
} else {
expect_error(
suppressMessages(build(
file.path(src, "testDummy"),
dest_path = dest,
quiet = TRUE
))
)
}
})
test_that("Config/build/clean-inst-doc FALSE", {
dest <- withr::local_tempdir()
expect_silent(
build(
test_path("testInstDoc"),
dest_path = dest,
quiet = TRUE,
vignettes = TRUE,
clean_doc = NULL
)
)
pkg <- file.path(dest, dir(dest))
expect_true(length(pkg) == 1)
expect_true(file.exists(pkg))
pkg_files <- untar(pkg, list = TRUE)
expect_true("testInstDoc/inst/doc/keep.me" %in% pkg_files)
expect_true("testInstDoc/inst/doc/test.html" %in% pkg_files)
})
test_that("Config/build/clean-inst-doc TRUE", {
src <- withr::local_tempdir()
dest <- withr::local_tempdir()
file.copy(test_path("testInstDoc"), src, recursive = TRUE)
desc::desc_set(
"Config/build/clean-inst-doc" = "TRUE",
file = file.path(src, "testInstDoc")
)
expect_silent(
build(
file.path(src, "testInstDoc"),
dest_path = dest,
quiet = TRUE,
vignettes = TRUE,
clean_doc = NULL
)
)
pkg <- file.path(dest, dir(dest))
expect_true(length(pkg) == 1)
expect_true(file.exists(pkg))
pkg_files <- untar(pkg, list = TRUE)
expect_false("testInstDoc/inst/doc/keep.me" %in% pkg_files)
expect_true("testInstDoc/inst/doc/test.html" %in% pkg_files)
})
test_that("bootstrap.R runs on build if present", {
src <- withr::local_tempdir()
dest <- withr::local_tempdir()
file.copy(test_path("testDummy"), src, recursive = TRUE)
writeLines(
c(
'dir.create("inst")',
'file.create("inst/file-created-by-bootstrap.txt")'
),
file.path(src, "testDummy", "bootstrap.R")
)
desc::desc_set(
"Config/build/bootstrap" = "TRUE",
file = file.path(src, "testDummy")
)
expect_silent(
build(
file.path(src, "testDummy"),
dest_path = dest,
quiet = TRUE
)
)
pkg <- file.path(dest, dir(dest))
expect_true(length(pkg) == 1)
expect_true(file.exists(pkg))
pkg_files <- untar(pkg, list = TRUE)
expect_true("testDummy/inst/file-created-by-bootstrap.txt" %in% pkg_files)
})
test_that("bootstrap.R does not run if Config/build/bootstrap is not TRUE", {
src <- withr::local_tempdir()
dest <- withr::local_tempdir()
file.copy(test_path("testDummy"), src, recursive = TRUE)
writeLines(
c(
'dir.create("inst")',
'file.create("inst/file-created-by-bootstrap.txt")'
),
file.path(src, "testDummy", "bootstrap.R")
)
expect_silent(
build(
file.path(src, "testDummy"),
dest_path = dest,
quiet = TRUE
)
)
pkg <- file.path(dest, dir(dest))
expect_true(length(pkg) == 1)
expect_true(file.exists(pkg))
pkg_files <- untar(pkg, list = TRUE)
expect_false("testDummy/inst/file-created-by-bootstrap.txt" %in% pkg_files)
})
test_that("bootstrap.R can output stdout, stderr, and warnings when run", {
src <- withr::local_tempdir()
dest <- withr::local_tempdir()
file.copy(test_path("testDummy"), src, recursive = TRUE)
writeLines(
c(
'message("output on stderr")',
'cat("output on stdout\\n")',
'warning("this is a warning")'
),
file.path(src, "testDummy", "bootstrap.R")
)
desc::desc_set(
"Config/build/bootstrap" = "TRUE",
file = file.path(src, "testDummy")
)
expect_output(
expect_message(
build(
file.path(src, "testDummy"),
dest_path = dest
),
"Running bootstrap.R"
),
"output on stderr.*?output on stdout.*?this is a warning"
)
})
pkgbuild/tests/testthat/test-c-registration.R 0000644 0001762 0000144 00000004350 14211634664 021120 0 ustar ligges users
test_that("update_c_registration does nothing if an init.c file already exists", {
skip_if(getRversion() < "3.4")
init_file <- test_path("testWithSrc", "src", "init.c")
on.exit(unlink(init_file))
writeLines('
#include
#include
#include // for NULL
#include
/* .Call calls */
extern SEXP add1(SEXP);
extern SEXP mult2(SEXP);
static const R_CallMethodDef CallEntries[] = {
{"add1", (DL_FUNC) &add1, 1},
{"mult2", (DL_FUNC) &mult2, 1},
{NULL, NULL, 0}
};
void R_init_testWithSrc(DllInfo *dll)
{
R_registerRoutines(dll, NULL, CallEntries, NULL, NULL);
R_useDynamicSymbols(dll, FALSE);
}', init_file)
expect_equal(
update_c_registration(test_path("testWithSrc")),
character()
)
})
test_that("update_c_registration works", {
skip_if(getRversion() < "3.4")
init_file <- test_path("testWithSrc", "src", "init.c")
on.exit(unlink(init_file))
expect_false(file.exists(init_file))
# Should return with no lines if there are no routines called
expect_equal(update_c_registration(test_path("testWithSrc")), character())
# Add a call and try to update again
src_file <- test_path("testWithSrc", "R", "c.R")
writeLines('
add1 <- function(x) {
.Call("add1", x)
}', src_file)
on.exit(unlink(src_file), add = TRUE)
init_lines <- update_c_registration(test_path("testWithSrc"))
expect_true(any(grepl("generated by pkgbuild", init_lines)))
expect_true(any(grepl('"add1",.*[(]DL_FUNC[)] &add1', init_lines)))
# update_c_registration should be idempotent if nothing has changed
expect_equal(
update_c_registration(test_path("testWithSrc")),
init_lines
)
writeLines('
add1 <- function(x) {
.Call("add1", x)
}
mult2 <- function(x) {
.Call("mult2", x)
}', src_file)
# update_c_registration should be idempotent if nothing has changed
update_c_registration(test_path("testWithSrc"))
init_src <- readLines(init_file)
expect_true(any(grepl("generated by pkgbuild", init_src)))
expect_true(any(grepl('"add1",.*[(]DL_FUNC[)] &add1', init_src)))
expect_true(any(grepl('"mult2",.*[(]DL_FUNC[)] &mult2', init_src)))
})
test_that("check_namespace_registration", {
expect_warning(check_namespace_registration(test_path("testWithSrc")))
})
pkgbuild/tests/testthat/testInstDoc/ 0000755 0001762 0000144 00000000000 14337377564 017343 5 ustar ligges users pkgbuild/tests/testthat/testInstDoc/NAMESPACE 0000644 0001762 0000144 00000000012 14337377564 020553 0 ustar ligges users export(a)
pkgbuild/tests/testthat/testInstDoc/DESCRIPTION 0000644 0001762 0000144 00000000433 14337377564 021051 0 ustar ligges users Package: testInstDoc
Title: Tools to make developing R code easier
License: GPL-2
Description:
Author: Hadley
Maintainer: Hadley
Version: 0.1
Config/build/clean-inst-doc: FALSE
VignetteBuilder:
knitr
Suggests:
knitr,
rmarkdown
pkgbuild/tests/testthat/testInstDoc/vignettes/ 0000755 0001762 0000144 00000000000 14337377564 021353 5 ustar ligges users pkgbuild/tests/testthat/testInstDoc/vignettes/test.Rmd 0000644 0001762 0000144 00000000547 14337377564 023004 0 ustar ligges users ---
title: "pkgbuild test"
output: rmarkdown::html_vignette
description: >
This is a vignette to be used in the pkgbuild tests.
vignette: >
%\VignetteIndexEntry{pkgbuild test}
%\VignetteEngine{knitr::rmarkdown}
\usepackage[utf8]{inputenc}
---
```{r, setup, include = FALSE}
knitr::opts_chunk$set(collapse = TRUE, comment = "#>")
```
```{r}
1:10
```
pkgbuild/tests/testthat/testInstDoc/R/ 0000755 0001762 0000144 00000000000 14521162602 017520 5 ustar ligges users pkgbuild/tests/testthat/testInstDoc/R/a.R 0000644 0001762 0000144 00000000007 14337377564 020104 0 ustar ligges users a <- 1
pkgbuild/tests/testthat/testInstDoc/R/b.R 0000644 0001762 0000144 00000000007 14337377564 020105 0 ustar ligges users b <- 2
pkgbuild/tests/testthat/testInstDoc/inst/ 0000755 0001762 0000144 00000000000 14337377564 020320 5 ustar ligges users pkgbuild/tests/testthat/testInstDoc/inst/doc/ 0000755 0001762 0000144 00000000000 14337377564 021065 5 ustar ligges users pkgbuild/tests/testthat/testInstDoc/inst/doc/keep.me 0000644 0001762 0000144 00000000017 14337377564 022332 0 ustar ligges users Pretty please.
pkgbuild/tests/testthat/test-compiler.R 0000644 0001762 0000144 00000002274 14323725614 020003 0 ustar ligges users
describe("has_compiler", {
withr::local_options(pkgbuild.has_compiler = NULL)
testthat::local_reproducible_output()
it("succeeds if a compiler exists", {
skip_if(is_windows() && !has_rtools())
without_cache({
without_compiler({
expect_false(has_compiler())
expect_error(check_compiler(), "Failed to compile C code")
})
cache_reset()
expect_true(has_compiler())
expect_true(check_compiler())
})
})
it("returns the value of the has_compiler option", {
skip_if(is_windows() && !has_rtools())
without_cache({
without_compiler({
withr::with_options(
c(pkgbuild.has_compiler = TRUE),
{
expect_true(has_compiler())
expect_error(check_compiler(), NA)
}
)
})
cache_reset()
withr::with_options(
c(pkgbuild.has_compiler = FALSE),
{
expect_false(has_compiler())
expect_error(check_compiler(), "Failed to compile C code")
}
)
withr::with_options(
list(pkgbuild.has_compiler = 1:2),
expect_snapshot(
error = TRUE,
has_compiler()
)
)
})
})
})
pkgbuild/tests/testthat/test-build-process.R 0000644 0001762 0000144 00000006740 14410345632 020741 0 ustar ligges users
# Package without source code --------------------------------------------
test_that("source builds return correct filenames", {
dir.create(tmp <- tempfile())
on.exit(unlink(tmp, recursive = TRUE), add = TRUE)
pr <- pkgbuild_process$new("testDummy", dest_path = tmp)
pr$wait(60000)
if (pr$is_alive()) {
pr$kill()
skip("has not finished in one minute")
}
expect_true(file.exists(pr$get_dest_path()))
expect_true(file.exists(pr$get_built_file()))
expect_true(!is.na(desc::desc(pr$get_built_file())$get("Packaged")))
})
test_that("binary builds return correct filenames", {
# building binaries also installs them to the library, so we need to skip on
# CRAN.
skip_on_cran()
dir.create(tmp <- tempfile())
on.exit(unlink(tmp, recursive = TRUE), add = TRUE)
pr <- pkgbuild_process$new("testDummy", binary = TRUE, dest_path = tmp)
pr$wait(60000)
if (pr$is_alive()) {
pr$kill()
skip("has not finished in one minute")
}
expect_true(file.exists(pr$get_dest_path()))
expect_true(file.exists(pr$get_built_file()))
expect_true(!is.na(desc::desc(pr$get_built_file())$get("Built")))
})
test_that("can build package without src without compiler", {
# building binaries also installs them to the library, so we need to skip on
# CRAN.
skip_on_cran()
dir.create(tmp <- tempfile())
on.exit(unlink(tmp, recursive = TRUE))
without_compiler({
pr <- pkgbuild_process$new("testDummy", binary = TRUE, dest_path = tmp)
pr$wait(60000)
if (pr$is_alive()) {
pr$kill()
skip("has not finished in one minute")
}
expect_true(file.exists(pr$get_dest_path()))
expect_true(file.exists(pr$get_built_file()))
expect_true(!is.na(desc::desc(pr$get_built_file())$get("Built")))
})
})
# Package with src code ---------------------------------------------------
test_that("source builds return correct filenames", {
dir.create(tmp <- tempfile())
on.exit(unlink(tmp, recursive = TRUE), add = TRUE)
pr <- pkgbuild_process$new("testWithSrc", dest_path = tmp, register_routines = FALSE)
pr$wait(60000)
if (pr$is_alive()) {
pr$kill()
skip("has not finished in one minute")
}
expect_true(file.exists(pr$get_dest_path()))
expect_true(file.exists(pr$get_built_file()))
expect_true(!is.na(desc::desc(pr$get_built_file())$get("Packaged")))
})
test_that("build package with src requires compiler", {
without_compiler({
expect_error(
{
pr <- pkgbuild_process$new("testWithSrc", dest_path = tempdir(), register_routines = FALSE)
pr$kill()
},
"Could not find tools"
)
})
})
test_that("can get output, exit status, etc.", {
dir.create(tmp <- tempfile())
on.exit(unlink(tmp, recursive = TRUE), add = TRUE)
pr <- pkgbuild_process$new("testDummy", dest_path = tmp)
pr$wait(60000)
if (pr$is_alive()) {
pr$kill()
skip("has not finished in one minute")
}
out <- pr$read_all_output()
expect_match(out, "* building", fixed = TRUE)
expect_error(err <- pr$read_all_error(), NA)
expect_equal(pr$get_exit_status(), 0)
path <- pr$get_dest_path()
on.exit(unlink(path))
})
test_that("can kill a build process", {
dir.create(tmp <- tempfile())
on.exit(unlink(tmp, recursive = TRUE), add = TRUE)
pr <- pkgbuild_process$new("testDummy", dest_path = tmp)
ret <- pr$kill()
if (!ret) skip("build finished before we could kill it")
ex_stat <- pr$get_exit_status()
if (.Platform$OS.type == "unix") {
expect_equal(ex_stat, -9)
} else {
expect_true(ex_stat != 0)
}
})
pkgbuild/tests/testthat/test-exclude.R 0000644 0001762 0000144 00000010746 14340633232 017616 0 ustar ligges users
test_that("copy_package_tree creates package dir", {
tmp <- withr::local_tempdir("pkgbuild-test-")
# link
withr::local_options(pkg.build_copy_method = "link")
unlink(tmp, recursive = TRUE)
expect_no_warning(
copy_package_tree(test_path("testDummy"), tmp)
)
expect_snapshot(
sort(dir(tmp, recursive = TRUE, include.dirs = TRUE))
)
# copy
withr::local_options(pkg.build_copy_method = "copy")
unlink(tmp, recursive = TRUE)
expect_no_warning(
copy_package_tree(test_path("testDummy"), tmp)
)
expect_snapshot(
sort(dir(tmp, recursive = TRUE, include.dirs = TRUE))
)
})
test_that("copy_package_tree errors", {
tmp <- withr::local_tempdir("pkgbuild-test-")
mkdirp(file.path(tmp, "testDummy"))
expect_error(
copy_package_tree(test_path("testDummy"), tmp),
"already exists"
)
})
test_that("exclusions", {
pkgdir <- file.path(withr::local_tempdir("pkgbuild-test-"), "pkg")
mkdirp(pkgdir)
writeLines(
c("Package: pkg", "Version: 1.0.0"),
file.path(pkgdir, "DESCRIPTION")
)
# create some structure with files to ignore and keep
writeLines(c(
"^docs$",
"^src/.*[.]o$"
), file.path(pkgdir, ".Rbuildignore"))
mkdirp(file.path(pkgdir, "src"))
file.create(file.path(pkgdir, "src", "src.c"))
file.create(file.path(pkgdir, "src", "src.o"))
mkdirp(file.path(pkgdir, "docs"))
file.create(file.path(pkgdir, "docs", "foo"))
file.create(file.path(pkgdir, "src", ".DS_Store"))
file.create(file.path(pkgdir, ".Rhistory"))
file.create(file.path(pkgdir, ".RData"))
file.create(file.path(pkgdir, "src", "foo.c~"))
file.create(file.path(pkgdir, "src", "foo.c.bak"))
file.create(file.path(pkgdir, "src", "foo.c.swp"))
file.create(file.path(pkgdir, "src", "foo.d"))
dir.create(file.path(pkgdir, ".git"))
file.create(file.path(pkgdir, ".git", "foo"))
files <- build_files(pkgdir)
expect_snapshot(files[, c("path", "exclude", "isdir", "trimmed")])
dest <- withr::local_tempdir("pkgbuild-test-")
copy_package_tree(pkgdir, dest)
})
test_that("get_copy_method", {
mockery::stub(get_copy_method, "is_windows", TRUE)
withr::local_options(pkg.build_copy_method = "link")
expect_equal(get_copy_method(), "copy")
withr::local_options(pkg.build_copy_method = "foobar")
expect_error(get_copy_method(), "pkg.build_copy_method")
withr::local_options(pkg.build_copy_method = 1:10)
expect_error(get_copy_method(), "It must be a string")
withr::local_options(pkg.build_copy_method = NULL)
mockery::stub(get_copy_method, "desc::desc_get", "link")
expect_equal(get_copy_method(), "copy")
})
test_that("Ignoring .Rbuildignore", {
pkgdir <- file.path(withr::local_tempdir("pkgbuild-test-"), "pkg")
mkdirp(pkgdir)
writeLines(
c("Package: pkg", "Version: 1.0.0"),
file.path(pkgdir, "DESCRIPTION")
)
# create some structure with files to ignore and keep
writeLines(c(
"^docs$",
"^src/.*[.]o$",
"^\\.Rbuildignore$"
), file.path(pkgdir, ".Rbuildignore"))
mkdirp(file.path(pkgdir, "src"))
file.create(file.path(pkgdir, "src", "src.c"))
file.create(file.path(pkgdir, "src", "src.o"))
mkdirp(file.path(pkgdir, "docs"))
file.create(file.path(pkgdir, "docs", "foo"))
files <- build_files(pkgdir)
expect_snapshot(files[, c("path", "exclude", "isdir", "trimmed")])
})
test_that("copying on windows", {
# this works on Unix as well
environment(cp)$wind <- TRUE
on.exit(environment(cp)$wind <- NULL, add = TRUE)
tmp <- withr::local_tempdir("pkgbuild-test-")
# link
withr::local_options(pkg.build_copy_method = "copy")
unlink(tmp, recursive = TRUE)
expect_no_warning(
copy_package_tree(test_path("testDummy"), tmp)
)
expect_snapshot(
sort(dir(tmp, recursive = TRUE, include.dirs = TRUE))
)
})
test_that("cp error", {
environment(cp)$wind <- TRUE
on.exit(environment(cp)$wind <- NULL, add = TRUE)
withr::local_dir(withr::local_tempdir())
expect_snapshot(error = TRUE, cp("foo", "bar"))
})
test_that("detect_cp_args", {
mockery::stub(
detect_cp_args,
"processx::run",
function(...) stop("nope")
)
expect_snapshot(detect_cp_args())
mockery::stub(
detect_cp_args,
"processx::run",
function(f1, f2) file.create(f2)
)
expect_snapshot(detect_cp_args())
})
test_that("cp error on Unix", {
skip_on_os("windows")
withr::local_dir(withr::local_tempdir())
expect_snapshot(
error = TRUE,
cp("foo", "bar"),
# do not include the cp output because it is slightly different on
# macOS, Linux, etc.
transform = function(x) utils::head(x, 3)
)
})
pkgbuild/tests/testthat/test-build_tools.R 0000644 0001762 0000144 00000000466 14211634664 020511 0 ustar ligges users
test_that("tests always run in environment with dev tools", {
without_cache({
expect_true(has_build_tools())
expect_equal(has_rtools(), is_windows())
})
})
test_that("unless specifically disabled", {
without_compiler({
expect_false(has_build_tools())
expect_false(has_rtools())
})
})
pkgbuild/tests/testthat/testWithSrc/ 0000755 0001762 0000144 00000000000 14152340747 017347 5 ustar ligges users pkgbuild/tests/testthat/testWithSrc/NAMESPACE 0000644 0001762 0000144 00000000012 14152340747 020557 0 ustar ligges users export(a)
pkgbuild/tests/testthat/testWithSrc/DESCRIPTION 0000644 0001762 0000144 00000000272 14152340747 021056 0 ustar ligges users Package: testWithSrc
Title: Tools to make developing R code easier
License: GPL-2
Description:
Author: Hadley
Maintainer: Hadley
Version: 0.1
pkgbuild/tests/testthat/testWithSrc/src/ 0000755 0001762 0000144 00000000000 14527147120 020132 5 ustar ligges users pkgbuild/tests/testthat/testWithSrc/src/add1.c 0000644 0001762 0000144 00000000565 14152340747 021121 0 ustar ligges users // In C ----------------------------------------
#include
#include
SEXP add1(SEXP a) {
SEXP result = PROTECT(allocVector(REALSXP, 1));
REAL(result)[0] = asReal(a) + 1;
UNPROTECT(1);
return result;
}
SEXP mult2(SEXP a) {
SEXP result = PROTECT(allocVector(REALSXP, 1));
REAL(result)[0] = asReal(a) * 2;
UNPROTECT(1);
return result;
}
pkgbuild/tests/testthat/testWithSrc/R/ 0000755 0001762 0000144 00000000000 14527147117 017552 5 ustar ligges users pkgbuild/tests/testthat/testWithSrc/R/a.R 0000644 0001762 0000144 00000000007 14152340747 020110 0 ustar ligges users a <- 1
pkgbuild/tests/testthat/testWithSrc/R/b.R 0000644 0001762 0000144 00000000007 14152340747 020111 0 ustar ligges users b <- 2
pkgbuild/tests/testthat/_snaps/ 0000755 0001762 0000144 00000000000 14526624207 016350 5 ustar ligges users pkgbuild/tests/testthat/_snaps/exclude.md 0000644 0001762 0000144 00000004674 14527147121 020332 0 ustar ligges users # copy_package_tree creates package dir
Code
sort(dir(tmp, recursive = TRUE, include.dirs = TRUE))
Output
[1] "testDummy" "testDummy/DESCRIPTION" "testDummy/NAMESPACE"
[4] "testDummy/R" "testDummy/R/a.R" "testDummy/R/b.R"
---
Code
sort(dir(tmp, recursive = TRUE, include.dirs = TRUE))
Output
[1] "testDummy" "testDummy/DESCRIPTION" "testDummy/NAMESPACE"
[4] "testDummy/R" "testDummy/R/a.R" "testDummy/R/b.R"
# exclusions
Code
files[, c("path", "exclude", "isdir", "trimmed")]
Output
path exclude isdir trimmed
1 .RData TRUE FALSE FALSE
2 .Rbuildignore FALSE FALSE FALSE
3 .Rhistory TRUE FALSE FALSE
4 .git TRUE TRUE FALSE
5 DESCRIPTION FALSE FALSE FALSE
6 docs TRUE TRUE FALSE
7 src FALSE TRUE TRUE
8 src/.DS_Store TRUE FALSE FALSE
9 src/foo.c.bak TRUE FALSE FALSE
10 src/foo.c.swp TRUE FALSE FALSE
11 src/foo.c~ TRUE FALSE FALSE
12 src/foo.d TRUE FALSE FALSE
13 src/src.c FALSE FALSE FALSE
14 src/src.o TRUE FALSE FALSE
# Ignoring .Rbuildignore
Code
files[, c("path", "exclude", "isdir", "trimmed")]
Output
path exclude isdir trimmed
1 .Rbuildignore FALSE FALSE FALSE
2 DESCRIPTION FALSE FALSE FALSE
3 docs TRUE TRUE FALSE
4 src FALSE TRUE TRUE
5 src/src.c FALSE FALSE FALSE
6 src/src.o TRUE FALSE FALSE
# copying on windows
Code
sort(dir(tmp, recursive = TRUE, include.dirs = TRUE))
Output
[1] "testDummy" "testDummy/DESCRIPTION" "testDummy/NAMESPACE"
[4] "testDummy/R" "testDummy/R/a.R" "testDummy/R/b.R"
# cp error
Code
cp("foo", "bar")
Condition
Error in `cp()`:
! Could not copy package files.
i Failed to copy 'foo' to 'bar'.
# detect_cp_args
Code
detect_cp_args()
Output
[1] "-pLR"
---
Code
detect_cp_args()
Output
[1] "-LR" "--preserve=timestamps"
# cp error on Unix
Code
cp("foo", "bar")
Condition
Error in `cp()`:
! Could not copy package files.
i Failed to copy 'foo' to 'bar'.
pkgbuild/tests/testthat/_snaps/build.md 0000644 0001762 0000144 00000001634 14527147117 017776 0 ustar ligges users # warnings can be turned into errors
Code
build(file.path(src, "testDummy"), dest_path = dest, quiet = TRUE)
Message
! Stopping as requested for a warning during `R CMD build`.
! The full output is printed below.
* checking for file '' ... OK
* preparing 'testDummy':
* checking DESCRIPTION meta-information ... OK
* checking for LF line-endings in source and make files and shell scripts
* checking for empty or unneeded directories
NB: this package now depends on R (>= 3.5.0)
WARNING: Added dependency on R >= 3.5.0 because serialized objects in
serialize/load version 3 cannot be read in older versions of R.
File(s) containing such objects:
'testDummy/inst/testthat-problems.rds'
* building 'testDummy_0.1.tar.gz'
Condition
Error in `force()`:
! converted from `R CMD build` warning.
pkgbuild/tests/testthat/_snaps/utils.md 0000644 0001762 0000144 00000001300 14527147122 020021 0 ustar ligges users # should_add_compiler_flags errors
Code
should_add_compiler_flags()
Condition
Error in `should_add_compiler_flags()`:
! Invalid `pkg.build_extra_flags` option.
i It must be `TRUE`, `FALSE` or "missing", not an integer vector.
---
Code
should_add_compiler_flags()
Condition
Error in `should_add_compiler_flags()`:
! Invalid `pkg_build_extra_flags` option.
i It must be `TRUE`, `FALSE` or "missing", not "foobar".
---
Code
should_add_compiler_flags()
Condition
Error in `should_add_compiler_flags()`:
! Invalid `PKG_BUILD_EXTRA_FLAGS` environment variable.
i Must be one of `true`, `false` or `missing`.
pkgbuild/tests/testthat/_snaps/style.md 0000644 0001762 0000144 00000000535 14527147121 020031 0 ustar ligges users # style
Code
cat(style(ok = "OK", "\n", note = "NOTE", "\n", warn = "WARN", "\n", err = "ERROR",
"\n", pale = "Not important", "\n", timing = "[1m]", "\n"))
Output
[32mOK[39m
[38;5;214mNOTE[39m
[1m[38;5;214mWARN[39m[22m
[31mERROR[39m
[38;5;247mNot important[39m
[36m[1m][39m
pkgbuild/tests/testthat/_snaps/compiler.md 0000644 0001762 0000144 00000000402 14527147121 020474 0 ustar ligges users # has_compiler: returns the value of the has_compiler option
Code
has_compiler()
Condition
Error in `has_compiler()`:
!
! Invalid `pkgbuild.has_compiler` option.
i It must be `TRUE` or `FALSE`, not an integer vector.
pkgbuild/tests/testthat/test-compile_dll.R 0000644 0001762 0000144 00000000342 14211634664 020446 0 ustar ligges users
test_that("can compile a DLL and clean up afterwards", {
expect_error(compile_dll("testWithSrc", quiet = TRUE, register_routines = FALSE), NA)
clean_dll("testWithSrc")
expect_equal(dir("testWithSrc/src"), "add1.c")
})
pkgbuild/tests/testthat/test-style.R 0000644 0001762 0000144 00000000432 14526624204 017321 0 ustar ligges users test_that("style", {
withr::local_options(cli.num_colors = 256)
expect_snapshot(
cat(style(
ok = "OK", "\n",
note = "NOTE", "\n",
warn = "WARN", "\n",
err = "ERROR", "\n",
pale = "Not important", "\n",
timing = "[1m]", "\n"
))
)
})
pkgbuild/tests/testthat/test-utils.R 0000644 0001762 0000144 00000007540 14340630410 017316 0 ustar ligges users
test_that("should_stop_for_warnings", {
withr::local_options(pkg.build_stop_for_warnings = NULL)
withr::local_envvar(PKG_BUILD_STOP_FOR_WARNINGS = NA_character_)
expect_false(should_stop_for_warnings())
withr::local_options(pkg.build_stop_for_warnings = FALSE)
withr::local_envvar(PKG_BUILD_STOP_FOR_WARNINGS = "true")
expect_false(should_stop_for_warnings())
withr::local_options(pkg.build_stop_for_warnings = TRUE)
withr::local_envvar(PKG_BUILD_STOP_FOR_WARNINGS = "false")
expect_true(should_stop_for_warnings())
withr::local_options(pkg.build_stop_for_warnings = NULL)
withr::local_envvar(PKG_BUILD_STOP_FOR_WARNINGS = "true")
expect_true(should_stop_for_warnings())
withr::local_options(pkg.build_stop_for_warnings = NULL)
withr::local_envvar(PKG_BUILD_STOP_FOR_WARNINGS = "false")
expect_false(should_stop_for_warnings())
withr::local_options(pkg.build_stop_for_warnings = 1:10)
withr::local_envvar(PKG_BUILD_STOP_FOR_WARNINGS = "false")
expect_error(should_stop_for_warnings(), "option must be")
withr::local_options(pkg.build_stop_for_warnings = NULL)
withr::local_envvar(PKG_BUILD_STOP_FOR_WARNINGS = "foobar")
expect_error(should_stop_for_warnings(), "environment variable must be")
})
test_that("isFALSE", {
pos <- list(FALSE, structure(FALSE, class = "foo"))
neg <- list(1, c(FALSE, TRUE), NA, list(FALSE))
for (p in pos) expect_true(isFALSE(p), info = p)
for (n in neg) expect_false(isFALSE(n), info = n)
})
test_that("should_add_compiler_flags", {
# should not be called if option is set
mockery::stub(
should_add_compiler_flags,
"makevars_user",
function() stop("dont")
)
# options is TRUE
withr::local_options(pkg.build_extra_flags = TRUE)
expect_true(should_add_compiler_flags())
# options is FALSE
withr::local_options(pkg.build_extra_flags = FALSE)
expect_false(should_add_compiler_flags())
# depends on whether Makevars exists
withr::local_options(pkg.build_extra_flags = "missing")
mockery::stub(
should_add_compiler_flags,
"makevars_user",
function() character()
)
expect_true(should_add_compiler_flags())
mockery::stub(
should_add_compiler_flags,
"makevars_user",
function() "foobar"
)
withr::local_options(pkg.build_extra_flags = "missing")
expect_false(should_add_compiler_flags())
mockery::stub(
should_add_compiler_flags,
"makevars_user",
function() stop("dont")
)
withr::local_options(pkg.build_extra_flags = NULL)
# env var true
withr::local_envvar(PKG_BUILD_EXTRA_FLAGS = "true")
expect_true(should_add_compiler_flags())
# env var false
withr::local_envvar(PKG_BUILD_EXTRA_FLAGS = "false")
expect_false(should_add_compiler_flags())
# depends on whether Makevars exists
withr::local_envvar(PKG_BUILD_EXTRA_FLAGS = "missing")
mockery::stub(
should_add_compiler_flags,
"makevars_user",
function() character()
)
expect_true(should_add_compiler_flags())
mockery::stub(
should_add_compiler_flags,
"makevars_user",
function() "foobar"
)
expect_false(should_add_compiler_flags())
# no option or env var, then TRUE
mockery::stub(
should_add_compiler_flags,
"makevars_user",
function() stop("dont")
)
withr::local_options(pkg.build_extra_flags = NULL)
withr::local_envvar(PKG_BUILD_EXTRA_FLAGS = NA_character_)
expect_true(should_add_compiler_flags())
})
test_that("should_add_compiler_flags errors", {
# invalid option type
withr::local_options(pkg.build_extra_flags = 1:10)
expect_snapshot(error = TRUE, should_add_compiler_flags())
# invalid option value
withr::local_options(pkg.build_extra_flags = "foobar")
expect_snapshot(error = TRUE, should_add_compiler_flags())
# invalid env var value
withr::local_options(pkg.build_extra_flags = NULL)
withr::local_envvar(PKG_BUILD_EXTRA_FLAGS = "foo")
expect_snapshot(error = TRUE, should_add_compiler_flags())
})
pkgbuild/tests/testthat/test-compiler-flags.R 0000644 0001762 0000144 00000001001 14337373664 021071 0 ustar ligges users
test_that("has_compiler_colored_diagnostics", {
mockery::stub(
has_compiler_colored_diagnostics,
"cache_exists",
function(...) stop("nope")
)
withr::local_envvar(PKG_BUILD_COLOR_DIAGNOSTICS = "true")
expect_true(has_compiler_colored_diagnostics())
withr::local_envvar(PKG_BUILD_COLOR_DIAGNOSTICS = "false")
expect_false(has_compiler_colored_diagnostics())
withr::local_envvar(PKG_BUILD_COLOR_DIAGNOSTICS = NA_character_)
expect_error(has_compiler_colored_diagnostics(), "nope")
})
pkgbuild/tests/testthat/test-archives.R 0000644 0001762 0000144 00000001776 14211634664 020003 0 ustar ligges users
test_that("is_zip_file", {
expect_true(is_zip_file(file.path("fixtures", "xxx.zip")))
expect_false(is_zip_file(file.path("fixtures", "xxx.gz")))
expect_false(is_zip_file(file.path("fixtures", "xxx.tar.gz")))
})
test_that("is_gz_file", {
expect_false(is_gz_file(file.path("fixtures", "xxx.zip")))
expect_true(is_gz_file(file.path("fixtures", "xxx.gz")))
expect_true(is_gz_file(file.path("fixtures", "xxx.tar.gz")))
})
test_that("is_tar_gz_file", {
expect_false(is_tar_gz_file(file.path("fixtures", "xxx.zip")))
expect_false(is_tar_gz_file(file.path("fixtures", "xxx.gz")))
expect_true(is_tar_gz_file(file.path("fixtures", "xxx.tar.gz")))
})
test_that("pkg_has_src", {
expect_false(pkg_has_src(file.path("fixtures", "testDummy_0.1.tar.gz")))
expect_true(pkg_has_src(file.path("fixtures", "testWithSrc_0.1.tar.gz")))
})
test_that("pkg_has_src on non-package files", {
expect_error(pkg_has_src(file.path("fixtures", "xxx.zip")))
expect_error(pkg_has_src(file.path("fixtures", "xxx.tar.gz")))
})
pkgbuild/tests/testthat/test-find-package-root.R 0000644 0001762 0000144 00000002004 14526673307 021460 0 ustar ligges users test_that("find_package_root", {
tmp <- tempfile()
on.exit(unlink(tmp, recursive = TRUE), add = TRUE)
mkdirp(file.path(tmp, "a", "b", "c", "d"))
lns <- "Package: this"
writeLines(lns, file.path(tmp, "DESCRIPTION"))
expect_equal(
readLines(file.path(find_package_root(tmp), "DESCRIPTION")),
lns
)
expect_equal(
readLines(file.path(
find_package_root(file.path(tmp, "a")), "DESCRIPTION"
)),
lns
)
expect_equal(
readLines(file.path(
find_package_root(file.path(tmp, "a", "b", "c", "d")), "DESCRIPTION"
)),
lns
)
wd <- getwd()
on.exit(setwd(wd), add = TRUE)
setwd(file.path(tmp, "a", "b", "c"))
expect_equal(
readLines(file.path(find_package_root("."), "DESCRIPTION")),
lns
)
})
test_that("find_package_root errors", {
expect_error(
find_package_root(basename(tempfile())),
"Path does not exist"
)
if (!file.exists("/DESCRIPTION")) {
expect_error(
find_package_root("/"),
"Could not find R package"
)
}
})
pkgbuild/tests/build-tools.R 0000644 0001762 0000144 00000000063 14152340747 015603 0 ustar ligges users library(pkgbuild)
check_build_tools(debug = TRUE)
pkgbuild/tests/testthat.R 0000644 0001762 0000144 00000000074 14152340747 015210 0 ustar ligges users library(testthat)
library(pkgbuild)
test_check("pkgbuild")
pkgbuild/R/ 0000755 0001762 0000144 00000000000 14535333212 012255 5 ustar ligges users pkgbuild/R/pkgbuild-package.R 0000644 0001762 0000144 00000000135 14211634664 015577 0 ustar ligges users #' @keywords internal
"_PACKAGE"
## usethis namespace: start
## usethis namespace: end
NULL
pkgbuild/R/rtools-cache.R 0000644 0001762 0000144 00000001433 14211634664 014772 0 ustar ligges users #' @export
#' @rdname has_rtools
rtools_path <- function() {
if (!is_windows()) {
return(NA_character_)
}
if (!rtools_path_is_set()) {
has_rtools()
}
cache_get("rtools_path")
}
rtools_path_is_set <- function() {
cache_exists("rtools_path")
}
rtools_path_set <- function(rtools) {
stopifnot(is.rtools(rtools))
path <- file.path(rtools$path, version_info[[rtools$version]]$path)
# If using gcc49 and _without_ a valid BINPREF already set
# Do NOT set BINPREF anymore for R 4.0 / rtools40
if (!is_R4() && using_gcc49() && is.null(rtools$valid_binpref)) {
Sys.setenv(BINPREF = file.path(rtools$path, "mingw_$(WIN)", "bin", "/"))
}
cache_set("rtools_path", path)
}
using_gcc49 <- function() {
grepl("4.9.3", Sys.getenv("R_COMPILED_BY"), fixed = TRUE)
}
pkgbuild/R/utils.R 0000644 0001762 0000144 00000013664 14526627124 013562 0 ustar ligges users dir.exists <- function(x) {
res <- file.exists(x) & file.info(x)$isdir
stats::setNames(res, x)
}
pkg_path <- function(path = ".") {
find_package_root(path)
}
pkg_name <- function(path = ".") {
desc::desc_get("Package", pkg_path(path))[[1]]
}
gcc_arch <- function() {
if (Sys.getenv("R_ARCH") == "/i386") "32" else "64"
}
is_windows <- function() {
.Platform$OS.type == "windows"
}
is_string <- function(x) {
is.character(x) && length(x) == 1 && !is.na(x)
}
is_na <- function(x) {
identical(x, NA) ||
identical(x, NA_integer_) ||
identical(x, NA_character_) ||
identical(x, NA_real_) ||
identical(x, NA_complex_)
}
is_dir <- function(x) {
isTRUE(file.info(x)$isdir)
}
# This is tools::makevars_user, provided here for backwards compatibility with older versions of R
makevars_user <- function() {
m <- character()
if (.Platform$OS.type == "windows") {
if (!is.na(f <- Sys.getenv("R_MAKEVARS_USER", NA_character_))) {
if (file.exists(f)) {
m <- f
}
} else if ((Sys.getenv("R_ARCH") == "/x64") && file.exists(f <- path.expand("~/.R/Makevars.win64"))) {
m <- f
} else if (file.exists(f <- path.expand("~/.R/Makevars.win"))) {
m <- f
} else if (file.exists(f <- path.expand("~/.R/Makevars"))) {
m <- f
}
} else {
if (!is.na(f <- Sys.getenv("R_MAKEVARS_USER", NA_character_))) {
if (file.exists(f)) {
m <- f
}
} else if (file.exists(f <- path.expand(paste0(
"~/.R/Makevars-",
Sys.getenv("R_PLATFORM")
)))) {
m <- f
} else if (file.exists(f <- path.expand("~/.R/Makevars"))) {
m <- f
}
}
m
}
last_char <- function(x) {
l <- nchar(x)
substr(x, l, l)
}
cat0 <- function(..., sep = "") {
cat(..., sep = "")
}
is_flag <- function(x) {
is.logical(x) && length(x) == 1 && !is.na(x)
}
flag_true_values <- c("true", "yes", "on", "1")
flag_false_values <- c("false", "no", "off", "0")
interpret_envvar_flag <- function(name, default = "false") {
env <- tolower(Sys.getenv(name, default))
if (env %in% flag_true_values) {
return(TRUE)
}
if (env %in% flag_false_values) {
return(FALSE)
}
if (is.na(env)) {
return(NA)
}
stop(cli::format_error(
"The {.envvar {name}} environment variable must be {.code true} or
{.code false}, if set."
))
}
get_config_flag_value <- function(name, default = FALSE) {
option_name <- paste0("pkg.build_", tolower(name))
opt <- getOption(option_name, NULL)
if (!is.null(opt)) {
if (!is_flag(opt)) {
stop(cli::format_error(
"The {.code {option_name}} option must be {.code TRUE} or
{.code FALSE}, if set."
))
}
return(opt)
}
envvar_name <- paste0("PKG_BUILD_", toupper(name))
interpret_envvar_flag(envvar_name, default = tolower(as.character(default)))
}
should_stop_for_warnings <- function() {
get_config_flag_value("stop_for_warnings")
}
isFALSE <- function(x) {
is.logical(x) && length(x) == 1L && !is.na(x) && !x
}
should_add_compiler_flags <- function() {
val <- getOption("pkg.build_extra_flags", NULL)
if (isTRUE(val)) {
return(TRUE)
}
if (isFALSE(val)) {
return(FALSE)
}
if (identical(val, "missing")) {
return(length(makevars_user()) == 0)
}
if (!is.null(val)) {
if (!is_string(val)) {
stop(cli::format_error(c(
"Invalid {.code pkg.build_extra_flags} option.",
i = "It must be {.code TRUE}, {.code FALSE} or {.str missing}, not
{.type {val}}."
)))
} else {
stop(cli::format_error(c(
"Invalid {.code pkg_build_extra_flags} option.",
i = "It must be {.code TRUE}, {.code FALSE} or {.str missing}, not
{.str {val}}."
)))
}
}
val <- Sys.getenv("PKG_BUILD_EXTRA_FLAGS", "true")
if (val %in% flag_true_values) {
return(TRUE)
}
if (val %in% flag_false_values) {
return(FALSE)
}
if (val %in% "missing") {
return(length(makevars_user()) == 0)
}
stop(cli::format_error(c(
"Invalid {.envvar PKG_BUILD_EXTRA_FLAGS} environment variable.",
i = "Must be one of {.code true}, {.code false} or {.code missing}."
)))
}
get_desc_config_flag <- function(path, name) {
name <- paste0("Config/build/", name)
val <- desc::desc_get(name, file = path)
if (is.na(val)) {
return(NULL)
}
lval <- tolower(val)
if (lval %in% flag_true_values) {
return(TRUE)
}
if (lval %in% flag_false_values) {
return(FALSE)
}
stop(cli::format_error(
"The {.code {name}} entry in {.path DESCRIPTION} must be {.code TRUE}
or {.code FALSE}.",
"i" = "It is {.val {val}}."
))
}
mkdirp <- function(path, mode = NULL) {
if (file.exists(path)) {
if (file.info(path)$isdir) {
if (is.null(mode)) {
return()
}
mode <- as.octmode(mode)
emode <- as.octmode(file.info(path)$mode)
if (emode == mode) {
return()
}
ret <- Sys.chmod(path, mode, use_umask = FALSE)
if (!ret) {
stop(cli::format_error(c(
"Path {.path {path}} exists, but could not update mode to
{.code {mode}} from {.code {emode}}."
)))
}
return()
}
stop(cli::format_error(c(
"Could not create directory {.path {path}}.",
i = "Path already exists, but it is not a directory."
)))
}
if (is.null(mode)) mode <- "0777"
wrg <- NULL
withCallingHandlers(
ret <- dir.create(
path,
showWarnings = TRUE,
recursive = TRUE,
mode = mode
),
warning = function(w) {
wrg <<- w
if (!is.null(findRestart("muffleWarning"))) {
invokeRestart("muffleWarning")
}
}
)
if (!ret) {
stop(cli::format_error(c(
"Could not create directory {.path {path}}.",
i = if (!is.null(wrg)) {
"From {.fn dir.create}: {conditionMessage(wrg)}."
} else {
"For reasons unknown."
}
)))
}
}
verb_for_cli <- function(x) {
x <- gsub("\n", "\f", x, fixed = TRUE)
x <- gsub(" ", "\u00a0", x, fixed = TRUE)
x
}
pkgbuild/R/build-bg.R 0000644 0001762 0000144 00000007635 14527146742 014113 0 ustar ligges users #' Build package in the background
#'
#' This R6 class is a counterpart of the [build()] function, and
#' represents a background process that builds an R package.
#'
#' @section Usage:
#' ```
#' bp <- pkgbuild_process$new(path = ".", dest_path = NULL,
#' binary = FALSE, vignettes = TRUE, manual = FALSE, args = NULL)
#' bp$get_dest_path()
#' ```
#'
#' Other methods are inherited from [callr::rcmd_process] and
#' `processx::process`.
#'
#' @section Arguments:
#' See the corresponding arguments of [build()].
#'
#' @section Details:
#' Most methods are inherited from [callr::rcmd_process] and
#' `processx::process`.
#'
#' `bp$get_dest_path()` returns the path to the built package.
#'
#' @section Examples:
#' ```
#' ## Here we are just waiting, but in a more realistic example, you
#' ## would probably run some other code instead...
#' bp <- pkgbuild_process$new("mypackage", dest_path = tempdir())
#' bp$is_alive()
#' bp$get_pid()
#' bp$wait()
#' bp$read_all_output_lines()
#' bp$read_all_error_lines()
#' bp$get_exit_status()
#' bp$get_dest_path()
#' ```
#'
#' @importFrom R6 R6Class
#' @name pkgbuild_process
NULL
#' @export
pkgbuild_process <- R6Class(
"pkgbuild_process",
inherit = callr::rcmd_process,
public = list(
initialize = function(path = ".", dest_path = NULL, binary = FALSE,
vignettes = TRUE, manual = FALSE, clean_doc = NULL,
args = NULL, needs_compilation = pkg_has_src(path),
compile_attributes = FALSE,
register_routines = FALSE, quiet = FALSE) {
rcb_init(
self, private, super, path, dest_path, binary, vignettes,
manual, clean_doc, args, needs_compilation, compile_attributes,
register_routines, quiet
)
},
finalize = function() {
unlink(private$makevars_file)
super$kill()
},
is_incomplete_error = function() FALSE,
read_all_error = function() "",
read_all_error_lines = function() character(),
read_error = function(n = -1) "",
read_error_lines = function(n = -1) character(),
get_dest_path = function() private$dest_path,
get_built_file = function() {
if (self$is_alive()) stop("Still alive")
if (self$get_exit_status() != 0) stop("Build process failed")
## Already copied?
if (!is.null(private$out_file)) {
return(private$out_file)
}
## No, copy, and remove temp dir, order is important here!
file_name <- dir(private$out_dir)
tmp_file <- file.path(private$out_dir, file_name)
file.copy(tmp_file, private$dest_path, overwrite = TRUE)
private$out_file <- file.path(private$dest_path, file_name)
unlink(private$out_dir, recursive = TRUE)
private$out_file
},
kill = function(...) {
unlink(private$makevars_file)
super$kill(...)
}
),
private = list(
path = NULL,
dest_path = NULL,
out_dir = NULL,
out_file = NULL,
makevars_file = NULL
)
)
rcb_init <- function(self, private, super, path, dest_path, binary,
vignettes, manual, clean_doc, args, needs_compilation,
compile_attributes, register_routines, quiet) {
options <- build_setup(
path, dest_path, binary, vignettes, manual, clean_doc,
args, needs_compilation, compile_attributes,
register_routines, quiet
)
private$path <- options$path
private$dest_path <- options$dest_path
private$out_dir <- options$out_dir
private$makevars_file <- tempfile()
## Build tools already checked in setup
withr_set_makevars(compiler_flags(debug = FALSE), new_path = private$makevars_file)
withr_with_envvar(
c("R_MAKEVARS_USER" = private$makevars_file), {
options <- callr::rcmd_process_options(
cmd = options$cmd,
cmdargs = c(options$path, options$args),
wd = options$out_dir,
stderr = "2>&1"
)
super$initialize(options)
invisible(self)
}
)
}
pkgbuild/R/with-debug.R 0000644 0001762 0000144 00000003565 14426741134 014455 0 ustar ligges users #' Temporarily set debugging compilation flags.
#'
#' @param code to execute.
#' @param CFLAGS flags for compiling C code
#' @param CXXFLAGS flags for compiling C++ code
#' @param FFLAGS flags for compiling Fortran code.
#' @param FCFLAGS flags for Fortran 9x code.
#' @inheritParams compiler_flags
#' @family debugging flags
#' @export
#' @examples
#' flags <- names(compiler_flags(TRUE))
#' with_debug(Sys.getenv(flags))
#' \dontrun{
#' install("mypkg")
#' with_debug(install("mypkg"))
#' }
with_debug <- function(code, CFLAGS = NULL, CXXFLAGS = NULL,
FFLAGS = NULL, FCFLAGS = NULL, debug = TRUE) {
defaults <- compiler_flags(debug = debug)
flags <- c(
CFLAGS = CFLAGS, CXXFLAGS = CXXFLAGS,
FFLAGS = FFLAGS, FCFLAGS = FCFLAGS
)
flags <- unlist(utils::modifyList(as.list(defaults), as.list(flags)))
withr_with_makevars(flags, code)
}
#' Tools for testing pkgbuild
#'
#' `with_compiler` temporarily disables code compilation by setting
#' `CC`, `CXX`, makevars to `test`. `without_cache`
#' resets the cache before and after running `code`.
#'
#' @param code Code to execute with broken compilers
#' @export
without_compiler <- function(code) {
flags <- c(
CC = "test",
CXX = "test",
CXX11 = "test",
FC = "test"
)
if (is_windows()) {
without_cache({
cache_set("rtools_path", "")
withr_with_makevars(flags, code)
})
} else {
without_cache({
withr_with_makevars(flags, code)
})
}
}
#' @export
#' @rdname without_compiler
without_cache <- function(code) {
cache_reset()
on.exit(cache_reset())
code
}
#' @export
#' @rdname without_compiler
without_latex <- function(code) {
withr_with_options(list(PKGBUILD_TEST_FIXTURE_HAS_LATEX = FALSE), code)
}
#' @export
#' @rdname without_compiler
with_latex <- function(code) {
withr_with_options(list(PKGBUILD_TEST_FIXTURE_HAS_LATEX = TRUE), code)
}
pkgbuild/R/styles.R 0000644 0001762 0000144 00000001225 14526623107 013730 0 ustar ligges users # This is from https://github.com/r-lib/rcmdcheck/blob/7ee14764c2b17ee2c2f4131a9e19d1b56a66ed0f/R/styles.R
style <- function(..., sep = "") {
args <- list(...)
st <- names(args)
styles <- list(
"ok" = cli::col_green,
"note" = cli::make_ansi_style("orange"),
"warn" = function(x) cli::style_bold(cli::make_ansi_style("orange")(x)),
"err" = cli::col_red,
"pale" = cli::make_ansi_style("darkgrey"),
"timing" = cli::make_ansi_style("cyan")
)
nms <- names(args)
x <- lapply(seq_along(args), function(i) {
if (nzchar(nms[i])) styles[[nms[i]]](args[[i]]) else args[[i]]
})
paste(unlist(x), collapse = sep)
}
pkgbuild/R/rtools-metadata.R 0000644 0001762 0000144 00000003572 14442114442 015506 0 ustar ligges users version_info <- list(
"2.11" = list(
version_min = "2.10.0",
version_max = "2.11.1",
path = c("bin", "perl/bin", "MinGW/bin")
),
"2.12" = list(
version_min = "2.12.0",
version_max = "2.12.2",
path = c("bin", "perl/bin", "MinGW/bin", "MinGW64/bin")
),
"2.13" = list(
version_min = "2.13.0",
version_max = "2.13.2",
path = c("bin", "MinGW/bin", "MinGW64/bin")
),
"2.14" = list(
version_min = "2.13.0",
version_max = "2.14.2",
path = c("bin", "MinGW/bin", "MinGW64/bin")
),
"2.15" = list(
version_min = "2.14.2",
version_max = "2.15.1",
path = c("bin", "gcc-4.6.3/bin")
),
"2.16" = list(
version_min = "2.15.2",
version_max = "3.0.0",
path = c("bin", "gcc-4.6.3/bin")
),
"3.0" = list(
version_min = "2.15.2",
version_max = "3.0.99",
path = c("bin", "gcc-4.6.3/bin")
),
"3.1" = list(
version_min = "3.0.0",
version_max = "3.1.99",
path = c("bin", "gcc-4.6.3/bin")
),
"3.2" = list(
version_min = "3.1.0",
version_max = "3.2.99",
path = c("bin", "gcc-4.6.3/bin")
),
"3.3" = list(
version_min = "3.2.0",
version_max = "3.3.99",
path = if (using_gcc49()) {
"bin"
} else {
c("bin", "gcc-4.6.3/bin")
}
),
"3.4" = list(
version_min = "3.3.0",
version_max = "3.6.3",
path = "bin"
),
"3.5" = list(
version_min = "3.3.0",
version_max = "3.6.3",
path = "bin"
),
"4.0" = list(
version_min = "4.0.0",
version_max = "4.1.99",
path = c("usr/bin", "ucrt64/bin")
),
"4.2" = list(
version_min = "4.2.0",
version_max = "4.2.99",
path = "usr/bin"
),
"4.3" = list(
version_min = "4.3.0",
version_max = "99.99.99",
path = "usr/bin"
),
"custom" = list(
version_min = "2.10.0",
version_max = "99.99.99",
path = if (getRversion() >= "4.0.0") "usr/bin" else "bin"
)
)
pkgbuild/R/has_src.R 0000644 0001762 0000144 00000003217 14211634664 014033 0 ustar ligges users #' Does a source package have `src/` directory?
#'
#' If it does, you definitely need build tools.
#'
#' @param path Path to package (or directory within package).
#' @export
pkg_has_src <- function(path = ".") {
if (is_dir(path)) {
src_path <- file.path(pkg_path(path), "src")
file.exists(src_path)
} else {
tryCatch(
{
files <- if (is_zip_file(path)) {
utils::unzip(path, list = TRUE)$Name
} else if (is_tar_gz_file(path)) {
utils::untar(path, list = TRUE)
} else {
stop("not a zip or tar.gz file")
}
if (!any(grepl("^[^/]+/DESCRIPTION$", files))) {
stop("no DESCRIPTION file")
}
any(grepl("^[^/]+/src/?$", files))
},
error = function(e) {
e$message <- paste(
path, "is not a valid package archive file,",
e$message
)
stop(e)
}
)
}
}
is_zip_file <- function(file) {
buf <- readBin(file, what = "raw", n = 4)
length(buf) == 4 &&
buf[1] == 0x50 &&
buf[2] == 0x4b &&
(buf[3] == 0x03 || buf[3] == 0x05 || buf[5] == 0x07) &&
(buf[4] == 0x04 || buf[4] == 0x06 || buf[4] == 0x08)
}
is_gz_file <- function(file) {
buf <- readBin(file, what = "raw", n = 3)
length(buf) == 3 &&
buf[1] == 0x1f &&
buf[2] == 0x8b &&
buf[3] == 0x08
}
is_tar_gz_file <- function(file) {
if (!is_gz_file(file)) {
return(FALSE)
}
con <- gzfile(file, open = "rb")
on.exit(close(con))
buf <- readBin(con, what = "raw", n = 262)
length(buf) == 262 &&
buf[258] == 0x75 &&
buf[259] == 0x73 &&
buf[260] == 0x74 &&
buf[261] == 0x61 &&
buf[262] == 0x72
}
pkgbuild/R/compile-dll.R 0000644 0001762 0000144 00000015126 14442271546 014616 0 ustar ligges users #' Compile a .dll/.so from source.
#'
#' `compile_dll` performs a fake R CMD install so code that
#' works here should work with a regular install (and vice versa).
#' During compilation, debug flags are set with
#' \code{\link{compiler_flags}(TRUE)}.
#'
#' Invisibly returns the names of the DLL.
#'
#' ## Configuration
#'
#' ### Options
#'
#' * `pkg.build_extra_flags`: set this to `FALSE` to to opt out from adding
#' debug compiler flags in `compile_dll()`. Takes precedence over the
#' `PKG_BUILD_EXTRA_FLAGS` environment variable. Possible values:
#'
#' - `TRUE`: add extra flags,
#' - `FALSE`: do not add extra flags,
#' - `"missing"`: add extra flags if the user does not have a
#' `$HOME/.R/Makevars` file.
#'
#' ### Environment variables
#'
#' * `PKG_BUILD_EXTRA_FLAGS`: set this to `false` to to opt out from adding
#' debug compiler flags in `compile_dll()`. The `pkg.build_extra_flags` option
#' takes precedence over this environment variable. Possible values:
#'
#' - `"true"`: add extra flags,
#' - `"false"`: do not add extra flags,
#' - `"missing"`: add extra flags if the user does not have a
#' `$HOME/.R/Makevars` file.
#'
#' @note If this is used to compile code that uses Rcpp, you will need to
#' add the following line to your `Makevars` file so that it
#' knows where to find the Rcpp headers:
#' `PKG_CPPFLAGS=`$(R_HOME)/bin/Rscript -e 'Rcpp:::CxxFlags()'``
#'
#' @inheritParams build
#' @param force If `TRUE`, for compilation even if [needs_compile()] is
#' `FALSE`.
#' @param debug If `TRUE`, and if no user Makevars is found, then the build
#' runs without optimisation (`-O0`) and with debug symbols (`-g`). See
#' [compiler_flags()] for details. If you have a user Makevars (e.g.,
#' `~/.R/Makevars`) then this argument is ignored.
#' @seealso [clean_dll()] to delete the compiled files.
#' @export
compile_dll <- function(path = ".",
force = FALSE,
compile_attributes = pkg_links_to_cpp11(path) || pkg_links_to_rcpp(path),
register_routines = FALSE,
quiet = FALSE,
debug = TRUE) {
path <- pkg_path(path)
if (!needs_compile(path) && !isTRUE(force)) {
return(invisible())
}
check_build_tools(quiet = TRUE)
update_registration(path, compile_attributes, register_routines, quiet)
# Mock install the package to generate the DLL
xflags <- should_add_compiler_flags()
if (!quiet) {
cli::cli_alert_info(c(
"Re-compiling {.pkg {pkg_name(path)}}",
if (debug && xflags) " (debug build)"
))
}
install_dir <- tempfile("devtools_install_")
dir.create(install_dir)
build <- function() {
install_min(
path,
dest = install_dir,
components = "libs",
args = if (needs_clean(path)) "--preclean",
quiet = quiet
)
invisible(dll_path(file.path(install_dir, pkg_name(path))))
}
if (xflags) {
withr_with_makevars(compiler_flags(debug), {
if (debug) {
withr_with_envvar(c(DEBUG = "true"), build())
} else {
build()
}
})
} else {
build()
}
}
#' Remove compiled objects from /src/ directory
#'
#' Invisibly returns the names of the deleted files.
#'
#' @inheritParams build
#' @seealso [compile_dll()]
#' @export
clean_dll <- function(path = ".") {
path <- pkg_path(path)
# Clean out the /src/ directory and children:
# * individual object files
# * overall package definition file
# * symbols.rds (added when run inside R CMD check)
pattern <- sprintf(
"\\.(o|sl|so|dylib|a|dll)$|(%s\\.def)$|^symbols.rds$",
pkg_name(path)
)
files <- dir(
file.path(path, "src"),
pattern = pattern,
full.names = TRUE,
recursive = TRUE
)
unlink(files)
invisible(files)
}
# Returns the full path and name of the DLL file
dll_path <- function(path = ".") {
name <- paste(pkg_name(path), .Platform$dynlib.ext, sep = "")
file.path(path, "src", name)
}
mtime <- function(x) {
x <- x[file.exists(x)]
if (length(x) == 0) {
return(NULL)
}
max(file.info(x)$mtime)
}
globs <- function(path = ".", x) {
old <- getwd()
on.exit(setwd(old), add = TRUE)
setwd(path)
Sys.glob(x)
}
# List all source files in the package
sources <- function(path = ".") {
srcdir <- file.path(path, "src")
src <- c(
dir(srcdir, "\\.(c.*|f|rs)$", recursive = TRUE, full.names = TRUE),
dir(srcdir, "^Cargo\\.toml$", recursive = TRUE, full.names = TRUE)
)
extra <- desc::desc_get("Config/build/extra-sources", path)
if (!is.na(extra)) {
glb <- trimws(strsplit(extra, ",", fixed = TRUE)[[1]])
xs <- file.path(path, globs(path, glb))
xfls <- unlist(lapply(
xs,
dir,
recursive = TRUE,
full.names = TRUE
))
src <- c(src, xs, xfls)
}
src
}
# List all header files in the package
headers <- function(path = ".") {
incldir <- file.path(path, "inst", "include")
srcdir <- file.path(path, "src")
c(
dir(srcdir, "^Makevars.*$", recursive = TRUE, full.names = TRUE),
dir(srcdir, "\\.h.*$", recursive = TRUE, full.names = TRUE),
dir(incldir, "\\.h.*$", recursive = TRUE, full.names = TRUE)
)
}
#' Does the package need recompiling?
#' (i.e. is there a source or header file newer than the dll)
#' @inheritParams build
#' @keywords internal
#' @export
needs_compile <- function(path = ".") {
source <- mtime(c(sources(path), headers(path)))
# no source files, so doesn't need compile
if (is.null(source)) {
return(FALSE)
}
dll <- mtime(dll_path(path))
# no dll, so needs compile
if (is.null(dll)) {
return(TRUE)
}
source > dll
}
# Does the package need a clean compile?
# (i.e. is there a header or Makevars newer than the dll)
needs_clean <- function(path = ".") {
headers <- mtime(headers(path))
# no headers, so never needs clean compile
if (is.null(headers)) {
return(FALSE)
}
dll <- mtime(dll_path(path))
# no dll, so needs compile
if (is.null(dll)) {
return(TRUE)
}
headers > dll
}
install_min <- function(path = ".", dest, components = NULL, args = NULL, quiet = FALSE) {
stopifnot(is.character(dest), length(dest) == 1, file.exists(dest))
poss <- c("R", "data", "help", "demo", "inst", "docs", "exec", "libs")
if (!is.null(components)) {
components <- match.arg(components, poss, several.ok = TRUE)
}
no <- setdiff(poss, components)
no_args <- paste0("--no-", no)
rcmd_build_tools(
"INSTALL",
c(
path,
paste("--library=", dest, sep = ""),
no_args,
"--no-multiarch",
"--no-test-load",
args
),
fail_on_status = TRUE,
quiet = quiet
)
invisible(file.path(dest, pkg_name(path)))
}
pkgbuild/R/rtools-config.R 0000644 0001762 0000144 00000001433 14211634664 015174 0 ustar ligges users # First check if gcc set by BINPREF/CC is valid and use that if so
scan_config_for_rtools <- function(debug = FALSE) {
if (debug) {
cat("Scanning R CMD config CC...\n")
}
if (!is_R4() && !using_gcc49()) {
return()
}
cc_path <- gsub("\n", "", callr::rcmd_safe("config", "CC")$stdout)
# remove '-m64' from tail if it exists
cc_path <- sub("[[:space:]]+-m[[:digit:]]+$", "", cc_path)
if (debug) {
cat("cc_path:", cc_path, "\n")
}
cc_path <- find_arch_exe(cc_path, debug = debug)
if (cc_path == "") {
NULL
} else {
install_path <- dirname(dirname(dirname(cc_path)))
if (debug) {
cat("install_path:", install_path, "\n")
}
rtools(install_path, "custom", valid_binpref = TRUE)
}
}
is_R4 <- function() {
R.Version()$major >= "4"
}
pkgbuild/R/withr.R 0000644 0001762 0000144 00000013252 14442271526 013546 0 ustar ligges users
withr_with_makevars <- function(new, code, path = makevars_user()) {
makevars_file <- tempfile()
on.exit(unlink(makevars_file), add = TRUE)
force(path)
withr_with_envvar(c(R_MAKEVARS_USER = makevars_file), {
withr_set_makevars(new, path, makevars_file)
force(code)
})
}
withr_set_makevars <- function(variables, old_path = withr_makevars_user(),
new_path = tempfile()) {
if (length(variables) == 0) {
return()
}
stopifnot(withr_is_named(variables))
old <- NULL
if (length(old_path) == 1 && file.exists(old_path)) {
lines <- readLines(old_path)
old <- lines
lines <- c(old, paste(names(variables), variables, sep = " += "))
} else {
lines <- paste(names(variables), variables, sep = " += ")
}
if (!identical(old, lines)) {
writeLines(con = new_path, lines)
}
old
}
withr_makevars_user <- function() {
tools::makevars_user()
}
withr_is_named <- function(x) {
!is.null(names(x)) && all(names(x) != "")
}
# -------------------------------------------------------------------------
withr_get_envvar <- function(envs, action = "replace") {
envs <- withr_as_envvars(envs)
Sys.getenv(names(envs), names = TRUE, unset = NA)
}
withr_set_envvar <- function(envs, action = "replace") {
envs <- withr_as_envvars(envs)
stopifnot(is.character(action), length(action) == 1)
action <- match.arg(action, c("replace", "prefix", "suffix"))
if (length(envs) == 0) {
return()
}
old <- Sys.getenv(names(envs), names = TRUE, unset = NA)
set <- !is.na(envs)
both_set <- set & !is.na(old)
if (any(both_set)) {
if (action == "prefix") {
envs[both_set] <- paste(envs[both_set], old[both_set])
}
else if (action == "suffix") {
envs[both_set] <- paste(old[both_set], envs[both_set])
}
}
if (any(set)) do.call("Sys.setenv", as.list(envs[set]))
if (any(!set)) Sys.unsetenv(names(envs)[!set])
invisible(old)
}
withr_with_envvar <- function(new, code, action = "replace") {
old <- withr_get_envvar(envs = new, action = action)
on.exit(withr_set_envvar(old))
withr_set_envvar(envs = new, action = action)
force(code)
}
withr_as_envvars <- function(envs) {
if (length(envs) == 0) {
return(envs)
}
stopifnot(withr_is_named(envs))
envs[withr_vlapply(envs, is.null)] <- NA
envs <- envs[!duplicated(names(envs), fromLast = TRUE)]
envs
}
withr_vlapply <- function(X, FUN, ...) {
vapply(X, FUN, FUN.VALUE = logical(1), ...)
}
withr_is_named <- function (x) {
!is.null(names(x)) && all(names(x) != "")
}
# -------------------------------------------------------------------------
withr_with_temp_libpaths <- function (code, action = "prefix") {
old <- .libPaths()
on.exit(.libPaths(old))
withr_set_temp_libpaths(action = action)
force(code)
}
withr_set_temp_libpaths <- function (action = "prefix") {
paths <- tempfile("temp_libpath")
dir.create(paths)
withr_set_libpaths(paths, action = action)
}
withr_set_libpaths <- function (paths, action = "replace") {
paths <- withr_as_character(paths)
paths <- normalizePath(paths, mustWork = TRUE)
old <- .libPaths()
paths <- withr_merge_new(old, paths, action)
.libPaths(paths)
invisible(old)
}
withr_merge_new <- function(old, new, action, merge_fun = c) {
action <- match.arg(action, c("replace", "prefix", "suffix"))
if (action == "suffix") {
new <- merge_fun(old, new)
}
else if (action == "prefix") {
new <- merge_fun(new, old)
}
new
}
withr_as_character <- function(x) {
nms <- names(x)
res <- as.character(x)
names(res) <- nms
res
}
# -------------------------------------------------------------------------
withr_with_options <- function(new, code) {
old <- withr_set_options(new_options = new)
on.exit(withr_reset_options(old))
force(code)
}
withr_set_options <- function(new_options) {
do.call(options, as.list(new_options))
}
withr_reset_options <- function(old_options) {
options(old_options)
}
# -------------------------------------------------------------------------
withr_with_path <- function(new, code,
action = c("prefix", "suffix", "replace")) {
old <- withr_get_path(path = new, action = action)
on.exit((function(old) withr_set_path(old, "replace"))(old))
withr_set_path(path = new, action = action)
force(code)
}
withr_set_path <- function(path, action = c("prefix", "suffix", "replace")) {
action <- match.arg(action)
path <- withr_as_character(path)
path <- normalizePath(path, mustWork = FALSE)
old <- withr_get_path()
path <- withr_merge_new(old, path, action)
path <- paste(path, collapse = .Platform$path.sep)
Sys.setenv(PATH = path)
invisible(old)
}
withr_merge_new <- function(old, new, action, merge_fun = c) {
action <- match.arg(action, c("replace", "prefix", "suffix"))
if (action == "suffix") {
new <- merge_fun(old, new)
}
else if (action == "prefix") {
new <- merge_fun(new, old)
}
new
}
withr_get_path <- function(...) {
strsplit(Sys.getenv("PATH"), .Platform$path.sep)[[1]]
}
withr_local_path <- function (new = list(),
action = c("prefix", "suffix", "replace"),
.local_envir = parent.frame()) {
old <- withr_get_path(path = new, action = action)
withr_defer((function(old) withr_set_path(old, "replace"))(old), frame = .local_envir)
withr_set_path(path = new, action = action)
invisible(old)
}
# -------------------------------------------------------------------------
withr_defer <- function(expr, frame = parent.frame(), after = FALSE) {
thunk <- as.call(list(function() expr))
do.call(on.exit, list(thunk, add = TRUE, after = after), envir = frame)
}
# -------------------------------------------------------------------------
pkgbuild/R/compiler-flags.R 0000644 0001762 0000144 00000005152 14535333212 015307 0 ustar ligges users #' Default compiler flags used by devtools.
#'
#' These default flags enforce good coding practice by ensuring that
#' \env{CFLAGS} and \env{CXXFLAGS} are set to `-Wall -pedantic`.
#' These tests are run by cran and are generally considered to be good practice.
#'
#' By default [compile_dll()] is run with `compiler_flags(TRUE)`,
#' and check with `compiler_flags(FALSE)`. If you want to avoid the
#' possible performance penalty from the debug flags, install the package.
#'
#' @param debug If `TRUE` adds `-g -O0` to all flags
#' (Adding \env{FFLAGS} and \env{FCFLAGS})
#' @family debugging flags
#' @export
#' @examples
#' compiler_flags()
#' compiler_flags(TRUE)
compiler_flags <- function(debug = FALSE) {
res <-
if (Sys.info()[["sysname"]] == "SunOS") {
c(
CFLAGS = "-g",
CXXFLAGS = "-g",
CXX11FLAGS = "-g",
CXX14FLAGS = "-g",
CXX17FLAGS = "-g",
CXX20FLAGS = "-g"
)
} else if (debug) {
c(
CFLAGS = "-UNDEBUG -Wall -pedantic -g -O0",
CXXFLAGS = "-UNDEBUG -Wall -pedantic -g -O0",
CXX11FLAGS = "-UNDEBUG -Wall -pedantic -g -O0",
CXX14FLAGS = "-UNDEBUG -Wall -pedantic -g -O0",
CXX17FLAGS = "-UNDEBUG -Wall -pedantic -g -O0",
CXX20FLAGS = "-UNDEBUG -Wall -pedantic -g -O0",
FFLAGS = "-g -O0",
FCFLAGS = "-g -O0"
)
} else {
c(
CFLAGS = "-Wall -pedantic",
CXXFLAGS = "-Wall -pedantic",
CXX11FLAGS = "-Wall -pedantic",
CXX14FLAGS = "-Wall -pedantic",
CXX17FLAGS = "-Wall -pedantic",
CXX20FLAGS = "-Wall -pedantic"
)
}
if (cli::num_ansi_colors() > 1 && has_compiler_colored_diagnostics()) {
flags <- c(
"CFLAGS", "CXXFLAGS", "CXX11FLAGS",
"CXX14FLAGS", "CXX17FLAGS", "CXX20FLAGS"
)
res[flags] <- paste(res[flags], "-fdiagnostics-color=always")
}
res
}
has_compiler_colored_diagnostics <- function() {
val <- interpret_envvar_flag("PKG_BUILD_COLOR_DIAGNOSTICS", NA_character_)
if (!is.na(val)) {
return(val)
}
if (cache_exists("has_compiler_colored_diagnostics")) {
return(cache_get("has_compiler_colored_diagnostics"))
}
# We cannot use the existing has_compiler setting, because it may not have
# run with -fdiagnostics-color=always
if (cache_exists("has_compiler")) {
old <- cache_get("has_compiler")
cache_remove("has_compiler")
on.exit(cache_set("has_compiler", old))
} else {
on.exit(cache_remove("has_compiler"))
}
res <- withr_with_makevars(c(CFLAGS = "-fdiagnostics-color=always"), has_compiler())
cache_set("has_compiler_colored_diagnostics", res)
res
}
pkgbuild/R/latex.R 0000644 0001762 0000144 00000000621 14211634664 013522 0 ustar ligges users #' Is latex installed?
#'
#' Checks for presence of pdflatex on path.
#'
#' @export
has_latex <- function() {
if (!is.null(fix <- getOption("PKGBUILD_TEST_FIXTURE_HAS_LATEX"))) {
return(fix)
}
nzchar(Sys.which("pdflatex"))
}
#' @export
#' @rdname has_latex
check_latex <- function() {
if (!has_latex()) {
stop("LaTeX not installed (pdflatex not found)", call. = FALSE)
}
TRUE
}
pkgbuild/R/c-registration.R 0000644 0001762 0000144 00000007713 14211634664 015350 0 ustar ligges users update_registration <- function(path, compile_attributes, register_routines, quiet) {
if (compile_attributes) {
if (pkg_links_to_cpp11(path)) {
cpp11::cpp_register(path, quiet = quiet)
} else if (pkg_links_to_rcpp(path)) {
unlink(file.path(path, c("R/RcppExports.R", "src/RcppExports.cpp")))
Rcpp::compileAttributes(path, verbose = !quiet)
}
} else if (register_routines) {
update_c_registration(path)
check_namespace_registration(path)
}
}
update_c_registration <- function(path) {
path <- pkg_path(path)
pkgbuild_init_file <- file.path(path, "src", "init.c")
should_update <- !file.exists(pkgbuild_init_file) || any(grepl("generated by pkgbuild", readLines(pkgbuild_init_file)))
if (!should_update) {
return(invisible(character()))
}
# package_native_routine_registration_skeleton is not available before R 3.4
if (getRversion() < "3.4.0") {
return(invisible(character()))
}
con <- textConnection(NULL, "w")
tools::package_native_routine_registration_skeleton(path, con = con, character_only = FALSE)
lines <- textConnectionValue(con)
close(con)
if (length(lines) == 0) {
return(invisible(lines))
}
if (!file.exists(pkgbuild_init_file)) {
lines <- remove_fixme(lines)
} else {
current_lines <- readLines(pkgbuild_init_file)
current_range <- pkgbuild_generated_section(current_lines)
new_range <- tools_generated_section(lines)
lines <- c(
current_lines[seq(1, min(current_range) - 1)],
lines[new_range],
current_lines[seq(max(current_range) + 1, length(current_lines))]
)
}
lines <- add_generation_message(lines)
writeLines(lines, pkgbuild_init_file)
invisible(lines)
}
remove_fixme <- function(lines) {
fixme_loc <- grep("/* FIXME: ", lines, fixed = TRUE)
lines <- lines[-seq(fixme_loc, fixme_loc + 2)]
lines
}
tools_generated_section <- function(lines) {
start_loc <- grep("/* .Call calls */", lines, fixed = TRUE)
end_loc <- grep("};", lines, fixed = TRUE)
seq(start_loc, end_loc)
}
pkgbuild_generated_section <- function(lines) {
start_loc <- grep("/* Section generated by pkgbuild, do not edit */", lines, fixed = TRUE)
end_loc <- grep("/* End section generated by pkgbuild */", lines, fixed = TRUE)
seq(start_loc, end_loc)
}
add_generation_message <- function(lines) {
start_loc <- grep("/* .Call calls */", lines, fixed = TRUE)
end_loc <- grep("};", lines, fixed = TRUE)
if (end_loc <= start_loc) {
stop("Malformed init.c format")
}
lines <- append(lines, "/* Section generated by pkgbuild, do not edit */", after = start_loc - 1)
lines <- append(lines, "/* End section generated by pkgbuild */", after = end_loc + 1)
lines
}
check_namespace_registration <- function(path) {
path <- pkg_path(path)
namespace_file <- file.path(path, "NAMESPACE")
if (!file.exists(namespace_file)) {
warning("NAMESPACE file missing", immediate. = TRUE)
}
pkg_namespace <- readLines(namespace_file, warn = FALSE)
has_registration <- any(grepl("^[[:space:]]*useDynLib.*[.]registration[[:space:]]*=[[:space:]]*TRUE", pkg_namespace))
if (!has_registration) {
warning(
immediate. = TRUE, call. = FALSE,
sprintf(
"NAMESPACE missing native routine registration:
* Add `#' @useDynLib %s, .registration = TRUE` to R files.
* Run `devtools::document()`",
pkg_name(path)
)
)
}
}
#' Test if a package path is linking to Rcpp or cpp11
#'
#' @inheritParams build
#' @export
#' @keywords internal
pkg_links_to_rcpp <- function(path) {
path <- pkg_path(path)
deps <- desc::desc_get_deps(file.path(path, "DESCRIPTION"))
any(deps$type == "LinkingTo" & deps$package == "Rcpp")
}
#' @rdname pkg_links_to_rcpp
#' @keywords internal
#' @export
pkg_links_to_cpp11 <- function(path) {
path <- pkg_path(path)
desc <- desc::desc(file = file.path(path, "DESCRIPTION"))
deps <- desc$get_deps()
desc$get_field("Package") == "cpp11" || any(deps$type == "LinkingTo" & deps$package == "cpp11")
}
pkgbuild/R/rcmd.R 0000644 0001762 0000144 00000005037 14253066774 013347 0 ustar ligges users #' Call R CMD 'command' with build tools active
#'
#' This is a wrapper around `callr::rcmd_safe()` that checks
#' that you have build tools available, and on Windows, automatically sets
#' the path to include Rtools.
#'
#' @param ... Parameters passed on to `rcmd_safe`.
#' @param env Additional environment variables to set. The defaults from
#' `callr::rcmd_safe_env()` are always set.
#' @inheritParams with_build_tools
#' @inheritParams build
#' @export
#' @examples
#' # These env vars are always set
#' callr::rcmd_safe_env()
#'
#' if (has_build_tools()) {
#' rcmd_build_tools("CONFIG", "CC")$stdout
#' rcmd_build_tools("CC", "--version")$stdout
#' }
rcmd_build_tools <- function(..., env = character(), required = TRUE, quiet = FALSE) {
env <- c(callr::rcmd_safe_env(), env)
if (!quiet) {
cli::cat_rule(paste0("R CMD ", ..1), col = "cyan")
}
warn_for_potential_errors()
callback <- if (cli::is_dynamic_tty()) {
block_callback(quiet)
} else {
simple_callback(quiet)
}
res <- with_build_tools(
{
withCallingHandlers(
callr::rcmd_safe(...,
env = env, spinner = FALSE, show = FALSE,
echo = FALSE, block_callback = callback, stderr = "2>&1"
),
error = function(e) {
if (!quiet) e$echo <- TRUE
asNamespace("callr")$err$throw(e)
}
)
},
required = required
)
msg_for_long_paths(res)
invisible(res)
}
msg_for_long_paths <- function(output) {
if (is_windows() &&
any(grepl("over-long path length", output$stdout))) {
message(
"\nIt seems that this package contains files with very long paths.\n",
"This is not supported on most Windows versions. Please contact the\n",
"package authors and tell them about this. See this GitHub issue\n",
"for more details: https://github.com/r-lib/remotes/issues/84\n"
)
}
}
warn_for_potential_errors <- function() {
if (is_windows() && grepl(" ", R.home()) &&
getRversion() <= "3.4.2") {
warning(
immediate. = TRUE,
"\n!!! Building will probably fail!\n",
"This version of R has trouble with building packages if\n",
"the R HOME directory (currently '", R.home(), "')\n",
"has space characters. Possible workarounds include:\n",
"- installing R to the C: drive,\n",
"- installing it into a path without a space, or\n",
"- creating a drive letter for R HOME via the `subst` windows command, and\n",
" starting R from the new drive.\n",
"See also https://github.com/r-lib/remotes/issues/98\n"
)
}
}
pkgbuild/R/cache.R 0000644 0001762 0000144 00000000761 14152340747 013455 0 ustar ligges users # Need to check for existence so load_all doesn't override known rtools location
if (!exists("cache")) {
cache <- new.env(parent = emptyenv())
}
cache_get <- function(name) {
get(name, envir = cache)
}
cache_exists <- function(name) {
exists(name, envir = cache)
}
cache_set <- function(name, value) {
assign(name, value, envir = cache)
}
cache_remove <- function(name) {
rm(list = name, envir = cache)
}
cache_reset <- function() {
rm(list = ls(envir = cache), envir = cache)
}
pkgbuild/R/build.R 0000644 0001762 0000144 00000024127 14442271526 013513 0 ustar ligges users #' Build package
#'
#' Building converts a package source directory into a single bundled file.
#' If `binary = FALSE` this creates a `tar.gz` package that can
#' be installed on any platform, provided they have a full development
#' environment (although packages without source code can typically be
#' installed out of the box). If `binary = TRUE`, the package will have
#' a platform specific extension (e.g. `.zip` for windows), and will
#' only be installable on the current platform, but no development
#' environment is needed.
#'
#' ## Configuration
#'
#' ### `DESCRIPTION` entries
#'
#' * `Config/build/clean-inst-doc` can be set to `FALSE` to avoid cleaning up
#' `inst/doc` when building a source package. Set it to `TRUE` to force a
#' cleanup. See the `clean_doc` argument.
#'
#' * `Config/build/copy-method` can be used to avoid copying large
#' directories in `R CMD build`. It works by copying (or linking) the
#' files of the package to a temporary directory, leaving out the
#' (possibly large) files that are not part of the package. Possible
#' values:
#'
#' - `none`: pkgbuild does not copy the package tree. This is the default.
#' - `copy`: the package files are copied to a temporary directory before
#' ` R CMD build`.
#' - `link`: the package files are symbolic linked to a temporary
#' directory before `R CMD build`. Windows does not have symbolic
#' links, so on Windows this is equivalent to `copy`.
#'
#' You can also use the `pkg.build_copy_method` option or the
#' `PKG_BUILD_COPY_METHOD` environment variable to set the copy method.
#' The option is consulted first, then the `DESCRIPTION` entry, then the
#' environment variable.
#'
#' * `Config/build/extra-sources` can be used to define extra source files
#' for pkgbuild to decide whether a package DLL needs to be recompiled in
#' `needs_compile()`. The syntax is a comma separated list of file names,
#' or globs. (See [utils::glob2rx()].) E.g. `src/rust/src/*.rs` or
#' `configure*`.
#'
#' * `Config/build/bootstrap` can be set to `TRUE` to run
#' `Rscript bootstrap.R` in the source directory prior to running subsequent
#' build steps.
#'
#' ### Options
#'
#' * `pkg.build_copy_method`: use this option to avoid copying large
#' directories when building a package. See possible values above, at the
#' `Config/build/copy-method` `DESCRIPTION` entry.
#'
#' * `pkg.build_stop_for_warnings`: if it is set to `TRUE`, then pkgbuild
#' will stop for `R CMD build` errors. It takes precedence over the
#' `PKG_BUILD_STOP_FOR_WARNINGS` environment variable.
#'
#' ### Environment variables
#'
#' * `PKG_BUILD_COLOR_DIAGNOSTICS`: set it to `false` to opt out of colored
#' compiler diagnostics. Set it to `true` to force colored compiler
#' diagnostics.
#'
#' * `PKG_BUILD_COPY_METHOD`: use this environment variable to avoid copying
#' large directories when building a package. See possible values above,
#' at the `Config/build/copy-method` `DESCRIPTION` entry.
#'
#' will stop for `R CMD build` errors. The `pkg.build_stop_for_warnings`
#' option takes precedence over this environment variable.
#'
#' @param path Path to a package, or within a package.
#' @param dest_path path in which to produce package. If it is an existing
#' directory, then the output file is placed in `dest_path` and named
#' according to the current R conversions (e.g. `.zip` for Windows binary
#' packages, `.tgz` for macOS binary packages, etc).
#' If it is an existing file, then it will be overwritten.
#' If `dest_path` does not exist, then it is used as a file name.
#' If `NULL`, it defaults to the parent directory of the package.
#' @param binary Produce a binary (`--binary`) or source (
#' `--no-manual --no-resave-data`) version of the package.
#' @param vignettes,manual For source packages: if `FALSE`, don't build PDF
#' vignettes (`--no-build-vignettes`) or manual (`--no-manual`).
#' @param args An optional character vector of additional command
#' line arguments to be passed to `R CMD build` if `binary = FALSE`,
#' or `R CMD install` if `binary = TRUE`.
#' @param quiet if `TRUE` suppresses output from this function.
#' @param needs_compilation Usually only needed if the packages has
#' C/C++/Fortran code. By default this is autodetected.
#' @param compile_attributes if `TRUE` and the package uses Rcpp, call
#' [Rcpp::compileAttributes()] before building the package. It is ignored
#' if package does not need compilation.
#' @param register_routines if `TRUE` and the package does not use Rcpp, call
#' register routines with
#' `tools::package_native_routine_registration_skeleton()` before building
#' the package. It is ignored if package does not need compilation.
#' @param clean_doc If `TRUE`, clean the files in `inst/doc` before building
#' the package. If `NULL` and the `Config/build/clean-inst-doc` entry is
#' present in `DESCRIPTION`, then that is used. Otherwise, if `NULL`,
#' and interactive, ask to remove the files prior to cleaning. In most
#' cases cleaning the files is the correct behavior to avoid stale
#' vignette outputs in the built package.
#' @export
#' @return a string giving the location (including file name) of the built
#' package
build <- function(path = ".", dest_path = NULL, binary = FALSE, vignettes = TRUE,
manual = FALSE, clean_doc = NULL, args = NULL, quiet = FALSE,
needs_compilation = pkg_has_src(path), compile_attributes = FALSE,
register_routines = FALSE) {
options <- build_setup(
path, dest_path, binary, vignettes, manual, clean_doc, args,
needs_compilation, compile_attributes, register_routines, quiet
)
on.exit(unlink(options$out_dir, recursive = TRUE), add = TRUE)
withr_with_makevars(
compiler_flags(debug = FALSE), {
output <- withr_with_temp_libpaths(
rcmd_build_tools(
options$cmd,
c(options$path, options$args),
wd = options$out_dir,
fail_on_status = TRUE,
required = FALSE, # already checked in setup
quiet = quiet
)
)
if (should_stop_for_warnings() &&
grepl("\n\\s*warning:", output$stdout, ignore.case = TRUE)) {
cli::cli_alert_warning(
"Stopping as requested for a warning during {.code R CMD build}.")
if (quiet) {
cli::cli_alert_warning("The full output is printed below.")
cli::cli_verbatim(output$stdout)
}
stop("converted from `R CMD build` warning.")
}
out_file <- dir(options$out_dir)
file.copy(
file.path(options$out_dir, out_file), options$dest_path,
overwrite = TRUE
)
if (is_dir(options$dest_path)) {
file.path(options$dest_path, out_file)
} else {
options$dest_path
}
}
)
}
build_setup <- function(path, dest_path, binary, vignettes, manual, clean_doc, args,
needs_compilation, compile_attributes, register_routines, quiet) {
if (!file.exists(path)) {
stop("`path` must exist", call. = FALSE)
}
if (!is_dir(path)) {
if (!binary) stop("`binary` must be TRUE for package files", call. = FALSE)
if (compile_attributes) {
stop("`compile_attributes` must be FALSE for package files", call. = FALSE)
}
if (register_routines) {
stop("`register_routines` must be FALSE for package files", call. = FALSE)
}
} else {
path <- pkg_path(path)
}
if (is.null(dest_path)) {
dest_path <- dirname(path)
}
bootstrap_file <- file.path(path, "bootstrap.R")
run_boostrap <- isTRUE(get_desc_config_flag(path, "bootstrap"))
if (file.exists(bootstrap_file) && run_boostrap) {
if (!quiet) message("Running bootstrap.R...")
callr::rscript(
bootstrap_file,
wd = path,
stderr = "2>&1",
show = !quiet
)
}
if (needs_compilation) {
update_registration(path, compile_attributes, register_routines, quiet)
}
if (binary) {
build_setup_binary(path, dest_path, args, needs_compilation)
} else {
build_setup_source(
path, dest_path, vignettes, manual, clean_doc, args,
needs_compilation
)
}
}
build_setup_binary <- function(path, dest_path, args, needs_compilation) {
if (needs_compilation) {
check_build_tools(quiet = TRUE)
}
# Build in temporary directory and then copy to final location
out_dir <- tempfile()
dir.create(out_dir)
list(
cmd = "INSTALL",
path = normalizePath(path),
args = c("--build", args),
out_dir = out_dir,
dest_path = dest_path
)
}
build_setup_source <- function(path, dest_path, vignettes, manual, clean_doc,
args, needs_compilation) {
if (!("--resave-data" %in% args)) {
args <- c(args, "--no-resave-data")
}
if (!manual) {
args <- unique(c(args, "--no-manual"))
}
if (!vignettes) {
args <- unique(c(args, "--no-build-vignettes"))
}
no_manual <- "--no-manual" %in% args
if (!no_manual && !has_latex()) {
message("pdflatex not found! Not building PDF manual.")
manual <- FALSE
}
if (needs_compilation && (vignettes || manual)) {
check_build_tools(quiet = TRUE)
}
build_vignettes <- !("--no-build-vignettes" %in% args)
if (is.null(clean_doc)) {
clean_doc <- get_desc_config_flag(path, "clean-inst-doc")
}
if (build_vignettes && (is.null(clean_doc) || isTRUE(clean_doc))) {
doc_dir <- file.path(path, "inst", "doc")
if (dir.exists(doc_dir)) {
if (is.null(clean_doc) && interactive()) {
message("Building the package will delete...\n '", doc_dir, "'\nAre you sure?")
res <- utils::menu(c("Yes", "No"))
if (res == 2) {
return()
}
}
unlink(doc_dir, recursive = TRUE)
}
}
# Build in temporary directory and then copy to final location
out_dir <- tempfile()
dir.create(out_dir)
copy_method <- get_copy_method(path)
if (copy_method != "none") {
pkgname <- desc::desc_get("Package", path)
tmppath <- tempfile("build-")
copy_package_tree(path, tmppath, pkgname)
path <- file.path(tmppath, pkgname)
}
list(
cmd = "build",
path = normalizePath(path),
args = args,
out_dir = out_dir,
dest_path = dest_path
)
}
pkgbuild/R/find-package-root.R 0000644 0001762 0000144 00000001461 14535333540 015700 0 ustar ligges users find_package_root <- function(path = ".") {
is_root <- function(path) {
identical(
normalizePath(path, winslash = "/"),
normalizePath(dirname(path), winslash = "/")
)
}
if (!file.exists(path)) {
stop("Path does not exist: ", path)
}
cur_path <- normalizePath(path, winslash = "/")
errmsg <- paste0(
"Could not find R package in `",
path,
"` or its parent directories."
)
max_depth <- 100
for (i in 1:max_depth) {
dsc_path <- file.path(cur_path, "DESCRIPTION")
if (file.exists(dsc_path) &&
any(grepl("^Package: ", readLines(dsc_path)))) {
return(cur_path)
} else if (is_root(cur_path)) {
stop(errmsg)
} else {
cur_path <- dirname(cur_path)
}
}
stop(errmsg, " Checked ", max_depth, " parent directories.") # nocov
}
pkgbuild/R/rtools-path.R 0000644 0001762 0000144 00000003444 14211634664 014667 0 ustar ligges users scan_path_for_rtools <- function(debug = FALSE) {
if (debug) {
cat("Scanning path...\n")
}
# Next looks for ls and gcc on path
ls_path <- Sys.which("ls")
if (ls_path == "") {
return(NULL)
}
if (debug) {
cat("ls:", ls_path, "\n")
}
# We have a candidate install_path
install_path <- dirname(dirname(ls_path))
gcc_path <- Sys.which("gcc")
if (debug) {
cat("gcc_path:", gcc_path, "\n")
}
if (gcc_path != "") {
# Check both candidate install paths are same
install_path2 <- dirname(dirname(dirname(gcc_path)))
if (tolower(install_path2) != tolower(install_path)) {
return(NULL)
}
} else {
# Maybe isn't on path, but is in default location
gcc_default <- find_arch_exe(
file.path(install_path, paste0("mingw_", gcc_arch()), "bin", "gcc.exe"),
debug = debug
)
if (gcc_default == "") {
return(NULL)
}
}
version <- installed_version(install_path, debug = debug)
if (debug) {
cat("Version:", version, "\n")
}
rtools(install_path, version)
}
find_arch_exe <- function(path, debug = FALSE) {
# Convert unix path to Windows
if (grepl("^/", path)) {
path <- convert_unix_path(path)
}
full_path <- Sys.which(path)
if (nchar(full_path) == 0) {
if (debug) {
cat("'", path, "' does not exist\n", sep = "")
}
return("")
}
# Then check architecture matches
file_info <- file.info(full_path)
if (file_info$exe != paste0("win", gcc_arch())) {
if (debug) {
cat(" Architecture doesn't match\n")
}
return("")
}
full_path
}
# This assumes cygpath is on your PATH,
# but it should be if you are using /foo/bar paths in R CMD config,
# so we don't need to handle this
convert_unix_path <- function(path) {
system2("cygpath", c("-m", path), stdout = TRUE)
}
pkgbuild/R/build-tools.R 0000644 0001762 0000144 00000005556 14426741134 014655 0 ustar ligges users #' Are build tools are available?
#'
#' `has_build_tools` returns a logical, `check_build_tools` throws
#' an error. `with_build_tools` checks that build tools are available,
#' then runs `code` in an correctly staged environment.
#' If run interactively from RStudio, and the build tools are not
#' available these functions will trigger an automated install.
#'
#' Errors like `running command
#' '"C:/PROGRA~1/R/R-34~1.2/bin/x64/R" CMD config CC' had status 127`
#' indicate the code expected Rtools to be on the system PATH. You can
#' then verify you have rtools installed with `has_build_tools()` and
#' temporarily add Rtools to the PATH `with_build_tools({ code })`.
#'
#' It is possible to add Rtools to your system PATH manually; you can use
#' [rtools_path()] to show the installed location. However because this
#' requires manual updating when a new version of Rtools is installed and the
#' binaries in Rtools may conflict with existing binaries elsewhere on the PATH it
#' is better practice to use `with_build_tools()` as needed.
#' @inheritParams has_rtools
#' @param quiet if `TRUE` suppresses output from this function.
#' @export
#' @seealso has_rtools
#' @examples
#' has_build_tools(debug = TRUE)
#' check_build_tools()
has_build_tools <- function(debug = FALSE) {
check <- getOption("buildtools.check", NULL)
has <- if (is_windows() && is_R4() && has_rtools(debug = debug)) {
TRUE
} else if (is_windows()) {
has_rtools(debug = debug)
} else {
has_compiler(debug = debug)
}
if (!has && !is.null(check)) {
check("Building R package from source")
} else {
has
}
}
#' @export
#' @rdname has_build_tools
check_build_tools <- function(debug = FALSE, quiet = FALSE) {
if (!has_build_tools(debug = debug)) {
stop(
"Could not find tools necessary to compile a package\n",
"Call `pkgbuild::check_build_tools(debug = TRUE)` to diagnose the problem.",
call. = FALSE
)
} else if (!isTRUE(quiet)) {
message("Your system is ready to build packages!")
}
invisible(TRUE)
}
#' @export
#' @rdname has_build_tools
#' @param code Code to rerun in environment where build tools are guaranteed to
#' exist.
#' @param required If `TRUE`, and build tools are not available,
#' will throw an error. Otherwise will attempt to run `code` without
#' them.
with_build_tools <- function(code, debug = FALSE, required = TRUE) {
if (required) {
check_build_tools(debug = debug, quiet = TRUE)
}
if (has_rtools()) {
withr_with_path(rtools_path(), code)
} else {
code
}
}
#' @rdname has_build_tools
#' @param .local_envir The environment to use for scoping.
#' @export
local_build_tools <- function(debug = FALSE, required = TRUE, .local_envir = parent.frame()) {
if (required) {
check_build_tools(debug = debug, quiet = TRUE)
}
if (has_rtools()) {
withr_local_path(rtools_path(), .local_envir = .local_envir)
}
}
pkgbuild/R/time.R 0000644 0001762 0000144 00000003753 14526625066 013361 0 ustar ligges users format_time <- local({
assert_diff_time <- function(x) {
stopifnot(inherits(x, "difftime"))
}
parse_ms <- function(ms) {
stopifnot(is.numeric(ms))
data.frame(
days = floor(ms / 86400000),
hours = floor((ms / 3600000) %% 24),
minutes = floor((ms / 60000) %% 60),
seconds = round((ms / 1000) %% 60, 1)
)
}
first_positive <- function(x) which(x > 0)[1]
trim <- function(x) gsub("^\\s+|\\s+$", "", x)
pretty_ms <- function(ms, compact = FALSE) {
stopifnot(is.numeric(ms))
parsed <- t(parse_ms(ms))
if (compact) {
units <- c("d", "h", "m", "s")
parsed2 <- parsed
parsed2[] <- paste0(parsed, units)
idx <- cbind(
apply(parsed, 2, first_positive),
seq_len(length(ms))
)
tmp <- paste0("~", parsed2[idx])
# handle NAs
tmp[is.na(parsed2[idx])] <- NA_character_
tmp
} else {
## Exact for small ones
exact <- paste0(ceiling(ms), "ms")
exact[is.na(ms)] <- NA_character_
## Approximate for others, in seconds
merge_pieces <- function(pieces) {
## handle NAs
if (all(is.na(pieces))) {
return(NA_character_)
}
## handle non-NAs
paste0(
if (pieces[1]) paste0(pieces[1], "d "),
if (pieces[2]) paste0(pieces[2], "h "),
if (pieces[3]) paste0(pieces[3], "m "),
if (pieces[4]) paste0(pieces[4], "s ")
)
}
approx <- trim(apply(parsed, 2, merge_pieces))
ifelse(ms < 1000, exact, approx)
}
}
pretty_sec <- function(sec, compact = FALSE) {
pretty_ms(sec * 1000, compact = compact)
}
pretty_dt <- function(dt, compact = FALSE) {
assert_diff_time(dt)
units(dt) <- "secs"
pretty_sec(as.vector(dt), compact = compact)
}
structure(
list(
.internal = environment(),
pretty_ms = pretty_ms,
pretty_sec = pretty_sec,
pretty_dt = pretty_dt
),
class = c("standalone_time", "standalone")
)
})
pkgbuild/R/callback.R 0000644 0001762 0000144 00000005305 14527147033 014144 0 ustar ligges users #' @importFrom utils head tail
# This is adapted from https://github.com/r-lib/rcmdcheck/blob/7ee14764c2b17ee2c2f4131a9e19d1b56a66ed0f/R/callback.R
block_callback <- function(quiet) {
partial_line <- ""
state <- "OK"
should_time <- FALSE
line_started <- Sys.time()
now <- NULL
prev_line <- ""
no <- function(x, what = "") {
pattern <- paste0(" \\.\\.\\. ", what, "$")
sub("^\\* ", "", sub(pattern, "", x))
}
time_if_long <- function() {
elapsed <- now - line_started
if (elapsed > as.difftime(1 / 3, units = "secs")) {
style(timing = paste0(" (", format_time$pretty_dt(elapsed), ")"))
} else {
""
}
}
do_line <- function(x) {
should_time <<- FALSE
now <<- Sys.time()
## Test mode is special. It will change the 'state' back to 'OK',
## once it is done.
xx <- if (is_new_check(x)) {
do_new_check(x)
} else if (grepl("^Status: ", x)) {
## We just skip the status, it is printed out anyway, as the return
## value
NA_character_
} else {
do_continuation(x)
}
prev_line <<- x
## NA_character_ can omit output
if (is.na(xx)) {
return()
}
if (should_time) xx <- style(xx, timing = time_if_long())
line_started <<- now
cat(xx, "\n", sep = "")
flush(stdout())
}
do_new_check <- function(x) {
should_time <<- TRUE
if (grepl(" \\.\\.\\. OK\\s*$", x)) {
state <<- "OK"
style(ok = cli::symbol$tick, " ", pale = no(x, "OK"))
} else if (grepl(" \\.\\.\\. NOTE\\s*$", x)) {
state <<- "NOTE"
style(note = c("N ", no(x, "NOTE")))
} else if (grepl(" \\.\\.\\. WARNING\\s*$", x)) {
state <<- "WARNING"
style(warn = c("W ", no(x, "WARNING")))
} else if (grepl(" \\.\\.\\. ERROR\\s*$", x)) {
state <<- "ERROR"
style(err = c("E ", no(x, "ERROR")))
} else if (grepl("^\\* checking tests \\.\\.\\.[ ]?$", x)) {
state <<- "tests"
style(pale = c(cli::symbol$line, " ", no(x)))
} else if (grepl("^\\* DONE\\s*$", x)) {
state <<- "OK"
NA_character_
} else {
style(pale = c(cli::symbol$line, " ", no(x)))
}
}
do_continuation <- function(x) {
paste0(" ", x)
}
function(x) {
if (quiet) {
return()
}
x <- paste0(partial_line, x)
partial_line <<- ""
lines <- strsplit(x, "\r?\n")[[1]]
if (last_char(x) != "\n") {
partial_line <<- tail(lines, 1)
lines <- head(lines, -1)
}
cat(" \r")
lapply(lines, do_line)
cat0(sub("^[\\* ]", " ", partial_line), "\r")
}
}
is_new_check <- function(x) {
grepl("^\\* ", x)
}
simple_callback <- function(quiet) {
function(x) {
if (quiet) {
return()
}
cat(x)
}
}
pkgbuild/R/rtools.R 0000644 0001762 0000144 00000020455 14442114442 013727 0 ustar ligges users #' Is Rtools installed?
#'
#' To build binary packages on windows, Rtools (found at
#' \url{https://CRAN.R-project.org/bin/windows/Rtools/}) needs to be on
#' the path. The default installation process does not add it, so this
#' script finds it (looking first on the path, then in the registry).
#' It also checks that the version of rtools matches the version of R.
#' `has_rtools()` determines if Rtools is installed, caching the results.
#' Afterward, run `rtools_path()` to find out where it's installed.
#'
#' @section Acknowledgements:
#' This code borrows heavily from RStudio's code for finding Rtools.
#' Thanks JJ!
#' @param debug If `TRUE`, will print out extra information useful for
#' debugging. If `FALSE`, it will use result cached from a previous run.
#' @return Either a visible `TRUE` if rtools is found, or an invisible
#' `FALSE` with a diagnostic [message()].
#' As a side-effect the internal package variable `rtools_path` is
#' updated to the paths to rtools binaries.
#' @keywords internal
#' @export
#' @examples
#' has_rtools()
has_rtools <- function(debug = FALSE) {
if (!debug && rtools_path_is_set()) {
return(!identical(rtools_path(), ""))
}
if (!is_windows()) {
return(FALSE)
}
# R 4.3.0 or later
if (getRversion() >= "4.3.0") {
rtools43_home <- Sys.getenv("RTOOLS43_HOME", "C:\\rtools43")
if (file.exists(file.path(rtools43_home, "usr", "bin"))) {
if (debug) {
cat("Found in Rtools 4.3 installation folder\n")
}
rtools_path_set(rtools(rtools43_home, "4.3"))
return(TRUE)
}
return(FALSE)
}
# R 4.2.x or later and ucrt?
ucrt <- is_ucrt()
if (ucrt) {
rtools42_home <- Sys.getenv("RTOOLS42_HOME", "C:\\rtools42")
if (file.exists(file.path(rtools42_home, "usr", "bin"))) {
if (debug) {
cat("Found in Rtools 4.2 installation folder\n")
}
rtools_path_set(rtools(rtools42_home, "4.2"))
return(TRUE)
}
}
# In R 4.0 we can use RTOOLS40_HOME, recent versions of Rtools40 work fine
# with ucrt as well, currently.
if (is_R4()) {
rtools40_home <- Sys.getenv("RTOOLS40_HOME", "C:\\rtools40")
fld <- if (ucrt) "ucrt64" else "usr"
if (file.exists(file.path(rtools40_home, fld, "bin"))) {
if (debug) {
cat("Found in Rtools 4.0 installation folder\n")
}
rtools_path_set(rtools(rtools40_home, "4.0"))
return(TRUE)
}
}
# First, R CMD config CC --------------------------------------------
# This does not work if 'make' is not yet on the path
from_config <- scan_config_for_rtools(debug)
if (is_compatible(from_config)) {
if (debug) {
cat("Found compatible gcc from R CMD config CC\n")
}
rtools_path_set(from_config)
return(TRUE)
}
# Next, try the path ------------------------------------------------
from_path <- scan_path_for_rtools(debug)
if (is_compatible(from_path)) {
if (debug) {
cat("Found compatible gcc on path\n")
}
rtools_path_set(from_path)
return(TRUE)
}
if (!is.null(from_path)) {
# Installed
if (is.null(from_path$version)) {
# but not from rtools
if (debug) {
cat("gcc and ls on path, assuming set up is correct\n")
}
return(TRUE)
} else {
# Installed, but not compatible
needed <- rtools_needed()
message(
"WARNING: Rtools ", from_path$version, " found on the path",
" at ", from_path$path, " is not compatible with R ", getRversion(), ".\n\n",
"Please download and install ", needed, " from ", rtools_url(needed),
", remove the incompatible version from your PATH."
)
return(invisible(FALSE))
}
}
# Next, try the registry --------------------------------------------------
registry_candidates <- scan_registry_for_rtools(debug)
if (length(registry_candidates) == 0) {
# Not on path or in registry, so not installled
needed <- rtools_needed()
message(
"WARNING: Rtools is required to build R packages, but is not ",
"currently installed.\n\n",
"Please download and install ", needed, " from ", rtools_url(needed), "."
)
return(invisible(FALSE))
}
from_registry <- Find(is_compatible, registry_candidates, right = TRUE)
if (is.null(from_registry)) {
# In registry, but not compatible.
versions <- vapply(registry_candidates, function(x) x$version, character(1))
needed <- rtools_needed()
message(
"WARNING: Rtools is required to build R packages, but no version ",
"of Rtools compatible with R ", getRversion(), " was found. ",
"(Only the following incompatible version(s) of Rtools were found: ",
paste(versions, collapse = ", "), ")\n\n",
"Please download and install ", needed, " from ", rtools_url(needed), "."
)
return(invisible(FALSE))
}
# On Rtools 3.x do an extra check if the installed version is accurate.
# With rtools40 this is no longer needed (it doesn't have a Version.txt)
if (isTRUE(from_registry$version < "4")) {
installed_ver <- installed_version(from_registry$path, debug = debug)
if (is.null(installed_ver)) {
# Previously installed version now deleted
needed <- rtools_needed()
message(
"WARNING: Rtools is required to build R packages, but the ",
"version of Rtools previously installed in ", from_registry$path,
" has been deleted.\n\n",
"Please download and install ", needed, " from ", rtools_url(needed), "."
)
return(invisible(FALSE))
}
if (installed_ver != from_registry$version) {
# Installed version doesn't match registry version
needed <- rtools_needed()
message(
"WARNING: Rtools is required to build R packages, but no version ",
"of Rtools compatible with R ", getRversion(), " was found. ",
"Rtools ", from_registry$version, " was previously installed in ",
from_registry$path, " but now that directory contains Rtools ",
installed_ver, ".\n\n",
"Please download and install ", needed, " from ", rtools_url(needed), "."
)
return(invisible(FALSE))
}
}
# Otherwise it must be ok :)
rtools_path_set(from_registry)
TRUE
}
is_ucrt <- function() {
identical(R.Version()$crt, "ucrt")
}
#' @rdname has_rtools
#' @usage NULL
#' @export
find_rtools <- has_rtools
#' @rdname has_rtools
#' @usage NULL
#' @export
setup_rtools <- has_rtools
#' @export
#' @rdname has_rtools
check_rtools <- function(debug = FALSE) {
if (is_windows() && !has_rtools(debug = debug)) {
stop("Rtools is not installed.", call. = FALSE)
}
TRUE
}
installed_version <- function(path, debug) {
if (!file.exists(file.path(path, "Rtools.txt"))) {
return(NULL)
}
# Find the version path
version_path <- file.path(path, "VERSION.txt")
if (debug) {
cat("VERSION.txt\n")
cat(readLines(version_path), "\n")
}
if (!file.exists(version_path)) {
return(NULL)
}
# Rtools is in the path -- now crack the VERSION file
contents <- NULL
try(contents <- readLines(version_path), silent = TRUE)
if (is.null(contents)) {
return(NULL)
}
# Extract the version
contents <- gsub("^\\s+|\\s+$", "", contents)
version_re <- "Rtools version (\\d\\.\\d+)\\.[0-9.]+$"
if (!grepl(version_re, contents)) {
return(NULL)
}
m <- regexec(version_re, contents)
regmatches(contents, m)[[1]][2]
}
is_compatible <- function(rtools) {
if (is.null(rtools)) {
return(FALSE)
}
if (is.null(rtools$version)) {
return(FALSE)
}
stopifnot(is.rtools(rtools))
info <- version_info[[rtools$version]]
if (is.null(info)) {
return(FALSE)
}
r_version <- getRversion()
r_version >= info$version_min && r_version <= info$version_max
}
rtools <- function(path, version, ...) {
structure(list(version = version, path = path, ...), class = "rtools")
}
is.rtools <- function(x) inherits(x, "rtools")
#' Retrieve a text string with the rtools version needed
#'
#' @keywords internal
#' @export
rtools_needed <- function(r_version = getRversion()) {
vi <- version_info
vi$custom <- NULL
for (i in rev(seq_along(vi))) {
version <- names(vi)[i]
info <- vi[[i]]
ok <- r_version >= info$version_min && r_version <= info$version_max
if (ok) {
return(paste("Rtools", version))
}
}
"the appropriate version of Rtools"
}
rtools_url <- function(needed) {
"https://cran.r-project.org/bin/windows/Rtools/"
}
pkgbuild/R/exclude.R 0000644 0001762 0000144 00000021235 14426741134 014041 0 ustar ligges users
copy_package_tree <- function(
path = ".",
dest,
pkgname = desc::desc_get("Package", path)) {
if (!file.exists(dest)) mkdirp(dest)
pkgdir <- file.path(dest, pkgname)
if (file.exists(pkgdir)) {
stop(cli::format_error(c(
"Cannot copy package tree to {.path {dest}}",
i = "Directory {.path {pkgdir}} already exists, and did not want
to overwrite."
)))
}
mkdirp(pkgdir)
paths <- build_files(path, pkgname)
method <- get_copy_method(path)
for (i in seq_len(nrow(paths))) {
# excluded, skip
if (paths$exclude[i]) next
if (paths$isdir[i] && paths$trimmed[i]) {
# trimmed directory, only create directory
# we do not try to update the mode of the directory, as it is not
# very important for R packages, and it might fail on some file
# systems.
mkdirp(file.path(pkgdir, paths$path[i]))
} else {
# not a directory, or a non-trimmed directory, recurse
src <- paths$realpath[i]
tgt <- file.path(pkgdir, paths$path[i])
if (method == "link") {
file.symlink(src, tgt)
} else if (paths$isdir[i]) {
cp(src, dirname(tgt), recursive = TRUE)
} else {
cp(src, tgt)
}
}
}
# TODO: should we return a trimming summary?
invisible()
}
get_copy_method <- function(path = ".") {
method <- getOption("pkg.build_copy_method", NA_character_)
values <- c("none", "copy", "link")
check_method <- function(method) {
# no symlinks on Windows
if (method == "link" && is_windows()) method <- "copy"
if (method %in% values) return(method)
stop(cli::format_error(c(
"Invalid {.code pkg.build_copy_method} value: {.val {method}}.",
i = "It must be one of {.str {values}}."
)))
}
if (!is_string(method) && !is_na(method)) {
stop(cli::format_error(c(
"Invalid {.code pkg.build_copy_method} value.",
i = "It must be a string, but it is {.type {method}}."
)))
}
if (!is.na(method)) return(check_method(method))
method <- desc::desc_get("Config/build/copy-method", path)
if (!is.na(method)) return(check_method(method))
method <- Sys.getenv("PKG_BUILD_COPY_METHOD", "none")
check_method(method)
}
build_files <- function(
path = ".",
pkgname = desc::desc_get("Package", path)) {
path <- normalizePath(path)
# patterns in .Rbuildignore
ign_file <- file.path(path, ".Rbuildignore")
ign <- if (file.exists(ign_file)) {
readLines(ign_file, warn = FALSE)
} else {
character()
}
ign <- ign[nzchar(ign)]
# make it case insensitive, that's how R matches them
if (length(ign)) ign <- paste0("(?i)", ign)
ptrn <- c(ign, re_exclude(pkgname))
ptrn_dir <- re_exclude_dir(pkgname)
# filter at the top level first, so we don't need to enumerate these
top <- dir(path, include.dirs = TRUE, all.files=TRUE, no.. = TRUE)
# now filter top
realtop <- file.path(path, top)
topfls <- data.frame(
stringsAsFactors = FALSE,
path = top,
realpath = realtop,
exclude = logical(length(top)),
isdir = file.info(realtop)$isdir
)
topfls <- exclude(path, topfls, ptrn, ptrn_dir)
# now create the rest of the files
sub <- unlist(lapply(
topfls$path[topfls$isdir & !topfls$exclude],
function(t) {
tf <- dir(file.path(path, t), include.dirs = TRUE, all.files = TRUE,
recursive = TRUE)
tf <- file.path(t, tf)
}
))
realsub <- file.path(path, sub)
subfls <- data.frame(
stringsAsFactors = FALSE,
path = sub,
realpath = realsub,
exclude = logical(length(sub)),
isdir = file.info(realsub)$isdir
)
subfls <- exclude(path, subfls, ptrn, ptrn_dir)
allfls <- rbind(topfls, subfls)
# Always keep this, so base R can do its own filtering, just in case
# it changes compared to ours
allfls$exclude[allfls$path == ".Rbuildignore"] <- FALSE
allfls <- exclude_downstream(allfls)
allfls
}
re_exclude <- function(pkg) {
c(
paste0(
"(?i)", # these are case insensitive
c(
"(^|/)\\.DS_Store$", # by macOS finder
"^\\.RData$", # .RData at /
"~$", "\\.bak$", "\\.swp$", # backup files
"(^|/)\\.#[^/]*$", "(^|/)#[^/]*#$", # more backup files (Emacs)
"^config\\.(cache|log|status)$", # leftover by autoconf
"(^|/)autom4te\\.cache$",
"^src/.*\\.d$", "^src/Makedeps$", # INSTALL leftover on Windows
"^inst/doc/Rplots\\.(ps|pdf)$" # Sweave leftover
)
),
"(^|/)\\._[^/]*$", # macOS resource forks
paste0( # hidden files
"(^|/)\\.",
c("Renviron",
"Rprofile",
"Rproj.user",
"Rhistory",
"Rapp.history",
"tex",
"log",
"aux",
"pdf",
"png",
"backups",
"cvsignore",
"cproject",
"directory",
"dropbox",
"exrc",
"gdb.history",
"gitattributes",
"github",
"gitignore",
"gitmodules",
"hgignore",
"hgtags",
"htaccess",
"latex2html-init",
"project",
"seed",
"settings",
"tm_properties"
),
"$"
),
paste0(
"(^|/)",
pkg,
"_[0-9.-]+",
"\\.(tar\\.gz|tar|tar\\.bz2|tar\\.xz|tgz|zip)",
"$"
)
)
}
re_exclude_dir <- function(pkg) {
c(
"^revdep$", # revdepcheck
paste0( # VC
"(^|/)",
c("CVS",
".svn",
".arch-ids",
".bzr",
".git",
".hg",
"_darcs",
".metadata"
),
"$"
),
"(^|/)[^/]*[Oo]ld$",
"(^|/)[^/]*\\.Rcheck",
"^src.*/\\.deps$"
)
}
exclude <- function(root, paths, patterns, patterns_dir) {
ex <- logical(nrow(paths))
for (p in patterns) {
ex <- ex | grepl(p, paths$path, perl = TRUE)
}
# additional regexes for directories, we don't need to check 'ex'
wdirs <- !ex & paths$isdir
paths_dirs <- paths$path[wdirs]
dex <- logical(length(paths_dirs))
for (p in patterns_dir) {
dex <- dex | grepl(p, paths_dirs, perl = TRUE)
}
ex[wdirs][dex] <- TRUE
paths$exclude <- ex
paths
}
exclude_downstream <- function(paths) {
# We don't actually need this now, but we could use it to optimize,
# because we could trim only the subsequent elements after a directory.
paths <- paths[order(paths$path), ]
# We need to take each excluded directory, and remove all paths in them
exdirs <- paste0(paths$path[paths$isdir & paths$exclude], "/")
del <- logical(nrow(paths))
for (ed in exdirs) {
del <- del | startsWith(paths$path, ed)
}
paths <- paths[!del, ]
# Now we mark the subdirectories that can be copied as is, i.e. none of
# their downstream contents are excluded
indirs <- which(paths$isdir & !paths$exclude)
trm <- logical(nrow(paths))
for (id in indirs) {
trm[id] <- any(
startsWith(paths$path, paste0(paths$path[id], "/")) & paths$exclude
)
}
paths$trimmed <- trm
# We can remove the subdirectories of non-trimmed directories as well
fulldirs <- paste0(paths$path[paths$isdir & !trm], "/")
del2 <- logical(nrow(paths))
for (fd in fulldirs) {
del2 <- del2 | startsWith(paths$path, fd)
}
paths <- paths[!del2, ]
rownames(paths) <- NULL
paths
}
cp <- local({
wind <- NULL
cpargs <- NULL
function(src, tgt, recursive = FALSE) {
if (is.null(wind)) wind <<- is_windows()
if (wind) {
if (!file.copy(src, tgt, recursive = recursive, copy.date = TRUE)) {
stop(cli::format_error(c(
"Could not copy package files.",
i = "Failed to copy {.path {src}} to {.path {tgt}}."
)))
}
} else {
if (is.null(cpargs)) cpargs <<- detect_cp_args()
ret <- processx::run(
"cp", c(cpargs, src, tgt),
stderr = "2>&1",
error_on_status = FALSE
)
if (ret$status != 0) {
stop(cli::format_error(c(
"Could not copy package files.",
i = "Failed to copy {.path {src}} to {.path {tgt}}.",
i = "{.code cp} output:",
" " = verb_for_cli(ret$stdout)
)))
}
}
}
})
detect_cp_args <- function() {
# we do this in a tempdir, because it might create a file a called
# `--preserve=timestamps`
dir.create(tmp <- tempfile())
old <- getwd()
on.exit({ setwd(old); unlink(tmp, recursive = TRUE) }, add = TRUE)
setwd(tmp)
f1 <- basename(tempfile())
f2 <- basename(tempfile())
file.create(f1)
tryCatch(
suppressWarnings(processx::run("cp", c("--preserve=timestamps", f1, f2))),
error = function(e) e
)
if (file.exists(f2)) {
c("-LR", "--preserve=timestamps")
} else {
"-pLR"
}
}
pkgbuild/R/compiler.R 0000644 0001762 0000144 00000005503 14323725614 014223 0 ustar ligges users #' Is a compiler available?
#'
#' @description
#' These functions check if a small C file can be compiled, linked, loaded
#' and executed.
#'
#' `has_compiler()` and `has_devel()` return `TRUE` or `FALSE`.
#' `check_compiler()` and `check_devel()`
#' throw an error if you don't have developer tools installed.
#' If the `"pkgbuild.has_compiler"` option is set to `TRUE` or `FALSE`,
#' no check is carried out, and the value of the option is used.
#'
#' The implementation is based on a suggestion by Simon Urbanek.
#' End-users (particularly those on Windows) should generally run
#' [check_build_tools()] rather than [check_compiler()].
#'
#'
#' @export
#' @inheritParams has_rtools
#' @seealso [check_build_tools()]
#' @examples
#' has_compiler()
#' check_compiler()
#'
#' with_build_tools(has_compiler())
has_compiler <- function(debug = FALSE) {
res <- getOption("pkgbuild.has_compiler")
if (!is.null(res)) {
if (is_flag(res)) return(res)
stop(cli::format_error(c(
"",
"!" = "Invalid {.code pkgbuild.has_compiler} option.",
"i" = "It must be {.code TRUE} or {.code FALSE}, not {.type {res}}."
)))
}
if (!debug && cache_exists("has_compiler")) {
return(cache_get("has_compiler"))
}
foo_path <- file.path(tempdir(), "foo.c")
cat("void foo(int *bar) { *bar=1; }\n", file = foo_path)
on.exit(unlink(foo_path))
res <- tryCatch(
{
if (debug) {
message("Trying to compile a simple C file")
}
callr::rcmd_safe(
"SHLIB",
"foo.c",
wd = tempdir(),
show = debug,
echo = debug,
fail_on_status = TRUE,
stderr = "2>&1"
)
if (debug) {
message("")
}
dylib <- file.path(tempdir(), paste0("foo", .Platform$dynlib.ext))
on.exit(unlink(dylib), add = TRUE)
dll <- dyn.load(dylib)
on.exit(dyn.unload(dylib), add = TRUE)
.C(dll$foo, 0L)[[1]] == 1L
},
error = function(e) {
FALSE
}
)
cache_set("has_compiler", res)
res
}
#' @export
#' @rdname has_compiler
check_compiler <- function(debug = FALSE) {
if (!has_compiler(debug)) {
stop("Failed to compile C code", call. = FALSE)
}
TRUE
}
#' @export
#' @rdname has_compiler
#' @usage NULL
has_devel <- check_build_tools
# The checking code looks for the objects in the package namespace, so defining
# dll here removes the following NOTE
# Registration problem:
# Evaluating 'dll$foo' during check gives error
# 'object 'dll' not found':
# .C(dll$foo, 0L)
# See https://github.com/wch/r-source/blob/d4e8fc9832f35f3c63f2201e7a35fbded5b5e14c/src/library/tools/R/QC.R#L1950-L1980
# Setting the class is needed to avoid a note about returning the wrong class.
# The local object is found first in the actual call, so current behavior is
# unchanged.
dll <- list(foo = structure(list(), class = "NativeSymbolInfo"))
pkgbuild/R/rtools-registry.R 0000644 0001762 0000144 00000001721 14211634664 015577 0 ustar ligges users read_registry <- function(...) {
tryCatch(
utils::readRegistry(...),
error = function(e) NULL
)
}
scan_registry_for_rtools <- function(debug = FALSE) {
if (debug) cat("Scanning registry...\n")
keys <- c(
read_registry("SOFTWARE\\R-core\\Rtools", hive = "HCU", view = "32-bit", maxdepth = 2),
read_registry("SOFTWARE\\R-core\\Rtools", hive = "HLM", view = "32-bit", maxdepth = 2),
read_registry("SOFTWARE\\R-core\\Rtools", hive = "HLM", view = "64-bit", maxdepth = 2)
)
if (is.null(keys)) {
return(NULL)
}
rts <- vector("list", length(keys))
for (i in seq_along(keys)) {
version <- names(keys)[[i]]
key <- keys[[version]]
if (!is.list(key) || is.null(key$InstallPath)) next
install_path <- normalizePath(key$InstallPath,
mustWork = FALSE, winslash = "/"
)
if (debug) cat("Found", install_path, "for", version, "\n")
rts[[i]] <- rtools(install_path, version)
}
Filter(Negate(is.null), rts)
}
pkgbuild/NEWS.md 0000644 0001762 0000144 00000014153 14535336726 013173 0 ustar ligges users # pkgbuild 1.4.3
* pkgbuild now does not need the crayon, rprojroot and prettyunits
packages.
# pkgbuild 1.4.2
* Running `bootstrap.R` now works with `pkgbuild_process`, so it also works
from pak (https://github.com/r-lib/pak/issues/508).
# pkgbuild 1.4.1
* New `Config/build/extra-sources` `DESCRIPTION` option to make pkgbuild aware
of extra source files to consider in `needs_compile()`.
* New `Config/build/bootstrap` `DESCRIPTION` option. Set it to `TRUE` to run
`Rscript bootstrap.R` in the package root prior to building the source
package (#157, @paleolimbot).
* pkgbuild now supports Rtools43.
* pkgbuild now always _appends_ its extra compiler flags to the ones that
already exist in the system and/or user `Makevars` files (#156).
# pkgbuild 1.4.0
* pkgbuild can now avoid copying large package directories when building a
source package. See the `PKG_BUILD_COPY_METHOD` environment variable in
`?build` or the package README (#59).
This is currently an experimental feature, and feedback is
appreciated.
* `R CMD build` warnings can now be turned into errors, by setting the
`pkg.build_stop_for_warnings` option to `TRUE` or by setting the
`PKG_BUILD_STOP_FOR_WARNINGS` environment variable to `true` (#114).
* `need_compile()` now knows about Rust source code files, i.e. `Cargo.toml`
and `*.rs` (#115).
* Now `pkgbuild::build()` will not clean up `inst/doc` by default if the
`Config/build/clean-inst-doc` entry in `DESCRIPTION` is set to `FALSE` (#128).
* New `PKG_BUILD_COLOR_DIAGNOSTICS` environment variable to opt out from
colored compiler output (#141).
* pkgbuild now works with a full XCode installation if the XCode Command
Line Tools are not installed, on macOS, in RStudio (#103).
# pkgbuild 1.3.1
* Accept Rtools40 for R 4.2, it works well, as long as the PATH includes
both `${RTOOLS40_HOME}/usr/bin` and `${RTOOLS40_HOME}/ucrt64/bin`.
E.g. `~/.Renviron` should contain now
```
PATH="${RTOOLS40_HOME}\usr\bin;${RTOOLS40_HOME}\ucrt64\bin;${PATH}"
```
to make Rtools40 work with both R 4.2.x (devel currently) and R 4.1.x and
R 4.0.x.
# pkgbuild 1.3.0
* pkgbuild now supports Rtools 4.2.
* pkgbuild now returns the correct path for R 3.x (#96).
* `build()` now always returns the path of the built package (#108).
* pkgbuild output now looks better in `.Rmd` documents and in general in non-dynamic terminals. You can also force dynamic and non-dynamic output now (#64).
* pkgbuild does not build the PDF manual now if `pdflatex` is not installed, even if `manual = TRUE` (#123).
# pkgbuild 1.2.1
* Gábor Csárdi is now the maintainer.
* `build_setup_source` now considers both command-line build arguments, as
well as parameters `vignettes` or `manual` when conditionally executing
flag-dependent behaviors (@dgkf, #120)
# pkgbuild 1.2.0
* pkgbuild is now licensed as MIT (#106)
* `compile_dll()` gains a `debug` argument for more control over the compile options used (@richfitz, #100)
* `pkgbuild_process()` and `build()` now use colored compiler diagnostics if supported (#102)
* Avoid documentation link ambiguity in R 4.1 (#105)
# pkgbuild 1.1.0
* `compile_dll()` now supports automatic cpp11 registration if the package links to cpp11.
* `rtools_needed` returns correct version instead of "custom" (@burgerga, #97)
# pkgbuild 1.0.8
* Fixes for capability RStudio 1.2. and Rtools 40, R 4.0.0
# pkgbuild 1.0.7
* Additional fixes for Rtools 40
# pkgbuild 1.0.6
* Support for RTools 40 and custom msys2 toolchains that are explicitly set
using the `CC` Makevars (#40).
# pkgbuild 1.0.5
* `check_build_tools()` gains a `quiet` argument, to control when the message
is displayed. The message is no longer displayed when `check_build_tools()`
is called internally by pkgbuild functions. (#83)
# pkgbuild 1.0.4
* `build()` gains a `clean_doc` argument, to control if the `inst/doc`
directory is cleaned before building. (#79, #75)
* `build()` and `pkgbuild_process` now have standard output and error are
correctly interleaved, by redirecting the standard error of build process
to the standard output (@gaborcsardi, #78).
* `check_build_tools()` now has a more helpful error message which points you
towards ways to debug the issue (#68).
* `pkgbuild_process` now do not set custom compiler flags, and it uses
the user's `Makevars` file (@gaborcsardi, #76).
* `rtools_path()` now returns `NA` on non-windows systems and also works when
`has_rtools()` has not been run previously (#74).
# pkgbuild 1.0.3
* Tests which wrote to the package library are now skipped on CRAN.
* `build()` can now build a tar.gz file directly (#55)
# pkgbuild 1.0.2
* `build()` and `compile_dll()` gain a `register_routines` argument, to
automatically register C routines with
`tools::package_native_routines_registration_skeleton()` (#50)
* `build()` will now warn if trying to build packages on R versions <= 3.4.2 on
Windows with a space in the R installation directory (#49)
* `build()` will now message if a build contains long paths, which are unsupported on windows
(#48)
* `compile_dll()` no longer doubles output, a regression caused by the styling callback.
(https://github.com/r-lib/devtools/issues/1877)
* `build()` output is now styled like that in the rcmdcheck package
(https://github.com/r-lib/devtools/issues/1874).
* `build()` no longer sets compile flags (#46)
# pkgbuild 1.0.1
* Preliminary support for rtools 4.0 (#40)
* `compile_dll()` now does not supply compiler flags if there is an existing
user defined Makevars file.
* `local_build_tools()` function added to provide a deferred equivalent to
`with_build_tools()`. So you can add rtools to the PATH until the end of a
function body.
# pkgbuild 1.0.0
* Add metadata to support Rtools 3.5 (#38).
* `build()` only uses the `--no-resave-data` argument in `R CMD build`
if the `--resave-data` argument wasn't supplied by the user
(@theGreatWhiteShark, #26)
* `build()` now cleans existing vignette files in `inst/doc` if they exist. (#10)
* `clean_dll()` also deletes `symbols.rds` which is created when `compile_dll()`
is run inside of `R CMD check`.
* First argument of all functions is now `path` rather than `pkg`.
pkgbuild/MD5 0000644 0001762 0000144 00000012073 14535342146 012375 0 ustar ligges users 087c94265ac71bd9fb174a6c7f82f7eb *DESCRIPTION
faf2baf0ecd138dc63fc451973987996 *LICENSE
5fba5a95f84bcf1d2405e167c7ecd4e6 *NAMESPACE
ce84b079e8013c1e1bb0d702e92aaa34 *NEWS.md
78b67ff42c1a26e46729aed96cf409b3 *R/build-bg.R
a62051336b2cb8b37c23d0e0aae56d29 *R/build-tools.R
5332a09284986d079d102f7380c76472 *R/build.R
2b9ad84f281faa439fe10c04532d422d *R/c-registration.R
8d41d120d4955be4a6fe8607ea96c174 *R/cache.R
21454efb84eb5a18056bdf7398f36674 *R/callback.R
7b0848d2a79d737edd2d2a882d0e3715 *R/compile-dll.R
da3c666884c5f7d0f9ffa01800ac311e *R/compiler-flags.R
f1a406e5772d7ec1c4795c361113c006 *R/compiler.R
f370d4cc2301e8e38560135eeee1d221 *R/exclude.R
e2546b166c5451d3a826178fb95a958c *R/find-package-root.R
6569915ddd3954f37aa09e57bbfd2edd *R/has_src.R
44ef843fd141c767d3029cb643d6a028 *R/latex.R
df6cc46bc7fae1a55b713f3d5065b35a *R/pkgbuild-package.R
7245e0871eeb4883cd9a9c1d05891c7d *R/rcmd.R
f551ea3042a32ae816845561f8ed00aa *R/rtools-cache.R
949db6c5b8746b45777de518e15f16b3 *R/rtools-config.R
86d9dbab9c58327d28f8fe3be75f6ee7 *R/rtools-metadata.R
47b06e012e10449ffaeccdae7da00843 *R/rtools-path.R
b1baa30e372abf4264be670be0095f9f *R/rtools-registry.R
2dd13e36b0fca4402565acfb222c3d64 *R/rtools.R
c92adeb11a5e67591e974c6f0d5ccdab *R/styles.R
c362b7ba1d9f4e5862d85901c1e3cc14 *R/time.R
ca568b62a08ace7ea4eaf33046f3a716 *R/utils.R
98bb021e6a9e06686af3830349e7b1cc *R/with-debug.R
6a1dc63e6ab3c14140f435eb672d7dd2 *R/withr.R
714cd2029e57f398bf9f9f1ff4c32702 *README.md
3280a80f4395a1db1f24ac6608cc6f70 *man/build.Rd
b16255149b3caf04d128de8053594c71 *man/clean_dll.Rd
3c9fa4f2463b025b9b38c8cfcda4db51 *man/compile_dll.Rd
73f325dcf528758ff067b0603c6a048e *man/compiler_flags.Rd
2389b5cc2aa56411e3b30d0e62b7263a *man/has_build_tools.Rd
b770baba0361a4388737b429b699950f *man/has_compiler.Rd
28b37e7ae90236503c5abf076ce680df *man/has_latex.Rd
483eac2edac3d166291adf95f1fc46e1 *man/has_rtools.Rd
d16da465eef5bd0c68c48b643b928bee *man/needs_compile.Rd
88a5840825815f8def991da5111fda98 *man/pkg_has_src.Rd
cc1e8d29bc22e105566a563c65175d38 *man/pkg_links_to_rcpp.Rd
7668f726d49928478dd83e383bcd7204 *man/pkgbuild-package.Rd
cc6699fab7f21a8a34afe30d30d78e8c *man/pkgbuild_process.Rd
fa69989496d2b1b4471e4c82948e599f *man/rcmd_build_tools.Rd
356852ee1b8d4d73bde41307fbfb9964 *man/rtools_needed.Rd
474083d45f34132224732b732e4164fe *man/with_debug.Rd
2e8086dd548443e4ad51c0aee9611ce1 *man/without_compiler.Rd
d11922ac9eab43de2d4ff0bb06b9465e *tests/build-tools.R
2fb58861d239d4cb77f513d8657104ea *tests/testthat.R
4d8706534667ef814069cbaedd29e877 *tests/testthat/_snaps/build.md
ab4886102479e59d26cc52c561b022b6 *tests/testthat/_snaps/compiler.md
fc63add8ded7896d0242ca00c6f3489c *tests/testthat/_snaps/exclude.md
bec9b69699853278a5eed25c29308765 *tests/testthat/_snaps/style.md
bdb20063b70d63f163200f3c75bd9e92 *tests/testthat/_snaps/utils.md
335cf2b43bac47c1f492e231cb977233 *tests/testthat/fixtures/testDummy_0.1.tar.gz
b08df40d59aa3c817f4d7651badc77e0 *tests/testthat/fixtures/testWithSrc_0.1.tar.gz
aef8f02891aa60e66955e23356e6e3a4 *tests/testthat/fixtures/xxx.gz
6dc77ce3ba4e9b5ecb2d5e53e7a129e2 *tests/testthat/fixtures/xxx.tar.gz
267812fc7bc60f0a742afcfc33acfc62 *tests/testthat/fixtures/xxx.zip
1a298502f88bbcdd5a7256edaa57480d *tests/testthat/test-archives.R
62988514d1bc664b725c3ffc66658299 *tests/testthat/test-build-process.R
a1d05a816a171025afb7c7247a60b896 *tests/testthat/test-build.R
86bcab16757e9c672f1f5263073f694b *tests/testthat/test-build_tools.R
b75ef7003cf9f964bae1a982db785d43 *tests/testthat/test-c-registration.R
8aafc02de8bb99a9d2ffdb990b92375c *tests/testthat/test-compile_dll.R
7a5bac2e1c076bbfec1e94df0b8fd7e8 *tests/testthat/test-compiler-flags.R
0b2a3ea5c950818b39171c83ed165a6b *tests/testthat/test-compiler.R
292759090fd642fdf2ef5caa3b0cee09 *tests/testthat/test-exclude.R
72efc0f2f28309dee337370ac3683d36 *tests/testthat/test-find-package-root.R
68e7408b02e8085a435b44913acdc66d *tests/testthat/test-rtools.R
def62e429ecb3dd1b190da179e097064 *tests/testthat/test-style.R
22c4024d36383120bc74c1f8aa66d147 *tests/testthat/test-utils.R
f2ccf899dbafd628e8fae8357dfdbe63 *tests/testthat/test-withr.R
3d687f7cc510f4b045ab5379a1546cfc *tests/testthat/testDummy/DESCRIPTION
85601cb90b291bb14a88bc9e7349b653 *tests/testthat/testDummy/NAMESPACE
26813d0f7f8e272af05102662163c53b *tests/testthat/testDummy/R/a.R
aa6661f9ad2794e7d2c6d8a36023e78b *tests/testthat/testDummy/R/b.R
4bcab09205448a0f7a368ad955997cd3 *tests/testthat/testInstDoc/DESCRIPTION
85601cb90b291bb14a88bc9e7349b653 *tests/testthat/testInstDoc/NAMESPACE
26813d0f7f8e272af05102662163c53b *tests/testthat/testInstDoc/R/a.R
aa6661f9ad2794e7d2c6d8a36023e78b *tests/testthat/testInstDoc/R/b.R
05a9473ea4dc54ad4ee75a7d41f132cf *tests/testthat/testInstDoc/inst/doc/keep.me
2241e854ebd36660cb0e132afce33bd5 *tests/testthat/testInstDoc/vignettes/test.Rmd
77191fb130945287a52f77be7be32132 *tests/testthat/testWithSrc/DESCRIPTION
85601cb90b291bb14a88bc9e7349b653 *tests/testthat/testWithSrc/NAMESPACE
26813d0f7f8e272af05102662163c53b *tests/testthat/testWithSrc/R/a.R
aa6661f9ad2794e7d2c6d8a36023e78b *tests/testthat/testWithSrc/R/b.R
f25a893824d1be847ed0e681595b9f78 *tests/testthat/testWithSrc/src/add1.c