Detecting an installed Common Lisp implementation programmatically
Asked Answered
G

3

5

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.

Garibay answered 9/6, 2016 at 23:8 Comment(1)
Python/ruby is "standard" because there is only one main implementation. Consider Cython and co. to see that the same problem exists outside CLReichel
A
3

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.

Aeneid answered 9/6, 2016 at 23:34 Comment(2)
This is pretty much exactly what I was looking for, and also what I was afraid of. I'll start toying around with package managers then.Garibay
Good luck! These kinds of scripts end up being very "testy" (as in, performing a lot of tests). I found that using a bash library with many small functions to do little jobs makes it much easier to keep it manageable. I personally use bashworks.Aeneid
P
4

You could use Roswell, which provides ways to set the implementation on a user or invocation level. You still need wrapper scripts, but roswell standardizes them.

Princedom answered 10/6, 2016 at 0:56 Comment(0)
R
4

Install the cl-launch Unix utility program which implements the abstraction described in @bishop's answer. The utility will detect most implementations of Common Lisp and can be used to execute a script or dump an executable which calls the content of a script (loads faster).

Reichel answered 10/6, 2016 at 15:57 Comment(0)
A
3

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.

Aeneid answered 9/6, 2016 at 23:34 Comment(2)
This is pretty much exactly what I was looking for, and also what I was afraid of. I'll start toying around with package managers then.Garibay
Good luck! These kinds of scripts end up being very "testy" (as in, performing a lot of tests). I found that using a bash library with many small functions to do little jobs makes it much easier to keep it manageable. I personally use bashworks.Aeneid

© 2022 - 2024 — McMap. All rights reserved.