source: orange/install-scripts/mac/build-osx-app-template.sh @ 11774:c75652222fa2

Revision 11774:c75652222fa2, 9.9 KB checked in by Ales Erjavec <ales.erjavec@…>, 5 months ago (diff)

Install PIL inside OSX application bundle, disable user site packages.

  • Property exe set to *
Line 
1#!/bin/bash -e
2#
3# Create (build) an Orange application bundle template
4#
5# example usage:
6#
7#   $ build-osx-app-template.sh $HOME/Orange.app
8#
9# Prerequisites:
10#     a working gcc compiler toolchain
11#     a working gfortran compiler on PATH
12
13
14function print_usage () {
15echo 'build-osx-app-template.sh [-t] [-k] some_path/Orange.app
16
17Build an Orange application template from scratch.
18This will download and build all requirements (Python, Qt4, ...) for a
19standalone .app distribution.
20
21Warning: This will take a lot of time.
22
23Options:
24    -t --build-temp DIR   A temporary build directory.
25    -k --keep-temp        Do not delete the temp directory after build.
26    -h --help             Print this help.
27'
28}
29
30while [[ ${1:0:1} = "-" ]]; do
31    case $1 in
32        -t|--build-temp)
33            BUILD_TEMP=$2
34            shift 2
35            ;;
36        -k|--keep-temp)
37            KEEP_TEMP=1
38            shift 1
39            ;;
40        -h|--help)
41            print_usage
42            exit 0
43            ;;
44        -*)
45            echo "Unknown option $1" >&2
46            print_usage
47            exit 1
48            ;;
49    esac
50done
51
52
53if [[ $BUILD_TEMP ]]; then
54    mkdir -p "$BUILD_TEMP"
55else
56    BUILD_TEMP=$(mktemp -d -t build-template)
57fi
58
59APP=$1
60
61if [[ ! $APP ]]; then
62    echo "Target application path must be specified" >&2
63    print_usage
64    exit 1
65fi
66
67mkdir -p "$APP"
68
69# Convert to absolute path
70APP=$(cd "$APP"; pwd)
71
72# Get absolute path to the bundle-lite template
73SCRIPT_DIR_NAME=$(dirname "$0")
74# Convert to absolute path
75SCRIPT_DIR_NAME=$(cd "$SCRIPT_DIR_NAME"; pwd)
76BUNDLE_LITE=$SCRIPT_DIR_NAME/bundle-lite/Orange.app
77
78
79# Versions of included 3rd party software
80
81PYTHON_VER=2.7.5
82PIP_VER=1.3.1
83DISTRIBUTE_VER=0.6.49
84NUMPY_VER=1.7.1
85SCIPY_VER=0.12.0
86QT_VER=4.7.4
87SIP_VER=4.14.6
88PYQT_VER=4.10.1
89PYQWT_VER=5.2.0
90
91# Number of make jobs
92MAKE_JOBS=${MAKE_JOBS:-$(sysctl -n hw.physicalcpu)}
93
94PYTHON=$APP/Contents/MacOS/python
95EASY_INSTALL=$APP/Contents/MacOS/easy_install
96PIP=$APP/Contents/MacOS/pip
97
98export MACOSX_DEPLOYMENT_TARGET=10.5
99
100SDK=/Developer/SDKs/MacOSX$MACOSX_DEPLOYMENT_TARGET.sdk
101
102
103function create_template {
104    # Create a minimal .app template with the expected dir structure
105    # Info.plist and icons.
106
107    mkdir -p "$APP"
108    mkdir -p "$APP"/Contents/MacOS
109    mkdir -p "$APP"/Contents/Resources
110
111    # Copy icons and Info.plist
112    cp "$BUNDLE_LITE"/Contents/Resources/* "$APP"/Contents/Resources
113    cp "$BUNDLE_LITE"/Contents/Info.plist "$APP"/Contents/Info.plist
114
115    cp "$BUNDLE_LITE"/Contents/PkgInfo $APP/Contents/PkgInfo
116
117    cat <<-'EOF' > "$APP"/Contents/MacOS/ENV
118        # Create an environment for running python from the bundle
119        # Should be run as "source ENV"
120
121        BUNDLE_DIR=`dirname "$0"`/../
122        BUNDLE_DIR=`perl -MCwd=realpath -e 'print realpath($ARGV[0])' "$BUNDLE_DIR"`/
123        FRAMEWORKS_DIR="$BUNDLE_DIR"Frameworks/
124        RESOURCES_DIR="$BUNDLE_DIR"Resources/
125
126        PYVERSION="2.7"
127
128        PYTHONEXECUTABLE="$FRAMEWORKS_DIR"Python.framework/Resources/Python.app/Contents/MacOS/Python
129        PYTHONHOME="$FRAMEWORKS_DIR"Python.framework/Versions/"$PYVERSION"/
130
131        DYLD_FRAMEWORK_PATH="$FRAMEWORKS_DIR"${DYLD_FRAMEWORK_PATH:+:$DYLD_FRAMEWORK_PATH}
132
133        export PYTHONEXECUTABLE
134        export PYTHONHOME
135        export PYTHONNOUSERSITE=1
136
137        export DYLD_FRAMEWORK_PATH
138
139        # Some non framework libraries are put in $FRAMEWORKS_DIR by machlib standalone
140        export DYLD_LIBRARY_PATH="$FRAMEWORKS_DIR"${DYLD_LIBRARY_PATH:+:$DYLD_LIBRARY_PATH}
141EOF
142
143}
144
145function install_python() {
146    download_and_extract "http://www.python.org/ftp/python/$PYTHON_VER/Python-$PYTHON_VER.tgz"
147
148    pushd Python-$PYTHON_VER
149
150    # _hashlib import fails with  Symbol not found: _EVP_MD_CTX_md
151    # The 10.5 sdk's libssl does not define it (even though it is v 0.9.7)
152    patch setup.py -i - <<-'EOF'
153        834c834
154        <         min_openssl_ver = 0x00907000
155        ---
156        >         min_openssl_ver = 0x00908000
157EOF
158
159    ./configure --enable-framework="$APP"/Contents/Frameworks \
160                --prefix="$APP"/Contents/Resources \
161                --with-universal-archs=intel \
162                --enable-universalsdk="$SDK"
163
164    make -j $MAKE_JOBS
165
166    # We don't want to install IDLE.app, Python Launcher.app, in /Applications
167    # on the build system.
168    make install PYTHONAPPSDIR=$(pwd)
169
170    popd
171
172    # PythonAppStart will be used for starting the application GUI.
173    # This needs to be symlinked here for Desktop services to read the app's
174    # Info.plist and not the contained Python.app's
175    ln -fs ../Frameworks/Python.framework/Resources/Python.app/Contents/MacOS/Python "$APP"/Contents/MacOS/PythonAppStart
176    ln -fs ../Frameworks/Python.framework/Resources/Python.app "$APP"/Contents/Resources/Python.app
177
178    cat <<-'EOF' > "$APP"/Contents/MacOS/python
179        #!/bin/bash
180
181        DIRNAME=$(dirname "$0")
182
183        # Set the proper env variables
184        source "$DIRNAME"/ENV
185
186        exec -a "$0" "$PYTHONEXECUTABLE" "$@"
187EOF
188
189    chmod +x "$APP"/Contents/MacOS/python
190
191    "$PYTHON" -c"import sys, hashlib"
192
193}
194
195function install_pip() {
196    download_and_extract "https://pypi.python.org/packages/source/p/pip/pip-$PIP_VER.tar.gz"
197
198    pushd pip-$PIP_VER
199
200    "$PYTHON" setup.py install
201    create_shell_start_script pip
202
203    "$PIP" --version
204
205    popd
206}
207
208function install_distribute() {
209    download_and_extract "https://pypi.python.org/packages/source/d/distribute/distribute-$DISTRIBUTE_VER.tar.gz"
210
211    pushd distribute-$DISTRIBUTE_VER
212
213    "$PYTHON" setup.py install
214    create_shell_start_script easy_install
215
216    "$EASY_INSTALL" --version
217
218    popd
219}
220
221function install_ipython {
222    # install with easy_install (does not work with pip)
223    "$EASY_INSTALL" ipython
224    create_shell_start_script ipython
225}
226
227function install_qt4 {
228    QT_VER_SHORT=${QT_VER%%\.[0-9]}
229
230    # 4.8.* (4.8 does not compile for x86_64 using 10.5 SDK)
231    #download_and_extract "http://download.qt-project.org/official_releases/qt/$QT_VER_SHORT/$QT_VER/qt-everywhere-opensource-src-$QT_VER.tar.gz"
232
233    # 4.7 or older
234    download_and_extract "http://download.qt-project.org/archive/qt/$QT_VER_SHORT/qt-everywhere-opensource-src-$QT_VER.tar.gz"
235
236    pushd qt-everywhere-opensource-src-$QT_VER
237
238    yes yes | ./configure -prefix "$APP"/Contents/Resources/Qt4 \
239                -libdir "$APP"/Contents/Frameworks \
240                -framework \
241                -release \
242                -opensource \
243                -no-qt3support \
244                -arch x86 -arch x86_64 \
245                -no-sql-psql \
246                -no-sql-ibase \
247                -no-sql-mysql \
248                -no-sql-odbc \
249                -no-sql-sqlite \
250                -no-sql-sqlite2 \
251                -nomake examples \
252                -nomake demos \
253                -nomake docs \
254                -nomake translations \
255                -sdk "$SDK"
256
257    make -j $MAKE_JOBS
258    make install
259
260    # Register plugins with Qt.
261    cat <<-EOF > "$APP"/Contents/Resources/qt.conf
262        [Paths]
263        Plugins = Resources/Qt4/plugins
264EOF
265
266    # In case the Python executable is invoked directly (not through
267    # Contents/MacOS/python) we also want it to find the plugins.
268    cat <<-EOF > "$APP"/Contents/Frameworks/Python.framework/Resources/Python.app/Contents/Resources/qt.conf
269        [Paths]
270        Plugins = ../../../../../Resources/Qt4/plugins
271EOF
272
273    popd
274}
275
276function install_sip {
277    download_and_extract "http://sourceforge.net/projects/pyqt/files/sip/sip-$SIP_VER/sip-$SIP_VER.tar.gz"
278    pushd sip-$SIP_VER
279
280    "$PYTHON" configure.py  --arch i386 --arch x86_64 --sdk "$SDK"
281
282    make -j $MAKE_JOBS
283    make install
284
285    "$PYTHON" -c"import sip"
286
287    popd
288
289}
290
291function install_pyqt4 {
292    download_and_extract "http://sourceforge.net/projects/pyqt/files/PyQt4/PyQt-$PYQT_VER/PyQt-mac-gpl-$PYQT_VER.tar.gz"
293    pushd PyQt-mac-gpl-$PYQT_VER
294
295    yes yes | "$PYTHON" configure.py --qmake "$APP"/Contents/Resources/Qt4/bin/qmake
296
297    make -j $MAKE_JOBS
298    make install
299
300    "$PYTHON" -c"from PyQt4 import QtGui, QtWebKit, QtSvg, QtNetwork"
301
302    popd
303}
304
305function install_pyqwt5 {
306    download_and_extract "http://sourceforge.net/projects/pyqwt/files/pyqwt5/PyQwt-$PYQWT_VER/PyQwt-$PYQWT_VER.tar.gz"
307
308    pushd PyQwt-$PYQWT_VER/configure
309
310    # configure.py fails (with ld: library not found for -lcrt1.10.5.o) trying to
311    # build static libraries
312    export CPPFLAGS="--shared"
313
314    PYQWT_VER_SHORT=${PYQWT_VER%%\.[0-9]}
315
316    "$PYTHON" configure.py -Q ../qwt-$PYQWT_VER_SHORT \
317                        --extra-cflags="-arch i386 -arch x86_64" \
318                        --extra-cxxflags="-arch i386 -arch x86_64" \
319                        --extra-lflags="-arch i386 -arch x86_64"
320    make -j $MAKE_JOBS
321    make install
322
323    unset CPPFLAGS
324
325    "$PYTHON" -c"import PyQt4.Qwt5"
326
327    popd
328}
329
330function install_numpy {
331    "$PIP" install numpy==$NUMPY_VER
332
333    "$PYTHON" -c"import numpy"
334}
335
336function install_scipy {
337    # This is tricky (req gfortran)
338    "$PIP" install scipy==$SCIPY_VER
339
340    "$PYTHON" -c"import scipy"
341}
342
343function download_and_extract() {
344    # Usage: download_and_extract http://example/source.tar.gz
345    #
346    # Download the specified .tar source package and extract it in the current dir
347    # If the source package is already present only extract it
348
349    URL=$1
350    if [[ ! $URL ]]; then
351        echo "An url expected"
352        exit 1
353    fi
354
355    SOURCE_TAR=$(basename "$URL")
356
357    if [[ ! -e $SOURCE_TAR ]]; then
358        echo "Downloading $SOURCE_TAR"
359        curl --fail -L --max-redirs 3 "$URL" -o "$SOURCE_TAR".part
360        mv "$SOURCE_TAR".part "$SOURCE_TAR"
361    fi
362    tar -xzf "$SOURCE_TAR"
363}
364
365
366function create_shell_start_script() {
367    # Usage: create_shell_start_script pip
368    #
369    # create a start script for the specified script in $APP/Contents/MacOS
370
371    SCRIPT=$1
372
373    cat <<-'EOF' > "$APP"/Contents/MacOS/"$SCRIPT"
374        #!/bin/bash
375
376        DIRNAME=$(dirname "$0")
377        NAME=$(basename "$0")
378
379        # Set the proper env variables
380        source "$DIRNAME"/ENV
381
382        exec -a "$0" "$DIRNAME"/python "$FRAMEWORKS_DIR"/Python.framework/Versions/Current/bin/"$NAME" "$@"
383EOF
384
385    chmod +x "$APP"/Contents/MacOS/"$SCRIPT"
386}
387
388function cleanup {
389    # Cleanup the application bundle by removing unnecesary files.
390    find "$APP"/Contents/ \( -name '*~' -or -name '*.bak' -or -name '*.pyc' -or -name '*.pyo' \) -delete
391
392    find "$APP"/Contents/Frameworks -name '*_debug*' -delete
393
394    find "$APP"/Contents/Frameworks -name '*.la' -delete
395    find "$APP"/Contents/Frameworks -name '*.a' -delete
396    find "$APP"/Contents/Frameworks -name '*.prl' -delete
397}
398
399function make_standalone {
400    "$PIP" install macholib
401    "$PYTHON" -m macholib standalone $APP
402    yes y | "$PIP" uninstall altgraph
403    yes y | "$PIP" uninstall macholib
404}
405
406pushd $BUILD_TEMP
407
408echo "Building template in $BUILD_TEMP"
409echo
410
411create_template
412
413install_python
414
415install_distribute
416
417install_pip
418
419install_numpy
420
421install_scipy
422
423install_qt4
424
425install_sip
426
427install_pyqt4
428
429install_pyqwt5
430
431install_ipython
432
433make_standalone
434
435cleanup
436
437popd
438
439if [[ ! $KEEP_TEMP ]]; then
440    rm -rf $BUILD_TEMP
441fi
Note: See TracBrowser for help on using the repository browser.