Writing Common Lisp code that executes from the command line, but not inside the interpreter

后端 未结 3 1820
甜味超标
甜味超标 2020-12-30 09:17

When writing Common Lisp code, I use SLIME. In particular, I compile the buffer containing definitions of functions by using C-C C-k, and then switch to the REPL to run thos

相关标签:
3条回答
  • 2020-12-30 09:26

    Fare Rideau wrote a nifty unix utility CL-Launch, which enables executing lisp software from the command line. It has integrated Quicklisp support and works on most of the Common Lisp implementations.

    Example script may look like this:

    #!/usr/bin/cl -sp "hunchentoot" -Q -E main
    
    (defun main (argv)
      (format t "~A: ~{~A ~}~%" (truename ".") argv)
      (hunchentoot:start
       (make-instance 'hunchentoot:acceptor
                      :document-root (truename ".")
                      :port 8080))
      (do ((x #\s (read-char)))
          ((char-equal x #\q) nil)))
    

    After adding +x permissions to script and invoking it, it will start http server in the current directory. "-sp" flag indicates package you want to load, so it's fairly clean way of abstracting shell script from the package.

    For more details refer: http://cliki.net/CL-Launch

    0 讨论(0)
  • 2020-12-30 09:28

    You can use the following trick:

    1. Define a dispatch function for shebang:

      (set-dispatch-macro-character #\# #\!
          (lambda (stream c n)
            (declare (ignore c n))
            (read-line stream)
            `(eval-when (:compile-toplevel :load-toplevel :execute)
               (pushnew :noscript *features*))))
      
    2. In your script file use #-:noscript:

      #!/usr/local/bin/sbcl --script
      
      (defun test (a) (print a))
      
      (test 1)
      #-:noscript (test 2)
      #+:noscript (test 3)
      

      Executing ./test.lisp will print 1 and 2, while C-c C-k will output 1 and 3.

    EDITS

    This trick should work, because the shebang line is removed altogether by sbcl --script, but not removed, when the file is loaded through SLIME or other mechanisms.

    The drawback of this approach is that we condition on absence of :noscript in features, and not presence of :script. To amend it, pushing of the appropriate feature should be done in sbcl --script processing itself.

    0 讨论(0)
  • 2020-12-30 09:42

    I had the same question and I have just stumbled upon this discussion. At least with sbcl it seems I can use (sb-ext:posix-getenv "_"). When run in slime it returns /usr/bin/emacs (or whatever the path to emacs is) and otherwise the command I use to invoke the script. So it is always possible to differentiate between slime and script invocation until you're an emacs contributor :)

    If you want to get the full pathname of the script you are invoking, you can use (truename (sb-ext:posix-getenv "_")). However, when run from slime it will return the effective emacs pathname, e.g. /usr/bin/emacs-24.5, so this might be less convenient.

    0 讨论(0)
提交回复
热议问题