# *** IMPORTANT ***

# Build Prerequisite requirements for Python 3.14.2 on macOS 13.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 ndevpython314
cd ndevpython314


# 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.19.tar.gz or later into sources from https://www.openssl.org/source
export MACOSX_DEPLOYMENT_TARGET=13.0
export LDFLAGS="-Wl,-macos_version_min,13.0"
tar -zxvf support/openssl-3.0.19.tar.gz
cd openssl-3.0.19
./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=13.0
export LDFLAGS="-Wl,-macos_version_min,13.0"
export CFLAGS="-mmacos-version-min=13.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 ..

# build LZ4 fast compression library for use in zstd library
# Download lz4-1.10.0.tar.gz from https://github.com/lz4/lz4/releases
export MACOSX_DEPLOYMENT_TARGET=13.0
export LDFLAGS="-Wl,-macos_version_min,13.0"
export CFLAGS="-mmacos-version-min=13.0 -Werror=partial-availability"
tar -zxvf support/lz4-1.10.0.tar.gz
cd lz4-1.10.0
cd build/cmake
mkdir builddir
cd builddir
cmake -DCMAKE_OSX_DEPLOYMENT_TARGET=13.0 -DBUILD_SHARED_LIBS=0 -DBUILD_STATIC_LIBS=1 -DCMAKE_BUILD_TYPE=Release -DCMAKE_PREFIX_PATH=/usr/local ..
make
sudo make install
unset CFLAGS
unset LDFLAGS
cd ../../../../

# build zstd library for the new Python compression module
# Download zstd-1.5.7.tar.gz or later from sourceforge
export MACOSX_DEPLOYMENT_TARGET=13.0
export LDFLAGS="-Wl,-macos_version_min,13.0"
export CFLAGS="-mmacos-version-min=13.0 -Werror=partial-availability"
tar -zxvf support/zstd-1.5.7.tar.gz
cd zstd-1.5.7
cd build/cmake
mkdir builddir
cd builddir
cmake -DCMAKE_OSX_DEPLOYMENT_TARGET=13.0 -DZSTD_BUILD_SHARED=0 -DCMAKE_BUILD_TYPE=Release -DCMAKE_PREFIX_PATH=/usr/local ..
make
sudo make install
unset CFLAGS
unset LDFLAGS
cd ../../../../


# Download sqlite-autoconf-3500400.tar.gz into sources from https://sqlite.org
export MACOSX_DEPLOYMENT_TARGET=13.0
export LDFLAGS="-Wl,-macos_version_min,13.0"
export CFLAGS="-mmacos-version-min=13.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-3500400.tar.gz
cd sqlite-autoconf-3500400
./configure --prefix=/usr/local --enable-threadsafe --disable-shared --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=13.0
tar -zxvf support/mpdecimal-4.0.0.tar.gz
cd mpdecimal-4.0.0
./configure --prefix=/usr/local --enable-static=yes --enable-shared=no --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.17-src.tar.gz into sources from sourceforge
# Download tk8.6.17-src.tar.gz into sources from sourceforge

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

# Now configure is broken with respect to availability on macos deployment targets
# And this code uses strchrnul which was not available to MacOS 10.15.4
# so apply the following patch to make sure strchrnul is not used since our min is macOS 10.13

kbhend@Mac sqlite3 % diff -u sqlite3.c~ sqlite3.c
--- tcltk/tcl8.6.17/pkgs/sqlite3.50.4/compat/sqlite3/sqlite3.c~	2025-08-11 05:49:08
+++ tcltk/tcl8.6.17/pkgs/sqlite3.50.4/compat/sqlite3/sqlite3.c	2026-01-29 11:52:07
@@ -31958,7 +31958,7 @@
   for(; (c=(*fmt))!=0; ++fmt){
     if( c!='%' ){
       bufpt = (char *)fmt;
-#if HAVE_STRCHRNUL
+#if 0 /* HAVE_STRCHRNUL */
       fmt = strchrnul(fmt, '%');
 #else
       do{ fmt++; }while( *fmt && *fmt != '%' );


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

export MACOSX_DEPLOYMENT_TARGET=13.0

export CFLAGS="-arch arm64 -mmacos-version-min=13.0"
# export CFLAGS="-arch x86_64 -mmacos-version-min=13.0"

cd tcl8.6.17/unix
./configure --enable-shared --enable-threads --libdir=/Frameworks/Python.framework/Versions/3.14/lib
make TCL_LIBRARY=/Frameworks/Python.framework/Versions/3.14/lib/tcl8.6 DESTDIR=${MYLIBS}
make install TCL_LIBRARY=/Frameworks/Python.framework/Versions/3.14/lib/tcl8.6 DESTDIR=${MYLIBS}
cd ../../
cd tk8.6.17/unix
./configure --libdir=/Frameworks/Python.framework/Versions/3.14/lib --enable-aqua --enable-shared --enable-threads

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

make install TCL_LIBRARY=/Frameworks/Python.framework/Versions/3.14/lib/tcl8.6 \
     TK_LIBRARY=/Frameworks/Python.framework/Versions/3.14/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.14/lib
chmod u+w libtk8.6.dylib
chmod u+w libtcl8.6.dylib
install_name_tool -id ${MYDEST}/Python.framework/Versions/3.14/lib/libtcl8.6.dylib ./libtcl8.6.dylib
install_name_tool -id ${MYDEST}/Python.framework/Versions/3.14/lib/libtk8.6.dylib ./libtk8.6.dylib


# Building Python 3.14.2 to be fully relocatable for macOS 13.0 and later

# Before building remember to rename any /Applications/Python 3.14.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.14.2.tar.xz into support from www.python.org

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

export MACOSX_DEPLOYMENT_TARGET=13.0

# now build Python 3.14.2 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 -jxvf support/Python-3.14.2.tar.xz
cd Python-3.14.2

export LDFLAGS="-Wl,-macos_version_min,13.0" 
export CFLAGS="-mmacos-version-min=13.0" 
./configure --prefix=${MYDEST} --enable-framework=${MYDEST} --with-ensurepip \
    TCLTK_CFLAGS="-I${MYLIBS}/usr/local/include" \
    TCLTK_LIBS="-L${MYDEST}/Python.framework/Versions/3.14/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 copy 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.14/Resources/Python.app/Contents
mkdir lib
cd lib
cp -R ${MYDEST}/Python.framework/Versions/3.14/lib/tcl8.6 ./
cp -R ${MYDEST}/Python.framework/Versions/3.14/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.14/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.14/
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.14/Python @rpath/Python python3.14
install_name_tool -add_rpath @executable_path/../ ./python3.14


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

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

# 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.14/Resources/Python.app/Contents/MacOS
install_name_tool -change ${MYDEST}/Python.framework/Versions/3.14/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.14/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.14/lib/python3.14/lib-dynload
install_name_tool -add_rpath @loader_path/../.. _tkinter.cpython-314-darwin.so
install_name_tool -change ${MYDEST}/Python.framework/Versions/3.14/lib/libtcl8.6.dylib @rpath/libtcl8.6.dylib _tkinter.cpython-314-darwin.so
install_name_tool -change ${MYDEST}/Python.framework/Versions/3.14/lib/libtk8.6.dylib @rpath/libtk8.6.dylib _tkinter.cpython-314-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.14/lib/python3.14/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.14 interpreter to install PySide6 for Qt 6.X

See Building_PySide6_for_Qt6_on_MacOSX.txt
