pkgbuild/0000755000176200001440000000000014160077122012053 5ustar liggesuserspkgbuild/NAMESPACE0000644000176200001440000000174314160060655013302 0ustar liggesusers# 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(callr,rcmd_process) importFrom(callr,rcmd_process_options) importFrom(cli,symbol) importFrom(crayon,bold) importFrom(crayon,green) importFrom(crayon,make_style) importFrom(crayon,red) importFrom(prettyunits,pretty_dt) importFrom(utils,head) importFrom(utils,tail) pkgbuild/LICENSE0000644000176200001440000000005614152340747013070 0ustar liggesusersYEAR: 2020 COPYRIGHT HOLDER: pkgbuild authors pkgbuild/README.md0000644000176200001440000000200214152340747013333 0ustar liggesusers# pkgbuild [![R build status](https://github.com/r-lib/pkgbuild/workflows/R-CMD-check/badge.svg)](https://github.com/r-lib/pkgbuild/actions) [![Codecov test coverage](https://codecov.io/gh/r-lib/pkgbuild/branch/main/graph/badge.svg)](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 You can install pkgbuild from github with: ``` r # install.packages("devtools") devtools::install_github("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) ``` pkgbuild/man/0000755000176200001440000000000014152340747012635 5ustar liggesuserspkgbuild/man/pkg_links_to_rcpp.Rd0000644000176200001440000000067514152340747016643 0ustar liggesusers% 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/has_build_tools.Rd0000644000176200001440000000417714152340747016307 0ustar liggesusers% 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}{\verb{[environment]}\cr 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.Rd0000644000176200001440000000054214152340747015410 0ustar liggesusers% 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.Rd0000644000176200001440000000113614152340747016522 0ustar liggesusers% 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.Rd0000644000176200001440000000040714152340747015075 0ustar liggesusers% 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.Rd0000644000176200001440000000072514152340747015736 0ustar liggesusers% 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.Rd0000644000176200001440000000370514152340747015414 0ustar liggesusers% 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. } \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.Rd0000644000176200001440000000170414152340747015573 0ustar liggesusers% 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{ \code{has_devel} returns \code{TRUE} or \code{FALSE}. \code{check_devel} throws an error if you don't have developer tools installed. Implementation 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.Rd0000644000176200001440000000061714152340747015045 0ustar liggesusers% 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.Rd0000644000176200001440000000560414154234431014222 0ustar liggesusers% 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 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. } pkgbuild/man/has_rtools.Rd0000644000176200001440000000255614152340747015311 0ustar liggesusers% 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.Rd0000644000176200001440000000167714152340747016125 0ustar liggesusers% 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.Rd0000644000176200001440000000201014152340747016441 0ustar liggesusers% 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.Rd0000644000176200001440000000162414152340747015250 0ustar liggesusers% 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.Rd0000644000176200001440000000051414152340747015752 0ustar liggesusers% 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.Rd0000644000176200001440000000236114152340747016465 0ustar liggesusers% 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}{ \preformatted{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 \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}{ \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() } } pkgbuild/DESCRIPTION0000644000176200001440000000211014160077122013553 0ustar liggesusersPackage: pkgbuild Title: Find Tools Needed to Build R Packages Version: 1.3.1 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("RStudio", role = "cph") ) 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. Imports: callr (>= 3.2.0), cli, crayon, desc, prettyunits, R6, rprojroot, withr (>= 2.3.0) Suggests: Rcpp, cpp11, testthat, covr License: MIT + file LICENSE Encoding: UTF-8 RoxygenNote: 7.1.2.9000 URL: https://github.com/r-lib/pkgbuild BugReports: https://github.com/r-lib/pkgbuild/issues Depends: R (>= 3.1) NeedsCompilation: no Packaged: 2021-12-20 12:30:29 UTC; gaborcsardi Author: Hadley Wickham [aut], Jim Hester [aut], Gábor Csárdi [aut, cre], RStudio [cph] Maintainer: Gábor Csárdi Repository: CRAN Date/Publication: 2021-12-20 13:00:02 UTC pkgbuild/tests/0000755000176200001440000000000014152340747013224 5ustar liggesuserspkgbuild/tests/testthat/0000755000176200001440000000000014160077122015055 5ustar liggesuserspkgbuild/tests/testthat/testDummy/0000755000176200001440000000000014152340747017057 5ustar liggesuserspkgbuild/tests/testthat/testDummy/NAMESPACE0000644000176200001440000000001214152340747020267 0ustar liggesusersexport(a) pkgbuild/tests/testthat/testDummy/DESCRIPTION0000644000176200001440000000027014152340747020564 0ustar liggesusersPackage: 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/0000755000176200001440000000000014152340747017260 5ustar liggesuserspkgbuild/tests/testthat/testDummy/R/a.r0000644000176200001440000000000714152340747017660 0ustar liggesusersa <- 1 pkgbuild/tests/testthat/testDummy/R/b.r0000644000176200001440000000000714152340747017661 0ustar liggesusersb <- 2 pkgbuild/tests/testthat/fixtures/0000755000176200001440000000000014152340747016735 5ustar liggesuserspkgbuild/tests/testthat/fixtures/xxx.zip0000644000176200001440000000024014152340747020304 0ustar liggesusersPK U8JgtxxxUT 0XXux xxx PK U8JgtxxxUT0Xux PKIApkgbuild/tests/testthat/fixtures/xxx.tar.gz0000644000176200001440000000021414152340747020710 0ustar liggesusers1XA 0F=ay-B87("y߄ݻT5(o"J0!ڠw˪|ϥVs.e_l?%MZpݿ{(pkgbuild/tests/testthat/fixtures/testWithSrc_0.1.tar.gz0000644000176200001440000000113514152340747022725 0ustar liggesusersXQk0^mI$JJ4t65NYMD+Hʶ2'; e[ФeB:q;sN0x'Q@8NV="kDPM)Peڅ2cSa:sjWWk6]7B86wSrV] ,fW:<\%'  õ\Z.+݅, ͯ_ldjq2YX}Bj]H b)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 '-ǎ3Ovvpkgbuild/tests/testthat/fixtures/xxx.gz0000644000176200001440000000003414152340747020123 0ustar liggesusers0Xxxxgtpkgbuild/tests/testthat/fixtures/testDummy_0.1.tar.gz0000644000176200001440000000063114152340747022435 0ustar liggesusersN0w8zkI @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-xfpkgbuild/tests/testthat/test-c-registration.R0000644000176200001440000000440114152340747021115 0ustar liggesuserscontext("c-registration.R") test_that("update_c_registration does nothig 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/test-compiler.R0000644000176200001440000000062114152340747017775 0ustar liggesuserscontext("test-compiler.R") describe("has_compiler", { 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()) }) }) }) pkgbuild/tests/testthat/test-build_tools.R0000644000176200001440000000051514152340747020504 0ustar liggesuserscontext("build_tools") 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/0000755000176200001440000000000014152340747017347 5ustar liggesuserspkgbuild/tests/testthat/testWithSrc/NAMESPACE0000644000176200001440000000001214152340747020557 0ustar liggesusersexport(a) pkgbuild/tests/testthat/testWithSrc/DESCRIPTION0000644000176200001440000000027214152340747021056 0ustar liggesusersPackage: 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/0000755000176200001440000000000014154234422020130 5ustar liggesuserspkgbuild/tests/testthat/testWithSrc/src/add1.c0000644000176200001440000000056514152340747021121 0ustar liggesusers// 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/0000755000176200001440000000000014154234422017542 5ustar liggesuserspkgbuild/tests/testthat/testWithSrc/R/a.r0000644000176200001440000000000714152340747020150 0ustar liggesusersa <- 1 pkgbuild/tests/testthat/testWithSrc/R/b.r0000644000176200001440000000000714152340747020151 0ustar liggesusersb <- 2 pkgbuild/tests/testthat/test-compile_dll.R0000644000176200001440000000040014152340747020441 0ustar liggesuserscontext("test-compile_dll.R") 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-rtools.r0000644000176200001440000000172414152340747017552 0ustar liggesuserscontext("test-rtools.R") 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.r0000644000176200001440000001173214152340747017327 0ustar liggesuserscontext("build") # 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") }) pkgbuild/tests/testthat/test-archives.R0000644000176200001440000000203314152340747017766 0ustar liggesusers context("Package archives") 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-build-process.r0000644000176200001440000000674414152340747021012 0ustar liggesuserscontext("pkgbuild_process") # 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/build-tools.R0000644000176200001440000000006314152340747015603 0ustar liggesuserslibrary(pkgbuild) check_build_tools(debug = TRUE) pkgbuild/tests/testthat.R0000644000176200001440000000007414152340747015210 0ustar liggesuserslibrary(testthat) library(pkgbuild) test_check("pkgbuild") pkgbuild/R/0000755000176200001440000000000014160057452012260 5ustar liggesuserspkgbuild/R/rtools-cache.R0000644000176200001440000000143314152340747014772 0ustar liggesusers#' @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.R0000644000176200001440000000273514152340747013555 0ustar liggesusersdir.exists <- function(x) { res <- file.exists(x) & file.info(x)$isdir stats::setNames(res, x) } pkg_path <- function(path = ".") { rprojroot::find_root("DESCRIPTION", 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_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 = "") } pkgbuild/R/build-bg.R0000644000176200001440000000765114152340747014104 0ustar liggesusers#' 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) rcb_init(self, private, super, path, dest_path, binary, vignettes, manual, clean_doc, args, needs_compilation, compile_attributes, register_routines), 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 ) ) #' @importFrom callr rcmd_process rcmd_process_options 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, assignment = "+=") withr::local_envvar("R_MAKEVARS_USER" = private$makevars_file) options <- 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.R0000644000176200001440000000364314152340747014453 0ustar liggesusers#' 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 withr::with_envvar #' @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.R0000644000176200001440000000116414152340747013733 0ustar liggesusers#' @importFrom crayon red green make_style bold # 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" = green, "note" = make_style("orange"), "warn" = make_style("orange") $ bold, "err" = red, "pale" = make_style("darkgrey"), "timing" = make_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.R0000644000176200001440000000343114160057452015504 0ustar liggesusersversion_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 = "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.R0000644000176200001440000000312114152340747014025 0ustar liggesusers#' 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.R0000644000176200001440000001232014152340747014605 0ustar liggesusers#' 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. #' #' @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 if (!quiet) message("Re-compiling ", pkg_name(path)) install_dir <- tempfile("devtools_install_") dir.create(install_dir) # If the user has a makevars file just use that if (length(makevars_user()) > 0) { install_min( path, dest = install_dir, components = "libs", args = if (needs_clean(path)) "--preclean", quiet = quiet ) } else { # Otherwise set makevars for fast development / debugging withr::with_makevars(compiler_flags(debug), assignment = "+=", { 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)))) } #' 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) } # List all source files in the package sources <- function(path = ".") { srcdir <- file.path(path, "src") dir(srcdir, "\\.(c.*|f)$", recursive = TRUE, full.names = TRUE) } # 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.R0000644000176200001440000000140014152340747015166 0ustar liggesusers# 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/compiler-flags.R0000644000176200001440000000476214154213431015312 0ustar liggesusers#' 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 (crayon::has_color() && 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() { 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.R0000644000176200001440000000060514152340747013524 0ustar liggesusers#' 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.R0000644000176200001440000000770014152340747015344 0ustar liggesusersupdate_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.R0000644000176200001440000000462514154232124013331 0ustar liggesusers#' 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) 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.R0000644000176200001440000000076114152340747013455 0ustar liggesusers# 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.R0000644000176200001440000001442714154234315013510 0ustar liggesusers#' 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. #' #' @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 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::local_makevars(compiler_flags(debug = FALSE), .assignment = "+=") 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 ) ) 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) } 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 (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) list( cmd = "build", path = normalizePath(path), args = args, out_dir = out_dir, dest_path = dest_path ) } pkgbuild/R/rtools-path.R0000644000176200001440000000335314152340747014666 0ustar liggesusersscan_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.R0000644000176200001440000000544014152340747014646 0ustar liggesusers#' 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) if(is_windows() && is_R4() && has_rtools(debug = debug)){ TRUE } else if (!is.null(check)) { check("Building R package from source") } else if (is_windows()) { has_rtools(debug = debug) } else { has_compiler(debug = debug) } } #' @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 #' @inheritParams withr::local_path #' @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/callback.R0000644000176200001440000000527614154214165014150 0ustar liggesusers#' @importFrom cli symbol #' @importFrom utils head tail #' @importFrom prettyunits pretty_dt # 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(" (", 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 = 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(symbol$line, " ", no(x))) } else if (grepl("^\\* DONE\\s*$", x)) { state <<- "OK" NA_character_ } else { style(pale = c(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.R0000644000176200001440000001752514160057452013737 0ustar liggesusers#' 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.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 doens'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) { paste0( "https://cran.r-project.org/bin/windows/Rtools/", if (needed == "Rtools 4.2") { " or https://www.r-project.org/nosvn/winutf8/ucrt3/" } ) } pkgbuild/R/compiler.R0000644000176200001440000000423214152340747014221 0ustar liggesusers#' Is a compiler available? #' #' `has_devel` returns `TRUE` or `FALSE`. `check_devel` #' throws an error if you don't have developer tools installed. Implementation #' 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) { 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.R0000644000176200001440000000170314152340747015577 0ustar liggesusersread_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.md0000644000176200001440000001062514160073522013155 0ustar liggesusers# 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 considerers 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/MD50000644000176200001440000000720414160077122012366 0ustar liggesusersb81242cb42d3fc8a52f40aa8b2c9e33b *DESCRIPTION 4fef0023850b083f3071e2cac81c4cfc *LICENSE a6990c99fedd15e111419a5263b82eca *NAMESPACE db4f1970d87d1b4fec7d6bca147affeb *NEWS.md 8ff29851e32c103bafecd6667e16a853 *R/build-bg.R d67b67aab5c1106a62723b94bc40c205 *R/build-tools.R 7d96d2d272d432bc7e4dc6ec54cee3f3 *R/build.R eda7b2d34943dc06d742df73bc28b6f7 *R/c-registration.R 8d41d120d4955be4a6fe8607ea96c174 *R/cache.R cfbd72fc7932bc4a05baa3368e8dd861 *R/callback.R 086f734351c3f58bfa2cc31a884d8582 *R/compile-dll.R 4c6e454156779c03d5cef7fa391701a0 *R/compiler-flags.R b110372f3b80823b810d4641c3af81b1 *R/compiler.R fd0876609b6b761c36cd165da7b7f146 *R/has_src.R a6445198e52e4121990a9aa2c7f60ff1 *R/latex.R d46600def40aa79e19d394c141232ce1 *R/rcmd.R c37998c53f57819f4583805df967f2d5 *R/rtools-cache.R 3685ed35d96d86d4c7c5e067ab52a478 *R/rtools-config.R d5d2e8c13dfa06782175b79e2f4661f9 *R/rtools-metadata.R f24838e0333dc2bc3a7ca6e8f27883d9 *R/rtools-path.R a47b642b208c96cd9886a023d1aca291 *R/rtools-registry.R 7c94ec5f9a80dc34635fa128bed37cd2 *R/rtools.R f005f154dcfde9d9b32708bd9eb8c76b *R/styles.R 260b980b205829677986ac73ef43211c *R/utils.R 56102ca890043ea697041357bff69560 *R/with-debug.R 28baee91d3b8b7fe522597c0c3b39e8f *README.md 26440e14d34a4d50820ad9dfbc613001 *man/build.Rd b16255149b3caf04d128de8053594c71 *man/clean_dll.Rd 198cef1b4369df908bb67294a186d690 *man/compile_dll.Rd 58b403f421a58c798253aaf43f84ddd0 *man/compiler_flags.Rd 57f92b0393410c4cfd5688d5f5f1ffdd *man/has_build_tools.Rd c00a4ac4cd7833f4e562133337c74ca1 *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 9a1b672e18a395337c38fab3126feae6 *man/pkgbuild_process.Rd fa69989496d2b1b4471e4c82948e599f *man/rcmd_build_tools.Rd 356852ee1b8d4d73bde41307fbfb9964 *man/rtools_needed.Rd 71e799d47a6458cdd95311616221a3d0 *man/with_debug.Rd 2e8086dd548443e4ad51c0aee9611ce1 *man/without_compiler.Rd d11922ac9eab43de2d4ff0bb06b9465e *tests/build-tools.R 2fb58861d239d4cb77f513d8657104ea *tests/testthat.R 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 c4bd7c279a480670f6ed045720f69e9c *tests/testthat/test-archives.R 3b2fbd3fd4b2a1d84bca24ea96945c75 *tests/testthat/test-build-process.r 1db2b5ee4c2317c835dba1059413c749 *tests/testthat/test-build.r d1b687fc83746b673c905f50e955a5d9 *tests/testthat/test-build_tools.R f62ac607e714ae6245ebb61469586880 *tests/testthat/test-c-registration.R 6a367497c505998a782524a57579e3da *tests/testthat/test-compile_dll.R 4536bffa7124f108937eab3ad2ffbaf2 *tests/testthat/test-compiler.R d7c27efc31b54e11ee14d699aa5cae6f *tests/testthat/test-rtools.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 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