# *** IMPORTANT ***

# Build Prerequisite requirements for Python 3.11.3 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 devpython
cd devpython


# 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-1.1.1u.tar.gz *or later* into sources from https://www.openssl.org/source

export MACOSX_DEPLOYMENT_TARGET=11.0
export LDFLAGS="-Wl,-macosx_version_min,11.0"

tar -zxvf ../sources/openssl-1.1.1u.tar.gz
cd openssl-1.1.1u
./config no-shared --prefix=/usr/local
make -j4
sudo make install


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

export MACOSX_DEPLOYMENT_TARGET=11.0
export LDFLAGS="-Wl,-macosx_version_min,11.0"
export CFLAGS="-mmacosx-version-min=11.0 -Werror=partial-availability"

tar -zxvf ../sources/xz-5.4.2.tar.gz
cd xz-5.4.2
./configure --disable-shared --prefix=/usr/local
make -j4
sudo make install


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

export MACOSX_DEPLOYMENT_TARGET=11.0
export LDFLAGS="-Wl,-macosx_version_min,11.0"
export CFLAGS="-mmacosx-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 ../sources/sqlite-autoconf-3410200.tar.gz
cd sqlite-autoconf-3410200
./configure --enable-threadsafe --enable-shared=no --enable-static=yes --disable-readline --disable-dependency-tracking
make -j4
sudo make install


# 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.12-src.tar.gz into sources from ftp://ftp.tcl.tk/pub/tcl//tcl8_6/tcl8.6.12-src.tar.gz
# Download tk8.6.12-src.tar.gz into sources from ftp://ftp.tcl.tk/pub/tcl//tcl8_6/tk8.6.12-src.tar.gz

mkdir tcltk
cd tcltk
tar -zxvf ../../sources/tcl8.6.12-src.tar.gz
tar -zxvf ../../sources/tk8.6.12-src.tar.gz

# 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 x86_64 -mmacosx-version-min=11.0"
cd tcl8.6.12/unix
./configure --enable-shared --enable-threads --libdir=/Frameworks/Python.framework/Versions/3.11/lib
make TCL_LIBRARY=/Frameworks/Python.framework/Versions/3.11/lib/tcl8.6 DESTDIR=${MYLIBS}
make install TCL_LIBRARY=/Frameworks/Python.framework/Versions/3.11/lib/tcl8.6 DESTDIR=${MYLIBS}
cd ../../
cd tk8.6.12/unix
./configure --libdir=/Frameworks/Python.framework/Versions/3.11/lib --enable-aqua --enable-shared --enable-threads

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

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

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

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

#     And finally:
#     if you are using Qt5,  we will be building a required PyQt5 python module, 
#     you will need to have built or
#         downloaded prebuilt versions of Qt 5.15.X or later first
#          So see Building_Qt5_From_Source_on_MacOSX.txt
#
#     if you are using Qt6, we will building the required PySide6 module, you will need to have built
#         or downloaded prebuilt versions of Qt 6.2.2 or later

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

# Before building remember to rename any /Applications/Python 3.11.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.11.3.tgz into sources from www.python.org

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

export MACOSX_DEPLOYMENT_TARGET=11.0

# now build Python 3.11.3 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 -xvf ../sources/Python-3.11.3.tgz
cd Python-3.11.3

export LDFLAGS="-Wl,-macosx_version_min,11.0" 
export CFLAGS="-mmacosx-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.11/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.11/Resources/Python.app/Contents
mkdir lib
cd lib
mv ${MYDEST}/Python.framework/Versions/3.11/lib/tcl8.6 ./
mv ${MYDEST}/Python.framework/Versions/3.11/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.11/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.11/
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.11/Python @rpath/Python python3.11
install_name_tool -add_rpath @executable_path/../ ./python3.11


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

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

# 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.11/Resources/Python.app/Contents/MacOS
install_name_tool -change ${MYDEST}/Python.framework/Versions/3.11/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.11/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.11/lib/python3.11/lib-dynload
install_name_tool -add_rpath @loader_path/../.. _tkinter.cpython-311-darwin.so
install_name_tool -change ${MYDEST}/Python.framework/Versions/3.11/lib/libtcl8.6.dylib @rpath/libtcl8.6.dylib _tkinter.cpython-311-darwin.so
install_name_tool -change ${MYDEST}/Python.framework/Versions/3.11/lib/libtk8.6.dylib @rpath/libtk8.6.dylib _tkinter.cpython-311-darwin.so


# We should now have a fully relocatable Python.framework


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

See Building_PySide6_for_Qt6_on_MacOSX.txt
