d2b9842d |
1 | (defpackage #:pkg-config |
bfd180f3 |
2 | (:use #:common-lisp #:clg-utils #+(or cmu clisp) #:ext #+sbcl #:sb-ext) |
3 | #+sbcl |
4 | (:import-from #:sb-int #:featurep) |
5 | (:export #:pkg-cflags #:pkg-libs #:pkg-exists-p #:pkg-version #:pkg-variable) |
6 | (:export #:featurep #:sbcl>=)) |
d2b9842d |
7 | |
8 | (in-package #:pkg-config) |
9 | |
3d36c5d6 |
10 | (defparameter *pkg-config* "/usr/bin/pkg-config") |
0df94f3b |
11 | |
d4f6e417 |
12 | |
f4e547b5 |
13 | #+(or sbcl cmu) |
bfd180f3 |
14 | (defun run-pkg-config (package error-p &rest options) |
0d07716f |
15 | (let ((process |
3d36c5d6 |
16 | (run-program |
0df94f3b |
17 | *pkg-config* (cons package options) :wait t :output :stream))) |
0d07716f |
18 | (unless process |
0df94f3b |
19 | (error "Unable to run ~A" *pkg-config*)) |
3d36c5d6 |
20 | (let ((exit-code (process-exit-code process))) |
bfd180f3 |
21 | (unless (or (not error-p) (zerop exit-code)) |
d4f6e417 |
22 | (error |
23 | (or |
bfd180f3 |
24 | (format nil "~A: ~{~A~%~}" *pkg-config* (read-lines (process-error process))) |
d4f6e417 |
25 | (format nil "~A terminated with exit code ~A" |
26 | *pkg-config* exit-code)))) |
3d36c5d6 |
27 | (let ((output (read-lines (process-output process)))) |
28 | (process-close process) |
d4f6e417 |
29 | (values output exit-code))))) |
0df94f3b |
30 | |
f4e547b5 |
31 | #+clisp |
bfd180f3 |
32 | (defun run-pkg-config (package error-p &rest options) |
33 | (let ((outfile (format nil "/tmp/clg-pkg-config-~A-output" (os:process-id))) |
34 | (errfile (format nil "/tmp/clg-pkg-config-~A-error" (os:process-id)))) |
35 | (unwind-protect |
36 | (let ((exit-code |
37 | (run-shell-command |
38 | (format nil "~A ~A ~{~A ~}2>~A" |
39 | *pkg-config* package |
40 | (mapcar #'(lambda (option) |
41 | (format nil "'~A'" option)) |
42 | options) |
43 | errfile) |
44 | :output outfile :if-output-exists :overwrite))) |
45 | (cond |
46 | ((= exit-code 127) (error "Unable to run ~A" *pkg-config*)) |
47 | ((and error-p (not (zerop exit-code))) |
48 | (with-open-file (output errfile) |
49 | (let ((errmsg (read-lines output))) |
50 | (error |
51 | (if (not errmsg) |
52 | (format nil "~A terminated with exit code ~A" *pkg-config* exit-code) |
53 | (format nil "~A: ~{~A~%~}" *pkg-config* errmsg)))))) |
54 | (t |
55 | (values |
56 | (with-open-file (output outfile) |
57 | (read-lines output)) |
58 | exit-code)))) |
59 | (progn |
60 | (delete-file outfile) |
61 | (delete-file errfile))))) |
62 | |
0df94f3b |
63 | |
64 | (defun pkg-cflags (package) |
d4f6e417 |
65 | (split-string (first (run-pkg-config package t "--cflags")))) |
66 | |
d2b9842d |
67 | (defun pkg-libs (package) |
68 | (split-string (first (run-pkg-config package t "--libs")))) |
69 | |
d4f6e417 |
70 | |
e7a1c08a |
71 | (defun pkg-exists-p (package &key version atleast-version max-version error) |
d4f6e417 |
72 | (let ((version-check |
73 | (cond |
74 | (version (format nil "= ~A" version)) |
75 | (atleast-version (format nil ">= ~A" atleast-version)) |
76 | (max-version (format nil "<= ~A" max-version)) |
77 | (t "")))) |
78 | (if error |
79 | (progn |
80 | (run-pkg-config package t "--print-errors" "--exists" version-check) |
81 | t) |
82 | (multiple-value-bind (output exit-code) |
83 | (run-pkg-config package nil "--exists" version-check) |
84 | (declare (ignore output)) |
85 | (zerop exit-code))))) |
86 | |
87 | |
88 | (defun pkg-version (package) |
89 | (first (run-pkg-config package t "--modversion"))) |
90 | |
91 | |
92 | (defun pkg-variable (package variable) |
93 | (first (run-pkg-config package t "--variable" variable))) |
bfd180f3 |
94 | |
95 | |
96 | (defun |#?-reader| (stream subchar arg) |
97 | (declare (ignore subchar arg)) |
98 | (let ((not-p (when (char= (peek-char nil stream) #\-) |
99 | (read-char stream))) |
100 | (conditional (read stream t nil t))) |
101 | (cond |
102 | (*read-suppress* (read stream t nil t)) |
103 | ((not *read-eval*) |
104 | (error 'reader-error |
105 | :format-control "Attempt to read #? while *READ-EVAL* is bound to NIL." |
106 | :format-arguments nil :stream stream)) |
107 | ((if not-p |
108 | (eval conditional) |
109 | (not (eval conditional))) |
110 | (let ((*read-suppress* t)) |
111 | (read stream t nil t))))) |
112 | (values)) |
113 | |
114 | (set-dispatch-macro-character #\# #\? #'|#?-reader|) |
115 | |
116 | |
117 | #+sbcl |
118 | (progn |
119 | (defun sbcl-version () |
97b1710c |
120 | (let* ((dot1 (position #\. (lisp-implementation-version))) |
121 | (dot2 (position #\. (lisp-implementation-version) :start (1+ dot1)))) |
bfd180f3 |
122 | (values |
123 | (parse-integer (lisp-implementation-version) :end dot1) |
124 | (parse-integer (lisp-implementation-version) :start (1+ dot1) :end dot2) |
97b1710c |
125 | (parse-integer (lisp-implementation-version) :start (1+ dot2) :junk-allowed t)))) |
bfd180f3 |
126 | (defun sbcl>= (req-major req-minor req-micro) |
127 | (multiple-value-bind (major minor micro) (sbcl-version) |
128 | (or |
129 | (> major req-major) |
130 | (and (= major req-major) (> minor req-minor)) |
131 | (and (= major req-major) (= minor req-minor) (>= micro req-micro)))))) |
132 | |
133 | #-sbcl |
134 | (defun sbcl>= (req-major req-minor req-micro) |
135 | (declare (ignore req-major req-minor req-micro)) |
136 | nil) |