CommonLispで実行ファイルを作る

ちょっとしたcommand line toolを作りたかったので調べてみた。


以下の記事を参考にした。

sbclのversionは 2.0.9 を使っている。

今回は実際に自分で手を動かしてみた結果をまとめている。

sbclで通常のlisp fileを実行ファイルにする

以下のような test.lisp ファイルを用意する。

(defun hello ()
  (print "hello world"))

sb-ext:save-lisp-and-die を使い実行ファイルを生成する。

~ (*´ω`*) < sbcl --load "test.lisp" \
                  --eval "(sb-ext:save-lisp-and-die #P\"foo.sh\" :toplevel #'hello :executable t)"

This is SBCL 2.0.9, an implementation of ANSI Common Lisp.
More information about SBCL is available at <http://www.sbcl.org/>.

SBCL is free software, provided as is, with absolutely no warranty.
It is mostly in the public domain; some portions are provided under
BSD-style licenses.  See the CREDITS and COPYING files in the
distribution for more information.
[undoing binding stack and other enclosing state... done]
[performing final GC... done]
[defragmenting immobile space... (fin,inst,fdefn,code,sym)=342+690+14902+16647+24900... done]
[saving current Lisp image into foo.sh:
writing 0 bytes from the read-only space at 0x50000000
writing 736 bytes from the static space at 0x50100000
writing 22446080 bytes from the dynamic space at 0x1000000000
writing 1806336 bytes from the immobile space at 0x50200000
writing 10543104 bytes from the immobile space at 0x52000000
done]
~ (*´ω`*) < ./foo.sh
"hello world"

sbclで通常のasd fileを元に実行ファイルにする

fukamachi/cl-projectcl-executable-sandbox というprojectを適当に立ち上げた。

cl-executable-sandbox.asd:

(defsystem "cl-executable-sandbox"
  :version "0.1.0"
  :author "takeokunn"
  :license "GPLv3"
  :build-operation "program-op"
  :build-pathname "foo"
  :entry-point "cl-executable-sandbox:hello"
  :components ((:module "src"
                :components
                ((:file "main"))))
  :description "")

src/main.lisp:

(defpackage cl-executable-sandbox
  (:use :cl)
  (:export :hello))
(in-package :cl-executable-sandbox)

(defun hello ()
  (print "hellow world"))

:build-operation:build-pathname:entry-point をasdに設定して asdf:makeを 叩くと実行ファイルが吐き出される。

~/.g/g/t/cl-executable-sandbox (*´ω`*) < ros run
* (ql:quickload :cl-executable-sandbox)
(asdf:make :cl-executable-sandbox)
(quit)
To load "cl-executable-sandbox":
  Load 1 ASDF system:
    cl-executable-sandbox
; Loading "cl-executable-sandbox"
[package cl-executable-sandbox]
(:CL-EXECUTABLE-SANDBOX)
* (quit)

~/.g/g/t/cl-executable-sandbox (*´ω`*) < ll
total 81264
-rw-r--r--  1 obara_t  staff    24B Oct 14 22:24 README.md
-rw-r--r--  1 obara_t  staff   726B Oct 15 00:35 cl-executable-sandbox.asd
-rwxr-xr-x  1 obara_t  staff    40M Oct 15 00:35 foo*
drwxr-xr-x  3 obara_t  staff    96B Oct 14 22:31 src/
drwxr-xr-x  3 obara_t  staff    96B Oct 14 22:31 tests/

~/.g/g/t/cl-executable-sandbox (*´ω`*) < ./foo
"hellow world"

roswellの場合

ros init <filename> でros fileを生成してmainに実行内容を書くだけ。簡単。

cl-executable-sandbox.asd:

(defsystem "cl-executable-sandbox"
  :version "0.1.0"
  :author "takeokunn"
  :license "GPLv3"
  :components ((:module "src"
                :components
                ((:file "main"))))
  :description "")

src/main.lisp:

(defpackage cl-executable-sandbox
  (:use :cl)
  (:export :hello))
(in-package :cl-executable-sandbox)

(defun hello ()
  (print "hellow world"))

foo.ros:

#!/bin/sh
#|-*- mode:lisp -*-|#
#|
exec ros -Q -- $0 "$@"
|#
(progn ;;init forms
  (ros:ensure-asdf)
  #+quicklisp(ql:quickload '(:cl-executable-sandbox) :silent t))

(defpackage :ros.script.foo.3811679307
  (:use :cl))
(in-package :ros.script.foo.3811679307)

(defun main (&rest argv)
  (declare (ignorable argv))
  (cl-executable-sandbox:hello))
;;; vim: set ft=lisp lisp:

commandはこんな感じで 叩くと良い。

~/.g/g/t/cl-executable-sandbox (*´ω`*) < ros init foo
Successfully generated: foo.ros

~/.g/g/t/cl-executable-sandbox (*´ω`*) < ros build foo.ros
WARNING: :SB-EVAL is no longer present in *FEATURES*
compressed 0 bytes into 8 at level -1
compressed 32768 bytes into 276 at level -1
compressed 27295744 bytes into 6450820 at level -1
compressed 2031616 bytes into 567980 at level -1
compressed 11960320 bytes into 3834828 at level -1

~/.g/g/t/cl-executable-sandbox (*´ω`*) < ./foo
"hellow world"

やっぱroswell便利すぎるのでは?

A Road to Common Lispではroswellがイマイチって書かれていたけど便利だなぁまじで良い。

command line argumentの挙動については次回書くはず。