asdf.lisp - clic - Clic is an command line interactive client for gopher written in Common LISP
 (HTM) git clone git://bitreich.org/clic/ git://enlrupgkhuxnvlhsf6lc3fziv5h2hhfrinws65d7roiv6bfj7d652fid.onion/clic/
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) Tags
 (DIR) README
 (DIR) LICENSE
       ---
       asdf.lisp (9329B)
       ---
            1 ;;;; -*- Mode: lisp; indent-tabs-mode: nil -*-
            2 ;;;
            3 ;;; asdf.lisp --- ASDF components for cffi/c2ffi.
            4 ;;;
            5 ;;; Copyright (C) 2015, Attila Lendvai <attila@lendvai.name>
            6 ;;;
            7 ;;; Permission is hereby granted, free of charge, to any person
            8 ;;; obtaining a copy of this software and associated documentation
            9 ;;; files (the "Software"), to deal in the Software without
           10 ;;; restriction, including without limitation the rights to use, copy,
           11 ;;; modify, merge, publish, distribute, sublicense, and/or sell copies
           12 ;;; of the Software, and to permit persons to whom the Software is
           13 ;;; furnished to do so, subject to the following conditions:
           14 ;;;
           15 ;;; The above copyright notice and this permission notice shall be
           16 ;;; included in all copies or substantial portions of the Software.
           17 ;;;
           18 ;;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
           19 ;;; EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
           20 ;;; MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
           21 ;;; NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
           22 ;;; HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
           23 ;;; WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
           24 ;;; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
           25 ;;; DEALINGS IN THE SOFTWARE.
           26 ;;;
           27 
           28 (in-package #:cffi/c2ffi)
           29 
           30 (defclass c2ffi-file (cl-source-file)
           31   ((package :initarg :package
           32             :initform nil
           33             :accessor c2ffi-file/package)
           34    (c2ffi-executable :initarg :c2ffi-executable
           35                      :accessor c2ffi-file/c2ffi-executable)
           36    (trace-c2ffi :initarg :trace-c2ffi
           37                 :accessor c2ffi-file/trace-c2ffi)
           38    (prelude :initform nil
           39             :initarg :prelude
           40             :accessor c2ffi-file/prelude)
           41    (sys-include-paths :initarg :sys-include-paths
           42                       :initform nil
           43                       :accessor c2ffi-file/sys-include-paths)
           44    (exclude-archs :initarg :exclude-archs
           45                   :initform nil
           46                   :accessor c2ffi-file/exclude-archs)
           47    ;; The following slots correspond to an arg of the same name for
           48    ;; the generator function. No accessors are needed, they just hold
           49    ;; the data until it gets delegated to the generator function using
           50    ;; SLOT-VALUE and a LOOP.
           51    (ffi-name-transformer :initarg :ffi-name-transformer
           52                          :initform 'default-ffi-name-transformer)
           53    (ffi-name-export-predicate :initarg :ffi-name-export-predicate
           54                               :initform 'default-ffi-name-export-predicate)
           55    (ffi-type-transformer :initarg :ffi-type-transformer
           56                          :initform 'default-ffi-type-transformer)
           57    (callback-factory :initarg :callback-factory
           58                      :initform 'default-callback-factory)
           59    (foreign-library-name :initarg :foreign-library-name
           60                          :initform nil)
           61    (foreign-library-spec :initarg :foreign-library-spec
           62                          :initform nil)
           63    (emit-generated-name-mappings :initarg :emit-generated-name-mappings
           64                                  :initform :t)
           65    (include-sources :initarg :include-sources
           66                     :initform :all)
           67    (exclude-sources :initarg :exclude-sources
           68                     :initform nil)
           69    (include-definitions :initarg :include-definitions
           70                         :initform :all)
           71    (exclude-definitions :initarg :exclude-definitions
           72                         :initform nil))
           73   (:default-initargs
           74    :type nil)
           75   (:documentation
           76    "The input of this ASDF component is a C header file and the configuration for
           77 the binding generation process. This header file will define the initial scope of
           78 the generation process, which can be further filtered by other configuration
           79 parameters.
           80 
           81 A clang/llvm based external program called 'c2ffi' is used to process this header
           82 file and generate a json spec file for each supported architecture triplet. Normally
           83 these .spec files are only (re)generated by the author of the lib and are checked into
           84 the corresponding source repository. It needs to be done manually by invoking the
           85 following command:
           86 
           87 (cffi/c2ffi:generate-spec :your-system)
           88 
           89 which is a shorthand for:
           90 
           91 (asdf:operate 'cffi/c2ffi::generate-spec-op :your-system)
           92 
           93 The generation of the underlying platform's json file must succeed, but the
           94 generation for the other arch's is allowed to fail
           95 \(see ENSURE-SPEC-FILE-IS-UP-TO-DATE for details).
           96 
           97 During the normal build process the json file is used as the input to generate
           98 a lisp file containing the CFFI definitions (see PROCESS-C2FFI-SPEC-FILE).
           99 This file will be placed next to the .spec file, and will be compiled as any
          100 other lisp file. This process requires loading the ASDF system called
          101 \"cffi/c2ffi-generator\" that has more dependencies than CFFI itself. If you
          102 want to avoid those extra dependencies in your project, then you can check in
          103 these generated lisp files into your source repository, but keep in mind that
          104 you'll need to manually force their regeneration if CFFI/C2FFI itself gets
          105 updated (by e.g. deleting them from the filesystem) ."))
          106 
          107 (defun input-file (operation component)
          108   (let ((files (input-files operation component)))
          109     (assert (length=n-p files 1))
          110     (first files)))
          111 
          112 (defclass generate-spec-op (downward-operation)
          113   ())
          114 
          115 (defun generate-spec (system)
          116   (asdf:operate 'generate-spec-op system))
          117 
          118 (defmethod input-files ((op generate-spec-op) (c c2ffi-file))
          119   (list (component-pathname c)))
          120 
          121 (defmethod component-depends-on ((op generate-spec-op) (c c2ffi-file))
          122   `((prepare-op ,c) ,@(call-next-method)))
          123 
          124 (defmethod output-files ((op generate-spec-op) (c c2ffi-file))
          125   (let* ((input-file (input-file op c))
          126          (spec-file (spec-path input-file)))
          127     (values
          128      (list spec-file)
          129      ;; Tell ASDF not to apply output translation.
          130      t)))
          131 
          132 (defmethod perform ((op generate-spec-op) (c asdf:component))
          133   (values))
          134 
          135 (defmethod perform ((op generate-spec-op) (c c2ffi-file))
          136   (let ((input-file (input-file op c))
          137         (*c2ffi-executable* (if (slot-boundp c 'c2ffi-executable)
          138                                 (c2ffi-file/c2ffi-executable c)
          139                                 *c2ffi-executable*))
          140         (*trace-c2ffi* (if (slot-boundp c 'trace-c2ffi)
          141                            (c2ffi-file/trace-c2ffi c)
          142                            *trace-c2ffi*)))
          143     ;; NOTE: we don't call OUTPUT-FILE here, which may be a violation
          144     ;; of the ASDF contract, that promises that OUTPUT-FILE can be
          145     ;; customized by users.
          146     (ensure-spec-file-is-up-to-date
          147      input-file
          148      :exclude-archs (c2ffi-file/exclude-archs c)
          149      :sys-include-paths (c2ffi-file/sys-include-paths c))))
          150 
          151 (defclass generate-lisp-op (downward-operation)
          152   ())
          153 
          154 (defmethod component-depends-on ((op generate-lisp-op) (c c2ffi-file))
          155   `((load-op ,(find-system "cffi/c2ffi-generator"))
          156     ,@(call-next-method)))
          157 
          158 (defmethod component-depends-on ((op compile-op) (c c2ffi-file))
          159   `((generate-lisp-op ,c) ,@(call-next-method)))
          160 
          161 (defmethod component-depends-on ((op load-source-op) (c c2ffi-file))
          162   `((generate-lisp-op ,c) ,@(call-next-method)))
          163 
          164 (defmethod input-files ((op generate-lisp-op) (c c2ffi-file))
          165   (list (output-file 'generate-spec-op c)))
          166 
          167 (defmethod input-files ((op compile-op) (c c2ffi-file))
          168   (list (output-file 'generate-lisp-op c)))
          169 
          170 (defmethod output-files ((op generate-lisp-op) (c c2ffi-file))
          171   (let* ((spec-file (input-file op c))
          172          (generated-lisp-file (make-pathname :type "lisp"
          173                                              :defaults spec-file)))
          174     (values
          175      (list generated-lisp-file)
          176      ;; Tell ASDF not to apply output translation.
          177      t)))
          178 
          179 (defmethod perform ((op generate-lisp-op) (c c2ffi-file))
          180   (let ((spec-file (input-file op c))
          181         (generated-lisp-file (output-file op c)))
          182     (with-staging-pathname (tmp-output generated-lisp-file)
          183       (format *debug-io* "~&; CFFI/C2FFI is generating the file ~S~%" generated-lisp-file)
          184       (apply 'process-c2ffi-spec-file
          185              spec-file (c2ffi-file/package c)
          186              :output tmp-output
          187              :output-encoding (asdf:component-encoding c)
          188              :prelude (let ((prelude (c2ffi-file/prelude c)))
          189                         (if (and (pathnamep prelude)
          190                                  (not (absolute-pathname-p prelude)))
          191                             (merge-pathnames* prelude (component-pathname c))
          192                             prelude))
          193              ;; The following slots and keyword args have the same name in the ASDF
          194              ;; component and in PROCESS-C2FFI-SPEC-FILE, and this loop copies them.
          195              (loop
          196                :for arg :in '(ffi-name-transformer
          197                               ffi-name-export-predicate
          198                               ffi-type-transformer
          199                               callback-factory
          200                               foreign-library-name
          201                               foreign-library-spec
          202                               emit-generated-name-mappings
          203                               include-sources
          204                               exclude-sources
          205                               include-definitions
          206                               exclude-definitions)
          207                :append (list (make-keyword arg)
          208                              (slot-value c arg)))))))
          209 
          210 ;; Allow for naked :cffi/c2ffi-file in asdf definitions.
          211 (setf (find-class 'asdf::cffi/c2ffi-file) (find-class 'c2ffi-file))