/[ascend]/trunk/scons/installgtk.py
ViewVC logotype

Contents of /trunk/scons/installgtk.py

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2144 - (show annotations) (download) (as text)
Wed Dec 23 13:04:19 2009 UTC (14 years, 6 months ago) by jpye
File MIME type: text/x-python
File size: 6593 byte(s)
More on mac issues.
1 # SCons support for bundled GTK installation
2 # Written by John Pye, Nov 2009
3
4
5 """
6 This tool installs the necessary files to allow GTK to run in a standalone
7 installation.
8
9 This approach is suitable for Mac (and maybe for Windows too) where we often
10 must assume that GTK+ is not separately installed on the system, or can't assume
11 that the version will be compatible.
12
13 Ultimately, it would be desirable for a Mac 'framework' to be utilised for this
14 purpose, but that option is not yet available.
15
16 Currently, this tool is a command-line thing that you must run after ASCEND
17 has been compiled, but before you run 'scons install'. It will copy all the
18 necessary files into dist/PyGTK.bundle; these files will then be copied by SCons
19 into their files (.dmg preparation folder) location.
20 """
21
22 import os.path
23 import glob
24 import subprocess, sys, os.path, re, shutil
25 from distutils.dir_util import copy_tree
26
27 otool_re = re.compile(r"""\s+(.+)\s\(compatibility version (.*), current version (.*)\)""")
28
29 def find_deps(binary):
30 deps = set()
31 P = subprocess.Popen(['/usr/bin/otool','-L',binary],stdout=subprocess.PIPE)
32 O = P.communicate()[0].strip()
33 for o in O.split("\n")[1:]:
34 m = otool_re.match(o)
35 #print " -->",m.group(1)
36 deps.add(m.group(1))
37 return deps
38
39 def reroute_deps(lib,gtksite,pysite,orig):
40 deps = find_deps(lib)
41 lib_is_gtk = (os.path.commonprefix([gtksite,orig]) == gtksite)
42 lib_is_py = (os.path.commonprefix([pysite,orig]) == pysite)
43 if lib_is_py:
44 print "LIB %s IS PY" % orig
45 if lib_is_gtk:
46 print "LIB %s IS GTK" % orig
47
48 rpath_used = False
49 for d in deps:
50 oldpath = d
51 r = os.path.commonprefix([oldpath,gtksite])
52 if r == gtksite:
53 # this dependency is pointing into the GTK installation location
54 dir, f = os.path.split(oldpath)
55 if lib_is_gtk:
56 newpath = "@loader_path/"+f
57 elif lib_is_py:
58 # construct relative path from python lib to GTK libs
59 uplevels = 1
60 rel = orig[len(os.path.commonprefix([pysite,orig])):]
61 print "RELPATH = ",rel
62 dir1,tail = os.path.split(rel)
63 while dir1:
64 uplevels += 1
65 dir1, tail = os.path.split(dir1)
66 newpath = "@loader_path" + ("/.."*uplevels) + "/lib/" + f
67 else:
68 r = os.path.commonprefix([oldpath,pysite])
69 if r == pysite:
70 # this dependency is pointing to a file installed inside Python
71 newpath = "python/" + oldpath[len(r):]
72 else:
73 continue
74
75 cmd = ['/usr/bin/install_name_tool','-change',oldpath,newpath,lib]
76 print "RELINK %s: %s --> %s" % (lib,oldpath,newpath)
77 #print " ".join(cmd)
78 P = subprocess.Popen(cmd,stdout=subprocess.PIPE)
79 P.communicate()
80 rpath_used = True
81
82 def find_and_replace(fname, pattern, replace):
83 t = open(fname).read()
84 t1 = pattern.sub(replace,t)
85 f = open(fname,'w')
86 f.write(t1)
87 f.close()
88
89 if __name__ == "__main__":
90 import modulefinder
91 M = modulefinder.ModuleFinder()
92 sys.path.append("..")
93 script = os.path.normpath(os.path.join(sys.path[0],"../pygtk/gtkbrowser.py"))
94 M.run_script(script)
95
96 pysite="/Library/Python/2.5/site-packages/"
97 if pysite[-1:]!="/":
98 raise RuntimeError("missing trailing slash in pysite")
99
100 gtksite = os.path.expanduser("~/gtk/inst/")
101 if gtksite[-1:]!="/":
102 raise RuntimeError("missing trailing slash in gtksite")
103
104 imports = set()
105 ignore_paths = ['/System/Library/Frameworks/Python.framework'
106 ,'/System/Library/Frameworks/Carbon.framework'
107 ,'/System/Library/Frameworks/Cocoa.framework'
108 ,'/usr/lib'
109 ,os.path.dirname(script)]
110 for name, m in M.modules.items():
111 if not m.__file__:
112 continue
113 ok = True
114 for i in ignore_paths:
115 if os.path.commonprefix([i,m.__file__]) == i:
116 ok = False
117 if ok is False:
118 continue
119
120 imports.add(m)
121 print m
122
123 print "\n\nChecking otool deps"
124
125 files = set()
126 pyfiles = set()
127 for m in imports:
128 files.add(m.__file__)
129
130 if m.__file__[-3:] == ".so":
131 print "FILE:",m.__file__
132 files |= find_deps(m.__file__)
133
134 elif m.__file__[-3:] == ".py":
135 print "PY:",m.__file__
136 pyfiles.add(m.__file__)
137
138 print "\n\nOTOOL DEPS"
139 for f in files:
140 if f[-3:] != ".py":
141 print f
142
143 print "\nAdd pixbuf loaders to list..."
144 loaders = glob.glob(gtksite+"lib/gtk-2.0/*/loaders/libpixbufloader-*.so")
145 for l in loaders:
146 print l
147 files.add(l)
148
149 print "\n\nFinding all GTK libs in the list"
150 gtkimports = set()
151 for f in files:
152 if os.path.commonprefix([gtksite,f]) == gtksite:
153 gtkimports.add(f)
154 print f
155
156 print "\n\nFinding all Python site-packages stuff in the list"
157 pyimports = set()
158 for f in files:
159 if os.path.commonprefix([pysite,f]) == pysite:
160 pyimports.add(f)
161 print f
162
163 # define the paths into which we'll copy all the stuff
164 distpath = os.path.normpath(os.path.join(sys.path[0],"../dist"))
165 targetpath = os.path.join(distpath,"PyGTK.bundle")
166 pytarget = os.path.join(targetpath,"python")
167 gtktarget = targetpath
168 gtklibtarget = os.path.join(gtktarget,"lib")
169
170 print "\n\nCopying all Python files into our bundle"
171 for f in pyfiles | pyimports:
172 if not os.path.commonprefix([f,pysite]) == pysite:
173 raise RuntimeError("Unknown python import '%s' in list" % f)
174 r = f[len(pysite):]
175 dir, f1 = os.path.split(r)
176 if not os.path.exists(os.path.join(pytarget,dir)):
177 os.makedirs(os.path.join(pytarget,dir))
178 print r
179 dest = os.path.join(pytarget,r)
180 shutil.copy(f, dest)
181 if dest[-3:] == ".so":
182 print " rerouting dependencies..."
183 reroute_deps(dest,gtksite,pysite,orig=f)
184
185 print "\n\nCopy all GTK libs into our bundle"
186 if not os.path.exists(gtklibtarget):
187 os.makedirs(gtklibtarget)
188 for f in gtkimports:
189 if not os.path.commonprefix([f, gtksite]) == gtksite:
190 raise RuntimeError("Unknown gtk import in list")
191 r = f[len(gtksite):]
192 dir, f1 = os.path.split(r)
193 dest = os.path.join(gtklibtarget, f1)
194 print dest
195 shutil.copy(f, dest)
196 reroute_deps(dest,gtksite,pysite,orig=f)
197
198 print "\nCopying GTK related files"
199 reldirs = ["etc/gtk-2.0", "etc/pango", "etc/fonts"]
200 for d in reldirs:
201 print "%s --> %s" % (os.path.join(gtksite,d),os.path.join(gtktarget,d))
202 copy_tree(os.path.join(gtksite,d),os.path.join(gtktarget,d))
203
204 print "\nFixing pixbuf loader paths"
205 loaderre = re.compile("%slib/gtk-2\\.0/[^/]+/loaders/" % re.escape(gtksite))
206 find_and_replace("%s/etc/gtk-2.0/gdk-pixbuf.loaders"%gtktarget,loaderre,"@loader_path/")
207
208 print "\nFixing absolute path sin GTK etc files"
209 etcfiles = ["%s/etc/%s" % (gtktarget, f) for f in
210 ['gtk-2.0/gtk.immodules', 'pango/pango.modules'] #'pango/pangorc',
211 ]
212 etcre = re.compile("%s"%re.escape(gtksite))
213 for e in etcfiles:
214 print e
215
216 print "\nTODO: copy localisation files (not yet implemented)"
217 #SHARE=`echo $PREFIX/share/locale/*/LC_MESSAGES/gimp*`
218
219
220
221
222

john.pye@anu.edu.au
ViewVC Help
Powered by ViewVC 1.1.22