1717# - XZ-iOS - build XZ for iOS
1818# - XZ-tvOS - build XZ for tvOS
1919# - XZ-watchOS - build XZ for watchOS
20+ # - libFFI-iOS - build libFFI for iOS
21+ # - libFFI-tvOS - build libFFI for tvOS
22+ # - libFFI-watchOS - build libFFI for watchOS
2023# - Python-macOS - build Python for macOS
2124# - Python-iOS - build Python for iOS
2225# - Python-tvOS - build Python for tvOS
@@ -30,7 +33,11 @@ BUILD_NUMBER=custom
3033MACOSX_DEPLOYMENT_TARGET =10.8
3134
3235# Version of packages that will be compiled by this meta-package
33- PYTHON_VERSION =3.8.9
36+ # PYTHON_VERSION is the full version number (e.g., 3.10.0b3)
37+ # PYTHON_MICRO_VERSION is the full version number, without any alpha/beta/rc suffix. (e.g., 3.10.0)
38+ # PYTHON_VER is the major/minor version (e.g., 3.10)
39+ PYTHON_VERSION =3.8.11
40+ PYTHON_MICRO_VERSION =$(shell echo $(PYTHON_VERSION ) | grep -Eo "\d+\.\d+\.\d+")
3441PYTHON_VER =$(basename $(PYTHON_VERSION ) )
3542
3643OPENSSL_VERSION_NUMBER =1.1.1
@@ -41,11 +48,13 @@ BZIP2_VERSION=1.0.8
4148
4249XZ_VERSION =5.2.5
4350
51+ LIBFFI_VERSION =3.3
52+
4453# Supported OS
4554OS =macOS iOS tvOS watchOS
4655
4756# macOS targets
48- TARGETS-macOS =macosx.x86_64
57+ TARGETS-macOS =macosx.x86_64 macosx.arm64
4958PYTHON_TARGETS-macOS =macOS
5059CFLAGS-macOS=-mmacosx-version-min =$(MACOSX_DEPLOYMENT_TARGET )
5160
8392distclean : clean
8493 rm -rf downloads
8594
86- downloads : downloads/openssl-$(OPENSSL_VERSION ) .tgz downloads/bzip2-$(BZIP2_VERSION ) .tgz downloads/xz-$(XZ_VERSION ) .tgz downloads/Python-$(PYTHON_VERSION ) .tgz
95+ downloads : downloads/openssl-$(OPENSSL_VERSION ) .tgz downloads/bzip2-$(BZIP2_VERSION ) .tgz downloads/xz-$(XZ_VERSION ) .tgz downloads/libffi- $( LIBFFI_VERSION ) .tgz downloads/ Python-$(PYTHON_VERSION ) .tgz
8796
8897update-patch :
8998 # Generate a diff from the clone of the python/cpython Github repository
@@ -141,6 +150,20 @@ downloads/xz-$(XZ_VERSION).tgz:
141150 mkdir -p downloads
142151 if [ ! -e downloads/xz-$( XZ_VERSION) .tgz ]; then curl --fail -L http://tukaani.org/xz/xz-$( XZ_VERSION) .tar.gz -o downloads/xz-$( XZ_VERSION) .tgz; fi
143152
153+ # ##########################################################################
154+ # LIBFFI
155+ # ##########################################################################
156+
157+ # Clean the LibFFI project
158+ clean-libFFI :
159+ rm -rf build/* /libffi-$(LIBFFI_VERSION ) \
160+ build/* /Support/libFFI
161+
162+ # Download original XZ source code archive.
163+ downloads/libffi-$(LIBFFI_VERSION ) .tgz :
164+ mkdir -p downloads
165+ if [ ! -e downloads/libffi-$( LIBFFI_VERSION) .tgz ]; then curl --fail -L http://github.com/libffi/libffi/releases/download/v$( LIBFFI_VERSION) /libffi-$( LIBFFI_VERSION) .tar.gz -o downloads/libffi-$( LIBFFI_VERSION) .tgz; fi
166+
144167# ##########################################################################
145168# Python
146169# ##########################################################################
@@ -156,7 +179,7 @@ clean-Python:
156179# Download original Python source code archive.
157180downloads/Python-$(PYTHON_VERSION ) .tgz :
158181 mkdir -p downloads
159- if [ ! -e downloads/Python-$( PYTHON_VERSION) .tgz ]; then curl -L https://www.python.org/ftp/python/$( PYTHON_VERSION ) /Python-$( PYTHON_VERSION) .tgz > downloads/Python-$( PYTHON_VERSION) .tgz; fi
182+ if [ ! -e downloads/Python-$( PYTHON_VERSION) .tgz ]; then curl -L https://www.python.org/ftp/python/$( PYTHON_MICRO_VERSION ) /Python-$( PYTHON_VERSION) .tgz > downloads/Python-$( PYTHON_VERSION) .tgz; fi
160183
161184# Some Python targets needed to identify the host build
162185PYTHON_DIR-macOS =build/macOS/Python-$(PYTHON_VERSION ) -macOS
@@ -191,6 +214,7 @@ LDFLAGS-$1=-arch $$(ARCH-$1) -isysroot=$$(SDK_ROOT-$1)
191214OPENSSL_DIR-$1=build/$2/openssl-$(OPENSSL_VERSION ) -$1
192215BZIP2_DIR-$1=build/$2/bzip2-$(BZIP2_VERSION ) -$1
193216XZ_DIR-$1=build/$2/xz-$(XZ_VERSION ) -$1
217+ LIBFFI_DIR-$1=build/$2/libffi-$(LIBFFI_VERSION )
194218
195219# Unpack OpenSSL
196220$$(OPENSSL_DIR-$1 ) /Makefile: downloads/openssl-$(OPENSSL_VERSION ) .tgz
@@ -262,24 +286,32 @@ $$(XZ_DIR-$1)/Makefile: downloads/xz-$(XZ_VERSION).tgz
262286$$(XZ_DIR-$1 ) /src/liblzma/.libs/liblzma.a: $$(XZ_DIR-$1 ) /Makefile
263287 cd $$(XZ_DIR-$1 ) && make && make install
264288
265- # macOS builds are compiled as a single build. As a result, the macOS Python
266- # build is configured in the `build` macro, rather than the `build-target` macro.
289+ # macOS builds use their own libFFI, and are compiled as a single
290+ # universal2 build. As a result, the macOS Python build is configured
291+ # in the `build` macro, rather than the `build-target` macro.
267292ifneq ($2,macOS)
293+ LIBFFI_BUILD_DIR-$1 =build_$$(SDK-$1 ) -$$(ARCH-$1 )
268294PYTHON_DIR-$1 =build/$2/Python-$(PYTHON_VERSION ) -$1
269295pyconfig.h-$1 =pyconfig-$$(ARCH-$1 ) .h
270296PYTHON_HOST-$1 =$(PYTHON_HOST )
271297
298+ # Build LibFFI
299+ $$(LIBFFI_DIR-$1 ) /libffi.$1.a : $$(LIBFFI_DIR-$1 ) /darwin_common
300+ cd $$(LIBFFI_DIR-$1 ) /$$(LIBFFI_BUILD_DIR-$1 ) && make
301+
302+ # Copy in the lib to a non-BUILD_DIR dependent location;
303+ # include the target in the final filename for disambiguation
304+ cp $$(LIBFFI_DIR-$1)/$$(LIBFFI_BUILD_DIR-$1)/.libs/libffi.a $$(LIBFFI_DIR-$1)/libffi.$1.a
305+
272306# Unpack Python
273307$$(PYTHON_DIR-$1 ) /Makefile : downloads/Python-$(PYTHON_VERSION ) .tgz $$(PYTHON_HOST-$1 )
274308 # Unpack target Python
275309 mkdir -p $$(PYTHON_DIR-$1 )
276310 tar zxf downloads/Python-$(PYTHON_VERSION ) .tgz --strip-components 1 -C $$(PYTHON_DIR-$1 )
277311 # Apply target Python patches
278312 cd $$(PYTHON_DIR-$1 ) && patch -p1 < $(PROJECT_DIR ) /patch/Python/Python.patch
279- # Copy in the embedded and platform/arch configuration
280- cp -f $(PROJECT_DIR ) /patch/Python/Setup.embedded $$(PYTHON_DIR-$1 ) /Modules/Setup.embedded
281- if [ -e " $( PROJECT_DIR) /patch/Python/Setup.$2 -$$ (ARCH-$1 )" ]; then \
282- cp -f $(PROJECT_DIR ) /patch/Python/Setup.$2 -$$(ARCH-$1 ) $$(PYTHON_DIR-$1 ) /Modules/Setup.$2 -$$(ARCH-$1 ) ; fi
313+ # Copy in the embedded module configuration
314+ cat $(PROJECT_DIR ) /patch/Python/Setup.embedded $(PROJECT_DIR ) /patch/Python/Setup.$2 > $$(PYTHON_DIR-$1 ) /Modules/Setup.local
283315 # Configure target Python
284316 cd $$(PYTHON_DIR-$1 ) && PATH=$(PROJECT_DIR ) /$(PYTHON_DIR-macOS ) /dist/bin:$(PATH ) ./configure \
285317 CC=" $$ (CC-$1 )" LD=" $$ (CC-$1 )" \
@@ -291,7 +323,7 @@ $$(PYTHON_DIR-$1)/Makefile: downloads/Python-$(PYTHON_VERSION).tgz $$(PYTHON_HOS
291323 $$(PYTHON_CONFIGURE-$2 )
292324
293325# Build Python
294- $$(PYTHON_DIR-$1 ) /dist/lib/libpython$(PYTHON_VER ) .a : build/$2/Support/OpenSSL build/$2/Support/BZip2 build/$2/Support/XZ $$(PYTHON_DIR-$1 ) /Makefile
326+ $$(PYTHON_DIR-$1 ) /dist/lib/libpython$(PYTHON_VER ) .a : build/$2/Support/OpenSSL build/$2/Support/BZip2 build/$2/Support/XZ build/$2/Support/libFFI $$(PYTHON_DIR-$1 ) /Makefile
295327 # Build target Python
296328 cd $$(PYTHON_DIR-$1 ) && PATH=" $( PROJECT_DIR) /$( PYTHON_DIR-macOS) /dist/bin:$( PATH) " make all install
297329
@@ -307,9 +339,11 @@ vars-$1:
307339 @echo "SDK-$1: $$(SDK-$1 ) "
308340 @echo "SDK_ROOT-$1: $$(SDK_ROOT-$1 ) "
309341 @echo "CC-$1: $$(CC-$1 ) "
342+ @echo "LIBFFI_BUILD_DIR-$1: $$(LIBFFI_BUILD_DIR-$1 ) "
310343 @echo "OPENSSL_DIR-$1: $$(OPENSSL_DIR-$1 ) "
311344 @echo "BZIP2_DIR-$1: $$(BZIP2_DIR-$1 ) "
312345 @echo "XZ_DIR-$1: $$(XZ_DIR-$1 ) "
346+ @echo "LIBFFI_DIR-$1: $$(LIBFFI_DIR-$1 ) "
313347 @echo "PYTHON_DIR-$1: $$(PYTHON_DIR-$1 ) "
314348 @echo "pyconfig.h-$1: $$(pyconfig.h-$1 ) "
315349
@@ -325,6 +359,7 @@ $$(foreach target,$$(TARGETS-$1),$$(eval $$(call build-target,$$(target),$1)))
325359OPENSSL_FRAMEWORK-$1=build/$1/Support/OpenSSL
326360BZIP2_FRAMEWORK-$1=build/$1/Support/BZip2
327361XZ_FRAMEWORK-$1=build/$1/Support/XZ
362+ LIBFFI_FRAMEWORK-$1=build/$1/Support/libFFI
328363PYTHON_FRAMEWORK-$1=build/$1/Support/Python
329364PYTHON_RESOURCES-$1=$$(PYTHON_FRAMEWORK-$1 ) /Resources
330365
@@ -333,11 +368,16 @@ $1: dist/Python-$(PYTHON_VER)-$1-support.$(BUILD_NUMBER).tar.gz
333368clean-$1:
334369 rm -rf build/$1
335370
336- dist/Python-$(PYTHON_VER ) -$1-support.$(BUILD_NUMBER ) .tar.gz: $$(BZIP2_FRAMEWORK-$1 ) $$(XZ_FRAMEWORK-$1 ) $$(OPENSSL_FRAMEWORK-$1 ) $$(PYTHON_FRAMEWORK-$1 )
371+ dist/Python-$(PYTHON_VER ) -$1-support.$(BUILD_NUMBER ) .tar.gz: $$(BZIP2_FRAMEWORK-$1 ) $$(XZ_FRAMEWORK-$1 ) $$(OPENSSL_FRAMEWORK-$1 ) $$(LIBFFI_FRAMEWORK-$1 ) $$( PYTHON_FRAMEWORK-$1 )
337372 mkdir -p dist
338373 echo "Python version: $(PYTHON_VERSION ) " > build/$1/Support/VERSIONS
339374 echo "Build: $(BUILD_NUMBER ) " >> build/$1/Support/VERSIONS
340375 echo "---------------------" >> build/$1/Support/VERSIONS
376+ ifeq ($1,macOS)
377+ echo "libFFI: macOS native" >> build/$1/Support/VERSIONS
378+ else
379+ echo "libFFI: $(LIBFFI_VERSION)" >> build/$1/Support/VERSIONS
380+ endif
341381 echo "BZip2: $(BZIP2_VERSION ) " >> build/$1/Support/VERSIONS
342382 echo "OpenSSL: $(OPENSSL_VERSION ) " >> build/$1/Support/VERSIONS
343383 echo "XZ: $(XZ_VERSION ) " >> build/$1/Support/VERSIONS
@@ -407,11 +447,18 @@ build/$1/xz/lib/liblzma.a: $$(foreach target,$$(TARGETS-$1),$$(XZ_DIR-$$(target)
407447 mkdir -p build/$1
408448 xcrun lipo -create -o $$@ $$^
409449
410- # macOS builds a single Python target; thus it needs to be
450+ # Build libFFI
451+ libFFI-$1: $$(LIBFFI_FRAMEWORK-$1 )
452+
453+ # macOS builds a single Python universal2 target; thus it needs to be
411454# configured in the `build` macro, not the `build-target` macro.
455+ # macOS also uses the system-provided libFFI, so there's no need to package
456+ # a libFFI framework for macOS.
412457ifeq ($1,macOS)
413458# Some targets that are needed for consistency between macOS and other builds,
414459# but are no-ops on macOS.
460+ $$(LIBFFI_FRAMEWORK-$1 ) :
461+
415462build/$1/$$(pyconfig.h-$1 ) :
416463
417464# Unpack Python
@@ -421,25 +468,54 @@ $$(PYTHON_DIR-$1)/Makefile: downloads/Python-$(PYTHON_VERSION).tgz
421468 tar zxf downloads/Python-$(PYTHON_VERSION ) .tgz --strip-components 1 -C $$(PYTHON_DIR-$1 )
422469 # Apply target Python patches
423470 cd $$(PYTHON_DIR-$1 ) && patch -p1 < $(PROJECT_DIR ) /patch/Python/Python.patch
424- # A locally hosted Python requires a full Setup.local configuration
425- # because there's no PYTHON_HOST_PLATFORM to cause Setup.local to be
426- # generated
427- cat $(PROJECT_DIR ) /patch/Python/Setup.embedded $(PROJECT_DIR ) /patch/Python/Setup.macOS-x86_64 > $$(PYTHON_DIR-$1 ) /Modules/Setup.local
471+ # Copy in the embedded module configuration
472+ cat $(PROJECT_DIR ) /patch/Python/Setup.embedded $(PROJECT_DIR ) /patch/Python/Setup.$1 > $$(PYTHON_DIR-$1 ) /Modules/Setup.local
428473 # Configure target Python
429474 cd $$(PYTHON_DIR-$1 ) && MACOSX_DEPLOYMENT_TARGET=$$(MACOSX_DEPLOYMENT_TARGET ) ./configure \
430475 --prefix=$(PROJECT_DIR ) /$$(PYTHON_DIR-$1 ) /dist \
431- --without-doc-strings --enable-ipv6 --without-ensurepip \
476+ --without-doc-strings --enable-ipv6 --without-ensurepip --enable-universalsdk --with-universal-archs=universal2 \
432477 $$(PYTHON_CONFIGURE-$1 )
433478
434479# Build Python
435- $$(PYTHON_DIR-$1 ) /dist/lib/libpython$(PYTHON_VER ) .a : build/$1/Support/OpenSSL build/$1/Support/BZip2 build/$1/Support/XZ $$(PYTHON_DIR-$1 ) /Makefile
480+ $$(PYTHON_DIR-$1 ) /dist/lib/libpython$(PYTHON_VER ) .a : build/$1/Support/OpenSSL build/$1/Support/BZip2 build/$1/Support/XZ build/$1/Support/libFFI $$(PYTHON_DIR-$1 ) /Makefile
436481 # Build target Python
437482 cd $$(PYTHON_DIR-$1 ) && PATH=" $( PROJECT_DIR) /$( PYTHON_DIR-$1 ) /dist/bin:$( PATH) " make all install
438483
439484else
485+ # The LibFFI folder is shared between all architectures for the OS
486+ LIBFFI_DIR-$1 =build/$1/libffi-$(LIBFFI_VERSION )
440487# The Python targets are the same as they are for every other library
441488PYTHON_TARGETS-$1 =$$(TARGETS-$1 )
442489
490+ # Unpack LibFFI and generate source & headers
491+ $$(LIBFFI_DIR-$1 ) /darwin_common : downloads/libffi-$(LIBFFI_VERSION ) .tgz
492+ # Unpack sources
493+ mkdir -p $$(LIBFFI_DIR-$1 )
494+ tar zxf downloads/libffi-$(LIBFFI_VERSION ) .tgz --strip-components 1 -C $$(LIBFFI_DIR-$1 )
495+ # Apply libffi patches. Apple builds of libffi use a utility script; that
496+ # script doesn't work with Python3 using the out-of-the-box version in
497+ # libffi 3.3. This patch adds some changes that will be included in libFFI
498+ # 3.4 (whenever that is released), plus some extra targets to support
499+ # tvOS and watchOS.
500+ cd $$(LIBFFI_DIR-$1 ) && patch -p1 < $(PROJECT_DIR ) /patch/libffi/libffi.patch
501+ # Configure the build
502+ cd $$(LIBFFI_DIR-$1 ) && python generate-darwin-source-and-headers.py --only-$(shell echo $1 | tr '[:upper:]' '[:lower:]')
503+
504+ $$(LIBFFI_FRAMEWORK-$1 ) : $$(LIBFFI_DIR-$1 ) /libffi.a
505+ # Create framework directory structure
506+ mkdir -p $$(LIBFFI_FRAMEWORK-$1 )
507+
508+ # Copy the headers.
509+ cp -f -r $$(LIBFFI_DIR-$1)/darwin_common/include $$(LIBFFI_FRAMEWORK-$1)/Headers
510+ cp -f -r $$(LIBFFI_DIR-$1)/darwin_$(shell echo $1 | tr '[:upper:]' '[:lower:]')/include/* $$(LIBFFI_FRAMEWORK-$1)/Headers
511+
512+ # Create the fat library
513+ xcrun libtool -no_warning_for_no_symbols -static \
514+ -o $$(LIBFFI_FRAMEWORK-$1)/libFFI.a $$^
515+
516+ $$(LIBFFI_DIR-$1 ) /libffi.a : $$(foreach target,$$(TARGETS-$1 ) ,$$(LIBFFI_DIR-$1 ) /libffi.$$(target ) .a)
517+ xcrun lipo -create -o $$@ $$^
518+
443519endif
444520
445521$1: Python-$1
@@ -479,7 +555,9 @@ vars-$1: $$(foreach target,$$(TARGETS-$1),vars-$$(target))
479555 @echo "OPENSSL_FRAMEWORK-$1: $$(OPENSSL_FRAMEWORK-$1 ) "
480556 @echo "BZIP2_FRAMEWORK-$1: $$(BZIP2_FRAMEWORK-$1 ) "
481557 @echo "XZ_FRAMEWORK-$1: $$(XZ_FRAMEWORK-$1 ) "
558+ @echo "LIBFFI_FRAMEWORK-$1: $$(LIBFFI_FRAMEWORK-$1 ) "
482559 @echo "PYTHON_FRAMEWORK-$1: $$(PYTHON_FRAMEWORK-$1 ) "
560+ @echo "LIBFFI_DIR-$1: $$(LIBFFI_DIR-$1 ) "
483561 @echo "PYTHON_RESOURCES-$1: $$(PYTHON_RESOURCES-$1 ) "
484562 @echo "PYTHON_TARGETS-$1: $$(PYTHON_TARGETS-$1 ) "
485563
0 commit comments