Introduction
Introduction Statistics Contact Development Disclaimer Help
tc2ffi.lisp - clic - Clic is an command line interactive client for gopher writ…
git clone git://bitreich.org/clic/ git://hg6vgqziawt5s4dj.onion/clic/
Log
Files
Refs
Tags
LICENSE
---
tc2ffi.lisp (9422B)
---
1 ;;;; -*- Mode: lisp; indent-tabs-mode: nil -*-
2 ;;;
3 ;;; c2ffi.lisp --- c2ffi related code
4 ;;;
5 ;;; Copyright (C) 2013, Ryan Pavlik <[email protected]>
6 ;;; Copyright (C) 2015, Attila Lendvai <[email protected]>
7 ;;;
8 ;;; Permission is hereby granted, free of charge, to any person
9 ;;; obtaining a copy of this software and associated documentation
10 ;;; files (the "Software"), to deal in the Software without
11 ;;; restriction, including without limitation the rights to use, copy,
12 ;;; modify, merge, publish, distribute, sublicense, and/or sell copies
13 ;;; of the Software, and to permit persons to whom the Software is
14 ;;; furnished to do so, subject to the following conditions:
15 ;;;
16 ;;; The above copyright notice and this permission notice shall be
17 ;;; included in all copies or substantial portions of the Software.
18 ;;;
19 ;;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20 ;;; EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21 ;;; MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
22 ;;; NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
23 ;;; HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
24 ;;; WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25 ;;; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26 ;;; DEALINGS IN THE SOFTWARE.
27 ;;;
28
29 (in-package #:cffi/c2ffi)
30
31 ;;; NOTE: Most of this has been taken over from cl-autowrap.
32
33 ;;; Note this is rather untested and not very extensive at the moment;
34 ;;; it should probably work on linux/win/osx though. Patches welcome.
35
36 (defun local-cpu ()
37 #+x86-64 "x86_64"
38 #+(and (not (or x86-64 freebsd)) x86) "i686"
39 #+(and (not x86-64) x86 freebsd) "i386"
40 #+arm "arm")
41
42 (defun local-vendor ()
43 #+(or linux windows) "-pc"
44 #+darwin "-apple"
45 #+(not (or linux windows darwin)) "-unknown")
46
47 (defun local-os ()
48 #+linux "-linux"
49 #+windows "-windows-msvc"
50 #+darwin "-darwin9"
51 #+freebsd "-freebsd")
52
53 (defun local-environment ()
54 #+linux "-gnu"
55 #-linux "")
56
57 (defun local-arch ()
58 (strcat (local-cpu) (local-vendor) (local-os) (local-environment)))
59
60 (defparameter *known-archs*
61 '("i686-pc-linux-gnu"
62 "x86_64-pc-linux-gnu"
63 "i686-pc-windows-msvc"
64 "x86_64-pc-windows-msvc"
65 "i686-apple-darwin9"
66 "x86_64-apple-darwin9"
67 "i386-unknown-freebsd"
68 "x86_64-unknown-freebsd"))
69
70 (defvar *c2ffi-executable* "c2ffi")
71
72 (defvar *trace-c2ffi* nil)
73
74 (defun c2ffi-executable-available? ()
75 ;; This is a hack to determine if c2ffi exists; it assumes if it
76 ;; doesn't exist, we will get a return code other than 0.
77 (zerop (nth-value 2 (uiop:run-program `(,*c2ffi-executable* "-h")
78 :ignore-error-status t))))
79
80 (defun run-program* (program args &key (output (if *trace-c2ffi* *standa…
81 (error-output (if *trace-c2ffi* *err…
82 ignore-error-status)
83 (when *trace-c2ffi*
84 (format *debug-io* "~&; Invoking: ~A~{ ~A~}~%" program args))
85 (zerop (nth-value 2 (uiop:run-program (list* program args) :output out…
86 :error-output error-output
87 :ignore-error-status ignore-erro…
88
89 (defun generate-spec-with-c2ffi (input-header-file output-spec-path
90 &key arch sys-include-paths ignore-erro…
91 "Run c2ffi on `INPUT-HEADER-FILE`, outputting to `OUTPUT-FILE` and
92 `MACRO-OUTPUT-FILE`, optionally specifying a target triple `ARCH`."
93 (uiop:with-temporary-file (:pathname tmp-macro-file
94 :keep *trace-c2ffi*)
95 nil ; workaround for an UIOP bug; delme eventually (attila, 2016-01-…
96 :close-stream
97 (let* ((arch (when arch (list "--arch" arch)))
98 (sys-include-paths (loop
99 :for dir :in sys-include-paths
100 :append (list "--sys-include" dir))))
101 ;; Invoke c2ffi to first emit C #define's into TMP-MACRO-FILE. We …
102 ;; to first generate a file of C global variables that are assigne…
103 ;; value of the corresponding #define's, so that in the second pas…
104 ;; the C compiler evaluates for us their right hand side and thus …
105 ;; get hold of their value. This is a kludge and eventually we cou…
106 ;; support generating cffi-grovel files, and in grovel mode not re…
107 ;; on this kludge anymore.
108 (when (run-program* *c2ffi-executable* (list* (namestring input-he…
109 "--driver" "null"
110 "--macro-file" (name…
111 (append arch sys-inc…
112 :output *standard-output*
113 :ignore-error-status ignore-error-status)
114 ;; Write a tmp header file that #include's the original input fi…
115 ;; the above generated macros file which will form the input for…
116 ;; final, second pass.
117 (uiop:with-temporary-file (:stream tmp-include-file-stream
118 :pathname tmp-include-file
119 :keep *trace-c2ffi*)
120 (format tmp-include-file-stream "#include \"~A\"~%" input-head…
121 (format tmp-include-file-stream "#include \"~A\"~%" tmp-macro-…
122 :close-stream
123 ;; Invoke c2ffi again to generate the final output.
124 (run-program* *c2ffi-executable* (list* (namestring tmp-includ…
125 "--output" (namestring…
126 (append arch sys-inclu…
127 :output *standard-output*
128 :ignore-error-status ignore-error-status))))))
129
130 (defun spec-path (base-name &key version (arch (local-arch)))
131 (check-type base-name pathname)
132 (make-pathname :defaults base-name
133 :name (strcat (pathname-name base-name)
134 (if version
135 (strcat "-" version)
136 "")
137 "."
138 arch)
139 :type "spec"))
140
141 (defun find-local-spec (base-name &optional (errorp t))
142 (let* ((spec-path (spec-path base-name))
143 (probed (probe-file spec-path)))
144 (if probed
145 spec-path
146 (when errorp
147 (error "c2ffi spec file not found for base name ~S" base-name)…
148
149 (defun ensure-spec-file-is-up-to-date (header-file-path
150 &key exclude-archs sys-include-pa…
151 (let ((spec-path (find-local-spec header-file-path nil)))
152 (flet ((regenerate-spec-file ()
153 (let ((local-arch (local-arch)))
154 (unless (c2ffi-executable-available?)
155 (error "No spec found for ~S on arch '~A' and c2ffi not…
156 header-file-path local-arch))
157 (generate-spec-with-c2ffi header-file-path
158 (spec-path header-file-path
159 :arch local-arch
160 :version version)
161 :arch local-arch
162 :sys-include-paths sys-include-…
163 ;; Try to run c2ffi for other architectures, but tolerate…
164 (dolist (arch *known-archs*)
165 (unless (or (string= local-arch arch)
166 (member arch exclude-archs :test #'string=))
167 (unless (generate-spec-with-c2ffi header-file-path
168 (spec-path header-f…
169 :arch ar…
170 :version…
171 :arch arch
172 :sys-include-paths …
173 :ignore-error-statu…
174 (warn "Failed to generate spec for other arch: ~S" …
175 (find-local-spec header-file-path))))
176 (if (and spec-path
177 (uiop:timestamp< (file-write-date header-file-path)
178 (file-write-date spec-path)))
179 spec-path ; it's up to date, just return it as is
180 (restart-case
181 (regenerate-spec-file)
182 (touch-old-copy ()
183 :report (lambda (stream)
184 (format stream "Update the modification time of …
185 ;; Make it only be visible when the spec file exists (but …
186 :test (lambda (condition)
187 (declare (ignore condition))
188 (not (null spec-path)))
189 ;; Update the last modification time. Yes, it's convoluted…
190 ;; but I can't see any other way.
191 (with-staging-pathname (tmp-file spec-path)
192 (copy-file spec-path tmp-file))
193 ;; The return value of RESTART-CASE
194 spec-path))))))
You are viewing proxied material from bitreich.org. The copyright of proxied material belongs to its original authors. Any comments or complaints in relation to proxied material should be directed to the original authors of the content concerned. Please see the disclaimer for more details.