-
Notifications
You must be signed in to change notification settings - Fork 58
Expand file tree
/
Copy pathbuild_python_framework
More file actions
executable file
·214 lines (184 loc) · 10.8 KB
/
build_python_framework
File metadata and controls
executable file
·214 lines (184 loc) · 10.8 KB
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
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
#!/bin/zsh
#
# Build script for universal Python 3 framework for InstallApplications
# Taken from https://github.com/munki/munki/blob/main/code/tools/build_python_framework.sh
# IMPORTANT
# Run this with your current directory being the path where this script is located
DEV_APPLICATION_ID='Developer ID Application: Erik Gomez (U7DN82F4L9)'
# Harcoded (commit) versions of relocatable-python
RP_SHA="fb4dd9b024b249c71713f14d887f4bcea78aa8b0" # https://github.com/gregneagle/relocatable-python/commits/main/
REQUIREMENTS="${TOOLSDIR}/py3_requirements.txt"
MACOS_VERSION=11 # use 10.9 for non-universal
PYTHON_VERSION=3.13.8
PYTHON_MAJOR_VERSION=3.13
PYTHON_PRERELEASE_VERSION=
PYTHON_BASEURL="https://www.python.org/ftp/python/%s/python-%s${PYTHON_PRERELEASE_VERSION}-macos%s.pkg"
PYTHONTOOLDIR="/tmp/relocatable-python-git"
FRAMEWORKDIR="/Library/installapplications"
PYTHON_BIN="$FRAMEWORKDIR/Python.framework/Versions/Current/bin/python3"
PYTHON_BIN_NEW="$FRAMEWORKDIR/Python.framework/Versions/Current/Resources/Python.app/Contents/MacOS/Python"
PIPCACHEDIR="/Users/${CONSOLEUSER}/Library/Caches/pip"
RP_BINDIR="/tmp/relocatable-python"
TYPE="recommended"
XCODE_PATH="/Applications/Xcode.app"
SITE_PACKAGES=~/Library/Python/${PYTHON_MAJOR_VERSION}/lib/python/site-packages
SITE_PACKAGES_BACKUP=~/Library/Python/${PYTHON_MAJOR_VERSION}/lib/python/site-packages-bk
# Set python bin version based on PYTHON_VERSION
PYTHON_BIN_VERSION="${PYTHON_VERSION%.*}"
# Variables
TOOLSDIR=$(dirname $0)
OUTPUTSDIR="$TOOLSDIR/outputs"
CONSOLEUSER=$(/usr/bin/stat -f "%Su" /dev/console)
RP_ZIP="/tmp/relocatable-python.zip"
echo "Creating InstallApplications Python Framework - $TYPE"
echo ""
# Create framework path if not present with 777 so sudo is not needed
if [ ! -d "${FRAMEWORKDIR}" ]; then
/usr/bin/sudo /bin/mkdir -m 777 -p "${FRAMEWORKDIR}"
fi
# remove existing Python.framework if present
if [ -d "${FRAMEWORKDIR}/Python.framework" ]; then
/usr/bin/sudo /bin/rm -rf "${FRAMEWORKDIR}/Python.framework"
fi
if [ -d "$TOOLSDIR/payload${FRAMEWORKDIR}/Python.framework" ]; then
/usr/bin/sudo /bin/rm -rf "$TOOLSDIR/payload${FRAMEWORKDIR}/Python.framework"
fi
# remove existing library Python.framework if present
if [ -d "${PIPCACHEDIR}" ]; then
echo "Removing pip cache to reduce framework build errors"
/usr/bin/sudo /bin/rm -rf "${PIPCACHEDIR}"
fi
# Ensure Xcode is set to run-time
sudo xcode-select -s "$XCODE_PATH"
if [ -e $XCODE_BUILD_PATH ]; then
XCODE_BUILD="$XCODE_BUILD_PATH"
else
ls -la /Applications
echo "Could not find required Xcode build. Exiting..."
exit 1
fi
# Download specific version of relocatable-python
echo "Downloading relocatable-python tool from github..."
echo ""
if [ -f "${RP_ZIP}" ]; then
/usr/bin/sudo /bin/rm -rf ${RP_ZIP}
fi
/usr/bin/curl https://github.com/gregneagle/relocatable-python/archive/${RP_SHA}.zip -L -o ${RP_ZIP}
if [ -d ${RP_BINDIR} ]; then
/usr/bin/sudo /bin/rm -rf ${RP_BINDIR}
fi
/usr/bin/unzip ${RP_ZIP} -d ${RP_BINDIR}
DL_RESULT="$?"
if [ "${DL_RESULT}" != "0" ]; then
echo "Error downloading relocatable-python tool: ${DL_RESULT}" 1>&2
exit 1
fi
# remove existing Python package folders and recreate
echo "Removing existing Python package folders and recreating"
echo ""
if [ -d "$TOOLSDIR" ]; then
/bin/mkdir -p "$TOOLSDIR/scripts"
/bin/rm -rf "$OUTPUTSDIR"
/bin/mkdir -p "$OUTPUTSDIR"
/bin/mkdir -p "$TOOLSDIR/payload${FRAMEWORKDIR}"
/usr/bin/sudo /usr/sbin/chown -R ${CONSOLEUSER}:wheel "$TOOLSDIR"
else
fi
# Move site-packages temporarily
if [ -d "$SITE_PACKAGES" ]; then
echo "Temporarily moving python installed site-packages"
echo ""
/bin/mv $SITE_PACKAGES $SITE_PACKAGES_BACKUP
fi
# build the framework
# Force the C path depending on the version of Python to allow tools like cffi/xattr to build without wheels otherwise it errors
# Can't use Apple's headers for 3.10 and higher as they are (currently) 3.9
# C_INCLUDE_PATH="/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/Current/Headers/"
export C_INCLUDE_PATH="/Library/installapplications/Python.framework/Versions/Current/Headers/"
C_INCLUDE_PATH="/Library/installapplications/Python.framework/Versions/Current/Headers/" RP_EXTRACT_BINDIR="${RP_BINDIR}/relocatable-python-${RP_SHA}"
"${RP_EXTRACT_BINDIR}/make_relocatable_python_framework.py" \
--baseurl "${PYTHON_BASEURL}" \
--python-version "${PYTHON_VERSION}" \
--os-version "${MACOS_VERSION}" \
--upgrade-pip \
--pip-requirements "${TOOLSDIR}/requirements_${TYPE}.txt" \
--destination "${FRAMEWORKDIR}"
RP_RESULT="$?"
if [ "${RP_RESULT}" != "0" ]; then
echo "Error running relocatable-python tool: ${RP_RESULT}" 1>&2
exit 1
fi
# Move site-packages temporarily
if [ -d "$SITE_PACKAGES_BACKUP" ]; then
echo "Moving python installed site-packages back to original path"
/bin/mv $SITE_PACKAGES_BACKUP $SITE_PACKAGES
fi
# move the framework to the Python package folder
echo "Moving Python.framework to payload folder"
echo ""
/bin/mv "${FRAMEWORKDIR}/Python.framework" "$TOOLSDIR/payload${FRAMEWORKDIR}/Python.framework"
RP_RESULT2="$?"
if [ "${RP_RESULT2}" != "0" ]; then
echo "Failed to move Python framework, likely due to a bug with relocatable python" 1>&2
exit 1
fi
# confirm truly universal
TOTAL_DYLIB=$(/usr/bin/find "$TOOLSDIR/payload${FRAMEWORKDIR}/Python.framework/Versions/${PYTHON_BIN_VERSION}/lib" -name "*.dylib" | /usr/bin/wc -l | /usr/bin/xargs)
UNIVERSAL_DYLIB=$(/usr/bin/find "$TOOLSDIR/payload${FRAMEWORKDIR}/Python.framework/Versions/${PYTHON_BIN_VERSION}/lib" -name "*.dylib" | /usr/bin/xargs file | /usr/bin/grep "2 architectures" | /usr/bin/wc -l | /usr/bin/xargs)
if [ "${TOTAL_DYLIB}" != "${UNIVERSAL_DYLIB}" ] ; then
echo "Dynamic Libraries do not match, resulting in a non-universal Python framework."
echo "Total Dynamic Libraries found: ${TOTAL_DYLIB}"
echo "Universal Dynamic Libraries found: ${UNIVERSAL_DYLIB}"
exit 1
fi
echo "Dynamic Libraries are confirmed as universal"
TOTAL_SO=$(/usr/bin/find "$TOOLSDIR/payload${FRAMEWORKDIR}/Python.framework/Versions/${PYTHON_BIN_VERSION}/lib" -name "*.so" | /usr/bin/wc -l | /usr/bin/xargs)
UNIVERSAL_SO=$(/usr/bin/find "$TOOLSDIR/payload${FRAMEWORKDIR}/Python.framework/Versions/${PYTHON_BIN_VERSION}/lib" -name "*.so" | /usr/bin/xargs file | /usr/bin/grep "2 architectures" | /usr/bin/wc -l | /usr/bin/xargs)
if [ "${TOTAL_SO}" != "${UNIVERSAL_SO}" ] ; then
echo "Shared objects do not match, resulting in a non-universal Python framework."
echo "Total shared objects found: ${TOTAL_SO}"
echo "Universal shared objects found: ${UNIVERSAL_SO}"
UNIVERSAL_SO_ARRAY=("${(@f)$(/usr/bin/find "$TOOLSDIR/payload${FRAMEWORKDIR}/Python.framework/Versions/${PYTHON_BIN_VERSION}/lib" -name "*.so" | /usr/bin/xargs file | /usr/bin/grep "2 architectures" | awk '{print $1;}' | sed 's/:*$//g')}")
TOTAL_SO_ARRAY=("${(@f)$(/usr/bin/find "$TOOLSDIR/payload${FRAMEWORKDIR}/Python.framework/Versions/${PYTHON_BIN_VERSION}/lib" -name "*.so" )}")
echo ${TOTAL_SO_ARRAY[@]} ${UNIVERSAL_SO_ARRAY[@]} | tr ' ' '\n' | sort | uniq -u
exit 1
fi
echo "Shared objects are confirmed as universal"
echo ""
# re-sign the framework so it will run on Apple Silicon
if [ -n "$DEV_APPLICATION_ID" ]; then
echo "Adding developer id code signing so the framework will run on Apple Silicon..."
/usr/bin/find "$TOOLSDIR/payload${FRAMEWORKDIR}/Python.framework/Versions/${PYTHON_BIN_VERSION}/bin" -type f -perm -u=x -exec /usr/bin/codesign --sign "$DEV_APPLICATION_ID" --timestamp --preserve-metadata=identifier,entitlements,flags,runtime -f {} \;
/usr/bin/find "$TOOLSDIR/payload${FRAMEWORKDIR}/Python.framework/Versions/${PYTHON_BIN_VERSION}/lib" -type f -perm -u=x -exec /usr/bin/codesign --sign "$DEV_APPLICATION_ID" --timestamp --preserve-metadata=identifier,entitlements,flags,runtime -f {} \;
/usr/bin/find "$TOOLSDIR/payload${FRAMEWORKDIR}/Python.framework/Versions/${PYTHON_BIN_VERSION}/lib" -type f -name "*dylib" -exec /usr/bin/codesign --sign "$DEV_APPLICATION_ID" --timestamp --preserve-metadata=identifier,entitlements,flags,runtime -f {} \;
/usr/bin/codesign --sign "$DEV_APPLICATION_ID" --timestamp --deep --force --preserve-metadata=identifier,entitlements,flags,runtime "$TOOLSDIR/payload${FRAMEWORKDIR}/Python.framework/Versions/${PYTHON_BIN_VERSION}/Resources/Python.app"
/usr/bin/codesign --sign "$DEV_APPLICATION_ID" --timestamp --force --preserve-metadata=identifier,entitlements,flags,runtime "$TOOLSDIR/payload${FRAMEWORKDIR}/Python.framework/Versions/${PYTHON_BIN_VERSION}/Python"
/usr/bin/codesign --sign "$DEV_APPLICATION_ID" --timestamp --force --preserve-metadata=identifier,entitlements,flags,runtime "$TOOLSDIR/payload${FRAMEWORKDIR}/Python.framework/Versions/Current/Python"
else
echo "Adding ad-hoc code signing so the framework will run on Apple Silicon..."
/usr/bin/find "$TOOLSDIR/payload${FRAMEWORKDIR}/Python.framework/Versions/${PYTHON_BIN_VERSION}/bin" -type f -perm -u=x -exec /usr/bin/codesign -s - --preserve-metadata=identifier,entitlements,flags,runtime -f {} \;
/usr/bin/find "$TOOLSDIR/payload${FRAMEWORKDIR}/Python.framework/Versions/${PYTHON_BIN_VERSION}/lib" -type f -perm -u=x -exec /usr/bin/codesign -s - --preserve-metadata=identifier,entitlements,flags,runtime -f {} \;
/usr/bin/find "$TOOLSDIR/payload${FRAMEWORKDIR}/Python.framework/Versions/${PYTHON_BIN_VERSION}/lib" -type f -name "*dylib" -exec /usr/bin/codesign -s - --preserve-metadata=identifier,entitlements,flags,runtime -f {} \;
/usr/bin/codesign -s - --deep --force --preserve-metadata=identifier,entitlements,flags,runtime "$TOOLSDIR/payload${FRAMEWORKDIR}/Python.framework/Versions/${PYTHON_BIN_VERSION}/Resources/Python.app"
/usr/bin/codesign -s - --force --preserve-metadata=identifier,entitlements,flags,runtime "$TOOLSDIR/payload${FRAMEWORKDIR}/Python.framework/Versions/${PYTHON_BIN_VERSION}/Python"
/usr/bin/codesign -s - --force --preserve-metadata=identifier,entitlements,flags,runtime "$TOOLSDIR/payload${FRAMEWORKDIR}/Python.framework/Versions/Current/Python"
fi
echo ""
# Print out some information about the signatures
echo "Printing out signature information"
/usr/sbin/spctl -a -vvvv "$TOOLSDIR/payload${FRAMEWORKDIR}/Python.framework/Versions/${PYTHON_BIN_VERSION}/Python"
/usr/sbin/spctl -a -vvvv "$TOOLSDIR/payload${FRAMEWORKDIR}/Python.framework/Versions/${PYTHON_BIN_VERSION}/lib/libssl.3.dylib"
# take ownership of the payload folder
echo ""
echo "Taking ownership of the Payload directory"
/usr/bin/sudo /usr/sbin/chown -R ${CONSOLEUSER}:wheel "$TOOLSDIR/payload"
# Zip and move the framework
echo ""
echo "Creating Python.framework.zip"
ZIPFILE="Python.framework.zip"
/usr/bin/ditto -c -k --sequesterRsrc "$TOOLSDIR/payload${FRAMEWORKDIR}/" ${ZIPFILE}
/bin/mv ${ZIPFILE} "$OUTPUTSDIR"
# Ensure outputs directory is owned by the current user
/usr/bin/sudo /usr/sbin/chown -R ${CONSOLEUSER}:wheel "$OUTPUTSDIR"
# Cleanup the temporary files
/usr/bin/sudo /bin/rm -rf "${FRAMEWORKDIR}"