forked from Shinmera/qt-libs
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathosx.lisp
100 lines (89 loc) · 4.61 KB
/
osx.lisp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
#|
This file is a part of Qtools
(c) 2015 Shirakumo http://tymoon.eu ([email protected])
Author: Nicolas Hafner <[email protected]>
|#
(in-package #:org.shirakumo.qtools.libs.generator)
;; Detect PM
(eval-when (:compile-toplevel :load-toplevel :execute)
;; Yes you can have multiple ones at the same time, but
;; we only allow one to simplify the code everywhere.
(setf *features* (remove-if (lambda (a) (find a '(:osx-ports :osx-brew :osx-fink))) *features*))
(pushnew (cond ((application-available-p "port") :osx-ports)
((application-available-p "brew") :osx-brew)
((application-available-p "fink") :osx-fink)
(T :osx-nopm)) *features*))
#+osx-ports (status 0 "Detected MacPorts.")
#+osx-brew (status 0 "Detected Homebrew.")
#+osx-fink (status 0 "Detected Fink.")
(defun dylib-dependencies (pathname)
(with-chdir (pathname)
(let ((lines (cl-ppcre:split "\\s*\\n\\s*" (uiop:run-program (format NIL "otool -L ~s" (file-name pathname)) :output :string))))
(mapcar (lambda (line)
(cl-ppcre:register-groups-bind (name) ("^(.*) \\(compatibility version" line)
name))
;; First two lines are the file itself again.
(cddr lines)))))
(defun dylib-set-options (pathname &key name dependencies rpaths add-rpaths remove-rpaths)
(assert (evenp (length dependencies)) ()
"Must supply a balanced number of DEPENDENCY and NEW pairs.")
(assert (evenp (length rpaths)) ()
"Must supply a balanced number of RPATH and NEW pairs.")
(with-chdir (pathname)
(run-here "install_name_tool ~@[-id ~s ~]~
~{-change ~s ~s ~}~
~{-rpath ~s ~s ~}~
~{-add_rpath ~s ~}~
~{-delete_rpath ~s ~}~
~s" name dependencies rpaths add-rpaths remove-rpaths (file-name pathname))))
(defun dylib-set-install-name (pathname name)
(dylib-set-options pathname :name name))
(defun dylib-set-dependency-name (pathname &rest pairs)
(dylib-set-options pathname :dependencies pairs))
(defun levenshtein-distance (a b)
(cond ((= 0 (length a)) (length b))
((= 0 (length b)) (length a))
(T
(let ((v0 (make-array (1+ (length b))))
(v1 (make-array (1+ (length b)))))
(dotimes (i (length v0)) (setf (aref v0 i) i))
(dotimes (i (length a) (aref v1 (length b)))
(incf (aref v1 0))
(dotimes (j (length b))
(let ((cost (if (char= (char a i) (char b j)) 0 1)))
(setf (aref v1 (1+ j)) (min (1+ (aref v1 j))
(1+ (aref v0 (1+ j)))
(+ cost (aref v0 j))))))
(dotimes (j (length v0))
(setf (aref v0 j) (aref v1 j))))))))
;; Attempts to find a good match by a distance function.
(defun find-similar (pathname files)
(cl-ppcre:register-groups-bind (NIL name) ("(lib)?([^.]*)" (file-name pathname))
(second (first (sort (loop for file in files
when (search name (file-name file))
collect (list (levenshtein-distance name (file-name file)) file))
#'< :key #'first)))))
(defun fix-dylib-paths (pathname &optional (replacements (uiop:directory-files pathname)))
;; Primitively change relative paths to use @loader-path and matching name in dir.
(let ((files (remove "dylib" replacements :key #'pathname-type :test-not #'string=))
(pairs ()))
(dolist (dep (dylib-dependencies pathname))
(unless (search "@loader_path/" dep)
(let* ((path (pathname dep))
(new (when (or (uiop:relative-pathname-p path)
(find dep '("/opt/local/" "/usr/local/" "/sw/lib/") :test (lambda (a b) (search b a))))
(let ((corresponding (find-similar (uiop:resolve-symlinks path) files)))
(when corresponding
(format NIL "@loader_path/~a" (uiop:native-namestring
(relative-pathname pathname corresponding))))))))
(when new
(status 0 "Replacing ~a's dependency ~s with ~s."
pathname dep new)
(push new pairs)
(push dep pairs)))))
;; Primitively set the install name to the file-name and set the new deps.
(dylib-set-options pathname :name (file-name pathname) :dependencies pairs))
pathname)
(defun fix-dylib-collection (files)
(dolist (file files)
(fix-dylib-paths file files)))