Search code examples
bashcommon-lispdetection

Detecting an installed Common Lisp implementation programmatically


I'm writing a Common Lisp application. I'd like to have a Bash script which will serve as the entry point to the application. Currently, I've written the script so that the user must pass in their name of the Common Lisp implementation to run it, so I would write ./script.sh clisp for GNU CLISP but someone with SBCL would have to write ./script.sh sbcl. This is necessary since, unlike languages like Python and Ruby, Common Lisp implementations do not have any standard name or standardized way of invoking them.

Is there any trick to detecting which Common Lisp implementation is installed, perhaps an environment variable or something? Basically, I'm looking for something better than forcing the user to pass in the name of the implementation.


Solution

  • TL;DR: I don't think there's a trick, but you need not require the clisp interpreter on every invocation.


    This is a relatively common pattern: you have a bash script that depends upon a certain executable being available, and it may well be available, but in different locations, possibly with the user having their own compiled version and/or the system having several alternatives.

    The approach I've seen boils down to this algorithm:

    1. If there is an environment variable that specifies the full path to an executable, prefer that
    2. Otherwise, if there is a configuration file in the user's home directory that specifies the location, and possibly other parameters, prefer that
    3. Otherwise, if there is a configuration in /etc that specifies the location, and possibly other parameters, prefer that
    4. Otherwise, ask the system package manager to list the packages matching your application's typical installation names

    The first three are easy enough to implement using the bash test functions and, I'm guessing, if you got this far you know how to do that. (If not, ask and I'll post examples.)

    It is the fourth point that becomes interesting. There are two variables to deal with. First, determining the package manager in the installed environment. There are no shortage of these, and I've seen both table approaches (mapping OS to a package manager) and inquiry approaches (looking for executable that match expected names like rpm, yum, emerge, etc). Second, determining the package name appropriate for your package manager. This too can be tricky. On the one hand, you're probably safe iterating through the list of known executable and grepping the list. On the other hand, your package manager may provide "virtual" or "alternative" packages that generically provide a service, regardless of the specific implementation. For example, you could grep the portage tree for dev-lisp and be reasonably sure to find one installed package.

    The easiest case is when your script is meant to be run in a small number of well-known environments: implement the one or more of the first three points to the let the user override the script's auto-selection, then your script's auto-selection just iterates over the known alternatives in your known environment until it finds one it prefers.

    The hard case is when you have to support multiple environments. You end up writing an abstraction layer that knows about the different possible package managers and how to interrogate those package systems for various packages, either at a generic level or for specific packages. Having done this for a script set that deployed on AIX, HP-UX, Solaris, a couple of Linux distros, and cygwin Windows I can say: not fun.


    As I read your question, you have a script that will be distributed to different users' machines whose environments you don't control. The only requirement of these target machines is they have bash and at least one Common LISP interpreter installed. From this, I inferred you couldn't install any loaders. However, if you can install, require, or detect the presence of any of the launchers mentioned in other answers, that will certainly save a ton of work.