-*-indented-text-*- [ Due to a general lack of time, this document is way too terse, and should be better organized, so be prepared to suffer a little. Improvements are welcome. Also, there will be some changes in the nearish future to allow add-on packages to avoid (if they choose) rebuilding unnecessarily. ] First, some terminology: when I say below I mean one of the following: emacs xemacs20 xemacs21 emacs19 emacs20 emacs21 but when I say , I mean one the same list as above, minus the generic "emacs" value. i.e.: xemacs20 xemacs21 emacs19 emacs20 emacs21 1) emacsen-common Each flavor of emacs must depend on emacsen-common. This package contains all of the Debian specific emacs flavor independent files like debian-rundir, and all the infrastructure implementing our mechanism for dealing with all the various emacsen. 2) Flavor indication [ NOTE: I am at least temporarily rescinding my recent changes (the ones detailed below). Though aesthetically appealing, they have caused too much trouble. For now (at least for Debian's current frozen release), please revert to the previous behavior of setting debian-emacs-flavor early in your particular emacsen's startup process and regardless of the setting of -q or --no-site-file. I believe that this reversion also means that emacsen maintainers can remove the emacsen-common version dependency... Thanks, and sorry for the short notice. (rlb). ] Each emacs binary must indicate it's "flavor" which must be the same as the name of the debian package. This is now handed with an argument to the debian-startup function discussed later. For example, the emacs21 package does this in startup.el like this: (debian-startup 'emacs21) This is a change from previous versions of emacsen-common. Once a flavor has been modified to follow this new approach, it should add a depends line to make sure the right version of emacsen common is installed: "Depends: emacsen-common (>= 1.4.10)". This change provides a better abstraction, and it minimizes the amount of code we have to insinuate into startup.el. 3) Emacs startup strategy We have the following startup files/directories: emacsen-common: /etc/emacs/site-start.{el,d} xemacs20: /etc/xemacs20/site-start.d xemacs21: /etc/xemacs21/site-start.d emacs19: /etc/emacs19/site-start.d emacs20: /etc/emacs20/site-start.d emacs21: /etc/emacs21/site-start.d /etc/emacs/site-start.el is a conffile, and is owned by emacsen-common. This file should not be modified by *any* add-on packages, or by any emacsen package maintainer. It is solely for the use of the local admin. It should be empty unless the local admin modifies it. The load-path for a given emacs flavor must include /etc/ and /etc/emacs in that order (see section 9 below), and on startup each emacsen must call (debian-startup) and then load "site-start". This means that /etc/emacs/site-start.el will be loaded if it exists, unless there's an /etc//site-start.el{,c} or /etc/emacs/site-start.elc which will take precedence. These site-start.el files are also the sole domain of the local system admin, and should be empty unless modified by the local admin. Given that the site-startup.el files are "off-limits" to the emacsen maintainers, the next question is, "From where can we run debian-startup?" The safest possibility, and the one I had originally intended was to modify lisp/startup.el to do the right thing, and I had also intended that --no-site-file would disable all of the debian startup bits, including calling debian startup. So I did this in emacs21's startup.el: ;; Debian version of site-start. (if site-run-file (progn ;; Load all the debian package snippets. ;; It's in here because we want -q to kill it too. (if (load "debian-startup" t t nil) (debian-startup 'emacs21)) ;; Now the normal site file... (load site-run-file t t nil))) This makes sure that debian's bits are setup as early as possible, and requires only minor modifications to the emacs source. An alternate possibility might be to use lisp/site-init.el, but I'm not sure that would work right. Feel free to contact me if you know better. debian-startup, among other things, sets debian-emacs-flavor and then calls debian-run-directories. debian-run-directories takes the union of all the file base names (i.e. without any .el or .elc extension, and without the directory component: i.e. /etc/xemacs/site-start.d/50foo.elc => foo). Then debian-startup temporarily augments the emacs load path to include /etc//site-start.d and /etc/emacs/site-start.d in that order, and then calls (load base-name) in alphabetical order. This result is that .elc files will take precedence over .el files in a given directory, and files in the site-start.d directory will take precedence over those in the emacs common directory. 4) Code locations In addition to the /etc//site-start* directories, we have the following directories (their use will be described shortly): emacsen-common: /usr/share/emacs/site-lisp/ xemacs20: /usr/share/xemacs20/site-lisp/ xemacs21: /usr/share/xemacs21/site-lisp/ emacs19: /usr/share/emacs19/site-lisp/ emacs20: /usr/share/emacs20/site-lisp/ emacs21: /usr/share/emacs21/site-lisp/ These are treated as part of the normal emacsen load path with the dir taking precedence over the emacs (common) dir. /usr/share//site-lisp should be used instead of the normal site-lisp directory for that flavor of emacs, and the package for a given flavor of emacs should not have the normal site-lisp directory. For example, instead of the emacs21 package having /usr/share/emacs/21.1/site-lisp, it should only have /usr/share/emacs21/site-lisp. This is important because it allows us to avoid having dangling directories for old versions across upgrades. We could have chosen to keep a compatibility symlink, but that seemed likely to mask bugs in the debianized packages. 5) Packages with only marginal emacs relevance Generally, if a normal package just contains some emacs helper files, and does not need to perform any byte-compilation or other emacs dependent activities upon installation (for performance or other reasons), then it is not necessary to specify a dependency on emacsen or any flavor of emacs, and the package may just include files located in the standard emacs add-on directories. 6) Emacs add-on package support (there are examples later which make this much clearer) A) Each package may place a file named the same as the package into /usr/lib/emacsen-common/packages/install/ /usr/lib/emacsen-common/packages/remove/ and the package must call /usr/lib/emacsen-common/emacs-package-install foo in the postinst and /usr/lib/emacsen-common/emacs-package-remove foo in the prerm. For now, "emacs-package-install foo" will conceptually just turn into a call for the common package emacs, and for each installed flavor to /usr/lib/emacsen-common/packages/install/foo The arguments to these scripts will be the flavor being installed (or just the common name "emacs") followed by a list of other flavors already installed, potentially including the current one. So if emacs21 and xemacs21 were installed, installing foo would result in calls to: /usr/lib/emacsen-common/packages/install/foo emacs emacs21 xemacs21 /usr/lib/emacsen-common/packages/install/foo emacs21 emacs21 xemacs21 /usr/lib/emacsen-common/packages/install/foo xemacs21 emacs21 xemacs21 emacs-package remove does the symmetric thing. B) Each emacsen main package must have a call to "/usr/lib/emacsen-common/emacs-install in its postinst and a call to "/usr/lib/emacsen-common/emacs-remove in it's prerm. The emacs-install script (for now) just executes /usr/lib/emacsen-common/packages/install/ for each installed , but might do more later. Similarly, emacs-remove would just be equivalent to /usr/lib/emacsen-common/packages/remove/ for now. Don't forget that the argument list to the add-on package install scripts will indicate both the flavor being installed, and the flavors already installed. In this case, since we're actually installing a flavor, the first argument won't appear in the subsequent arguments. C) Each add-on package has the right to place files into the following directories: /etc//site-start.d /usr/share//site-lisp/ D) Each add-on package must declare relevant dependencies on other packages (including other add-on packages). Note that add-on packages should not depend on emacsen-common directly, but rather on either the virtual package "emacsen" (see below), or some appropriate combination of flavors (i.e. Depends: emacs21 | emacs10). In addition, any tools needed by the install/remove scripts must be listed as package dependencies. For example, many add-on packages will probably use make in the install script, so they need to add "Depends: make" to their control file. emacsen-common will make sure that the install/remove scripts are ordered to respect inter-add-on package dependencies. 7) Mandatory binary symlink Each emacsen main package must have a symlink /usr/bin/ to /usr/bin/ so that when add-on package install/remove scripts are called, they can just use /usr/bin/$ARGV[0] to get the right binary for byte-compilation. 8) Virtual package Each emacsen main package will "Provides: emacsen". It would be nice to use "emacs", but for historical reasons, and given the nature of the packaging system, we can't. Packages that just need to make sure some flavor of emacs is installed should just "Depends: emacsen". If they depend on specific flavors of emacs, then they should list those dependencies explicitly instead. 9) Emacs lisp load path. At a minimum, each emacs must have the following directories in the given order in their load path: /etc/ /etc/emacs /usr/local/share/emacs//site-lisp /usr/local/share/emacs/site-lisp /usr/share/emacs//site-lisp /usr/share/emacs/site-lisp where is the normal emacs upstream version number for the relevant flavor like 20.2 or 19.34. Emacs add-on packages may not modify load-path directly. They must use (debian-pkg-add-load-path-item ). This function will make sure that their additions end up in the right place -- before the emacs system directories, but after the /usr/local/ directories. Also, add-on packages will need to either check (fboundp 'debian-pkg-add-load-path-item) before calling this function, or add a dependency on emacsen-common (>= 1.4.14). 10) Usage of autoload instead of load in the site-start.d files. It's been suggested, and is probably a good idea that maintainers switch to using autoload rather than load when possible in their site-start.d files. For example, instead of (load "some-package), you should use autoloads for all the top level, user visible functions. Currently the calc package has a good example of this. That's it. I think this gives the add-on package maintainers the flexibility they need to be able to DTRT, and I think the common case won't be all that difficult. Examples (I've been told that there may be some bugs in these examples, but I haven't had time to check through them yet. So don't take them as gospel at the moment. I suggest that you loook at existing packages for examples of working code. I will probably be revamping these soon, but I don't want to do it now since there are probably about to be some changes that will invalidate some of this): 1) Xemacs21 and the add-on packages tm and auctex are already installed, and now someone installs emacs21. In it's postinst, emacs21 would make this call: /usr/lib/emacsen-common/emacs-install emacs21 which would result in calls to /usr/lib/emacsen-common/packages/install/auctex emacs xemacs21 /usr/lib/emacsen-common/packages/install/auctex emacs21 xemacs21 /usr/lib/emacsen-common/packages/emacs21/install/tm emacs xemacs21 /usr/lib/emacsen-common/packages/emacs/install/tm emacs21 xemacs21 2) Now, given (1), assume that someone removes xemacs21. In it's postinst, xemacs21 would make this call: /usr/lib/emacsen-common/emacs-remove xemacs21 which would result in calls to /usr/lib/emacsen-common/packages/remove/auctex emacs emacs21 xemacs21 /usr/lib/emacsen-common/packages/remove/auctex xemacs21 emacs21 xemacs21 /usr/lib/emacsen-common/packages/remove/tm emacs emacs21 xemacs21 /usr/lib/emacsen-common/packages/remove/tm xemacs21 emacs21 xemacs21 3) Now assume emacs21 and xemacs21 are installed, and that someone removes tm. The call to emacsen-package-remove in tm's prerm will result in the following calls: /usr/lib/emacsen-common/packages/remove/tm emacs emacs21 xemacs21 /usr/lib/emacsen-common/packages/remove/tm emacs21 emacs21 xemacs21 /usr/lib/emacsen-common/packages/remove/tm xemacs21 emacs21 xemacs21 In the remove/tm file, tm is responsible for cleaning up any files it put into it's allowed locations: /etc//site-start.d/ /usr/share//site-lisp/tm 4) Finally, here are sample install and remove scripts for a hypothetical package "foo" that only needs to byte compile a list of files for each flavor: #!/bin/sh # /usr/lib/emacsen-common/packages/install/foo # [ This particular script hasn't been tested, so be careful. ] set -e FLAVOR=$1 echo install/foo: Handling install of emacsen flavor ${FLAVOR} byte_compile_options="-batch -f batch-byte-compile" el_files="some-file.el some-other-file.el etc.el" el_dir=/usr/share/emacs/site-lisp/foo/ elc_dir=/usr/share/${FLAVOR}/site-lisp/foo/ if [ ${FLAVOR} != emacs ] then echo install/foo: byte-compiling for ${FLAVOR} [ -d ${elc_dir} ] || mkdir ${elc_dir} # Copy the temp .el files (cd ${el_dir} && cp ${el_files} ${elc_dir}) # Byte compile them (cd ${elc_dir} \ && ${FLAVOR} ${byte_compile_options} ${el_files} 2> /dev/null) # remove the redundant .el files # presumes that any .el files in the dir are trash. rm ${elc_dir}/*.el fi exit 0; #!/bin/sh # /usr/lib/emacsen-common/packages/remove/foo # [ This particular script hasn't been tested either, so be careful. ] set -e FLAVOR=$1 elc_dir=/usr/share/${FLAVOR}/site-lisp/foo echo remove/foo: Handling removal of emacsen flavor ${FLAVOR} if [ ${FLAVOR} != emacs ] then echo emacsen-common: purging byte-compiled files for ${FLAVOR} rm -f ${elc_dir}/*.elc [ -d ${elc_dir} -a `ls -la ${elc_dir}|wc -l` -gt 3 ] && rmdir ${elc_dir} fi exit 0;