update ecldoc for new example of asdf

This commit is contained in:
Bo Yao 2017-03-15 22:37:32 -04:00
parent fb7117a171
commit b2a3924784
4 changed files with 193 additions and 26 deletions

View file

@ -1,10 +1,10 @@
#+TITLE: Build an asdf system with dependences
#+TITLE: Build an asdf system with dependencies
#+AUTHOR: Bo Yao <icerove@gmail.com>
Besides the simple situation that we write Lisp without depending on any other Lisp libraries, a more practical example is build a library depends on other asdf systems or Quicklisp projects. Thanks to the ECL's great extension on ~asdf:make-build~, it's almost as easy as build a library without dependences. Because Quicklisp also uses asdf to load systems with dependences, just make sure you have successfully load and run your library in ECL REPL (or ~*slime-repl*~). Don't worry Quicklisp, asdf, swank and other unused libraries are packed into the executable or library, ECL will only build and pack libraries your project depends on (that is, all dependences you put in your ~.asd~ file, and their dependences, nothing more even you are build in a image already load with lots of other libraries).
Besides the simple situation that we write Lisp without depending on any other Lisp libraries, a more practical example is build a library depends on other asdf systems or Quicklisp projects. ECL provides a useful extension for asdf called ~asdf:make-build~, it's almost as easy as build a library without dependencies. Because Quicklisp also uses asdf to load systems with dependencies, just make sure you have successfully load and run your library in ECL REPL (or ~*slime-repl*~). Don't worry Quicklisp, asdf, swank and other unused libraries are packed into the executable or library, ECL will only build and pack libraries your project depends on (that is, all dependence you put in your ~.asd~ file, and their dependencies, nothing more even you are build in a image already load with lots of other libraries).
** Example code to build
We use a simple project depends on alexandria to demostrate the steps. Consists of ~example-with-dep.asd~, ~package.lisp~ and ~example.lisp~. For convinience, we list these files here:
We use a simple project depends on alexandria to demonstrate the steps. Consists of ~example-with-dep.asd~, ~package.lisp~ and ~example.lisp~. For convenience, we list these files here:
#+BEGIN_SRC common-lisp
;;;; example-with-dep.asd
@ -62,7 +62,7 @@ Use this in REPL to make a shared library:
:monolithic t)
#+END_SRC
Here ~:monolithic t~ means to let ECL solve dependence and build all denpendence into one library named ~example-with-dep--all-systems.so~ in this directory.
Here ~:monolithic t~ means to let ECL solve dependence and build all dependence into one library named ~example-with-dep--all-systems.so~ in this directory.
To use it, we use a simple C program:
@ -121,7 +121,7 @@ You can also build all dependent libraries separately as several ~.so~ files and
#+END_SRC
Note here is no ~:monolithic t~ and we also need to build ~bordeaux-threads~ because ~cl-fad~ depends on it. The building sequence doesn't matter and the result ~.so~ files can also be used in your future program if these libraries are not modified.
And We need to init all these modules using ~ecl_init_module~, the name convention is to init ~cl-fad~ you need:
And We need to initialize all these modules using ~ecl_init_module~, the name convention is to initialize ~cl-fad~ you need:
#+BEGIN_SRC c
extern void init_dll_CL_FAD(cl_object);

View file

@ -1,8 +1,8 @@
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
BUILD AN ASDF SYSTEM WITH DEPENDENCES
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
BUILD AN ASDF SYSTEM WITH DEPENDENCIES
Bo Yao <icerove@gmail.com>
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Table of Contents
@ -16,24 +16,24 @@ Table of Contents
Besides the simple situation that we write Lisp without depending on any
other Lisp libraries, a more practical example is build a library
depends on other asdf systems or Quicklisp projects. Thanks to the ECL's
great extension on `asdf:make-build', it's almost as easy as build a
library without dependences. Because Quicklisp also uses asdf to load
systems with dependences, just make sure you have successfully load and
run your library in ECL REPL (or `*slime-repl*'). Don't worry Quicklisp,
asdf, swank and other unused libraries are packed into the executable or
library, ECL will only build and pack libraries your project depends on
(that is, all dependences you put in your `.asd' file, and their
dependences, nothing more even you are build in a image already load
with lots of other libraries).
depends on other asdf systems or Quicklisp projects. ECL provides a
useful extension for asdf called `asdf:make-build', it's almost as easy
as build a library without dependencies. Because Quicklisp also uses
asdf to load systems with dependencies, just make sure you have
successfully load and run your library in ECL REPL (or
`*slime-repl*'). Don't worry Quicklisp, asdf, swank and other unused
libraries are packed into the executable or library, ECL will only build
and pack libraries your project depends on (that is, all dependence you
put in your `.asd' file, and their dependencies, nothing more even you
are build in a image already load with lots of other libraries).
1 Example code to build
═══════════════════════
We use a simple project depends on alexandria to demostrate the
We use a simple project depends on alexandria to demonstrate the
steps. Consists of `example-with-dep.asd', `package.lisp' and
`example.lisp'. For convinience, we list these files here:
`example.lisp'. For convenience, we list these files here:
┌────
│ ;;;; example-with-dep.asd
@ -41,7 +41,7 @@ with lots of other libraries).
│ :serial t
│ :depends-on (:alexandria)
│ :components ((:file "package")
(:file "example")))
(:file "example")))
└────
┌────
@ -100,7 +100,7 @@ with lots of other libraries).
└────
Here `:monolithic t' means to let ECL solve dependence and build all
denpendence into one library named `example-with-dep--all-systems.so'
dependence into one library named `example-with-dep--all-systems.so'
in this directory.
To use it, we use a simple C program:
@ -169,8 +169,8 @@ with lots of other libraries).
`bordeaux-threads' because `cl-fad' depends on it. The building
sequence doesn't matter and the result `.so' files can also be used in
your future program if these libraries are not modified. And We need
to init all these modules using `ecl_init_module', the name convention
is to init `cl-fad' you need:
to initialize all these modules using `ecl_init_module', the name
convention is to initialize `cl-fad' you need:
┌────
│ extern void init_dll_CL_FAD(cl_object);

View file

@ -4,8 +4,10 @@
@menu
* Compiling with ECL::
* Compiling with ASDF::
@c * Compiling with Matroska::
@c * Compiling with ASDF::
@end menu
@cindex System building
@ -282,3 +284,168 @@ In this post, some file types that can be compiled to with ECL were introduced.
ECL provides a high-level interface @code{c:build-*} for each native
format. In case of @emph{Portable FASL} bytecodes compiler is needed.
@node Compiling with ASDF
@subsection Compiling with ASDF
Besides the simple situation that we write Lisp without depending on any other Lisp libraries, a more practical example is build a library depends on other asdf systems or Quicklisp projects. ECL provides a useful extension for asdf called @code{asdf:make-build}, it's almost as easy as build a library without dependencies. Because Quicklisp also uses asdf to load systems with dependencies, just make sure you have successfully load and run your library in ECL REPL (or @code{*slime-repl*}). Don't worry Quicklisp, asdf, swank and other unused libraries are packed into the executable or library, ECL will only build and pack libraries your project depends on (that is, all dependence you put in your @code{.asd} file, and their dependencies, nothing more even you are build in a image already load with lots of other libraries).
@node Example code to build
@subsubsection Example code to build
We use a simple project depends on alexandria to demonstrate the steps. Consists of @code{example-with-dep.asd}, @code{package.lisp} and @code{example.lisp}. For convenience, we list these files here:
@lisp
;;;; example-with-dep.asd
(defsystem :example-with-dep
:serial t
:depends-on (:alexandria)
:components ((:file "package")
(:file "example")))
@end lisp
@lisp
;;;; package.lisp
(in-package :cl-user)
(defpackage :example
(:use :cl)
(:export :test-function))
@end lisp
@lisp
;;;; example.lisp
(in-package :example)
(defun test-function (n)
(format t "Factorial of ~a is: ~a~%" n (alexandria:factorial n)))
@end lisp
Before any kind you build, you need to push full path of this directory (@code{asdf_with_dependence/}) into @code{asdf:*central-registry*}.
@node Build it as an single executable
@subsubsection Build it as an single executable
Use this in REPL to make a executable:
@lisp
(asdf:make-build :example-with-dep
:type :program
:move-here #P"./"
:epilogue-code '(progn (example:test-function 5)
(si:exit)))
@end lisp
Here the @code{:epilogue-code} is what to do after loading our library, we can use arbitrary Lisp forms here. You can also write this code in your Lisp files and directly build them without this @code{:epilogue-code} option to have the same effect.
Run the program in console will display the following and exit:
@example
Factorial of 5 is: 120
@end example
@node Build it as shared library and use in C
@subsubsection Build it as shared library and use in C
Use this in REPL to make a shared library:
@lisp
(asdf:make-build :example-with-dep
:type :shared-library
:move-here #P"./"
:monolithic t)
@end lisp
Here @code{:monolithic t} means to let ECL solve dependence and build all dependence into one library named @code{example-with-dep--all-systems.so} in this directory.
To use it, we use a simple C program:
@example
/* test.c */
#include <ecl/ecl.h>
int main (int argc, char **argv) @{
extern void init_dll_EXAMPLE_WITH_DEP__ALL_SYSTEMS(cl_object);
cl_boot(argc, argv);
ecl_init_module(NULL, init_dll_EXAMPLE_WITH_DEP__ALL_SYSTEMS);
/* do things with the Lisp library */
cl_eval(c_string_to_object("(example:test-function 5)"));
cl_shutdown();
return 0;
@}
@end example
Note the name convention here: an asdf system named @code{example-with-dep} will compiled to @code{example-with-dep--all-systems.so} and in the C code should be init with @code{init_dll_EXAMPLE_WITH_DEP__ALL_SYSTEMS}. Compile it using:
@example
gcc test.c example-with-dep--all-systems.so -o test -lecl
@end example
ECL's library path and current directory may not be in your @code{LD_LIBRARY_PATH}, so call @code{./test} using:
@example
LD_LIBRARY_PATH=/usr/local/lib/:. ./test
@end example
This will show:
@example
Factorial of 5 is: 120
@end example
You can also build all dependent libraries separately as several @code{.so} files and link them together. For example, if you are building a library called @code{complex-example}, that depends on @code{alexandria} and @code{cl-fad}, you can also do these in ECL REPL:
@lisp
(asdf:make-build :complex-example
:type :shared-library
:move-here #P"./")
(asdf:make-build :alexandria
:type :shared-library
:move-here #P"./")
(asdf:make-build :cl-fad
:type :shared-library
:move-here #P"./")
(asdf:make-build :bordeaux-threads
:type :shared-library
:move-here #P"./")
@end lisp
Note here is no @code{:monolithic t} and we also need to build @code{bordeaux-threads} because @code{cl-fad} depends on it. The building sequence doesn't matter and the result @code{.so} files can also be used in your future program if these libraries are not modified.
And We need to initialize all these modules using @code{ecl_init_module}, the name convention is to initialize @code{cl-fad} you need:
@example
extern void init_dll_CL_FAD(cl_object);
/* after cl_boot(argc, argv);
and if B depends on A, you should first init A then B. */
ecl_init_module(NULL, init_dll_CL_FAD);
@end example
You can easily figure out name conventions with other libraries.
@node Build it as static library and use in C
@subsubsection Build it as static library and use in C
To build a static library, use:
@lisp
(asdf:make-build :example-with-dep
:type :static-library
:move-here #P"./"
:monolithic t)
@end lisp
That will generate a @code{example-with-dep--all-systems.a} in current directory and we need to replace @code{init_dll_EXAMPLE_WITH_DEP__ALL_SYSTEMS} with @code{init_lib_EXAMPLE_WITH_DEP__ALL_SYSTEMS}. (The code is given in test-static.c) And compile it using:
@example
gcc test-static.c example-with-dep--all-systems.a -o test-static -lecl
@end example
Then run it:
@example
LD_LIBRARY_PATH=/usr/local/lib/ ./test-static
@end example
Note we don't need to give current path in @code{LD_LIBRARY_PATH} here, since our Lisp library is statically bundled to the executable.
The result is same as the shared library example above. You can also build all dependent libraries separately to static libraries. To use them you also need replace names like @code{init_dll_CL_FAD} to @code{init_lib_CL_FAD}.

View file

@ -54,4 +54,4 @@ For the ANSI-compliant LOOP macro.
The @ecl{} project also owes a lot to the people who have tested this
program and contributed with suggestions, error messages and
documentation: Eric Marsden, Hannu Koivisto, Jeff Bowden and Yuto
Hayamizu, and others whose name we may have omitted.
Hayamizu, Bo Yao and others whose name we may have omitted.