#+TITLE: PortaCL: Easing the Creation of CL Portability Libraries * Rationale Sometimes you want to do something based upon *features*. Often, that results in lots of reader conditionals, and a final reader conditional duplicating and negating all previous conditionals. Ew! * API ** ASDF Components: port-file, port-module It's not uncommon for a portability library to include something like: :(:file : #+sbcl "port-sbcl" : #+clisp "port-clisp" : #-(or sbcl clisp) (error "not supported")) port-file and port-modules allow you to specify things more like so: :(:port-file "port-~A") or, less positionally, :(:port-file "port-~/implementation/") Whether such magical divinations are a good thing is left to you to decide. port-file and port-module both also support specification of an :alternate-file, which if specified will be used in place of throwing a not-implemented error. E.g., for use if only one or two implementations need special behavior. You can also specify :not-found-condition, the condition type which will be thrown if no applicable file is found. (e.g., you might prefer 'not-supported instead, or 'not-necessary if a missing component is okay). ** Condition: not-implemented Useful for indicating a particular thing is not implemented. This is the default condition thrown when an implementation-specific ASDF component is not found. ** Condition: not-supported A particular thing is not implemented and won't be. E.g., because the lisp implementation lacks the necessary features. ** Condition: not-necessary If this thing is not implemented, it didn't need to be. When specified as the :not-found-condition in a defsystem form, will cause operations on the component to be considered successful even if the component could not be found. ** Function: featurep feature-expression Given a feature expression, returns true if that expression is true. see [[http://www.lispworks.com/documentation/HyperSpec/Body/24_aba.htm][CLHS 24.1.2.1]] for details. ** Macro: define-feature-test test-name-or-names lambda-list [documentation] &body Defines a feature test which shall return true if the given feature expressions apply. see [[http://repo.kepibu.org/portaCL/feature-tests.lisp][feature-tests.lisp]] for usage examples. ** Macro: feature-cond ([feature-conditional] [clause]+)* A macro version of #+foo (thing) #+bar (thing2) #-(or foo bar) (no-thing), with all the caveats and shortcomings that implies. ** Macro: feature-ecase ([[feature-conditional] [clause]+]+) feature-case, except always includes a final (error 'not-implemented). * Future Ideas ** ASDF component enhancements *** platform / operating system It might be useful to also offer up the operating system for interpolation into port-files. (e.g., via ~/platform/ or ~/operating-system/). *** shared-implementation support It might also be useful to offer a way to specify that certain implementations should be treated just like another implementation. E.g., :(:port-file "port-~a" :treat-as (:ecl :sbcl)) could be used by usocket, instead of futzing with :alternate-file. ** Other porting styles? Per-file implementation is not the only possible or used porting approach. Perhaps some others should also be supported? * SLIME's defimplementation * Xach's CLOS-based approach * Any others? * Bugs * ASDF systems sometimes try to recursively load themselves a couple hundred times. (Though I've seen that even without loading portaCL, so may not be entirely my bug...) * Constructs similar to the ones below will result in an incorrect package-error: :(list #+(or) #+package:notexported a b c) :(list #+(or) #+notapackage:foo a b c) NOTE: this bug is shared by the standard readers of at least SBCL, Clisp, and Lispworks; but not by Allegro. * see also [[http://www.cliki.net/trivial-features][trivial-features]] smooths out the unnecessary differences between implementation *features* [[http://common-lisp.net/project/alexandria/][alexandria]] implements a #'featurep which exactly matches that used by the standard's #+/#- readmacros. [[http://common-lisp.net/project/cl-syntax-sugar/][cl-syntax-sugar]] Offers a feature-case reader which is almost certainly more useful than portaCL's feature-cond macro.