Skip to content

How to unload a dll loaded via library.dynam()?

4 messages · Brian Ripley, Berwin A Turlach

#
[Moved to R-devel as suggested.]

library.dynam.unload() does work if the OS is cooperative.  And if you 
have your package set up correctly and unload the namespace (and not 
just detach the package if there is a namespace) then the shared 
object/DLL will be unloaded. There are examples in several base R 
packages (grDevices, grid, methods, splines, stats, tools).

However, there are several instances on Windows (tcltk is one) where 
reloading the package DLL does not work, and this seems to be because 
dependent DLLs are already loaded and do not run their initializations 
correctly.  I've not seen problems on Linux.  On Solaris reloading a 
different shared object of the same name into a process used not to 
work (you got the first version under that name): I've not checked 
recently.
On Fri, 20 Feb 2009, G?bor Cs?rdi wrote:

            
Why not use the one already provided?

  
    
#
G'day all,

On Fri, 20 Feb 2009 04:01:07 +0000 (GMT)
Prof Brian Ripley <ripley at stats.ox.ac.uk> wrote:

            
I guess I have a similar code-install-test development cycle as Alex;
and I seem to work on a cooperative OS (Kubuntu 8.04).

My set up is that I install packages on which I work into a separate
library.  To test changes to such packages, I start R in a directory
which contains a .Rprofile file which, via .libPaths(), adds the above
library to the library path.  In this R session I then test the changes.

I also used to quit and restart R whenever I re-installed a package with
namespace to test the changes made.  Somehow I got the impression that
this was the way to proceed when namespaces were introduced; and I did
not realise until recently that better ways (unloading the namespace)
exist.

However, I noticed the following behaviour under R 2.8.1 and "R version
2.9.0 Under development (unstable) (2009-02-19 r47958)" which I found
surprising:

1) In the running R session, issue the command "unloadNamespace(XXX)"
2) Do changes to the code of the package; e.g. add a "print("hello
   world")" statement to one of the R functions.
3) Install the new package
4) In the running R session, issue the command "library(XXX)" and call
   the R function that was changed.  
   
Result: "Hello world" is not printed, somehow the old R function is
still used.  If I issue the commands "unloadNamespace(XXX)" and
"library(XXX)" once more then a call to the R function that was changed
will print "Hello world"; i.e. the new code is used.

If the above sequence is changed to 2), 3) and then 1), then 4) behaves
"as expected" and the new R code is used immediately.

As far as I can tell, if via the .onUnload() hook the shared object is
unloaded via library.dynam.unload(), changes in the C code take effect
no matter whether I perform the above steps in the sequence 1-2-3-4 or
2-3-1-4.

My preference is to use the sequence 1-2-3-4 since it seems to be the
"more logical and cleaner" sequence; and I have vague memories that I
managed to crash R in the past after using 2-3 and then trying to quit
R.

I am wondering why does it make a difference with respect to R code in
which order these steps are done but not with respect to compiled
code.  Well, I guess I understand why the order does not matter for
compiled code, but I do not understand why the order matters for R
code.  I could not find anything in the documentation that would
explain this behaviour, or indicate that this is the intended
behaviour.  

Enlightening comments and/or pointers to where this behaviour is
documented would be welcome.

Cheers,

	Berwin

=========================== Full address =============================
Berwin A Turlach                            Tel.: +65 6516 4416 (secr)
Dept of Statistics and Applied Probability        +65 6516 6650 (self)
Faculty of Science                          FAX : +65 6872 3919       
National University of Singapore     
6 Science Drive 2, Blk S16, Level 7          e-mail: statba at nus.edu.sg
Singapore 117546                    http://www.stat.nus.edu.sg/~statba
#
This was rather a large shift of subject, so I've pruned the 
recipients list.

Is lazy loading involved?  If so I have an idea that may or may not be 
relevant.  We do cache in memory the lazy-loading database for speed 
on slow (network-mounted or USB drive) file systems.  Now the cache is 
flushed at least if you do detach(foo, unload = TRUE) or but I can 
envisage a set of circumstances in which it might not be.

So perhaps try detach(foo, unload = TRUE) or not using lazy-loading 
when developing the package?
On Fri, 20 Feb 2009, Berwin A Turlach wrote:

            

  
    
#
G'day Brian,

On Fri, 20 Feb 2009 11:37:18 +0000 (GMT)
Prof Brian Ripley <ripley at stats.ox.ac.uk> wrote:

            
Well, yes, from the clean unloading of compiled code to the clean
unloading of R code.  :-)  
Though, I also confirmed that the former is possible on a cooperative
OS when library.dynam.unload() is correctly used via an .onUnload()
hook.
Yes, the DESCRIPTION file has the default "LazyLoad: yes" entry. 

If I set "LazyLoad: no", then both sequences use the new version of the
R code immediately.
As far as I can tell, "detach(foo, unload=TRUE)" and
"unloadNamespace(foo)" behave identical on my machines (while the
DESCRIPTION file has "LazyLoad: yes"); the modified R code is only used
if either of this command is given (followed by "library(foo)") after
the new version of the package was installed.
Unfortunately, the former does not work and although the latter works I
am hesitant to use it since:

a) as I understand it, most packages that use S4 methods need
lazy-loading (though the particular package with which I noticed the
behaviour does not have S4 methods); and

b) it seems that these days the DESCRIPTION file is the only way of
switching lazy loading on and off and that there is no way of
overriding that value.  Knowing myself, I would forget changing the
DESCRIPTION file back to "LazyLoad: yes" before building the .tar.gz
file for distribution (once the package is ready).  As it is, I have
already to remember to take "-Wall -pedantic" out of the Makevars file
in the src/ directory; but I am reminded of that by R CMD check.

Well, thinking a bit more about b), I could probably complicate my
Makefile a bit more such that a "make install" first modifies the
DESCRIPTION file to "LazyLoad: no" before installing the package to the
local library and that "make build" first modifies the DESCRIPTION in
the opposite way.  But this would still leave concern a).

Cheers,

	Berwin