Update clones
This commit is contained in:
parent
77fe2d5efb
commit
62f229e4d1
44 changed files with 2046 additions and 1804 deletions
|
@ -8,6 +8,8 @@
|
|||
<meta name="description" content="A collection of examples of using Common Lisp">
|
||||
<meta name="viewport" content=
|
||||
"width=device-width, initial-scale=1">
|
||||
<link rel="icon" href=
|
||||
"assets/cl-logo-blue.png"/>
|
||||
<link rel="stylesheet" href=
|
||||
"assets/style.css">
|
||||
<script type="text/javascript" src=
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
<meta name="description" content="A collection of examples of using Common Lisp">
|
||||
<meta name="viewport" content=
|
||||
"width=device-width, initial-scale=1">
|
||||
<link rel="icon" href=
|
||||
"assets/cl-logo-blue.png"/>
|
||||
<link rel="stylesheet" href=
|
||||
"assets/style.css">
|
||||
<script type="text/javascript" src=
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
<meta name="description" content="A collection of examples of using Common Lisp">
|
||||
<meta name="viewport" content=
|
||||
"width=device-width, initial-scale=1">
|
||||
<link rel="icon" href=
|
||||
"assets/cl-logo-blue.png"/>
|
||||
<link rel="stylesheet" href=
|
||||
"assets/style.css">
|
||||
<script type="text/javascript" src=
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
<meta name="description" content="A collection of examples of using Common Lisp">
|
||||
<meta name="viewport" content=
|
||||
"width=device-width, initial-scale=1">
|
||||
<link rel="icon" href=
|
||||
"assets/cl-logo-blue.png"/>
|
||||
<link rel="stylesheet" href=
|
||||
"assets/style.css">
|
||||
<script type="text/javascript" src=
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
<meta name="description" content="A collection of examples of using Common Lisp">
|
||||
<meta name="viewport" content=
|
||||
"width=device-width, initial-scale=1">
|
||||
<link rel="icon" href=
|
||||
"assets/cl-logo-blue.png"/>
|
||||
<link rel="stylesheet" href=
|
||||
"assets/style.css">
|
||||
<script type="text/javascript" src=
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
<meta name="description" content="A collection of examples of using Common Lisp">
|
||||
<meta name="viewport" content=
|
||||
"width=device-width, initial-scale=1">
|
||||
<link rel="icon" href=
|
||||
"assets/cl-logo-blue.png"/>
|
||||
<link rel="stylesheet" href=
|
||||
"assets/style.css">
|
||||
<script type="text/javascript" src=
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
<meta name="description" content="A collection of examples of using Common Lisp">
|
||||
<meta name="viewport" content=
|
||||
"width=device-width, initial-scale=1">
|
||||
<link rel="icon" href=
|
||||
"../assets/cl-logo-blue.png"/>
|
||||
<link rel="stylesheet" href=
|
||||
"../assets/style.css">
|
||||
<script type="text/javascript" src=
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
<meta name="description" content="A collection of examples of using Common Lisp">
|
||||
<meta name="viewport" content=
|
||||
"width=device-width, initial-scale=1">
|
||||
<link rel="icon" href=
|
||||
"assets/cl-logo-blue.png"/>
|
||||
<link rel="stylesheet" href=
|
||||
"assets/style.css">
|
||||
<script type="text/javascript" src=
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
<meta name="description" content="A collection of examples of using Common Lisp">
|
||||
<meta name="viewport" content=
|
||||
"width=device-width, initial-scale=1">
|
||||
<link rel="icon" href=
|
||||
"assets/cl-logo-blue.png"/>
|
||||
<link rel="stylesheet" href=
|
||||
"assets/style.css">
|
||||
<script type="text/javascript" src=
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
<meta name="description" content="A collection of examples of using Common Lisp">
|
||||
<meta name="viewport" content=
|
||||
"width=device-width, initial-scale=1">
|
||||
<link rel="icon" href=
|
||||
"assets/cl-logo-blue.png"/>
|
||||
<link rel="stylesheet" href=
|
||||
"assets/style.css">
|
||||
<script type="text/javascript" src=
|
||||
|
@ -68,7 +70,7 @@ in other languages, and can do more.</p>
|
|||
<blockquote>
|
||||
<p>Just like in languages that support exception handling (Java, C++,
|
||||
Python, etc.), a condition represents, for the most part, an
|
||||
“exceptional” situation. However, even more so that those languages,
|
||||
“exceptional” situation. However, even more so than those languages,
|
||||
<em>a condition in Common Lisp can represent a general situation where
|
||||
some branching in program logic needs to take place</em>, not
|
||||
necessarily due to some error condition. Due to the highly
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
<meta name="description" content="A collection of examples of using Common Lisp">
|
||||
<meta name="viewport" content=
|
||||
"width=device-width, initial-scale=1">
|
||||
<link rel="icon" href=
|
||||
"assets/cl-logo-blue.png"/>
|
||||
<link rel="stylesheet" href=
|
||||
"assets/style.css">
|
||||
<script type="text/javascript" src=
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
<meta name="description" content="A collection of examples of using Common Lisp">
|
||||
<meta name="viewport" content=
|
||||
"width=device-width, initial-scale=1">
|
||||
<link rel="icon" href=
|
||||
"assets/cl-logo-blue.png"/>
|
||||
<link rel="stylesheet" href=
|
||||
"assets/style.css">
|
||||
<script type="text/javascript" src=
|
||||
|
@ -82,6 +84,34 @@ In a recipe or two we also use
|
|||
<li><a href="http://gigamonkeys.com/book/files-and-file-io.html">Files and File I/O in Practical Common Lisp</a></li>
|
||||
</ul>
|
||||
|
||||
<h3 id="getting-the-components-of-a-pathname">Getting the components of a pathname</h3>
|
||||
|
||||
<h4 id="file-extension">File extension</h4>
|
||||
|
||||
<p>The file extension is called “pathname type” in Lisp parlance:</p>
|
||||
|
||||
<pre><code class="language-lisp">(pathname-type "~/foo.org") ;; => "org"
|
||||
</code></pre>
|
||||
|
||||
<h4 id="file-basename">File basename</h4>
|
||||
|
||||
<p>The basename is called the “name” -</p>
|
||||
|
||||
<pre><code class="language-lisp">(pathname-name "~/foo.org") ;; => "foo"
|
||||
(pathname-name "~/foo") ;; => "foo"
|
||||
</code></pre>
|
||||
|
||||
<p>If a directory pathname has a trailing slash, <code>pathname-name</code> may return <code>nil</code>; use <code>pathname-directory</code> instead -</p>
|
||||
|
||||
<pre><code class="language-lisp">(pathname-name "~/foo/") ;; => NIL
|
||||
(first (last (pathname-directory #P"~/foo/"))) ;; => "foo"
|
||||
</code></pre>
|
||||
|
||||
<h4 id="parent-directory">Parent directory</h4>
|
||||
|
||||
<pre><code class="language-lisp">(uiop:pathname-parent-directory-pathname #P"/foo/bar/quux/") ;; => #P"/foo/bar/"
|
||||
</code></pre>
|
||||
|
||||
<h3 id="testing-whether-a-file-exists">Testing whether a file exists</h3>
|
||||
|
||||
<p>Use the function
|
||||
|
@ -211,6 +241,16 @@ is somewhere on your filesystem and you want the path to <code>src/web/</code>.
|
|||
|
||||
<p>This will work on another user’s machine, where the system sources are located in another location.</p>
|
||||
|
||||
<h3 id="setting-the-current-working-directory">Setting the current working directory</h3>
|
||||
|
||||
<p>Use <a href="https://asdf.common-lisp.dev/uiop.html#Function-uiop_002fos_003achdir"><code>uiop:chdir</code></a> <em><code>path</code></em>:</p>
|
||||
|
||||
<pre><code class="language-lisp">(uiop:chdir "/bin/")
|
||||
0
|
||||
</code></pre>
|
||||
|
||||
<p>The trailing slash in <em>path</em> is optional.</p>
|
||||
|
||||
<h3 id="opening-a-file">Opening a file</h3>
|
||||
|
||||
<p>Common Lisp has
|
||||
|
@ -518,13 +558,6 @@ has a function called <a href="https://gitlab.common-lisp.net/alexandria/alexand
|
|||
|
||||
<p>Both <code>alexandria:write-string-into-file</code> and <code>str:to-file</code> take the same keyword arguments as <code>cl:open</code> that controls file creation: <code>:if-exists</code> and <code>if-does-not-exists</code>.</p>
|
||||
|
||||
<h3 id="getting-the-file-extension">Getting the file extension</h3>
|
||||
|
||||
<p>The file extension is a pathname type in Lisp parlance:</p>
|
||||
|
||||
<pre><code class="language-lisp">(pathname-type "~/foo.org") ;; => "org"
|
||||
</code></pre>
|
||||
|
||||
<h3 id="getting-file-attributes-size-access-time">Getting file attributes (size, access time,…)</h3>
|
||||
|
||||
<p><a href="https://www.common-lisp.net/project/osicat/">Osicat</a> (in Quicklisp)
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
<meta name="description" content="A collection of examples of using Common Lisp">
|
||||
<meta name="viewport" content=
|
||||
"width=device-width, initial-scale=1">
|
||||
<link rel="icon" href=
|
||||
"assets/cl-logo-blue.png"/>
|
||||
<link rel="stylesheet" href=
|
||||
"assets/style.css">
|
||||
<script type="text/javascript" src=
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
<meta name="description" content="A collection of examples of using Common Lisp">
|
||||
<meta name="viewport" content=
|
||||
"width=device-width, initial-scale=1">
|
||||
<link rel="icon" href=
|
||||
"assets/cl-logo-blue.png"/>
|
||||
<link rel="stylesheet" href=
|
||||
"assets/style.css">
|
||||
<script type="text/javascript" src=
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
<meta name="description" content="A collection of examples of using Common Lisp">
|
||||
<meta name="viewport" content=
|
||||
"width=device-width, initial-scale=1">
|
||||
<link rel="icon" href=
|
||||
"assets/cl-logo-blue.png"/>
|
||||
<link rel="stylesheet" href=
|
||||
"assets/style.css">
|
||||
<script type="text/javascript" src=
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
<meta name="description" content="A collection of examples of using Common Lisp">
|
||||
<meta name="viewport" content=
|
||||
"width=device-width, initial-scale=1">
|
||||
<link rel="icon" href=
|
||||
"assets/cl-logo-blue.png"/>
|
||||
<link rel="stylesheet" href=
|
||||
"assets/style.css">
|
||||
<script type="text/javascript" src=
|
||||
|
@ -85,13 +87,16 @@ a book containing recipes and other information about the preparation and cookin
|
|||
</li>
|
||||
<li><a href="functions.html">Functions</a></li>
|
||||
<li><a href="data-structures.html">Data Structures</a></li>
|
||||
<li><a href="strings.html">Strings</a></li>
|
||||
<li><a href="strings.html">Strings</a>
|
||||
<ul>
|
||||
<li><a href="regexp.html">Regular Expressions</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="numbers.html">Numbers</a></li>
|
||||
<li><a href="iteration.html">Loops, iteration, mapping</a></li>
|
||||
<li><a href="arrays.html">Multidimensional Arrays</a></li>
|
||||
<li><a href="dates_and_times.html">Dates and Times</a></li>
|
||||
<li><a href="pattern_matching.html">Pattern Matching</a></li>
|
||||
<li><a href="regexp.html">Regular Expressions</a></li>
|
||||
<li><a href="io.html">Input/Output</a></li>
|
||||
<li><a href="files.html">Files and Directories</a></li>
|
||||
<li><a href="error_handling.html">Error and condition handling</a></li>
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
<meta name="description" content="A collection of examples of using Common Lisp">
|
||||
<meta name="viewport" content=
|
||||
"width=device-width, initial-scale=1">
|
||||
<link rel="icon" href=
|
||||
"assets/cl-logo-blue.png"/>
|
||||
<link rel="stylesheet" href=
|
||||
"assets/style.css">
|
||||
<script type="text/javascript" src=
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
<meta name="description" content="A collection of examples of using Common Lisp">
|
||||
<meta name="viewport" content=
|
||||
"width=device-width, initial-scale=1">
|
||||
<link rel="icon" href=
|
||||
"assets/cl-logo-blue.png"/>
|
||||
<link rel="stylesheet" href=
|
||||
"assets/style.css">
|
||||
<script type="text/javascript" src=
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
<meta name="description" content="A collection of examples of using Common Lisp">
|
||||
<meta name="viewport" content=
|
||||
"width=device-width, initial-scale=1">
|
||||
<link rel="icon" href=
|
||||
"assets/cl-logo-blue.png"/>
|
||||
<link rel="stylesheet" href=
|
||||
"assets/style.css">
|
||||
<script type="text/javascript" src=
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
<meta name="description" content="A collection of examples of using Common Lisp">
|
||||
<meta name="viewport" content=
|
||||
"width=device-width, initial-scale=1">
|
||||
<link rel="icon" href=
|
||||
"assets/cl-logo-blue.png"/>
|
||||
<link rel="stylesheet" href=
|
||||
"assets/style.css">
|
||||
<script type="text/javascript" src=
|
||||
|
@ -560,7 +562,7 @@ of warnings and errors during development.</p>
|
|||
|
||||
<h2 id="using-lispworks-from-emacs-and-slime">Using LispWorks from Emacs and Slime</h2>
|
||||
|
||||
<p>To do that, start LispWorks normally, start a Swank server and connect to it from Emacs (Swank is the backend part of Slime).</p>
|
||||
<p>To do that, you have two possibilities. The first one is to start LispWorks normally, start a Swank server and connect to it from Emacs (Swank is the backend part of Slime).</p>
|
||||
|
||||
<p>First, let’s load the dependencies:</p>
|
||||
|
||||
|
@ -586,6 +588,27 @@ of warnings and errors during development.</p>
|
|||
(capi:contain button)
|
||||
</code></pre>
|
||||
|
||||
<p>The second possibility is to create a non-GUI LispWorks image, with
|
||||
Swank loaded, and to run this image from SLIME or SLY. For example, to
|
||||
create a so-called <code>console</code> image with multiprocessing enabled:</p>
|
||||
|
||||
<pre><code class="language-lisp">(in-package "CL-USER")
|
||||
(load-all-patches)
|
||||
(save-image "~/lw-console"
|
||||
:console t
|
||||
:multiprocessing t
|
||||
:environment nil)
|
||||
</code></pre>
|
||||
|
||||
<p>and run LispWorks like this to create the new image ~/lw-console:</p>
|
||||
|
||||
<pre><code>lispworks-7-0-0-x86-linux -build /tmp/resave.lisp
|
||||
</code></pre>
|
||||
|
||||
<p>However: <code>console</code> is implemented <strong>only for Windows and Mac</strong>.</p>
|
||||
|
||||
<p>See LispWorks’ documentation.</p>
|
||||
|
||||
<h2 id="see-also">See also</h2>
|
||||
|
||||
<ul>
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
<meta name="description" content="A collection of examples of using Common Lisp">
|
||||
<meta name="viewport" content=
|
||||
"width=device-width, initial-scale=1">
|
||||
<link rel="icon" href=
|
||||
"assets/cl-logo-blue.png"/>
|
||||
<link rel="stylesheet" href=
|
||||
"assets/style.css">
|
||||
<script type="text/javascript" src=
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
<meta name="description" content="A collection of examples of using Common Lisp">
|
||||
<meta name="viewport" content=
|
||||
"width=device-width, initial-scale=1">
|
||||
<link rel="icon" href=
|
||||
"assets/cl-logo-blue.png"/>
|
||||
<link rel="stylesheet" href=
|
||||
"assets/style.css">
|
||||
<script type="text/javascript" src=
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
<meta name="description" content="A collection of examples of using Common Lisp">
|
||||
<meta name="viewport" content=
|
||||
"width=device-width, initial-scale=1">
|
||||
<link rel="icon" href=
|
||||
"assets/cl-logo-blue.png"/>
|
||||
<link rel="stylesheet" href=
|
||||
"assets/style.css">
|
||||
<script type="text/javascript" src=
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
<meta name="description" content="A collection of examples of using Common Lisp">
|
||||
<meta name="viewport" content=
|
||||
"width=device-width, initial-scale=1">
|
||||
<link rel="icon" href=
|
||||
"assets/cl-logo-blue.png"/>
|
||||
<link rel="stylesheet" href=
|
||||
"assets/style.css">
|
||||
<script type="text/javascript" src=
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
<meta name="description" content="A collection of examples of using Common Lisp">
|
||||
<meta name="viewport" content=
|
||||
"width=device-width, initial-scale=1">
|
||||
<link rel="icon" href=
|
||||
"assets/cl-logo-blue.png"/>
|
||||
<link rel="stylesheet" href=
|
||||
"assets/style.css">
|
||||
<script type="text/javascript" src=
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
<meta name="description" content="A collection of examples of using Common Lisp">
|
||||
<meta name="viewport" content=
|
||||
"width=device-width, initial-scale=1">
|
||||
<link rel="icon" href=
|
||||
"assets/cl-logo-blue.png"/>
|
||||
<link rel="stylesheet" href=
|
||||
"assets/style.css">
|
||||
<script type="text/javascript" src=
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
<meta name="description" content="A collection of examples of using Common Lisp">
|
||||
<meta name="viewport" content=
|
||||
"width=device-width, initial-scale=1">
|
||||
<link rel="icon" href=
|
||||
"assets/cl-logo-blue.png"/>
|
||||
<link rel="stylesheet" href=
|
||||
"assets/style.css">
|
||||
<script type="text/javascript" src=
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
<meta name="description" content="A collection of examples of using Common Lisp">
|
||||
<meta name="viewport" content=
|
||||
"width=device-width, initial-scale=1">
|
||||
<link rel="icon" href=
|
||||
"assets/cl-logo-blue.png"/>
|
||||
<link rel="stylesheet" href=
|
||||
"assets/style.css">
|
||||
<script type="text/javascript" src=
|
||||
|
@ -396,7 +398,7 @@ output to be shown on the main console screen.</p>
|
|||
(bt:make-thread
|
||||
(lambda ()
|
||||
(format top-level "Hello from thread!"))
|
||||
:name "hello")))
|
||||
:name "hello"))
|
||||
nil)
|
||||
</code></pre>
|
||||
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
<meta name="description" content="A collection of examples of using Common Lisp">
|
||||
<meta name="viewport" content=
|
||||
"width=device-width, initial-scale=1">
|
||||
<link rel="icon" href=
|
||||
"assets/cl-logo-blue.png"/>
|
||||
<link rel="stylesheet" href=
|
||||
"assets/style.css">
|
||||
<script type="text/javascript" src=
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
<meta name="description" content="A collection of examples of using Common Lisp">
|
||||
<meta name="viewport" content=
|
||||
"width=device-width, initial-scale=1">
|
||||
<link rel="icon" href=
|
||||
"assets/cl-logo-blue.png"/>
|
||||
<link rel="stylesheet" href=
|
||||
"assets/style.css">
|
||||
<script type="text/javascript" src=
|
||||
|
@ -84,7 +86,7 @@ location information, and more.</p>
|
|||
<p>How to build (self-contained) executables is, by default, implementation-specific (see
|
||||
below for portable ways). With SBCL, as says
|
||||
<a href="http://www.sbcl.org/manual/index.html#Function-sb_002dext_003asave_002dlisp_002dand_002ddie">its documentation</a>,
|
||||
it is a matter of calling <code>save-lisp-and-die</code> with the <code>executable</code> argument to T:</p>
|
||||
it is a matter of calling <code>save-lisp-and-die</code> with the <code>:executable</code> argument to T:</p>
|
||||
|
||||
<pre><code class="language-lisp">(sb-ext:save-lisp-and-die #P"path/name-of-executable" :toplevel #'my-app:main-function :executable t)
|
||||
</code></pre>
|
||||
|
@ -107,21 +109,21 @@ In that case, we re-use the image with <code>sbcl --core name-of-image</code>.</
|
|||
<p>Cannot save core with multiple threads running.</p>
|
||||
</blockquote>
|
||||
|
||||
<p>So we must run the command from a simple SBCL repl.</p>
|
||||
<p>We must run the command from a simple SBCL repl, from the terminal.</p>
|
||||
|
||||
<p>I suppose your project has Quicklisp dependencies. You must then:</p>
|
||||
|
||||
<ul>
|
||||
<li>ensure Quicklisp is installed and loaded at the Lisp startup (you
|
||||
completed Quicklisp installation),</li>
|
||||
<li><code>load</code> the project’s .asd,</li>
|
||||
<li><code>asdf:load-asd</code> the project’s .asd (recommended instead of just <code>load</code>),</li>
|
||||
<li>install the dependencies,</li>
|
||||
<li>build the executable.</li>
|
||||
</ul>
|
||||
|
||||
<p>That gives:</p>
|
||||
|
||||
<pre><code class="language-lisp">(load "my-app.asd")
|
||||
<pre><code class="language-lisp">(asdf:load-asd "my-app.asd")
|
||||
(ql:quickload "my-app")
|
||||
(sb-ext:save-lisp-and-die #p"my-app-binary" :toplevel #'my-app:main :executable t)
|
||||
</code></pre>
|
||||
|
@ -141,7 +143,7 @@ version 3.1, ASDF allows to do that. It introduces the <a href="https://common-l
|
|||
that reads parameters from the .asd. Add this to your .asd declaration:</p>
|
||||
|
||||
<pre><code>:build-operation "program-op" ;; leave as is
|
||||
:build-pathname "<binary-name>"
|
||||
:build-pathname "<here your final binary name>"
|
||||
:entry-point "<my-package:main-function>"
|
||||
</code></pre>
|
||||
|
||||
|
@ -158,6 +160,82 @@ build:
|
|||
--eval '(quit)'
|
||||
</code></pre>
|
||||
|
||||
<h3 id="with-deploy---ship-foreign-libraries-dependencies">With Deploy - ship foreign libraries dependencies</h3>
|
||||
|
||||
<p>All this is good, you can create binaries that work on your machine…
|
||||
but maybe not on someone else’s or on your server. Your program
|
||||
probably relies on C shared libraries that are defined somewhere on
|
||||
your filesystem. For example, <code>libssl</code> might be located on</p>
|
||||
|
||||
<pre><code>/usr/lib/x86_64-linux-gnu/libssl.so.1.1
|
||||
</code></pre>
|
||||
|
||||
<p>but on your VPS, maybe somewhere else.</p>
|
||||
|
||||
<p><a href="https://github.com/Shinmera/deploy">Deploy</a> to the rescue.</p>
|
||||
|
||||
<p>It will create a <code>bin/</code> directory with your binary and the required
|
||||
foreign libraries. It will auto-discover the ones your program needs,
|
||||
but you can also help it (or tell it to not do so much).</p>
|
||||
|
||||
<p>Its use is very close to the above recipe with <code>asdf:make</code> and the
|
||||
<code>.asd</code> project configuration. Use this:</p>
|
||||
|
||||
<pre><code class="language-lisp">:defsystem-depends-on (:deploy) ;; (ql:quickload "deploy") before
|
||||
:build-operation "deploy-op" ;; instead of "program-op"
|
||||
:build-pathname "my-application-name" ;; doesn't change
|
||||
:entry-point "my-package:my-start-function" ;; doesn't change
|
||||
</code></pre>
|
||||
|
||||
<p>and build your binary with <code>(asdf:make :my-app)</code> like before.</p>
|
||||
|
||||
<p>Now, ship the <code>bin/</code> directory to your users.</p>
|
||||
|
||||
<p>When you run the binary, you’ll see it uses the shipped libraries:</p>
|
||||
|
||||
<pre><code class="language-lisp">$ ./my-app
|
||||
==> Performing warm boot.
|
||||
-> Runtime directory is /home/debian/projects/my-app/bin/
|
||||
-> Resource directory is /home/debian/projects/my-app/bin/
|
||||
==> Running boot hooks.
|
||||
==> Reloading foreign libraries.
|
||||
-> Loading foreign library #<LIBRARY LIBRT>.
|
||||
-> Loading foreign library #<LIBRARY LIBMAGIC>.
|
||||
==> Launching application.
|
||||
[…]
|
||||
</code></pre>
|
||||
|
||||
<p>Success!</p>
|
||||
|
||||
<p>A note regarding <code>libssl</code>. It’s easier, on Linux at least, to
|
||||
rely on your OS’ current installation, so we’ll tell Deploy to not
|
||||
bother shipping it (nor <code>libcrypto</code>):</p>
|
||||
|
||||
<pre><code class="language-lisp">#+linux (deploy:define-library cl+ssl::libssl :dont-deploy T)
|
||||
#+linux (deploy:define-library cl+ssl::libcrypto :dont-deploy T)
|
||||
</code></pre>
|
||||
|
||||
<p>The day you want to ship a foreign library that Deploy doesn’t find, you can instruct it like this:</p>
|
||||
|
||||
<pre><code class="language-lisp">(deploy:define-library cl+ssl::libcrypto
|
||||
;; ^^^ CFFI system name. Find it with a call to "apropos".
|
||||
:path "/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1")
|
||||
</code></pre>
|
||||
|
||||
<p>A last remark. Once you built your binary and you run it for the first
|
||||
time, you might get a funny message from ASDF that tries to upgrade
|
||||
itself, finds nothing into a <code>~/common-lisp/asdf/</code> repository, and
|
||||
quits. To tell it to not upgrade itself, add this into your .asd:</p>
|
||||
|
||||
<pre><code class="language-lisp">;; Tell ASDF to not update itself.
|
||||
(deploy:define-hook (:deploy asdf) (directory)
|
||||
(declare (ignorable directory))
|
||||
#+asdf (asdf:clear-source-registry)
|
||||
#+asdf (defun asdf:upgrade-asdf () nil))
|
||||
</code></pre>
|
||||
|
||||
<p>But there is more, so we refer you to Deploy’s documentation.</p>
|
||||
|
||||
<h3 id="with-roswell-or-buildapp">With Roswell or Buildapp</h3>
|
||||
|
||||
<p><a href="https://roswell.github.io">Roswell</a>, an implementation manager, script launcher and
|
||||
|
@ -270,9 +348,13 @@ ECL is more involved and takes the longer to compile of these three implementati
|
|||
<h3 id="building-a-smaller-binary-with-sbcls-core-compression">Building a smaller binary with SBCL’s core compression</h3>
|
||||
|
||||
<p>Building with SBCL’s core compression can dramatically reduce your
|
||||
application binary’s size. In our case, we passed from 120MB to 23MB,
|
||||
application binary’s size. In our case, it reduced it from 120MB to 23MB,
|
||||
for a loss of a dozen milliseconds of start-up time, which was still
|
||||
under 50ms!</p>
|
||||
under 50ms.</p>
|
||||
|
||||
<div class="info-box info">
|
||||
<strong>Note:</strong> SBCL 2.2.6 switched to compression with zstd instead of zlib, which provides smaller binaries and faster compression and decompression times. Un-official numbers are: about 4x faster compression, 2x faster decompression, and smaller binaries by 10%.
|
||||
</div>
|
||||
|
||||
<p>Your SBCL must be built with core compression, see the documentation: <a href="http://www.sbcl.org/manual/#Saving-a-Core-Image">http://www.sbcl.org/manual/#Saving-a-Core-Image</a></p>
|
||||
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
<meta name="description" content="A collection of examples of using Common Lisp">
|
||||
<meta name="viewport" content=
|
||||
"width=device-width, initial-scale=1">
|
||||
<link rel="icon" href=
|
||||
"assets/cl-logo-blue.png"/>
|
||||
<link rel="stylesheet" href=
|
||||
"assets/style.css">
|
||||
<script type="text/javascript" src=
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
<meta name="description" content="A collection of examples of using Common Lisp">
|
||||
<meta name="viewport" content=
|
||||
"width=device-width, initial-scale=1">
|
||||
<link rel="icon" href=
|
||||
"assets/cl-logo-blue.png"/>
|
||||
<link rel="stylesheet" href=
|
||||
"assets/style.css">
|
||||
<script type="text/javascript" src=
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
<meta name="description" content="A collection of examples of using Common Lisp">
|
||||
<meta name="viewport" content=
|
||||
"width=device-width, initial-scale=1">
|
||||
<link rel="icon" href=
|
||||
"assets/cl-logo-blue.png"/>
|
||||
<link rel="stylesheet" href=
|
||||
"assets/style.css">
|
||||
<script type="text/javascript" src=
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
<meta name="description" content="A collection of examples of using Common Lisp">
|
||||
<meta name="viewport" content=
|
||||
"width=device-width, initial-scale=1">
|
||||
<link rel="icon" href=
|
||||
"assets/cl-logo-blue.png"/>
|
||||
<link rel="stylesheet" href=
|
||||
"assets/style.css">
|
||||
<script type="text/javascript" src=
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
<meta name="description" content="A collection of examples of using Common Lisp">
|
||||
<meta name="viewport" content=
|
||||
"width=device-width, initial-scale=1">
|
||||
<link rel="icon" href=
|
||||
"assets/cl-logo-blue.png"/>
|
||||
<link rel="stylesheet" href=
|
||||
"assets/style.css">
|
||||
<script type="text/javascript" src=
|
||||
|
@ -440,7 +442,7 @@ either with a simple <code>C-c C-c</code> in Slime, or when we <code>load</code>
|
|||
|
||||
<p>A class slot accepts a <code>:type</code> slot option. It is however generally
|
||||
<em>not</em> used to check the type of the initform. SBCL, starting with
|
||||
<a href="http://www.sbcl.org/news.html#1.5.9">version 1.5.9</a> released on
|
||||
<a href="http://www.sbcl.org/all-news.html#1.5.9">version 1.5.9</a> released on
|
||||
november 2019, now gives those warnings, meaning that this:</p>
|
||||
|
||||
<pre><code class="language-lisp">(defclass foo ()
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
<meta name="description" content="A collection of examples of using Common Lisp">
|
||||
<meta name="viewport" content=
|
||||
"width=device-width, initial-scale=1">
|
||||
<link rel="icon" href=
|
||||
"assets/cl-logo-blue.png"/>
|
||||
<link rel="stylesheet" href=
|
||||
"assets/style.css">
|
||||
<script type="text/javascript" src=
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
<meta name="description" content="A collection of examples of using Common Lisp">
|
||||
<meta name="viewport" content=
|
||||
"width=device-width, initial-scale=1">
|
||||
<link rel="icon" href=
|
||||
"assets/cl-logo-blue.png"/>
|
||||
<link rel="stylesheet" href=
|
||||
"assets/style.css">
|
||||
<script type="text/javascript" src=
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
<meta name="description" content="A collection of examples of using Common Lisp">
|
||||
<meta name="viewport" content=
|
||||
"width=device-width, initial-scale=1">
|
||||
<link rel="icon" href=
|
||||
"assets/cl-logo-blue.png"/>
|
||||
<link rel="stylesheet" href=
|
||||
"assets/style.css">
|
||||
<script type="text/javascript" src=
|
||||
|
@ -347,9 +349,12 @@ parameter:</p>
|
|||
handling extension on top of Hunchentoot. It provides:</p>
|
||||
|
||||
<ul>
|
||||
<li>dispatch based on HTTP method (otherwise cumbersome in Hunchentoot)</li>
|
||||
<li>arguments extraction from the url path</li>
|
||||
<li>and decorators.</li>
|
||||
<li><strong>dispatch</strong> based on the HTTP method, such as GET or POST (which is otherwise cumbersome to do in Hunchentoot)</li>
|
||||
<li><strong>arguments extraction</strong> from the url path</li>
|
||||
<li><strong>decorators</strong> (functions to run before the route body, typically used to add a layer of authentication or changing the returned content type)</li>
|
||||
<li><strong>URL generation</strong> from route names and given URL parameters</li>
|
||||
<li>visualization of routes</li>
|
||||
<li>and more</li>
|
||||
</ul>
|
||||
|
||||
<p>To use it, don’t create a server with <code>hunchentoot:easy-acceptor</code> but
|
||||
|
@ -365,7 +370,7 @@ serve static content the usual way with Hunchentoot.</p>
|
|||
|
||||
<p>Then define a route like this:</p>
|
||||
|
||||
<pre><code class="language-lisp">(easy-routes:defroute name ("/foo/:x" :method :get) (y &get z)
|
||||
<pre><code class="language-lisp">(easy-routes:defroute my-route-name ("/foo/:x" :method :get) (y &get z)
|
||||
(format nil "x: ~a y: ~a z: ~a" x y z))
|
||||
</code></pre>
|
||||
|
||||
|
@ -377,6 +382,18 @@ body.</p>
|
|||
<p>These parameters can take an <code>:init-form</code> and <code>:parameter-type</code>
|
||||
options as in <code>define-easy-handler</code>.</p>
|
||||
|
||||
<p>Now, imagine that we are deeper in our web application logic, and we
|
||||
want to redirect our user to the route “/foo/3”. Instead of hardcoding
|
||||
the URL, we can <strong>generate the URL from its name</strong>. Use
|
||||
<code>easy-routes:genurl</code> like this:</p>
|
||||
|
||||
<pre><code class="language-lisp">(easy-routes:genurl my-route-name :id 3)
|
||||
;; => /foo/3
|
||||
|
||||
(easy-routes:genurl my-route-name :id 3 :y "yay")
|
||||
;; => /foo/3?y=yay
|
||||
</code></pre>
|
||||
|
||||
<p><strong>Decorators</strong> are functions that are executed before the route body. They
|
||||
should call the <code>next</code> parameter function to continue executing the
|
||||
decoration chain and the route body finally. Examples:</p>
|
||||
|
@ -973,7 +990,7 @@ Listening on localhost:9003.
|
|||
|
||||
<p>We can start our executable in a shell and send it to the background (<code>C-z bg</code>), or run it inside a <code>tmux</code> session. These are not the best but hey, it works©.</p>
|
||||
|
||||
<h3 id="daemonizing-restarting-in-case-of-crashes-handling-logs-with-systemd">Daemonizing, restarting in case of crashes, handling logs with Systemd</h3>
|
||||
<h3 id="systemd-daemonizing-restarting-in-case-of-crashes-handling-logs">Systemd: Daemonizing, restarting in case of crashes, handling logs</h3>
|
||||
|
||||
<p>This is actually a system-specific task. See how to do that on your system.</p>
|
||||
|
||||
|
@ -981,47 +998,59 @@ Listening on localhost:9003.
|
|||
|
||||
<p>Deploying an app with Systemd is as simple as writing a configuration file:</p>
|
||||
|
||||
<pre><code>$ emacs -nw /etc/systemd/system/my-app.service
|
||||
<pre><code>$ sudo emacs -nw /etc/systemd/system/my-app.service
|
||||
[Unit]
|
||||
Description=stupid simple example
|
||||
Description=your lisp app on systemd example
|
||||
|
||||
[Service]
|
||||
WorkingDirectory=/path/to/your/app
|
||||
ExecStart=/usr/local/bin/sthg sthg
|
||||
WorkingDirectory=/path/to/your/project/directory/
|
||||
ExecStart=/usr/bin/make run # or anything
|
||||
Type=simple
|
||||
Restart=on-failure
|
||||
|
||||
[Install]
|
||||
WantedBy=network.target
|
||||
</code></pre>
|
||||
|
||||
<p>Then we have a command to start it:</p>
|
||||
<p>Then we have a command to <code>start</code> it, only now:</p>
|
||||
|
||||
<pre><code>sudo systemctl start my-app.service
|
||||
</code></pre>
|
||||
|
||||
<p>a command to check its status:</p>
|
||||
<p>and a command to install the service, to <strong>start the app after a boot
|
||||
or reboot</strong> (that’s the “[Install]” part):</p>
|
||||
|
||||
<pre><code>sudo systemctl enable my-app.service
|
||||
</code></pre>
|
||||
|
||||
<p>Then we can check its <code>status</code>:</p>
|
||||
|
||||
<pre><code>systemctl status my-app.service
|
||||
</code></pre>
|
||||
|
||||
<p>and Systemd can handle <strong>logging</strong> (we write to stdout or stderr, it writes logs):</p>
|
||||
<p>and see our application’s <strong>logs</strong> (we can write to stdout or stderr,
|
||||
and Systemd handles the logging):</p>
|
||||
|
||||
<pre><code>journalctl -f -u my-app.service
|
||||
<pre><code>journalctl -u my-app.service
|
||||
</code></pre>
|
||||
|
||||
<p>and it handles crashes and <strong>restarts the app</strong>:</p>
|
||||
<p>(you can also use the <code>-f</code> option to see log updates in real time, and in that case augment the number of lines with <code>-n 50</code> or <code>--lines</code>).</p>
|
||||
|
||||
<pre><code>Restart=on-failure
|
||||
</code></pre>
|
||||
<p>Systemd handles crashes and <strong>restarts the application</strong>. That’s the <code>Restart=on-failure</code> line.</p>
|
||||
|
||||
<p>and it can <strong>start the app after a reboot</strong>:</p>
|
||||
<p>Now keep in mind a couple things:</p>
|
||||
|
||||
<pre><code>[Install]
|
||||
WantedBy=basic.target
|
||||
</code></pre>
|
||||
|
||||
<p>to enable it:</p>
|
||||
|
||||
<pre><code>sudo systemctl enable my-app.service
|
||||
</code></pre>
|
||||
<ul>
|
||||
<li>we want our app to crash so that it can be re-started automatically:
|
||||
you’ll want the <code>--disable-debugger</code> flag with SBCL.</li>
|
||||
<li>Systemd will, by default, run your app as root. If you rely on your
|
||||
Lisp to read your startup file (<code>~/.sbclrc</code>), especially to setup
|
||||
Quicklisp, you will need to use the <code>--userinit</code> flag, or to set the
|
||||
Systemd user with <code>User=xyz</code> in the <code>[service]</code> section. And if you
|
||||
use a startup file, be aware that the line <code>(user-homedir-pathname)</code>
|
||||
will not return the same result depending on the user, so the snippet
|
||||
might not find Quicklisp’s setup.lisp file.</li>
|
||||
</ul>
|
||||
|
||||
<p>See more: <a href="https://www.freedesktop.org/software/systemd/man/systemd.service.html">https://www.freedesktop.org/software/systemd/man/systemd.service.html</a>.</p>
|
||||
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
<meta name="description" content="A collection of examples of using Common Lisp">
|
||||
<meta name="viewport" content=
|
||||
"width=device-width, initial-scale=1">
|
||||
<link rel="icon" href=
|
||||
"assets/cl-logo-blue.png"/>
|
||||
<link rel="stylesheet" href=
|
||||
"assets/style.css">
|
||||
<script type="text/javascript" src=
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
<meta name="description" content="A collection of examples of using Common Lisp">
|
||||
<meta name="viewport" content=
|
||||
"width=device-width, initial-scale=1">
|
||||
<link rel="icon" href=
|
||||
"assets/cl-logo-blue.png"/>
|
||||
<link rel="stylesheet" href=
|
||||
"assets/style.css">
|
||||
<script type="text/javascript" src=
|
||||
|
|
Loading…
Add table
Reference in a new issue