|
1 #!/usr/bin/python |
|
2 """fixapplepython23 - Fix Apple-installed Python 2.3 (on Mac OS X 10.3) |
|
3 |
|
4 Python 2.3 (and 2.3.X for X<5) have the problem that building an extension |
|
5 for a framework installation may accidentally pick up the framework |
|
6 of a newer Python, in stead of the one that was used to build the extension. |
|
7 |
|
8 This script modifies the Makefile (in .../lib/python2.3/config) to use |
|
9 the newer method of linking extensions with "-undefined dynamic_lookup" |
|
10 which fixes this problem. |
|
11 |
|
12 The script will first check all prerequisites, and return a zero exit |
|
13 status also when nothing needs to be fixed. |
|
14 """ |
|
15 import sys |
|
16 import os |
|
17 import gestalt |
|
18 |
|
19 MAKEFILE='/System/Library/Frameworks/Python.framework/Versions/2.3/lib/python2.3/config/Makefile' |
|
20 CHANGES=(( |
|
21 'LDSHARED=\t$(CC) $(LDFLAGS) -bundle -framework $(PYTHONFRAMEWORK)\n', |
|
22 'LDSHARED=\t$(CC) $(LDFLAGS) -bundle -undefined dynamic_lookup\n' |
|
23 ),( |
|
24 'BLDSHARED=\t$(CC) $(LDFLAGS) -bundle -framework $(PYTHONFRAMEWORK)\n', |
|
25 'BLDSHARED=\t$(CC) $(LDFLAGS) -bundle -undefined dynamic_lookup\n' |
|
26 ),( |
|
27 'CC=\t\tgcc\n', |
|
28 'CC=\t\t/System/Library/Frameworks/Python.framework/Versions/2.3/lib/python2.3/config/PantherPythonFix/run-gcc\n' |
|
29 ),( |
|
30 'CXX=\t\tc++\n', |
|
31 'CXX=\t\t/System/Library/Frameworks/Python.framework/Versions/2.3/lib/python2.3/config/PantherPythonFix/run-g++\n' |
|
32 )) |
|
33 |
|
34 GCC_SCRIPT='/System/Library/Frameworks/Python.framework/Versions/2.3/lib/python2.3/config/PantherPythonFix/run-gcc' |
|
35 GXX_SCRIPT='/System/Library/Frameworks/Python.framework/Versions/2.3/lib/python2.3/config/PantherPythonFix/run-g++' |
|
36 SCRIPT="""#!/bin/sh |
|
37 export MACOSX_DEPLOYMENT_TARGET=10.3 |
|
38 exec %s "${@}" |
|
39 """ |
|
40 |
|
41 def findline(lines, start): |
|
42 """return line starting with given string or -1""" |
|
43 for i in range(len(lines)): |
|
44 if lines[i][:len(start)] == start: |
|
45 return i |
|
46 return -1 |
|
47 |
|
48 def fix(makefile, do_apply): |
|
49 """Fix the Makefile, if required.""" |
|
50 fixed = False |
|
51 lines = open(makefile).readlines() |
|
52 |
|
53 for old, new in CHANGES: |
|
54 i = findline(lines, new) |
|
55 if i >= 0: |
|
56 # Already fixed |
|
57 continue |
|
58 i = findline(lines, old) |
|
59 if i < 0: |
|
60 print 'fixapplepython23: Python installation not fixed (appears broken)' |
|
61 print 'fixapplepython23: missing line:', old |
|
62 return 2 |
|
63 lines[i] = new |
|
64 fixed = True |
|
65 |
|
66 if fixed: |
|
67 if do_apply: |
|
68 print 'fixapplepython23: Fix to Apple-installed Python 2.3 applied' |
|
69 os.rename(makefile, makefile + '~') |
|
70 open(makefile, 'w').writelines(lines) |
|
71 return 0 |
|
72 else: |
|
73 print 'fixapplepython23: Fix to Apple-installed Python 2.3 should be applied' |
|
74 return 1 |
|
75 else: |
|
76 print 'fixapplepython23: No fix needed, appears to have been applied before' |
|
77 return 0 |
|
78 |
|
79 def makescript(filename, compiler): |
|
80 """Create a wrapper script for a compiler""" |
|
81 dirname = os.path.split(filename)[0] |
|
82 if not os.access(dirname, os.X_OK): |
|
83 os.mkdir(dirname, 0755) |
|
84 fp = open(filename, 'w') |
|
85 fp.write(SCRIPT % compiler) |
|
86 fp.close() |
|
87 os.chmod(filename, 0755) |
|
88 print 'fixapplepython23: Created', filename |
|
89 |
|
90 def main(): |
|
91 # Check for -n option |
|
92 if len(sys.argv) > 1 and sys.argv[1] == '-n': |
|
93 do_apply = False |
|
94 else: |
|
95 do_apply = True |
|
96 # First check OS version |
|
97 if sys.byteorder == 'little': |
|
98 # All intel macs are fine |
|
99 print "fixapplypython23: no fix is needed on MacOSX on Intel" |
|
100 sys.exit(0) |
|
101 |
|
102 if gestalt.gestalt('sysv') < 0x1030: |
|
103 print 'fixapplepython23: no fix needed on MacOSX < 10.3' |
|
104 sys.exit(0) |
|
105 |
|
106 if gestalt.gestalt('sysv') >= 0x1040: |
|
107 print 'fixapplepython23: no fix needed on MacOSX >= 10.4' |
|
108 sys.exit(0) |
|
109 |
|
110 # Test that a framework Python is indeed installed |
|
111 if not os.path.exists(MAKEFILE): |
|
112 print 'fixapplepython23: Python framework does not appear to be installed (?), nothing fixed' |
|
113 sys.exit(0) |
|
114 # Check that we can actually write the file |
|
115 if do_apply and not os.access(MAKEFILE, os.W_OK): |
|
116 print 'fixapplepython23: No write permission, please run with "sudo"' |
|
117 sys.exit(2) |
|
118 # Create the shell scripts |
|
119 if do_apply: |
|
120 if not os.access(GCC_SCRIPT, os.X_OK): |
|
121 makescript(GCC_SCRIPT, "gcc") |
|
122 if not os.access(GXX_SCRIPT, os.X_OK): |
|
123 makescript(GXX_SCRIPT, "g++") |
|
124 # Finally fix the makefile |
|
125 rv = fix(MAKEFILE, do_apply) |
|
126 #sys.exit(rv) |
|
127 sys.exit(0) |
|
128 |
|
129 if __name__ == '__main__': |
|
130 main() |