# *** IMPORTANT ***

# Build Prerequisite requirements for Python 3.13.1 on macOS 11.0 and later users:
#
#     First make sure you are using the latest XCode for your version of Mac OSX
#     Then make sure you have the command line tools (CLT) installed (via xcode-select --install)
#
#
#     For Python's pip3 and lzma module, and other Python functionality you will need to
#     compile and install the headers and static library versions of liblzma.a (xz),
#     libssl.a (libopenssl), and libcrypto.a (libopenssl), along side
#     static versions of sqlite, and a specially built internal TclTk library
#

# Create a build folder where all of the work will be done

cd 
mkdir ndevpython
cd ndevpython


# If you are using XCode 10.X on MacOSX 10.14.X, remember to install the command line tools 
# and their headers!  The headers are now not installed by default.  An installer package
# for the headers can be found here:
# 
# /Library/Developer/CommandLineTools/Packages/macOS_SDK_headers_for_macOS_10.14.pkg

# First build the main prerequisites
# Download openssl-3.0.15.tar.gz or later into sources from https://www.openssl.org/source
export MACOSX_DEPLOYMENT_TARGET=11.0
export LDFLAGS="-Wl,-macos_version_min,11.0"
tar -zxvf support/openssl-3.0.15.tar.gz
cd openssl-3.0.15
./config no-shared --prefix=/usr/local
make -j4
sudo make install
unset LDFLAGS
cd ..


# Download xz-5.2.3.tar.gz or later into sources from https://tukaani.org/xz/  (via sourceforge)

export MACOSX_DEPLOYMENT_TARGET=11.0
export LDFLAGS="-Wl,-macos_version_min,11.0"
export CFLAGS="-mmacos-version-min=11.0 -Werror=partial-availability"

tar -zxvf support/xz-5.2.3.tar.gz
cd xz-5.2.3
./configure --disable-shared --prefix=/usr/local
make -j4
sudo make install
unset CFLAGS
unset LDFLAGS
cd ..


# Download sqlite-autoconf-3450300.tar.gz into sources from 
# https://sqlite.org/2021/sqlite-autoconf-3450300.tar.gz"

export MACOSX_DEPLOYMENT_TARGET=11.0
export LDFLAGS="-Wl,-macos_version_min,11.0"
export CFLAGS="-mmacos-version-min=11.0 -Werror=partial-availability -Os -DSQLITE_ENABLE_FTS5 \
            -DSQLITE_ENABLE_FTS4 -DSQLITE_ENABLE_FTS3_PARENTHESIS -DSQLITE_ENABLE_JSON1 \
            -DSQLITE_ENABLE_RTREE -DSQLITE_TCL=0 "
tar -zxvf support/sqlite-autoconf-3450300.tar.gz
cd sqlite-autoconf-3450300
./configure --prefix=/usr/local --enable-threadsafe --enable-shared=no --enable-static=yes --disable-readline --disable-dependency-tracking
make -j4
sudo make install
unset LDFLAGS
unset CFLAGS
cd ..


# Download mpdecimal-4.0.0.tar.gz from:
# https://www.bytereef.org/software/mpdecimal/releases/mpdecimal-4.0.0.tar.gz

export MACOSX_DEPLOYMENT_TARGET=11.0
tar -zxvf support/mpdecimal-4.0.0.tar.gz
cd mpdecimal-4.0.0
./configure --prefix=/usr/local --disable-cxx MACHINE=universal
make -j4
sudo make install
cd ..


# Specify the future home for the Python.framework and interim tcltk pieces

mkdir libraries
cd libraries
export MYLIBS=`pwd`
mkdir Frameworks
cd Frameworks
export MYDEST=`pwd`
cd ../../

# To enable the Tk / tkinter graphical ui for Python we will need to make a special 
# combined build of tcl and tk and build it right "in place" for the future 
# Python.framework to install around

# Download tcl8.6.15-src.tar.gz into sources from sourceforge
# Download tk8.6.15-src.tar.gz into sources from sourceforge

mkdir tcltk
cd tcltk
tar -zxvf ../support/tcl8.6.15-src.tar.gz
tar -zxvf ../support/tk8.6.15-src.tar.gz

For this version - no backport patches are needed.


# Note: TCL_LIBRARY and TK_LIBRARY and libdir are appended to DESTDIR to get actual paths

export MACOSX_DEPLOYMENT_TARGET=11.0
export CFLAGS="-arch arm64 -mmacos-version-min=11.0"
cd tcl8.6.15/unix
./configure --enable-shared --enable-threads --libdir=/Frameworks/Python.framework/Versions/3.13/lib
make TCL_LIBRARY=/Frameworks/Python.framework/Versions/3.13/lib/tcl8.6 DESTDIR=${MYLIBS}
make install TCL_LIBRARY=/Frameworks/Python.framework/Versions/3.13/lib/tcl8.6 DESTDIR=${MYLIBS}
cd ../../
cd tk8.6.15/unix
./configure --libdir=/Frameworks/Python.framework/Versions/3.13/lib --enable-aqua --enable-shared --enable-threads

make TCL_LIBRARY=/Frameworks/Python.framework/Versions/3.13/lib/tcl8.6 \
     TK_LIBRARY=/Frameworks/Python.framework/Versions/3.13/lib/tk8.6 \
     DESTDIR=${MYLIBS}

make install TCL_LIBRARY=/Frameworks/Python.framework/Versions/3.13/lib/tcl8.6 \
     TK_LIBRARY=/Frameworks/Python.framework/Versions/3.13/lib/tk8.6 \
     DESTDIR=${MYLIBS}

unset CFLAGS

# As a last step fixup the dylib official names to properly reflect their new home

cd ${MYDEST}/Python.framework/Versions/3.13/lib
chmod u+w libtk8.6.dylib
chmod u+w libtcl8.6.dylib
install_name_tool -id ${MYDEST}/Python.framework/Versions/3.13/lib/libtcl8.6.dylib ./libtcl8.6.dylib
install_name_tool -id ${MYDEST}/Python.framework/Versions/3.13/lib/libtk8.6.dylib ./libtk8.6.dylib


# Building Python 3.13.1 to be fully relocatable for macOS 11.0 and later

# Before building remember to rename any /Applications/Python 3.13.app to save it and 
# replace it afterwards as the damn python installation from source always overwrites
# it no matter the configure prefix used

# Download Python-3.13.1.tgz into support from www.python.org

cd ${MYDEST}
cd ../../

export MACOSX_DEPLOYMENT_TARGET=11.0

# now build Python 3.13.1 as a framework
# no need to worry about what symbols exist in what version of 
# macOS any longer, since Python 3.9.1 and later use and test for weak symbols

tar -zxvf support/Python-3.13.1.tgz
cd Python-3.13.1

export LDFLAGS="-Wl,-macos_version_min,11.0" 
export CFLAGS="-mmacos-version-min=11.0" 
./configure --prefix=${MYDEST} --enable-framework=${MYDEST} --with-ensurepip \
    TCLTK_CFLAGS="-I${MYLIBS}/usr/local/include" \
    TCLTK_LIBS="-L${MYDEST}/Python.framework/Versions/3.13/lib -ltcl8.6 -ltk8.6"

make -j4
make frameworkinstall


# Now due to changes in Python3 since 3.9, the places it looks for the tcl8.6 and
# tk8.6 folders moves if Python3 is NOT installed in the standard framework
# location (not in /Library/Framework/Python.framework).
# So Python3 can not find its platform independent tcltk (tkinter) libraries
# on macOS if moved.   Because an "app" is needed for gui activity, these libraries
# must be found relative to the internal Python.app

# To allow our Python to fully moveable we must move these tcltk platform 
# independent files to a new lib folder placed in Python.app/Contents/
# so that they can always be found as follows:

cd ${MYDEST}/Python.framework/Versions/3.13/Resources/Python.app/Contents
mkdir lib
cd lib
cp -R ${MYDEST}/Python.framework/Versions/3.13/lib/tcl8.6 ./
cp -R ${MYDEST}/Python.framework/Versions/3.13/lib/tk8.6 ./

cd ${MYDEST}
cd ../../

# next update path in order to use the newly built/installed Python.framework's
# and then use pip3 to install all other required python packages to its site-packages

export PATH=${MYDEST}/Python.framework/Versions/3.13/bin:${PATH}
which pip3

pip3 install six
pip3 install html5lib
pip3 install lxml
pip3 install Pillow
pip3 install regex
pip3 install css-parser
pip3 install cssselect
pip3 install chardet
pip3 install certifi
pip3 install urllib3
pip3 install dulwich


# Now a complete Python.framework has been built in ${MYDEST}
# But we still need to make it a relocatable framework

# To make it relocatable we need to use otool and install_name_tool to change
# the dylib name and path to it from all executables in the Python.framework

# A Quick Guide: On Mac OS X, one may use:
#     "otool -D <file>" to view the install name of a dylib
#     "otool -L <file>" to view the dependencies
#     "otool -l <file> | grep LC_RPATH -A2" to view the RPATHs
#     "install_name_tool -id ..." to change an install name
#     "install_name_tool -change ..." to change the dependencies
#     "install_name_tool -rpath ... -add_rpath ... -delete_rpath ..." to change RPATHs
 
# Make the framework's main dylib relocatable using rpath

cd ${MYDEST}/Python.framework/Versions/3.13/
chmod u+w Python
otool -D ./Python
install_name_tool -id @rpath/Python ./Python

# Change the dependencies of the executable files in bin to point to the relocatable 
# framework in a relative way and add the proper rpath to find the Python (renamed dylib)

cd bin
install_name_tool -change ${MYDEST}/Python.framework/Versions/3.13/Python @rpath/Python python3.13
install_name_tool -add_rpath @executable_path/../ ./python3.13


# so that python3 can find the Qt Frameworks and proper plugins for PyQt5

install_name_tool -add_rpath @executable_path/../../../../ ./python3.13

# now do the same for the Python.app stored inside the Python.framework Resources 
# This app is needed to allow gui use by python for plugins

cd ${MYDEST}/Python.framework/Versions/3.13/Resources/Python.app/Contents/MacOS
install_name_tool -change ${MYDEST}/Python.framework/Versions/3.13/Python @rpath/Python ./Python
install_name_tool -add_rpath @executable_path/../../../../ ./Python

# And finally we need to change the name id on the libtk and libtcl to be rpath based
# and fix the _tkinter*.so to have an rpath with a @loader_path back up to the lib dir 
# where they live

cd ${MYDEST}/Python.framework/Versions/3.13/lib
otool -D libtk8.6.dylib
otool -D libtcl8.6.dylib
install_name_tool -id @rpath/libtcl8.6.dylib ./libtcl8.6.dylib
install_name_tool -id @rpath/libtk8.6.dylib ./libtk8.6.dylib
cd ${MYDEST}/Python.framework/Versions/3.13/lib/python3.13/lib-dynload
install_name_tool -add_rpath @loader_path/../.. _tkinter.cpython-313-darwin.so
install_name_tool -change ${MYDEST}/Python.framework/Versions/3.13/lib/libtcl8.6.dylib @rpath/libtcl8.6.dylib _tkinter.cpython-313-darwin.so
install_name_tool -change ${MYDEST}/Python.framework/Versions/3.13/lib/libtk8.6.dylib @rpath/libtk8.6.dylib _tkinter.cpython-313-darwin.so

# There is one final nit that needs to be addressed as Pillow installs a libjpeg binary with a dangling rpth that needs to be removed
cd ${MYDEST}/Python.framework/Versions/3.13/lib/python3.13/site-packages/
cd PIL/.dylibs
otool -l ./libjpeg.62.4.0.dylib | grep LC_RPATH -A2
install_name_tool -delete_rpath /Users/runner/work/Pillow/Pillow/build/deps/darwin/lib ./libjpeg.62.4.0.dylib


# We should now have a fully relocatable Python.framework


# We will now use this just-built Python3.13 interpreter to install PySide6 for Qt 6.X

See Building_PySide6_for_Qt6_on_MacOSX.txt
