| tasdf.lisp - clic - Clic is an command line interactive client for gopher writt… | |
| git clone git://bitreich.org/clic/ git://hg6vgqziawt5s4dj.onion/clic/ | |
| Log | |
| Files | |
| Refs | |
| Tags | |
| LICENSE | |
| --- | |
| tasdf.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 <[email protected]> | |
| 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-predica… | |
| 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 configur… | |
| 77 the binding generation process. This header file will define the initial… | |
| 78 the generation process, which can be further filtered by other configura… | |
| 79 parameters. | |
| 80 | |
| 81 A clang/llvm based external program called 'c2ffi' is used to process th… | |
| 82 file and generate a json spec file for each supported architecture tripl… | |
| 83 these .spec files are only (re)generated by the author of the lib and ar… | |
| 84 the corresponding source repository. It needs to be done manually by inv… | |
| 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 … | |
| 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 ge… | |
| 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… | |
| 100 other lisp file. This process requires loading the ASDF system called | |
| 101 \"cffi/c2ffi-generator\" that has more dependencies than CFFI itself. If… | |
| 102 want to avoid those extra dependencies in your project, then you can che… | |
| 103 these generated lisp files into your source repository, but keep in mind… | |
| 104 you'll need to manually force their regeneration if CFFI/C2FFI itself ge… | |
| 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~%" ge… | |
| 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-pathnam… | |
| 192 prelude)) | |
| 193 ;; The following slots and keyword args have the same name … | |
| 194 ;; component and in PROCESS-C2FFI-SPEC-FILE, and this loop … | |
| 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)) |