Prevent R from executing code in R profile when installing packages - r

I have some code in my R profile that I've found interferes with package installation. For example, I like to automatically load devtools when I'm working on packages, so I have this
if (file.exists("DESCRIPTION")) {
try({suppressMessages(library(devtools))})
}
However, I've found that this interferes with package installation, I get errors like ERROR: lazy loading failed for package ‘rlang’. If I comment out the loading of devtools in the R profile, the package installs without error.
Is there any way to check if .Rprofile is being executed during package installation so that I could put that condition in the if and stop devtools from loading at inappropriate times?

I’d generally recommend against putting such code into your ~/.Rprofile! — The ~/.Rprofile should contain only general configuration that is always valid. For further customisation, use a project-local ~/.Rprofile instead.
However, I would make one exception to the above guideline, because one useful distinction you can make is to only execute certain code in interactive sessions:
if (interactive()) {
if (file.exists("DESCRIPTION")) {
try({suppressMessages(library(devtools))})
}
}

.Rprofile files are sourced on R startup. They won't be called later by other functions so you can't use the checking logic during install.packages().
For this reason loading packages using RProfile is not always advisable as it can make your code non-reproducible. However, as a helper package, devtools is probably a good exception (ignoring your particular problem here).
If you use base R only you can tell R not to load Rprofile during startup by using the --vanilla or --no-init-file arguments.
If you are using RStudio one workaround would be to use project level Rprofile files. Rstudio starts a new R session for each project, and loads the user Rprofile from the project root. If it then can't find that it will attempt to load the user RProfile.
Create a new project and within the the project options tick the option to disable the Rprofile loading.
Whenever you want to install a package switch to this project.
One caveat is to make sure you are running this as the only project session open, having multiple RStudio sessions open when installing new packages can lead to problems without putting the Rprofile in the mix.
Rstudio article on startup files https://support.rstudio.com/hc/en-us/articles/360047157094-Managing-R-with-Rprofile-Renviron-Rprofile-site-Renviron-site-rsession-conf-and-repos-conf
Base R documentation on R initialization https://stat.ethz.ch/R-manual/R-devel/library/base/html/Startup.html
A diagram of the R startup flow and some commentary on use of renviron and rprofile
https://rstats.wtf/r-startup.html

Related

r: errors creating package with devtools & roxygen2

I'm writing a package containing several functions to make running and evaluating models more streamlined.
I have a function that I'm going to make the first function within my package detailed with roxygen2 comments, which I can include into this write-up as an edit if necessary, but my issue is more with Package Creation.
I've created a separate .R file for the function and it lives within the R folder in within my package folder. I've run R CMD build pkgname and R CMD INSTALL pkgname successfully.
At the document() stage I run it (from console or whether in my terminal using R -e 'library(devtools);document()', deleting the existing NAMESPACE file first) and I get the following error: Try removing ‘/Library/Frameworks/R.framework/Versions/ 3.5/Resources/library/00LOCK-pkgname.
I've already seen the [issue posted here][1] and haven't had success after deleting the 00LOCK-pkgname folder, for two reasons: when I run document(), even when it throws the above error, it doesn't stop running, it just keeps looping (that happens whether I run this in R or use the Terminal). Additionally, no matter how many times I delete the folder, it keeps re-appearing even though I've stopped running the function.
Any insight into why that error is being thrown and the document() function continually runs in a loop?
Best answer I've found is in this blog post: Hilary Parker R-Package Blog Post
The steps I follow to document and install are as follows:
Within the project that contains my package, open a new R Script and run setwd('..')
Run devtools::document()
Run devtools::install()
This works for me when initially installing my package and also updating it.

R check for a package: optimize the way DLLs are built and checked

I want to optimize my process for building a package. I have in pckgname/src some fortran code (f90):
pckgname/src/FortranFile1.f90
pckgname/src/FortranFile2.f90
I am under RStudio. When I build the package, it creates the src-i386 and src-x64 folders, inside which executable files in .o are produced
pckgname/src-i386/FortranFile1.o
pckgname/src-i386/FortranFile2.o
pckgname/src-x64/FortranFile1.o
pckgname/src-x64/FortranFile2.o
then dll files are produced into each of these folders from the .o files:
pckgname/src-i386/dllname.dll
pckgname/src-x64/dllname.dll
thereafter if I want to check the code successfully, I need to manually copy paste the dll into these two folders (in the previous version of the question i wrote code instead of dll which might have led to misunderstandings)
pckgname/inst/libs/x64/dllname.dll
pckgname/libs/X64/dllname.dll
My question is: is it normal that I have to do this or is there a shorter way without having to copy paste by hand dllname.dll
into these two folders? It could be indeed a source of error.
NB: If i don't copy the dlls into the said folders I get the following error messages (translated from the French):
Error in inDL(x, as.logical(local), as.logical(now), ...) :
impossible to load shared object 'C:/Users/username/Documents/pckgname/inst/libs/x64/dllname.dll':
LoadLibrary failure: The specified module can't be found
Error in inDL(x, as.logical(local), as.logical(now), ...) :
impossible to load shared object 'C:/Users/username/Documents/pckgname/libs/x64/dllname.dll':
LoadLibrary failure: The specified module can't be found.
[...]
`cleanup` is deprecated
The short answer
Is it normal that I have to do this?
No. If path/to/package is the directory you are developing your package in, and you have everything set up for your package to call your Fortran subroutines correctly (see "The long answer"), you can run
R CMD build path/to/package
at the command prompt, and a tarball will be constructed for you with everything in the right place (note you will need Rtools for this). Then you should be able to run
R CMD check packagename_versionnumber.tar.gz
from the command prompt to check your package, without any problems (stemming from the .dll files being in the wrong place -- you may have other problems, in which case I would suggest asking a new question with the ERROR, WARNING, or NOTE listed in the question).
If you prefer to work just from R, you can even
devtools::check("path/to/package")
without having to run devtools::build() or R CMD build ("devtools::check()... [b]undles the package before checking it" -- Hadley's chapter on checking; see also Karl Broman's chapter on checking).
The long answer
I think your question has to do with three issues potentially:
The difference between directory structure of packages before and after they're installed. (You may want to read the "What is a package?" section of Hadley's Package structure chapter -- luckily R CMD build at the command prompt or devtools::build() in R will take care of that for you)
Using INSTALL vs. BUILD (from the comments to the original version of this answer)
The proper way to set up a package to call Fortran subroutines.
You may need quite a bit of advice on the process of developing R packages itself. Some good guides include (in increasing order of detail):
Karl Broman's R package primer
Hadley Wickham's R packages
The Writing R Extensions manual
In particular, there are some details about having compiled code in an R package that you may want to be aware of. You may want to first read Hadley's chapter on compiled code (Broman doesn't have one), but then you honestly need to read most of the Writing R Extensions manual, in particular sections 1.1, 1.2, 1.5.4, and 1.6, and all of chapters 5 and 6.
In the mean time, I've setup a GitHub repository here that demonstrates a toy example R package FortranExample that shows how to correctly setup a package with Fortran code. The steps I took were:
Create the basic package structure using devtools::create("FortranExample").
Eliminate the "Depends" line in the DESCRIPTION, as it set a dependence on R >= 3.5.1, which will throw a warning in check (I have now also revised the "License" field to eliminate a warning about not specifying a proper license).
Make a src/ directory and add toy Fortran code there (it just doubles a double value).
Use tools::package_native_routine_registration_skeleton("FortranExample") to generate the symbol registration code that I placed in src/init.c (See Writing R Extensions, section 5.4).
Create a nice R wrapper for using .Fortran() to call the Fortran code (placed in R/example_function.R).
In that same file use the #' #useDynLib FortranExample Roxygen tag to add useDynLib(FortranExample) to the NAMESPACE file; if you don't use Roxygen, you can put it there manually (See Writing R Extensions 1.5.4 and 5.2).
Now we have a package that's properly set up to deal with the Fortran code. I have tested on a Windows machine (running Windows 8.1 and R 3.5.1) both the paths of running
R CMD build FortranExample
R CMD check FortranExample_0.0.0.9000.tar.gz
from the command prompt, and of running
devtools::check("FortranExample")
from R. There were no errors, and the only warning was the "License" issue mentioned above.
After cleaning up the after-effects of running devtools::check("FortranExample") (for some reason the cleanup option is now deprecated; see below for an R function to handle this for you inspired by devtools::clean_dll()), I used
devtools::install("FortranExample")
to successfully install the package and tested its function, getting:
FortranExample::example_function(2.0)
# [1] 4
The cleanup function I mentioned is
clean_source_dirs <- function(path) {
paths <- file.path(path, paste0("src", c("", "-i386", "-x64")))
file_pattern <- "\\.o|so|dll|a|sl|dyl"
unlink(list.files(path = paths, pattern = file_pattern, full.names = TRUE))
}
No, it is not normal and there is a solution to this problem. Make use of Makevars.win. The reason for your problem is that .dlls are looking for dependencies in places defined by environment variable PATH and relative paths defined during the linking. Linking is being done when running the command R CMD INSTALL as it is stated in Mingw preferences plus some custom parameters defined in the file Makevars.win (Windows platform dependent). As soon as the resulting library is copied, the binding to the places where dependent .dlls were situated may become broken, so if you put dlls in a place where typically dependent libraries reside, such as, for instance, $(R_HOME)/bin/$(ARCH)/,
cp -f <your library relative path>.dll $(R_HOME)/bin/$(ARCH)/<your library>.dll
during the check R will be looking for your dependencies specifically there too, so you will not miss the dependencies. Very crude solution, but it worked in my case.

Load my own R package

I made an R package for personal use, but the way I load it is by individual files. Such as:
source("../compr/R/compr.R")
source("../compr/R/error_df.R")
source("../compr/R/rmse.R")
I would like to load the entire package, which is called compr, as I would other libraries.
If you are using RStudio, I would suggest creating a project and setting it to your compr directory. After that you will be able to use devtools::load_all() to load your package directly.
If you don't want to do this, or you don't use RStudio devtools::load_all('path/to/compr') will also work.
P.S. compr directory needs to be the root of the package i.e. the place where your DESCRIPTION file is.

R alternative to install.packages() function

Is there any documentation on manually installing a package in a user library when the R.home() path is locked down and incomplete (no etc, no bin, just library?) The system does NOT support shelling out to execute R CMD, which I believe standard R does.
I would like to build existing source packages (from CRAN) and install into a user library directory, so that I can use the library() function and get all the usual namespace and *.Rdx and *.Rdb files.
At the moment, I'm plodding through install.packages, tools::.build_package, and tools:::.install.packages source, using a standard MacOS R and the r source. Hopefully this has been documented in a more user-friendly fashion and my google searches have missed it.
Thanks.
You don't need to use a different install.packages method, rather you only need to specify a writable location for storing packages and give it precedence over the system default one. A simple way to accomplish this is to set an R_LIBS environment variable. For instance, in my .bashrc I have
export R_LIBS='/home/username/.local/lib/R-3.3.3'
Then, by default, all packages are installed here. Further, packages installed both here and the system-wide location will give priority to the ones here when loading.
You can verify that the location is being used by checking .libPaths() in your R session.

Purging previous versions of functions when developing packages in R

I am developing a package in R. Let's call it mypkg.
Because some functions behave differently when they are run from a package (I am not sure why--but this is not the question), I am editing functions in the package, then rebuilding the package from the command line. For some reason a given R instance retains older versions of the functions even though the source has been changed and the package rebuilt and re-installed. I need to start a new instance to see the changes.
Here is the typical workflow.
Make changes to myfunction() in mypkg.R
In R: detach(package:mypkg); remove.packages("mypkg")
Command line: R CMD INSTALL --build c:\mypkg
Notifies me that it has been installed to the default library
In R: library(mypkg)
In R: myfunction() runs the previous version before changes.
[The next three steps I want to avoid]
Start a new R instance
In R: library(mypkg)
myfunction() works as expected
Run under R.2.14.1.
I am looking for suggestions of how to improve this workflow to avoid starting a new R instance.
You need to try to unload the package as well as detach it. ?detach has:
If a package has a namespace, detaching it does not by default
unload the namespace (and may not even with ‘unload=TRUE’), and
detaching will not in general unload any dynamically loaded
compiled code (DLLs). Further, registered S3 methods from the
namespace will not be removed. If you use ‘library’ on a package
whose namespace is loaded, it attaches the exports of the already
loaded namespace. So detaching and re-attaching a package may not
refresh some or all components of the package, and is inadvisable.
Note the last sentence in particular.
Try:
detach(package:mypkg, unload = TRUE)
Note that the "If a package has a namespace" now means all packages as this was changed in R 2.14.0 (IIRC the version number)
If the code you are changing is R code, consider using assignInNamespace() to assign an object/function in your global workspace (i.e. the newer version of function in mypkg) to the namespace of mypkg. For example we have function foo() in mypkg and locally we have newfoo() which is the newer version of foo():
assignInNamespace("foo", newfoo, "mypkg")
If the changes relate to C code, or the above don't work, then perhaps you should follow the advice of R Core and spawn a new R instance instead of trying to detach your package.
See also the devtools package of Hadley Wickham and Emacs+ESS might make the development process easier (spawning new R instances etc) if you speak Emacs.

Resources