Project

General

Profile

Bundle-python » History » Version 33

Adrian Georgescu, 11/08/2016 03:13 PM

1 1 Saúl Ibarra Corretgé
h1. Building a Python Framework to bundle inside Blink
2
3
In order to avoid using the system Python a custom Framework build is needed. Using a bundled Python version will make the package bigger in size, but all package versions are controlled and not up to the environment. Also, we can use the latest Python version, with latest bugfixes and features, since Apple only updates the system Python version on every major OS release.
4
5 13 Saúl Ibarra Corretgé
The following instructions only apply for 64bit builds, 32bit builds are no longer supported.
6 7 Adrian Georgescu
7 22 Adrian Georgescu
Blink dependencies must be installed under the following directory structure:
8
9
* Distribution/Frameworks/
10
* Distribution/Resources/lib
11 1 Saúl Ibarra Corretgé
 
12 7 Adrian Georgescu
h2. Building the Python Framework itself
13 1 Saúl Ibarra Corretgé
14 18 Saúl Ibarra Corretgé
* Install it using Homebrew
15 1 Saúl Ibarra Corretgé
16
<pre>
17 18 Saúl Ibarra Corretgé
brew install python
18 1 Saúl Ibarra Corretgé
</pre>
19
20 18 Saúl Ibarra Corretgé
The framework will be installed and linked with Homebrew supplied OpenSSL and SQLite versions. Those libraries will need to be copied too.
21 1 Saúl Ibarra Corretgé
22 18 Saúl Ibarra Corretgé
*NOTE*: Be careful when copying the framework around, it contains symlinks and if @cp -r@ is used the size will we doubled, use @cp -a@ instead.
23 22 Adrian Georgescu
24
The Python framework is found in
25
26
<pre>
27 27 Adrian Georgescu
cp -a /usr/local/Cellar/python/2.7.12_2/Frameworks/Python.framework ~/work/blink/Distribution/Frameworks/
28 22 Adrian Georgescu
</pre>
29
30 2 Saúl Ibarra Corretgé
* Reduce the size of the Python Framework:
31
32 1 Saúl Ibarra Corretgé
There are a number of things that can (and must when submitting a sandbox app to Mac App Store) be removed from the framework directory to make it smaller in size:
33
34
<pre>
35 27 Adrian Georgescu
cd ~/work/blink/Distribution/Frameworks//Python.framework
36 26 Adrian Georgescu
find . -name *.pyc -exec rm -r "{}" \; 
37
find . -name *.pyo -exec rm -r "{}" \; 
38 24 Adrian Georgescu
rm -r Versions/Current/lib/python2.7/config/python.o
39
rm -r Versions/Current/Mac
40
rm -r Versions/Current/bin
41
rm -r Versions/Current/share
42
rm -r Versions/Current/Resources/*
43
rm -r Versions/Current/Resources/*.app
44
rm -r Versions/Current/lib/python2.7/test
45
rm -r Versions/Current/lib/python2.7/plat-*
46
rm -r Versions/Current/lib/python2.7/idlelib
47
rm -r Versions/Current/lib/python2.7/curses
48
rm -r Versions/Current/lib/python2.7/lib2to3
49
rm -r Versions/Current/lib/python2.7/lib-tk
50
rm -r Versions/Current/lib/python2.7/bsddb
51
rm -r Versions/Current/lib/python2.7/lib-dynload/gdbm.so
52
rm -r Versions/Current/lib/python2.7/lib-dynload/readline.so
53 1 Saúl Ibarra Corretgé
</pre>
54 3 Saúl Ibarra Corretgé
55 1 Saúl Ibarra Corretgé
Replace @Versions/Current/lib/python2.7/site.py@ with an empty file.
56 28 Adrian Georgescu
57
<pre>
58
rm Versions/Current/lib/python2.7/site.py
59
touch Versions/Current/lib/python2.7/site.py
60
</pre>
61 5 Saúl Ibarra Corretgé
62
h2. Compiling PyObjC
63
64 13 Saúl Ibarra Corretgé
In order to get a PyObjC version that will work with the framework created above (Python 2.7, 64bits) an equivalent Python must be used to compile it. That is, if has to be a Python 2.7 version (it doesn't have to be the exact version) and it has to be a 64bit version. The MACOSX_DEPLOYMENT_TARGET must also be set to the appropriate value.
65 5 Saúl Ibarra Corretgé
66
PyObjcC can be installed with easy_install or pip. We install it in 2 steps to save some compilation time due to a bug in the build system:
67 1 Saúl Ibarra Corretgé
68 5 Saúl Ibarra Corretgé
<pre>
69
pip install pyobjc-core
70
pip install pyobjc
71 23 Adrian Georgescu
pip install pycrypto
72 1 Saúl Ibarra Corretgé
</pre>
73
74 5 Saúl Ibarra Corretgé
When compiling PyObjC a Python package will be created for every system framework, but not all of them are needed (at the moment), so just pick the ones we use:
75
76
<pre>
77
AddressBook
78
AppKit
79 1 Saúl Ibarra Corretgé
Cocoa
80 5 Saúl Ibarra Corretgé
CoreFoundation
81
Foundation
82 13 Saúl Ibarra Corretgé
JavaScriptCore
83 5 Saúl Ibarra Corretgé
LaunchServices
84 1 Saúl Ibarra Corretgé
PyObjCTools
85
Quartz
86 13 Saúl Ibarra Corretgé
ScriptingBridge
87
StoreKit
88 1 Saúl Ibarra Corretgé
WebKit
89 8 Adrian Georgescu
objc
90 6 Saúl Ibarra Corretgé
</pre>
91
92 1 Saúl Ibarra Corretgé
93 21 Adrian Georgescu
For example this is the content of a Resources/lib bundled with Blink Cocoa as of November 3rd, 2016 (including sipsimple dependencies & all):
94 20 Adrian Georgescu
95 1 Saúl Ibarra Corretgé
<pre>
96
AVFoundation
97
AddressBook
98
AppKit
99
Cocoa
100
CoreFoundation
101
Crypto
102
Foundation
103
LaunchServices
104
PyObjCTools
105
Quartz
106
ScriptingBridge
107
WebKit
108
_cffi_backend.so
109
_ldap.so
110
_markerlib
111
application
112
cffi
113
cjson.so
114
cryptography
115
cryptography-1.5.1.dist-info
116
dateutil
117
dns
118
dsml.py
119
enum
120
eventlib
121
formencode
122
gmpy2.so
123
gnutls
124
greenlet.so
125
idna
126
ipaddress.py
127
ldap
128
ldapurl.py
129
ldif.py
130
lxml
131
msrplib
132
objc
133
otr
134
pkg_resources
135
pyasn1
136
pycparser
137
pydispatch
138
pytz
139
service_identity
140
sipsimple
141
six.py
142
sqlobject
143
twisted
144
xcaplib
145 21 Adrian Georgescu
</pre>
146
147
148
*NOTE:* The _objc_ package is located inside a _PyObjC_ directory, just copy it from there, without the parent directory.
149
150
*NOTE:* _PyObjCTools_ is not a valid Python package, as it lacks a @__init__.py@ file, an empty one needs to be manually created with this content:
151
152
<pre>
153
__import__('pkg_resources').declare_namespace(__name__)
154
</pre>
155
156 25 Adrian Georgescu
h2. Fix library paths
157
158
All libraries must have their relative path change to the Framework path bundled within Blink.app
159
160
<pre>
161
#!/bin/sh
162
163
old_path="local/lib/\|local/Cellar/\|/usr/local/opt/libmpc/lib/\|/usr/local/opt/mpfr/lib/\|Frameworks/Frameworks/\|/Users/adigeo/work/ag-projects/video/local/lib/"
164
new_path="@executable_path/../Frameworks/"
165
166
for library in $@; do
167
  install_name_tool -id $new_path$library $library
168
  dependencies=$(otool -L $library | grep $old_path | awk '{print $1}')
169
  for dependency in $dependencies; do
170
      new_basename=$(basename $dependency)
171
      new_name="$new_path$new_basename"
172
      echo $dependency $new_name $library
173
      install_name_tool -change $dependency $new_name $library
174
  done
175 1 Saúl Ibarra Corretgé
done
176
</pre>
177
178
A script is available in ./build_scripts/ directory
179
180
<pre>
181
./build_scripts/change_lib_names.sh Distribution/Frameworks/Python.framework/Versions/2.7/lib/python2.7/lib-dynload/*.so
182
chmod +w Distribution/Frameworks/Python.framework/Versions/Current/Python
183
./build_scripts/change_lib_names.sh Distribution/Frameworks/Python.framework/Versions/Current/Python
184
</pre>
185
186 33 Adrian Georgescu
*NOTE*: Python.framework as well as all other libraries must be signed using command line tools. Make sure when building Blink that "Code sign on copy" option is disabled for Python.framework. This script can be used to sign all libraries and frameworks
187
188
<pre>
189
sos=`find ./Resources/lib -name *.so`; for s in $sos; do codesign -f -s '3rd Party Mac Developer Application: AG Projects' $s; done
190
sos=`find ./Frameworks -name *.dylib`; for s in $sos; do codesign -f -s '3rd Party Mac Developer Application: AG Projects' $s; done
191
sos=`find ./Frameworks -name *.so`; for s in $sos; do codesign -f -s '3rd Party Mac Developer Application: AG Projects' $s; done
192
sos=`find ./Frameworks -name *.o`; for s in $sos; do codesign -f -s '3rd Party Mac Developer Application: AG Projects' $s; done
193
sos=`find ./Frameworks -name *.a`; for s in $sos; do codesign -f -s '3rd Party Mac Developer Application: AG Projects' $s; done
194
</pre>
195
196
A script is available in ./build_scripts/ directory
197
198
<pre>
199
./build_scripts/codesign.sh 
200
</pre>
201 29 Adrian Georgescu
202 21 Adrian Georgescu
h2. Module exceptions
203
204
When copying built Python modules into the distribution folder, care must be taken with the 2 following packages:
205
206
* zope: an empty @__init__.py@ file must be created in the @zope@ directory
207
* cryptography: the @*-dist.info@ must be copied too
208
209
h1. Creating a sandbox (Python virtualenv)
210
211
<pre>
212
sudo easy_install pip
213
sudo pip install virtualenv virtualenvwrapper
214
</pre>
215
216
Add to ~.bashrc
217
218
<pre>
219
# Virtualenv
220
export WORKON_HOME=$HOME/.virtualenvs
221
export PIP_VIRTUALENV_BASE=$WORKON_HOME
222
export PIP_RESPECT_VIRTUALENV=true
223
export VIRTUALENVWRAPPER_SCRIPT=/usr/local/bin/virtualenvwrapper.sh
224
[[ -f /usr/local/bin/virtualenvwrapper_lazy.sh ]] && source /usr/local/bin/virtualenvwrapper_lazy.sh
225
</pre>
226
227
Creating a sandbox:
228
229
<pre>
230
mkvirtualenv -p $(which python2.7) sandbox
231
</pre>
232
233
Exiting the sandbox:
234
235
<pre>
236
deactivate
237
</pre>
238
239
Entering the sandbox:
240
241
<pre>
242
workon sandbox
243 19 Adrian Georgescu
</pre>