diff --git a/Lib/ctypes/test/test_as_parameter.py b/Lib/ctypes/test/test_as_parameter.py index f9d27cb89d..da172b345a 100644 --- a/Lib/ctypes/test/test_as_parameter.py +++ b/Lib/ctypes/test/test_as_parameter.py @@ -1,9 +1,11 @@ +import os import unittest from ctypes import * from ctypes.test import need_symbol import _ctypes_test -dll = CDLL(_ctypes_test.__file__) + +dll = CDLL(getattr(_ctypes_test, '__file__', os.environ['TEST_EXECUTABLE'])) try: CALLBACK_FUNCTYPE = WINFUNCTYPE diff --git a/Lib/ctypes/test/test_bitfields.py b/Lib/ctypes/test/test_bitfields.py index 66acd62e68..95216920e6 100644 --- a/Lib/ctypes/test/test_bitfields.py +++ b/Lib/ctypes/test/test_bitfields.py @@ -25,7 +25,7 @@ ("R", c_short, 6), ("S", c_short, 7)] -func = CDLL(_ctypes_test.__file__).unpack_bitfields +func = CDLL(getattr(_ctypes_test, '__file__', os.environ['TEST_EXECUTABLE'])).unpack_bitfields func.argtypes = POINTER(BITS), c_char ##for n in "ABCDEFGHIMNOPQRS": diff --git a/Lib/ctypes/test/test_callbacks.py b/Lib/ctypes/test/test_callbacks.py index 1099cf9a69..e9caf8032d 100644 --- a/Lib/ctypes/test/test_callbacks.py +++ b/Lib/ctypes/test/test_callbacks.py @@ -1,4 +1,5 @@ import functools +import os import unittest from test import support @@ -161,7 +162,7 @@ def test_integrate(self): # Derived from some then non-working code, posted by David Foster - dll = CDLL(_ctypes_test.__file__) + dll = CDLL(getattr(_ctypes_test, '__file__', os.environ['TEST_EXECUTABLE'])) # The function prototype called by 'integrate': double func(double); CALLBACK = CFUNCTYPE(c_double, c_double) @@ -212,7 +213,7 @@ def test_callback_register_int(self): # Issue #8275: buggy handling of callback args under Win64 # NOTE: should be run on release builds as well - dll = CDLL(_ctypes_test.__file__) + dll = CDLL(getattr(_ctypes_test, '__file__', os.environ['TEST_EXECUTABLE'])) CALLBACK = CFUNCTYPE(c_int, c_int, c_int, c_int, c_int, c_int) # All this function does is call the callback with its args squared func = dll._testfunc_cbk_reg_int @@ -228,7 +229,7 @@ def test_callback_register_double(self): # Issue #8275: buggy handling of callback args under Win64 # NOTE: should be run on release builds as well - dll = CDLL(_ctypes_test.__file__) + dll = CDLL(getattr(_ctypes_test, '__file__', os.environ['TEST_EXECUTABLE'])) CALLBACK = CFUNCTYPE(c_double, c_double, c_double, c_double, c_double, c_double) # All this function does is call the callback with its args squared diff --git a/Lib/ctypes/test/test_cfuncs.py b/Lib/ctypes/test/test_cfuncs.py index ac2240fa19..b08b5f7581 100644 --- a/Lib/ctypes/test/test_cfuncs.py +++ b/Lib/ctypes/test/test_cfuncs.py @@ -1,6 +1,7 @@ # A lot of failures in these tests on Mac OS X. # Byte order related? +import os import unittest from ctypes import * from ctypes.test import need_symbol @@ -8,7 +9,7 @@ import _ctypes_test class CFunctions(unittest.TestCase): - _dll = CDLL(_ctypes_test.__file__) + _dll = CDLL(getattr(_ctypes_test, '__file__', os.environ['TEST_EXECUTABLE'])) def S(self): return c_longlong.in_dll(self._dll, "last_tf_arg_s").value @@ -206,7 +207,7 @@ @need_symbol('WinDLL') class stdcallCFunctions(CFunctions): - _dll = stdcall_dll(_ctypes_test.__file__) + _dll = stdcall_dll(getattr(_ctypes_test, '__file__', os.environ['TEST_EXECUTABLE'])) if __name__ == '__main__': unittest.main() diff --git a/Lib/ctypes/test/test_checkretval.py b/Lib/ctypes/test/test_checkretval.py index e9567dc391..3c3fbf103c 100644 --- a/Lib/ctypes/test/test_checkretval.py +++ b/Lib/ctypes/test/test_checkretval.py @@ -1,3 +1,4 @@ +import os import unittest from ctypes import * @@ -14,7 +15,7 @@ def test_checkretval(self): import _ctypes_test - dll = CDLL(_ctypes_test.__file__) + dll = CDLL(getattr(_ctypes_test, '__file__', os.environ['TEST_EXECUTABLE'])) self.assertEqual(42, dll._testfunc_p_p(42)) dll._testfunc_p_p.restype = CHECKED diff --git a/Lib/ctypes/test/test_funcptr.py b/Lib/ctypes/test/test_funcptr.py index e0b9b54e97..1c05dcc22c 100644 --- a/Lib/ctypes/test/test_funcptr.py +++ b/Lib/ctypes/test/test_funcptr.py @@ -1,3 +1,4 @@ +import os import unittest from ctypes import * @@ -8,7 +9,10 @@ WINFUNCTYPE = CFUNCTYPE import _ctypes_test -lib = CDLL(_ctypes_test.__file__) + + +lib = CDLL(getattr(_ctypes_test, '__file__', os.environ['TEST_EXECUTABLE'])) + class CFuncPtrTestCase(unittest.TestCase): def test_basic(self): diff --git a/Lib/ctypes/test/test_functions.py b/Lib/ctypes/test/test_functions.py index f9e92e1cc6..0e2255b62e 100644 --- a/Lib/ctypes/test/test_functions.py +++ b/Lib/ctypes/test/test_functions.py @@ -7,6 +7,7 @@ from ctypes import * from ctypes.test import need_symbol +import os import sys, unittest try: @@ -16,7 +17,9 @@ WINFUNCTYPE = CFUNCTYPE import _ctypes_test -dll = CDLL(_ctypes_test.__file__) + + +dll = CDLL(getattr(_ctypes_test, '__file__', os.environ['TEST_EXECUTABLE'])) if sys.platform == "win32": windll = WinDLL(_ctypes_test.__file__) diff --git a/Lib/ctypes/test/test_libc.py b/Lib/ctypes/test/test_libc.py index 56285b5ff8..f78a152ade 100644 --- a/Lib/ctypes/test/test_libc.py +++ b/Lib/ctypes/test/test_libc.py @@ -1,9 +1,12 @@ +import os import unittest from ctypes import * import _ctypes_test -lib = CDLL(_ctypes_test.__file__) + +lib = CDLL(getattr(_ctypes_test, '__file__', os.environ['TEST_EXECUTABLE'])) + def three_way_cmp(x, y): """Return -1 if x < y, 0 if x == y and 1 if x > y""" diff --git a/Lib/ctypes/test/test_parameters.py b/Lib/ctypes/test/test_parameters.py index 38af7ac13d..872d3f364a 100644 --- a/Lib/ctypes/test/test_parameters.py +++ b/Lib/ctypes/test/test_parameters.py @@ -1,3 +1,4 @@ +import os import unittest from ctypes.test import need_symbol import test.support @@ -140,7 +141,7 @@ import _ctypes_test from ctypes import CDLL, c_void_p, ArgumentError - func = CDLL(_ctypes_test.__file__)._testfunc_p_p + func = CDLL(getattr(_ctypes_test, '__file__', os.environ['TEST_EXECUTABLE']))._testfunc_p_p func.restype = c_void_p # TypeError: has no from_param method self.assertRaises(TypeError, setattr, func, "argtypes", (object,)) diff --git a/Lib/ctypes/test/test_pickling.py b/Lib/ctypes/test/test_pickling.py index c4a79b9779..833608b629 100644 --- a/Lib/ctypes/test/test_pickling.py +++ b/Lib/ctypes/test/test_pickling.py @@ -1,8 +1,11 @@ import unittest +import os import pickle from ctypes import * import _ctypes_test -dll = CDLL(_ctypes_test.__file__) + + +dll = CDLL(getattr(_ctypes_test, '__file__', os.environ['TEST_EXECUTABLE'])) class X(Structure): _fields_ = [("a", c_int), ("b", c_double)] diff --git a/Lib/ctypes/test/test_pointers.py b/Lib/ctypes/test/test_pointers.py index e97515879f..d678be3800 100644 --- a/Lib/ctypes/test/test_pointers.py +++ b/Lib/ctypes/test/test_pointers.py @@ -1,3 +1,4 @@ +import os import unittest, sys from ctypes import * @@ -20,7 +21,7 @@ self.assertRaises(TypeError, A, c_ulong(33)) def test_pass_pointers(self): - dll = CDLL(_ctypes_test.__file__) + dll = CDLL(getattr(_ctypes_test, '__file__', os.environ['TEST_EXECUTABLE'])) func = dll._testfunc_p_p if sizeof(c_longlong) == sizeof(c_void_p): func.restype = c_longlong @@ -38,7 +39,7 @@ self.assertEqual(res[0], 12345678) def test_change_pointers(self): - dll = CDLL(_ctypes_test.__file__) + dll = CDLL(getattr(_ctypes_test, '__file__', os.environ['TEST_EXECUTABLE'])) func = dll._testfunc_p_p i = c_int(87654) @@ -77,7 +78,7 @@ return 0 callback = PROTOTYPE(func) - dll = CDLL(_ctypes_test.__file__) + dll = CDLL(getattr(_ctypes_test, '__file__', os.environ['TEST_EXECUTABLE'])) # This function expects a function pointer, # and calls this with an integer pointer as parameter. # The int pointer points to a table containing the numbers 1..10 @@ -143,7 +144,7 @@ def test_charpp(self): """Test that a character pointer-to-pointer is correctly passed""" - dll = CDLL(_ctypes_test.__file__) + dll = CDLL(getattr(_ctypes_test, '__file__', os.environ['TEST_EXECUTABLE'])) func = dll._testfunc_c_p_p func.restype = c_char_p argv = (c_char_p * 2)() diff --git a/Lib/ctypes/test/test_prototypes.py b/Lib/ctypes/test/test_prototypes.py index cd0c649de3..539351f798 100644 --- a/Lib/ctypes/test/test_prototypes.py +++ b/Lib/ctypes/test/test_prototypes.py @@ -1,3 +1,4 @@ +import os from ctypes import * from ctypes.test import need_symbol import unittest @@ -23,7 +24,9 @@ # In this case, there would have to be an additional reference to the argument... import _ctypes_test -testdll = CDLL(_ctypes_test.__file__) + + +testdll = CDLL(getattr(_ctypes_test, '__file__', os.environ['TEST_EXECUTABLE'])) # Return machine address `a` as a (possibly long) non-negative integer. # Starting with Python 2.5, id(anything) is always non-negative, and diff --git a/Lib/ctypes/test/test_refcounts.py b/Lib/ctypes/test/test_refcounts.py index f2edfa6400..0e4dd7c126 100644 --- a/Lib/ctypes/test/test_refcounts.py +++ b/Lib/ctypes/test/test_refcounts.py @@ -1,3 +1,4 @@ +import os import unittest from test import support import ctypes @@ -7,7 +8,10 @@ OtherCallback = ctypes.CFUNCTYPE(ctypes.c_int, ctypes.c_int, ctypes.c_ulonglong) import _ctypes_test -dll = ctypes.CDLL(_ctypes_test.__file__) + + +dll = ctypes.CDLL(getattr(_ctypes_test, '__file__', os.environ['TEST_EXECUTABLE'])) + class RefcountTestCase(unittest.TestCase): diff --git a/Lib/ctypes/test/test_returnfuncptrs.py b/Lib/ctypes/test/test_returnfuncptrs.py index 1974f40df6..7b76fae44c 100644 --- a/Lib/ctypes/test/test_returnfuncptrs.py +++ b/Lib/ctypes/test/test_returnfuncptrs.py @@ -1,5 +1,6 @@ import unittest from ctypes import * +import os import _ctypes_test @@ -8,7 +9,7 @@ def test_with_prototype(self): # The _ctypes_test shared lib/dll exports quite some functions for testing. # The get_strchr function returns a *pointer* to the C strchr function. - dll = CDLL(_ctypes_test.__file__) + dll = CDLL(getattr(_ctypes_test, '__file__', os.environ['TEST_EXECUTABLE'])) get_strchr = dll.get_strchr get_strchr.restype = CFUNCTYPE(c_char_p, c_char_p, c_char) strchr = get_strchr() @@ -20,7 +21,7 @@ self.assertRaises(TypeError, strchr, b"abcdef") def test_without_prototype(self): - dll = CDLL(_ctypes_test.__file__) + dll = CDLL(getattr(_ctypes_test, '__file__', os.environ['TEST_EXECUTABLE'])) get_strchr = dll.get_strchr # the default 'c_int' would not work on systems where sizeof(int) != sizeof(void *) get_strchr.restype = c_void_p @@ -34,7 +35,7 @@ self.assertRaises(TypeError, strchr, b"abcdef") def test_from_dll(self): - dll = CDLL(_ctypes_test.__file__) + dll = CDLL(getattr(_ctypes_test, '__file__', os.environ['TEST_EXECUTABLE'])) # _CFuncPtr instances are now callable with a tuple argument # which denotes a function name and a dll: strchr = CFUNCTYPE(c_char_p, c_char_p, c_char)(("my_strchr", dll)) @@ -50,13 +51,13 @@ if key == 0: return "my_strchr" if key == 1: - return CDLL(_ctypes_test.__file__) + return CDLL(getattr(_ctypes_test, '__file__', os.environ['TEST_EXECUTABLE'])) raise IndexError # _CFuncPtr instances are now callable with a tuple argument # which denotes a function name and a dll: strchr = CFUNCTYPE(c_char_p, c_char_p, c_char)( - BadSequence(("my_strchr", CDLL(_ctypes_test.__file__)))) + BadSequence(("my_strchr", CDLL(getattr(_ctypes_test, '__file__', os.environ['TEST_EXECUTABLE']))))) self.assertTrue(strchr(b"abcdef", b"b"), "bcdef") self.assertEqual(strchr(b"abcdef", b"x"), None) self.assertRaises(ArgumentError, strchr, b"abcdef", 3.0) diff --git a/Lib/ctypes/test/test_slicing.py b/Lib/ctypes/test/test_slicing.py index a3932f1767..6d7bfff8f2 100644 --- a/Lib/ctypes/test/test_slicing.py +++ b/Lib/ctypes/test/test_slicing.py @@ -1,3 +1,4 @@ +import os import unittest from ctypes import * from ctypes.test import need_symbol @@ -62,7 +63,7 @@ def test_char_ptr(self): s = b"abcdefghijklmnopqrstuvwxyz" - dll = CDLL(_ctypes_test.__file__) + dll = CDLL(getattr(_ctypes_test, '__file__', os.environ['TEST_EXECUTABLE'])) dll.my_strdup.restype = POINTER(c_char) dll.my_free.restype = None res = dll.my_strdup(s) @@ -94,7 +95,7 @@ dll.my_free(res) def test_char_ptr_with_free(self): - dll = CDLL(_ctypes_test.__file__) + dll = CDLL(getattr(_ctypes_test, '__file__', os.environ['TEST_EXECUTABLE'])) s = b"abcdefghijklmnopqrstuvwxyz" class allocated_c_char_p(c_char_p): @@ -130,7 +131,7 @@ def test_wchar_ptr(self): s = "abcdefghijklmnopqrstuvwxyz\0" - dll = CDLL(_ctypes_test.__file__) + dll = CDLL(getattr(_ctypes_test, '__file__', os.environ['TEST_EXECUTABLE'])) dll.my_wcsdup.restype = POINTER(c_wchar) dll.my_wcsdup.argtypes = POINTER(c_wchar), dll.my_free.restype = None diff --git a/Lib/ctypes/test/test_stringptr.py b/Lib/ctypes/test/test_stringptr.py index c20951f4ce..fde0eef1c7 100644 --- a/Lib/ctypes/test/test_stringptr.py +++ b/Lib/ctypes/test/test_stringptr.py @@ -1,10 +1,12 @@ +import os import unittest from test import support from ctypes import * import _ctypes_test -lib = CDLL(_ctypes_test.__file__) + +lib = CDLL(getattr(_ctypes_test, '__file__', os.environ['TEST_EXECUTABLE'])) class StringPtrTestCase(unittest.TestCase): diff --git a/Lib/ctypes/test/test_unicode.py b/Lib/ctypes/test/test_unicode.py index 60c75424b7..8c008b466b 100644 --- a/Lib/ctypes/test/test_unicode.py +++ b/Lib/ctypes/test/test_unicode.py @@ -1,3 +1,4 @@ +import os import unittest import ctypes from ctypes.test import need_symbol @@ -7,7 +8,7 @@ @need_symbol('c_wchar') class UnicodeTestCase(unittest.TestCase): def test_wcslen(self): - dll = ctypes.CDLL(_ctypes_test.__file__) + dll = ctypes.CDLL(getattr(_ctypes_test, '__file__', os.environ['TEST_EXECUTABLE'])) wcslen = dll.my_wcslen wcslen.argtypes = [ctypes.c_wchar_p] @@ -34,7 +35,7 @@ t.unicode = "foo\0bar\0\0" -func = ctypes.CDLL(_ctypes_test.__file__)._testfunc_p_p +func = ctypes.CDLL(getattr(_ctypes_test, '__file__', os.environ['TEST_EXECUTABLE']))._testfunc_p_p class StringTestCase(UnicodeTestCase): def setUp(self): diff --git a/Lib/ctypes/test/test_values.py b/Lib/ctypes/test/test_values.py index 435fdd22ea..a57f9cf054 100644 --- a/Lib/ctypes/test/test_values.py +++ b/Lib/ctypes/test/test_values.py @@ -4,6 +4,7 @@ import _imp import importlib.util +import os import unittest import sys from ctypes import * @@ -16,7 +17,7 @@ def test_an_integer(self): # This test checks and changes an integer stored inside the # _ctypes_test dll/shared lib. - ctdll = CDLL(_ctypes_test.__file__) + ctdll = CDLL(getattr(_ctypes_test, '__file__', os.environ['TEST_EXECUTABLE'])) an_integer = c_int.in_dll(ctdll, "an_integer") x = an_integer.value self.assertEqual(x, ctdll.get_an_integer()) @@ -28,7 +29,7 @@ self.assertEqual(x, ctdll.get_an_integer()) def test_undefined(self): - ctdll = CDLL(_ctypes_test.__file__) + ctdll = CDLL(getattr(_ctypes_test, '__file__', os.environ['TEST_EXECUTABLE'])) self.assertRaises(ValueError, c_int.in_dll, ctdll, "Undefined_Symbol") class PythonValuesTestCase(unittest.TestCase): diff --git a/Lib/ctypes/test/test_win32.py b/Lib/ctypes/test/test_win32.py index e51bdc8ad6..78ba8e6786 100644 --- a/Lib/ctypes/test/test_win32.py +++ b/Lib/ctypes/test/test_win32.py @@ -1,6 +1,7 @@ # Windows specific tests from ctypes import * +import os import unittest, sys from test import support @@ -102,7 +103,7 @@ ("right", c_long), ("bottom", c_long)] - dll = CDLL(_ctypes_test.__file__) + dll = CDLL(getattr(_ctypes_test, '__file__', os.environ['TEST_EXECUTABLE'])) pt = POINT(15, 25) left = c_long.in_dll(dll, 'left') diff --git a/Lib/ctypes/util.py b/Lib/ctypes/util.py index 0c2510e161..6c3c43f11d 100644 --- a/Lib/ctypes/util.py +++ b/Lib/ctypes/util.py @@ -67,7 +67,7 @@ return fname return None -elif os.name == "posix" and sys.platform == "darwin": +elif os.name == "posix" and sys.platform in ('darwin', 'ios', 'tvos', 'watchos'): from ctypes.macholib.dyld import dyld_find as _dyld_find def find_library(name): possible = ['lib%s.dylib' % name, diff --git a/Lib/distutils/tests/test_cygwinccompiler.py b/Lib/distutils/tests/test_cygwinccompiler.py index 0912ffd15c..959aa90522 100644 --- a/Lib/distutils/tests/test_cygwinccompiler.py +++ b/Lib/distutils/tests/test_cygwinccompiler.py @@ -5,11 +5,14 @@ from io import BytesIO from test.support import run_unittest -from distutils import cygwinccompiler -from distutils.cygwinccompiler import (check_config_h, - CONFIG_H_OK, CONFIG_H_NOTOK, - CONFIG_H_UNCERTAIN, get_versions, - get_msvcr) +# Importing cygwinccompiler attempts to import other tools +# that may not exist unless you're on win32. +if sys.platform == 'win32': + from distutils import cygwinccompiler + from distutils.cygwinccompiler import (check_config_h, + CONFIG_H_OK, CONFIG_H_NOTOK, + CONFIG_H_UNCERTAIN, get_versions, + get_msvcr) from distutils.tests import support class FakePopen(object): @@ -25,6 +28,7 @@ self.stdout = os.popen(cmd, 'r') +@unittest.skipUnless(sys.platform == "win32", "These tests are only for win32") class CygwinCCompilerTestCase(support.TempdirManager, unittest.TestCase): diff --git a/Lib/distutils/util.py b/Lib/distutils/util.py index 2ce5c5b64d..6e10a0c4a5 100644 --- a/Lib/distutils/util.py +++ b/Lib/distutils/util.py @@ -170,7 +170,7 @@ if _environ_checked: return - if os.name == 'posix' and 'HOME' not in os.environ: + if os.name == 'posix' and 'HOME' not in os.environ and sys.platform not in ('ios', 'tvos', 'watchos'): try: import pwd os.environ['HOME'] = pwd.getpwuid(os.getuid())[5] diff --git a/Lib/importlib/_bootstrap_external.py b/Lib/importlib/_bootstrap_external.py index 5f67226adf..96f771fbe6 100644 --- a/Lib/importlib/_bootstrap_external.py +++ b/Lib/importlib/_bootstrap_external.py @@ -52,7 +52,7 @@ # Bootstrap-related code ###################################################### _CASE_INSENSITIVE_PLATFORMS_STR_KEY = 'win', -_CASE_INSENSITIVE_PLATFORMS_BYTES_KEY = 'cygwin', 'darwin' +_CASE_INSENSITIVE_PLATFORMS_BYTES_KEY = 'cygwin', 'darwin', 'ios', 'tvos', 'watchos' _CASE_INSENSITIVE_PLATFORMS = (_CASE_INSENSITIVE_PLATFORMS_BYTES_KEY + _CASE_INSENSITIVE_PLATFORMS_STR_KEY) diff --git a/Lib/platform.py b/Lib/platform.py index 3f3f25a2c9..deb4165665 100755 --- a/Lib/platform.py +++ b/Lib/platform.py @@ -447,6 +447,47 @@ # If that also doesn't work return the default values return release, versioninfo, machine +def iOS_ver(): + """ Get iOS/tvOS version information, and return it as a + tuple (system, release). All tuple entries are strings. + + Equivalent of: + system = [[UIDevice currentDevice].model] UTF8String] + release = [[UIDevice currentDevice].systemVersion] UTF8String] + + """ + from ctypes import cast, cdll, c_void_p, c_char_p + from ctypes import util + objc = cdll.LoadLibrary(util.find_library(b'objc')) + uikit = cdll.LoadLibrary(util.find_library(b'UIKit')) + + objc.objc_getClass.restype = c_void_p + objc.objc_getClass.argtypes = [c_char_p] + objc.objc_msgSend.restype = c_void_p + objc.objc_msgSend.argtypes = [c_void_p, c_void_p] + objc.sel_registerName.restype = c_void_p + objc.sel_registerName.argtypes = [c_char_p] + + UIDevice = c_void_p(objc.objc_getClass(b'UIDevice')) + SEL_currentDevice = c_void_p(objc.sel_registerName(b'currentDevice')) + device = c_void_p(objc.objc_msgSend(UIDevice, SEL_currentDevice)) + + SEL_systemVersion = c_void_p(objc.sel_registerName(b'systemVersion')) + systemVersion = c_void_p(objc.objc_msgSend(device, SEL_systemVersion)) + + SEL_systemName = c_void_p(objc.sel_registerName(b'systemName')) + systemName = c_void_p(objc.objc_msgSend(device, SEL_systemName)) + + # UTF8String returns a const char*; + SEL_UTF8String = c_void_p(objc.sel_registerName(b'UTF8String')) + objc.objc_msgSend.restype = c_char_p + + system = objc.objc_msgSend(systemName, SEL_UTF8String).decode() + release = objc.objc_msgSend(systemVersion, SEL_UTF8String).decode() + + return system, release + + def _java_getprop(name, default): from java.lang import System @@ -603,7 +644,7 @@ default in case the command should fail. """ - if sys.platform in ('dos', 'win32', 'win16'): + if sys.platform in ('dos', 'win32', 'win16', 'ios', 'tvos', 'watchos'): # XXX Others too ? return default @@ -745,6 +786,13 @@ csid, cpu_number = vms_lib.getsyi('SYI$_CPU', 0) return 'Alpha' if cpu_number >= 128 else 'VAX' + # iOS, tvOS and watchOS processor is the same as machine + def get_ios(): + return '' + + get_tvos = get_ios + get_watchos = get_ios + def from_subprocess(): """ Fall back to `uname -p` @@ -1208,11 +1256,13 @@ system, release, version = system_alias(system, release, version) if system == 'Darwin': - # macOS (darwin kernel) - macos_release = mac_ver()[0] - if macos_release: - system = 'macOS' - release = macos_release + if sys.platform in ('ios', 'tvos'): + system, release = iOS_ver() + else: + macos_release = mac_ver()[0] + if macos_release: + system = 'macOS' + release = macos_release if system == 'Windows': # MS platforms diff --git a/Lib/site.py b/Lib/site.py index b11cd48e69..3c0fb81ccb 100644 --- a/Lib/site.py +++ b/Lib/site.py @@ -294,6 +294,9 @@ if sys.platform == 'darwin' and sys._framework: return f'{userbase}/lib/python/site-packages' + elif sys.platform in ('ios', 'tvos', 'watchos'): + from sysconfig import get_path + return get_path('purelib', sys.platform) return f'{userbase}/lib/python{version[0]}.{version[1]}/site-packages' diff --git a/Lib/subprocess.py b/Lib/subprocess.py index 6e61cc2e5e..994e2d0518 100644 --- a/Lib/subprocess.py +++ b/Lib/subprocess.py @@ -97,7 +97,7 @@ "CREATE_NO_WINDOW", "DETACHED_PROCESS", "CREATE_DEFAULT_ERROR_MODE", "CREATE_BREAKAWAY_FROM_JOB"]) else: - if sys.platform in {"emscripten", "wasi"}: + if sys.platform in {"emscripten", "wasi", "ios", "tvos", "watchos"}: def _fork_exec(*args, **kwargs): raise OSError( errno.ENOTSUP, f"{sys.platform} does not support processes." @@ -1896,7 +1896,7 @@ else: self.returncode = waitstatus_to_exitcode(sts) - def _internal_poll(self, _deadstate=None, _waitpid=os.waitpid, + def _internal_poll(self, _deadstate=None, _waitpid=None, _WNOHANG=os.WNOHANG, _ECHILD=errno.ECHILD): """Check if child process has terminated. Returns returncode attribute. @@ -1905,6 +1905,8 @@ outside of the local scope (nor can any methods it calls). """ + if _waitpid is None: + _waitpid = os.waitpid if self.returncode is None: if not self._waitpid_lock.acquire(False): # Something else is busy calling waitpid. Don't allow two diff --git a/Lib/sysconfig.py b/Lib/sysconfig.py index e21b7303fe..026934bb34 100644 --- a/Lib/sysconfig.py +++ b/Lib/sysconfig.py @@ -95,6 +95,33 @@ 'scripts': '{base}/Scripts', 'data': '{base}', }, + 'ios': { + 'stdlib': '{installed_base}/lib/python%s' % sys.version[:3], + 'platstdlib': '{installed_base}/lib/python%s' % sys.version[:3], + 'purelib': '{installed_base}/lib/python%s/site-packages' % sys.version[:3], + 'platlib': '{installed_base}/lib/python%s/site-packages' % sys.version[:3], + 'include': '{installed_base}/include', + 'scripts': '{installed_base}/bin', + 'data': '{installed_base}/Resources', + }, + 'tvos': { + 'stdlib': '{installed_base}/lib/python%s' % sys.version[:3], + 'platstdlib': '{installed_base}/lib/python%s' % sys.version[:3], + 'purelib': '{installed_base}/lib/python%s/site-packages' % sys.version[:3], + 'platlib': '{installed_base}/lib/python%s/site-packages' % sys.version[:3], + 'include': '{installed_base}/include', + 'scripts': '{installed_base}/bin', + 'data': '{installed_base}/Resources', + }, + 'watchos': { + 'stdlib': '{installed_base}/lib/python%s' % sys.version[:3], + 'platstdlib': '{installed_base}/lib/python%s' % sys.version[:3], + 'purelib': '{installed_base}/lib/python%s/site-packages' % sys.version[:3], + 'platlib': '{installed_base}/lib/python%s/site-packages' % sys.version[:3], + 'include': '{installed_base}/include', + 'scripts': '{installed_base}/bin', + 'data': '{installed_base}/Resources', + }, } # For the OS-native venv scheme, we essentially provide an alias: @@ -282,12 +309,19 @@ 'home': 'posix_home', 'user': 'nt_user', } + if sys.platform in ('ios', 'tvos', 'watchos'): + return { + 'prefix': sys.platform, + 'home': sys.platform, + 'user': sys.platform, + } if sys.platform == 'darwin' and sys._framework: return { 'prefix': 'posix_prefix', 'home': 'posix_home', 'user': 'osx_framework_user', } + return { 'prefix': 'posix_prefix', 'home': 'posix_home', diff --git a/Lib/test/support/__init__.py b/Lib/test/support/__init__.py index 3b2f33979d..86e7fb2d47 100644 --- a/Lib/test/support/__init__.py +++ b/Lib/test/support/__init__.py @@ -47,7 +47,7 @@ "check__all__", "skip_if_buggy_ucrt_strfptime", "check_disallow_instantiation", "check_sanitizer", "skip_if_sanitizer", # sys - "is_jython", "is_android", "is_emscripten", "is_wasi", + "is_jython", "is_android", "is_emscripten", "is_wasi", "is_apple_mobile", "check_impl_detail", "unix_shell", "setswitchinterval", # network "open_urlresource", @@ -500,7 +500,7 @@ is_android = hasattr(sys, 'getandroidapilevel') -if sys.platform not in ('win32', 'vxworks'): +if sys.platform not in ('win32', 'vxworks', 'ios', 'tvos', 'watchos'): unix_shell = '/system/bin/sh' if is_android else '/bin/sh' else: unix_shell = None @@ -510,12 +510,25 @@ is_emscripten = sys.platform == "emscripten" is_wasi = sys.platform == "wasi" -has_fork_support = hasattr(os, "fork") and not is_emscripten and not is_wasi +# Apple mobile platforms (iOS/tvOS/watchOS) are POSIX-like but do not +# have subprocess or fork support. +is_apple_mobile = sys.platform in ('ios', 'tvos', 'watchos') + +has_fork_support = ( + hasattr(os, "fork") + and not is_emscripten + and not is_wasi + and not is_apple_mobile +) def requires_fork(): return unittest.skipUnless(has_fork_support, "requires working os.fork()") -has_subprocess_support = not is_emscripten and not is_wasi +has_subprocess_support = ( + not is_emscripten + and not is_wasi + and not is_apple_mobile +) def requires_subprocess(): """Used for subprocess, os.spawn calls, fd inheritance""" diff --git a/Lib/test/test_asyncio/test_events.py b/Lib/test/test_asyncio/test_events.py index 05d9107b28..76a6100a1e 100644 --- a/Lib/test/test_asyncio/test_events.py +++ b/Lib/test/test_asyncio/test_events.py @@ -542,6 +542,8 @@ self._basetest_create_connection(conn_fut) @socket_helper.skip_unless_bind_unix_socket + @unittest.skipIf(sys.platform in ('ios', 'tvos', 'watchos'), + "%s doesn't fully support UNIX sockets." % sys.platform) def test_create_unix_connection(self): # Issue #20682: On Mac OS X Tiger, getsockname() returns a # zero-length address for UNIX socket. @@ -634,6 +636,8 @@ self.assertEqual(cm.exception.reason, 'CERTIFICATE_VERIFY_FAILED') @unittest.skipIf(ssl is None, 'No ssl module') + @unittest.skipIf(sys.platform in ('ios', 'tvos', 'watchos'), + "%s doesn't fully support UNIX sockets." % sys.platform) def test_create_ssl_connection(self): with test_utils.run_test_server(use_ssl=True) as httpd: create_connection = functools.partial( @@ -645,6 +649,8 @@ @socket_helper.skip_unless_bind_unix_socket @unittest.skipIf(ssl is None, 'No ssl module') + @unittest.skipIf(sys.platform in ('ios', 'tvos', 'watchos'), + "%s doesn't fully support UNIX sockets." % sys.platform) def test_create_ssl_unix_connection(self): # Issue #20682: On Mac OS X Tiger, getsockname() returns a # zero-length address for UNIX socket. @@ -860,6 +866,8 @@ return server, path @socket_helper.skip_unless_bind_unix_socket + @unittest.skipIf(sys.platform in ('ios', 'tvos', 'watchos'), + "%s doesn't fully support UNIX sockets." % sys.platform) def test_create_unix_server(self): proto = MyProto(loop=self.loop) server, path = self._make_unix_server(lambda: proto) @@ -888,6 +896,8 @@ server.close() @unittest.skipUnless(hasattr(socket, 'AF_UNIX'), 'No UNIX Sockets') + @unittest.skipIf(sys.platform in ('ios', 'tvos', 'watchos'), + "%s doesn't fully support UNIX sockets." % sys.platform) def test_create_unix_server_path_socket_error(self): proto = MyProto(loop=self.loop) sock = socket.socket() @@ -953,6 +963,8 @@ @socket_helper.skip_unless_bind_unix_socket @unittest.skipIf(ssl is None, 'No ssl module') + @unittest.skipIf(sys.platform in ('ios', 'tvos', 'watchos'), + "%s doesn't fully support UNIX sockets." % sys.platform) def test_create_unix_server_ssl(self): proto = MyProto(loop=self.loop) server, path = self._make_ssl_unix_server( @@ -983,6 +995,8 @@ server.close() @unittest.skipIf(ssl is None, 'No ssl module') + @unittest.skipIf(sys.platform in ('ios', 'tvos', 'watchos'), + "%s doesn't fully support UNIX sockets." % sys.platform) def test_create_server_ssl_verify_failed(self): proto = MyProto(loop=self.loop) server, host, port = self._make_ssl_server( @@ -1013,6 +1027,8 @@ @socket_helper.skip_unless_bind_unix_socket @unittest.skipIf(ssl is None, 'No ssl module') + @unittest.skipIf(sys.platform in ('ios', 'tvos', 'watchos'), + "%s doesn't fully support UNIX sockets." % sys.platform) def test_create_unix_server_ssl_verify_failed(self): proto = MyProto(loop=self.loop) server, path = self._make_ssl_unix_server( @@ -1073,6 +1089,8 @@ @socket_helper.skip_unless_bind_unix_socket @unittest.skipIf(ssl is None, 'No ssl module') + @unittest.skipIf(sys.platform in ('ios', 'tvos', 'watchos'), + "%s doesn't fully support UNIX sockets." % sys.platform) def test_create_unix_server_ssl_verified(self): proto = MyProto(loop=self.loop) server, path = self._make_ssl_unix_server( diff --git a/Lib/test/test_asyncio/test_streams.py b/Lib/test/test_asyncio/test_streams.py index 098a0da344..1df5654356 100644 --- a/Lib/test/test_asyncio/test_streams.py +++ b/Lib/test/test_asyncio/test_streams.py @@ -60,6 +60,8 @@ self._basetest_open_connection(conn_fut) @socket_helper.skip_unless_bind_unix_socket + @unittest.skipIf(sys.platform in ('ios', 'tvos', 'watchos'), + "%s doesn't fully support UNIX sockets." % sys.platform) def test_open_unix_connection(self): with test_utils.run_test_unix_server() as httpd: conn_fut = asyncio.open_unix_connection(httpd.address) @@ -91,6 +93,8 @@ @socket_helper.skip_unless_bind_unix_socket @unittest.skipIf(ssl is None, 'No ssl module') + @unittest.skipIf(sys.platform in ('ios', 'tvos', 'watchos'), + "%s doesn't fully support UNIX sockets." % sys.platform) def test_open_unix_connection_no_loop_ssl(self): with test_utils.run_test_unix_server(use_ssl=True) as httpd: conn_fut = asyncio.open_unix_connection( @@ -119,6 +123,8 @@ self._basetest_open_connection_error(conn_fut) @socket_helper.skip_unless_bind_unix_socket + @unittest.skipIf(sys.platform in ('ios', 'tvos', 'watchos'), + "%s doesn't fully support UNIX sockets." % sys.platform) def test_open_unix_connection_error(self): with test_utils.run_test_unix_server() as httpd: conn_fut = asyncio.open_unix_connection(httpd.address) @@ -637,6 +643,8 @@ self.assertEqual(messages, []) @socket_helper.skip_unless_bind_unix_socket + @unittest.skipIf(sys.platform in ('ios', 'tvos', 'watchos'), + "%s doesn't fully support UNIX sockets." % sys.platform) def test_start_unix_server(self): class MyServer: diff --git a/Lib/test/test_asyncio/test_unix_events.py b/Lib/test/test_asyncio/test_unix_events.py index 2f68459d30..c9f9f48097 100644 --- a/Lib/test/test_asyncio/test_unix_events.py +++ b/Lib/test/test_asyncio/test_unix_events.py @@ -276,6 +276,8 @@ @unittest.skipUnless(hasattr(socket, 'AF_UNIX'), 'UNIX Sockets are not supported') +@unittest.skipIf(sys.platform in ('ios', 'tvos', 'watchos'), + "%s doesn't fully support UNIX sockets." % sys.platform) class SelectorEventLoopUnixSocketTests(test_utils.TestCase): def setUp(self): diff --git a/Lib/test/test_fcntl.py b/Lib/test/test_fcntl.py index fc8c39365f..00e988fdcc 100644 --- a/Lib/test/test_fcntl.py +++ b/Lib/test/test_fcntl.py @@ -25,7 +25,7 @@ start_len = "qq" if (sys.platform.startswith(('netbsd', 'freebsd', 'openbsd')) - or sys.platform == 'darwin'): + or sys.platform in ('darwin', 'ios', 'tvos', 'watchos')): if struct.calcsize('l') == 8: off_t = 'l' pid_t = 'i' diff --git a/Lib/test/test_httpservers.py b/Lib/test/test_httpservers.py index 1f041aa121..3af807f6f9 100644 --- a/Lib/test/test_httpservers.py +++ b/Lib/test/test_httpservers.py @@ -401,7 +401,7 @@ with open(os.path.join(self.tempdir, filename), 'wb') as f: f.write(os_helper.TESTFN_UNDECODABLE) response = self.request(self.base_url + '/') - if sys.platform == 'darwin': + if sys.platform in ('darwin', 'ios', 'tvos', 'watchos'): # On Mac OS the HFS+ filesystem replaces bytes that aren't valid # UTF-8 into a percent-encoded value. for name in os.listdir(self.tempdir): diff --git a/Lib/test/test_importlib/extension/test_finder.py b/Lib/test/test_importlib/extension/test_finder.py index b6663a4484..fbd553a629 100644 --- a/Lib/test/test_importlib/extension/test_finder.py +++ b/Lib/test/test_importlib/extension/test_finder.py @@ -2,10 +2,13 @@ machinery = util.import_importlib('importlib.machinery') +import sys import unittest import warnings +@unittest.skipIf(sys.platform in ('ios', 'tvos', 'watchos'), + '%s does not support dynamic loading' % sys.platform) class FinderTests(abc.FinderTests): """Test the finder for extension modules.""" diff --git a/Lib/test/test_importlib/extension/test_loader.py b/Lib/test/test_importlib/extension/test_loader.py index 5080009bee..9cf9fb3d8a 100644 --- a/Lib/test/test_importlib/extension/test_loader.py +++ b/Lib/test/test_importlib/extension/test_loader.py @@ -13,6 +13,8 @@ from test.support.script_helper import assert_python_failure +@unittest.skipIf(sys.platform in ('ios', 'tvos', 'watchos'), + '%s does not support dynamic loading' % sys.platform) class LoaderTests(abc.LoaderTests): """Test load_module() for extension modules.""" @@ -90,6 +92,9 @@ Source_LoaderTests ) = util.test_both(LoaderTests, machinery=machinery) + +@unittest.skipIf(sys.platform in ('ios', 'tvos', 'watchos'), + '%s does not support dynamic loading' % sys.platform) class MultiPhaseExtensionModuleTests(abc.LoaderTests): # Test loading extension modules with multi-phase initialization (PEP 489). diff --git a/Lib/test/test_io.py b/Lib/test/test_io.py index 5528c461e5..42fcfe8c64 100644 --- a/Lib/test/test_io.py +++ b/Lib/test/test_io.py @@ -608,7 +608,7 @@ # On Windows and Mac OSX this test consumes large resources; It takes # a long time to build the >2 GiB file and takes >2 GiB of disk space # therefore the resource must be enabled to run this test. - if sys.platform[:3] == 'win' or sys.platform == 'darwin': + if sys.platform[:3] == 'win' or sys.platform in ('darwin', 'ios', 'tvos', 'watchos'): support.requires( 'largefile', 'test requires %s bytes and a long time to run' % self.LARGE) diff --git a/Lib/test/test_logging.py b/Lib/test/test_logging.py index 5d4ddedd05..b119a43d8e 100644 --- a/Lib/test/test_logging.py +++ b/Lib/test/test_logging.py @@ -1787,9 +1787,21 @@ # just need a name - file can't be present, or we'll get an # 'address already in use' error. os.remove(fn) + # Check the size of the socket file name. If it exceeds 108 + # characters (UNIX_PATH_MAX), it can't be used as a UNIX socket. + # In this case, fall back to a path constructed somewhere that + # is known to be short. + if len(fn) > 108: + fd, fn = tempfile.mkstemp(prefix='test_logging_', suffix='.sock', dir='/tmp') + os.close(fd) + # just need a name - file can't be present, or we'll get an + # 'address already in use' error. + os.remove(fn) return fn @unittest.skipUnless(hasattr(socket, "AF_UNIX"), "Unix sockets required") +@unittest.skipIf(sys.platform in ('ios', 'tvos', 'watchos'), + "%s doesn't fully support UNIX sockets." % sys.platform) class UnixSocketHandlerTest(SocketHandlerTest): """Test for SocketHandler with unix sockets.""" @@ -1873,6 +1885,8 @@ self.assertEqual(self.log_output, "spam\neggs\n") @unittest.skipUnless(hasattr(socket, "AF_UNIX"), "Unix sockets required") +@unittest.skipIf(sys.platform in ('ios', 'tvos', 'watchos'), + "%s doesn't fully support UNIX sockets." % sys.platform) class UnixDatagramHandlerTest(DatagramHandlerTest): """Test for DatagramHandler using Unix sockets.""" @@ -1967,6 +1981,8 @@ self.assertEqual(self.log_output, b'<11>sp\xc3\xa4m\x00') @unittest.skipUnless(hasattr(socket, "AF_UNIX"), "Unix sockets required") +@unittest.skipIf(sys.platform in ('ios', 'tvos', 'watchos'), + "%s doesn't fully support UNIX sockets." % sys.platform) class UnixSysLogHandlerTest(SysLogHandlerTest): """Test for SysLogHandler with Unix sockets.""" diff --git a/Lib/test/test_mailcap.py b/Lib/test/test_mailcap.py index 97a8fac6e0..63274a7b52 100644 --- a/Lib/test/test_mailcap.py +++ b/Lib/test/test_mailcap.py @@ -219,7 +219,8 @@ ] self._run_cases(cases) - @unittest.skipUnless(os.name == "posix", "Requires 'test' command on system") + @unittest.skipUnless(os.name == "posix" and sys.platform not in ('ios', 'tvos', 'watchos'), + "Requires 'test' command on system") @unittest.skipIf(sys.platform == "vxworks", "'test' command is not supported on VxWorks") def test_test(self): # findmatch() will automatically check any "test" conditions and skip diff --git a/Lib/test/test_marshal.py b/Lib/test/test_marshal.py index aae86cc257..bb48a85517 100644 --- a/Lib/test/test_marshal.py +++ b/Lib/test/test_marshal.py @@ -260,7 +260,10 @@ if os.name == 'nt': MAX_MARSHAL_STACK_DEPTH = 1000 else: - MAX_MARSHAL_STACK_DEPTH = 2000 + if sys.platform in ('ios', 'tvos', 'watchos'): + MAX_MARSHAL_STACK_DEPTH = 1500 + else: + MAX_MARSHAL_STACK_DEPTH = 2000 for i in range(MAX_MARSHAL_STACK_DEPTH - 2): last.append([0]) last = last[-1] diff --git a/Lib/test/test_mmap.py b/Lib/test/test_mmap.py index 213a44d56f..9908e9a2c8 100644 --- a/Lib/test/test_mmap.py +++ b/Lib/test/test_mmap.py @@ -245,7 +245,7 @@ with open(TESTFN, "r+b") as f: self.assertRaises(ValueError, mmap.mmap, f.fileno(), mapsize, access=4) - if os.name == "posix": + if os.name == "posix" and sys.platform not in ('ios', 'tvos', 'watchos'): # Try incompatible flags, prot and access parameters. with open(TESTFN, "r+b") as f: self.assertRaises(ValueError, mmap.mmap, f.fileno(), mapsize, @@ -896,7 +896,7 @@ unlink(TESTFN) def _make_test_file(self, num_zeroes, tail): - if sys.platform[:3] == 'win' or sys.platform == 'darwin': + if sys.platform[:3] == 'win' or sys.platform in ('darwin', 'ios', 'tvos', 'watchos'): requires('largefile', 'test requires %s bytes and a long time to run' % str(0x180000000)) f = open(TESTFN, 'w+b') diff --git a/Lib/test/test_platform.py b/Lib/test/test_platform.py index 9b2cd201f3..dcd3a7a241 100644 --- a/Lib/test/test_platform.py +++ b/Lib/test/test_platform.py @@ -315,7 +315,7 @@ def test_mac_ver(self): res = platform.mac_ver() - if platform.uname().system == 'Darwin': + if platform.uname().system == 'Darwin' and sys.platform not in ('ios', 'tvos', 'watchos'): # We are on a macOS system, check that the right version # information is returned output = subprocess.check_output(['sw_vers'], text=True) @@ -347,6 +347,10 @@ else: self.assertEqual(res[2], 'PowerPC') + @unittest.skipUnless(sys.platform in ('ios', 'tvos', 'watchos'), "iOS/tvOS/watchOS only test") + def test_ios_ver(self): + res = platform.ios_ver() + @unittest.skipUnless(sys.platform == 'darwin', "OSX only test") def test_mac_ver_with_fork(self): diff --git a/Lib/test/test_posix.py b/Lib/test/test_posix.py index f44b8d0403..50a9bfa5b2 100644 --- a/Lib/test/test_posix.py +++ b/Lib/test/test_posix.py @@ -75,12 +75,19 @@ "getpid", "getpgrp", "getppid", "getuid", "sync", ] + # getgroups can't be invoked on iOS/tvOS/watchOS. + if sys.platform not in ('ios', 'tvos', 'watchos'): + NO_ARG_FUNCTIONS.append("getgroups") + for name in NO_ARG_FUNCTIONS: posix_func = getattr(posix, name, None) if posix_func is not None: with self.subTest(name): - posix_func() - self.assertRaises(TypeError, posix_func, 1) + try: + posix_func() + self.assertRaises(TypeError, posix_func, 1) + except Exception as e: + self.fail('Problem invoking %s: %s' % (name, e)) @unittest.skipUnless(hasattr(posix, 'getresuid'), 'test needs posix.getresuid()') @@ -780,9 +787,10 @@ check_stat(uid, gid) self.assertRaises(OSError, chown_func, first_param, 0, -1) check_stat(uid, gid) - if 0 not in os.getgroups(): - self.assertRaises(OSError, chown_func, first_param, -1, 0) - check_stat(uid, gid) + if hasattr(os, 'getgroups') and sys.platform not in ('ios', 'tvos', 'watchos'): + if 0 not in os.getgroups(): + self.assertRaises(OSError, chown_func, first_param, -1, 0) + check_stat(uid, gid) # test illegal types for t in str, float: self.assertRaises(TypeError, chown_func, first_param, t(uid), gid) @@ -1129,7 +1137,7 @@ self.assertIsInstance(hi, int) self.assertGreaterEqual(hi, lo) # OSX evidently just returns 15 without checking the argument. - if sys.platform != "darwin": + if sys.platform not in ('darwin', 'ios', 'tvos', 'watchos'): self.assertRaises(OSError, posix.sched_get_priority_min, -23) self.assertRaises(OSError, posix.sched_get_priority_max, -23) diff --git a/Lib/test/test_shutil.py b/Lib/test/test_shutil.py index 7003386345..55c83ec81e 100644 --- a/Lib/test/test_shutil.py +++ b/Lib/test/test_shutil.py @@ -1758,6 +1758,8 @@ check_chown(dirname, uid, gid) +@unittest.skipIf(sys.platform in ('ios', 'tvos', 'watchos'), + "%s doesn't support other executable." % sys.platform) class TestWhich(BaseTest, unittest.TestCase): def setUp(self): @@ -2625,6 +2627,7 @@ self.assertGreaterEqual(size.lines, 0) @unittest.skipUnless(os.isatty(sys.__stdout__.fileno()), "not on tty") + @unittest.skipUnless(os.allows_subprocesses, 'Test requires support for subprocesses.') @unittest.skipUnless(hasattr(os, 'get_terminal_size'), 'need os.get_terminal_size()') def test_stty_match(self): diff --git a/Lib/test/test_socket.py b/Lib/test/test_socket.py index 613363722c..ac48352d0f 100755 --- a/Lib/test/test_socket.py +++ b/Lib/test/test_socket.py @@ -1146,7 +1146,7 @@ # I've ordered this by protocols that have both a tcp and udp # protocol, at least for modern Linuxes. if (sys.platform.startswith(('freebsd', 'netbsd', 'gnukfreebsd')) - or sys.platform in ('linux', 'darwin')): + or sys.platform in ('linux', 'darwin', 'ios', 'tvos', 'watchos')): # avoid the 'echo' service on this platform, as there is an # assumption breaking non-standard port/protocol entry services = ('daytime', 'qotd', 'domain') @@ -3541,7 +3541,8 @@ def _testFDPassCMSG_LEN(self): self.createAndSendFDs(1) - @unittest.skipIf(sys.platform == "darwin", "skipping, see issue #12958") + @unittest.skipIf(sys.platform in ("darwin", 'iOS', 'tvos', 'watchos'), + "skipping, see issue #12958") @unittest.skipIf(AIX, "skipping, see issue #22397") @requireAttrs(socket, "CMSG_SPACE") def testFDPassSeparate(self): @@ -3552,7 +3553,8 @@ maxcmsgs=2) @testFDPassSeparate.client_skip - @unittest.skipIf(sys.platform == "darwin", "skipping, see issue #12958") + @unittest.skipIf(sys.platform in ("darwin", 'iOS', 'tvos', 'watchos'), + "skipping, see issue #12958") @unittest.skipIf(AIX, "skipping, see issue #22397") def _testFDPassSeparate(self): fd0, fd1 = self.newFDs(2) @@ -3565,7 +3567,8 @@ array.array("i", [fd1]))]), len(MSG)) - @unittest.skipIf(sys.platform == "darwin", "skipping, see issue #12958") + @unittest.skipIf(sys.platform in ("darwin", 'iOS', 'tvos', 'watchos'), + "skipping, see issue #12958") @unittest.skipIf(AIX, "skipping, see issue #22397") @requireAttrs(socket, "CMSG_SPACE") def testFDPassSeparateMinSpace(self): @@ -3579,7 +3582,8 @@ maxcmsgs=2, ignoreflags=socket.MSG_CTRUNC) @testFDPassSeparateMinSpace.client_skip - @unittest.skipIf(sys.platform == "darwin", "skipping, see issue #12958") + @unittest.skipIf(sys.platform in ("darwin", 'iOS', 'tvos', 'watchos'), + "skipping, see issue #12958") @unittest.skipIf(AIX, "skipping, see issue #22397") def _testFDPassSeparateMinSpace(self): fd0, fd1 = self.newFDs(2) @@ -3603,7 +3607,8 @@ nbytes = self.sendmsgToServer([msg]) self.assertEqual(nbytes, len(msg)) - @unittest.skipIf(sys.platform == "darwin", "see issue #24725") + @unittest.skipIf(sys.platform in ("darwin", 'iOS', 'tvos', 'watchos'), + "skipping, see issue #12958") def testFDPassEmpty(self): # Try to pass an empty FD array. Can receive either no array # or an empty array. @@ -4423,28 +4428,38 @@ pass @requireAttrs(socket.socket, "sendmsg") +@unittest.skipIf(sys.platform in ('ios', 'tvos', 'watchos'), + "%s doesn't fully support UNIX sockets." % sys.platform) @requireAttrs(socket, "AF_UNIX") class SendmsgUnixStreamTest(SendmsgStreamTests, SendrecvmsgUnixStreamTestBase): pass @requireAttrs(socket.socket, "recvmsg") +@unittest.skipIf(sys.platform in ('ios', 'tvos', 'watchos'), + "%s doesn't fully support UNIX sockets." % sys.platform) @requireAttrs(socket, "AF_UNIX") class RecvmsgUnixStreamTest(RecvmsgTests, RecvmsgGenericStreamTests, SendrecvmsgUnixStreamTestBase): pass @requireAttrs(socket.socket, "recvmsg_into") +@unittest.skipIf(sys.platform in ('ios', 'tvos', 'watchos'), + "%s doesn't fully support UNIX sockets." % sys.platform) @requireAttrs(socket, "AF_UNIX") class RecvmsgIntoUnixStreamTest(RecvmsgIntoTests, RecvmsgGenericStreamTests, SendrecvmsgUnixStreamTestBase): pass @requireAttrs(socket.socket, "sendmsg", "recvmsg") +@unittest.skipIf(sys.platform in ('ios', 'tvos', 'watchos'), + "%s doesn't fully support UNIX sockets." % sys.platform) @requireAttrs(socket, "AF_UNIX", "SOL_SOCKET", "SCM_RIGHTS") class RecvmsgSCMRightsStreamTest(SCMRightsTest, SendrecvmsgUnixStreamTestBase): pass @requireAttrs(socket.socket, "sendmsg", "recvmsg_into") +@unittest.skipIf(sys.platform in ('ios', 'tvos', 'watchos'), + "%s doesn't fully support UNIX sockets." % sys.platform) @requireAttrs(socket, "AF_UNIX", "SOL_SOCKET", "SCM_RIGHTS") class RecvmsgIntoSCMRightsStreamTest(RecvmsgIntoMixin, SCMRightsTest, SendrecvmsgUnixStreamTestBase): diff --git a/Lib/test/test_socketserver.py b/Lib/test/test_socketserver.py index 2edb1e0c0e..67a3ecfcda 100644 --- a/Lib/test/test_socketserver.py +++ b/Lib/test/test_socketserver.py @@ -8,6 +8,7 @@ import select import signal import socket +import sys import tempfile import threading import unittest @@ -198,12 +199,16 @@ self.stream_examine) @requires_unix_sockets + @unittest.skipIf(sys.platform in ('ios', 'tvos', 'watchos'), + "%s doesn't fully support UNIX sockets." % sys.platform) def test_UnixStreamServer(self): self.run_server(socketserver.UnixStreamServer, socketserver.StreamRequestHandler, self.stream_examine) @requires_unix_sockets + @unittest.skipIf(sys.platform in ('ios', 'tvos', 'watchos'), + "%s doesn't fully support UNIX sockets." % sys.platform) def test_ThreadingUnixStreamServer(self): self.run_server(socketserver.ThreadingUnixStreamServer, socketserver.StreamRequestHandler, diff --git a/Lib/test/test_sundry.py b/Lib/test/test_sundry.py index de2e7305cc..ccf240397d 100644 --- a/Lib/test/test_sundry.py +++ b/Lib/test/test_sundry.py @@ -1,5 +1,6 @@ """Do a minimal test of all the modules that aren't otherwise tested.""" import importlib +import sys from test import support from test.support import import_helper from test.support import warnings_helper @@ -20,7 +21,8 @@ import distutils.bcppcompiler import distutils.ccompiler - import distutils.cygwinccompiler + if sys.platform.startswith('win'): + import distutils.cygwinccompiler import distutils.filelist import distutils.text_file import distutils.unixccompiler diff --git a/Lib/test/test_sysconfig.py b/Lib/test/test_sysconfig.py index f2b93706b2..8bcc5ae09f 100644 --- a/Lib/test/test_sysconfig.py +++ b/Lib/test/test_sysconfig.py @@ -333,7 +333,7 @@ self.assertTrue(os.path.isfile(config_h), config_h) def test_get_scheme_names(self): - wanted = ['nt', 'posix_home', 'posix_prefix', 'posix_venv', 'nt_venv', 'venv'] + wanted = ['nt', 'posix_home', 'posix_prefix', 'posix_venv', 'nt_venv', 'venv', 'tvos', 'watchos'] if HAS_USER_BASE: wanted.extend(['nt_user', 'osx_framework_user', 'posix_user']) self.assertEqual(get_scheme_names(), tuple(sorted(wanted))) diff --git a/Lib/test/test_threading.py b/Lib/test/test_threading.py index f7dea136a8..feea7146e6 100644 --- a/Lib/test/test_threading.py +++ b/Lib/test/test_threading.py @@ -1170,6 +1170,8 @@ os.set_blocking(r, False) return (r, w) + @unittest.skipIf(sys.platform in ('ios', 'tvos', 'watchos'), + "%s doesn't have os.pipe" % sys.platform) def test_threads_join(self): # Non-daemon threads should be joined at subinterpreter shutdown # (issue #18808) @@ -1198,6 +1200,8 @@ # The thread was joined properly. self.assertEqual(os.read(r, 1), b"x") + @unittest.skipIf(sys.platform in ('ios', 'tvos', 'watchos'), + "%s doesn't have os.pipe" % sys.platform) def test_threads_join_2(self): # Same as above, but a delay gets introduced after the thread's # Python code returned but before the thread state is deleted. diff --git a/Lib/test/test_venv.py b/Lib/test/test_venv.py index d96cf1e6c7..0878f1bdd1 100644 --- a/Lib/test/test_venv.py +++ b/Lib/test/test_venv.py @@ -16,7 +16,7 @@ import tempfile from test.support import (captured_stdout, captured_stderr, requires_zlib, skip_if_broken_multiprocessing_synchronize, verbose, - requires_subprocess, is_emscripten) + requires_subprocess, is_apple_mobile, is_emscripten) from test.support.os_helper import (can_symlink, EnvironmentVarGuard, rmtree) import unittest import venv @@ -34,7 +34,7 @@ or sys._base_executable != sys.executable, 'cannot run venv.create from within a venv on this platform') -if is_emscripten: +if is_emscripten or is_apple_mobile: raise unittest.SkipTest("venv is not available on Emscripten.") @requires_subprocess() diff --git a/Lib/test/test_zipfile.py b/Lib/test/test_zipfile.py index 848bf4f76d..ed6969348c 100644 --- a/Lib/test/test_zipfile.py +++ b/Lib/test/test_zipfile.py @@ -1166,6 +1166,7 @@ self.skipTest('requires write access to the installed location') unlink(filename) + @unittest.skipIf(sys.dont_write_bytecode, "Test requires ability to write bytecode") def test_write_pyfile(self): self.requiresWriteAccess(os.path.dirname(__file__)) with TemporaryFile() as t, zipfile.PyZipFile(t, "w") as zipfp: @@ -1210,6 +1211,7 @@ self.assertCompiledIn('email/__init__.py', names) self.assertCompiledIn('email/mime/text.py', names) + @unittest.skipIf(sys.dont_write_bytecode, "Test requires ability to write bytecode") def test_write_filtered_python_package(self): import test packagedir = os.path.dirname(test.__file__) diff --git a/Lib/webbrowser.py b/Lib/webbrowser.py index 44974d433b..ae4e18802b 100755 --- a/Lib/webbrowser.py +++ b/Lib/webbrowser.py @@ -596,6 +596,57 @@ # what to do if _tryorder is now empty? +# +# Platform support for iOS +# +if sys.platform == 'ios': + class MobileSafari(BaseBrowser): + def open(self, url, new=0, autoraise=True): + # This code is the equivalent of: + # NSURL *nsurl = [NSURL URLWithString:url]; + # [[UIApplication sharedApplication] openURL:nsurl]; + from ctypes import cdll, c_void_p, c_char_p, c_uint32 + from ctypes import util + objc = cdll.LoadLibrary(util.find_library(b'objc')) + cf = cdll.LoadLibrary(util.find_library(b'CoreFoundation')) + objc.objc_getClass.restype = c_void_p + objc.objc_getClass.argtypes = [c_char_p] + objc.sel_registerName.restype = c_void_p + objc.sel_registerName.argtypes = [c_char_p] + cf.CFStringCreateWithCString.restype = c_void_p + cf.CFStringCreateWithCString.argtypes = [c_void_p, c_char_p, c_uint32] + + # Get an NSString describing the URL + kCFStringEncodingUTF8 = 0x08000100 + url = c_void_p(cf.CFStringCreateWithCString(None, url.encode('utf-8'), kCFStringEncodingUTF8)) + autorelease = c_void_p(objc.sel_registerName(b'autorelease')) + objc.objc_msgSend.argtypes = [c_void_p, c_void_p] + objc.objc_msgSend.restype = c_void_p + objc.objc_msgSend(url, autorelease) + + # Get an NSURL object representing the URL + NSURL = c_void_p(objc.objc_getClass(b'NSURL')) + urlWithString_ = c_void_p(objc.sel_registerName(b'URLWithString:')) + objc.objc_msgSend.restype = c_void_p + objc.objc_msgSend.argtypes = [c_void_p, c_void_p, c_void_p] + nsurl = c_void_p(objc.objc_msgSend(NSURL, urlWithString_, url)) + + # Get the shared UIApplication instance + UIApplication = c_void_p(objc.objc_getClass(b'UIApplication')) + sharedApplication = c_void_p(objc.sel_registerName(b'sharedApplication')) + objc.objc_msgSend.argtypes = [c_void_p, c_void_p] + objc.objc_msgSend.restype = c_void_p + shared_app = c_void_p(objc.objc_msgSend(UIApplication, sharedApplication)) + + # Open the URL on the shared application + openURL_ = c_void_p(objc.sel_registerName(b'openURL:')) + objc.objc_msgSend.argtypes = [c_void_p, c_void_p, c_void_p] + objc.objc_msgSend.restype = None + objc.objc_msgSend(shared_app, openURL_, nsurl) + + return True + + register("mobilesafari", None, MobileSafari(), preferred=True) # # Platform support for Windows diff --git a/Modules/_posixsubprocess.c b/Modules/_posixsubprocess.c index 9132f13e81..36e00f7bfd 100644 --- a/Modules/_posixsubprocess.c +++ b/Modules/_posixsubprocess.c @@ -31,10 +31,20 @@ #include "posixmodule.h" +#if defined(__APPLE__) +#include "TargetConditionals.h" +#endif + #ifdef _Py_MEMORY_SANITIZER # include #endif +// iOS/tvOS/watchOS *define* a number of POSIX functions, but you can't use them +// because they aren't conventional multiprocess environments. +#if TARGET_OS_IPHONE +# undef HAVE_FORK +#endif + #if defined(__ANDROID__) && __ANDROID_API__ < 21 && !defined(SYS_getdents64) # include # define SYS_getdents64 __NR_getdents64 @@ -660,11 +670,15 @@ saved_errno = 0; for (i = 0; exec_array[i] != NULL; ++i) { const char *executable = exec_array[i]; +#if defined(__ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__) || defined(__ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__) + errno = ENOTSUP; +#else if (envp) { execve(executable, argv, envp); } else { execv(executable, argv); } +#endif if (errno != ENOENT && errno != ENOTDIR && saved_errno == 0) { saved_errno = errno; } @@ -730,7 +744,9 @@ PyObject *preexec_fn, PyObject *preexec_fn_args_tuple) { - +/* iOS/tvOS/watchOS define the existence of fork, but it cannot be invoked; + * so fail fast if any attempt is made to invoke fork_exec */ +#ifdef HAVE_FORK pid_t pid; #ifdef VFORK_USABLE @@ -749,7 +765,7 @@ pid = fork(); } } else -#endif +#endif /* VFORK_USABLE */ { pid = fork(); } @@ -757,7 +773,6 @@ if (pid != 0) { return pid; } - /* Child process. * See the comment above child_exec() for restrictions imposed on * the code below. @@ -780,6 +795,9 @@ py_fds_to_keep, preexec_fn, preexec_fn_args_tuple); _exit(255); return 0; /* Dead code to avoid a potential compiler warning. */ +#else /* HAVE_FORK */ + return -1; +#endif /* HAVE_FORK */ } @@ -810,7 +828,9 @@ int need_after_fork = 0; int saved_errno = 0; int allow_vfork; - +/* iOS/tvOS/watchOS define the existence of fork, but it cannot be invoked; + * so fail fast if any attempt is made to invoke fork_exec */ +#ifdef HAVE_FORK if (!PyArg_ParseTuple( args, "OOpO!OOiiiiiiiiii" _Py_PARSE_PID "OOOiOp:fork_exec", &process_args, &executable_list, @@ -982,7 +1002,6 @@ goto cleanup; #endif /* HAVE_SETREUID */ } - /* This must be the last thing done before fork() because we do not * want to call PyOS_BeforeFork() if there is any chance of another * error leading to the cleanup: code without calling fork(). */ @@ -1017,7 +1036,7 @@ } old_sigmask = &old_sigs; } -#endif +#endif /* VFORK_USABLE */ pid = do_fork_exec(exec_array, argv, envp, cwd, p2cread, p2cwrite, c2pread, c2pwrite, @@ -1049,7 +1068,7 @@ * the thread signal mask. */ (void) pthread_sigmask(SIG_SETMASK, old_sigmask, NULL); } -#endif +#endif /* VFORK_USABLE */ if (need_after_fork) PyOS_AfterFork_Parent(); @@ -1078,8 +1097,10 @@ PyGC_Enable(); } Py_XDECREF(gc_module); - return pid == -1 ? NULL : PyLong_FromPid(pid); +#else /* HAVE_FORK */ + return NULL; +#endif } diff --git a/Modules/faulthandler.c b/Modules/faulthandler.c index 08c40834c4..5c110d7211 100644 --- a/Modules/faulthandler.c +++ b/Modules/faulthandler.c @@ -1,3 +1,7 @@ +#ifdef __APPLE__ +# include "TargetConditionals.h" +#endif /* __APPLE__ */ + #include "Python.h" #include "pycore_initconfig.h" // _PyStatus_ERR #include "pycore_pyerrors.h" // _Py_DumpExtensionModules @@ -21,6 +25,11 @@ # include #endif +// tvOS and watchOS don't provide a number of important POSIX functions. +#if defined(__ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__) || defined(__ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__) +# undef HAVE_SIGALTSTACK +#endif /* TVOS || WATCHOS */ + /* Using an alternative stack requires sigaltstack() and sigaction() SA_ONSTACK */ #if defined(HAVE_SIGALTSTACK) && defined(HAVE_SIGACTION) diff --git a/Modules/makesetup b/Modules/makesetup index 9b20e3c9f6..23be532f6a 100755 --- a/Modules/makesetup +++ b/Modules/makesetup @@ -166,7 +166,7 @@ esac case $arg in -framework) libs="$libs $arg"; skip=libs; - # OSX/OSXS/Darwin framework link cmd + # OSX/OSXS/Darwin/iOS/tvOS/watchOS framework link cmd ;; -[IDUCfF]*) cpps="$cpps $arg";; -Xcompiler) skip=cpps;; @@ -186,6 +186,7 @@ *.c++) srcs="$srcs $arg";; *.cxx) srcs="$srcs $arg";; *.cpp) srcs="$srcs $arg";; + *.S) srcs="$srcs $arg";; # Assembly src \$\(*_CFLAGS\)) cpps="$cpps $arg";; \$\(*_INCLUDES\)) cpps="$cpps $arg";; \$\(*_LIBS\)) libs="$libs $arg";; @@ -220,7 +221,16 @@ done case $doconfig in yes) - LIBS="$LIBS $libs" + # sed has a character limit for multiline substitutions on some + # installs. If you have a lot of customized module configurations, + # the LOCALMODLIBS definition can end up exceeding that line length. + # To ensure this doesn't happen, only include $libs if it adds + # something, and put each library definition on it's own line. This + # requires escaping for when this script runs, and escaping for when + # the output is run through sed. + if test "$libs"; then + LIBS="$LIBS \\\\\\\\\\$NL\t$libs" + fi MODS="$MODS $mods" BUILT="$BUILT $mods" ;; @@ -245,6 +255,7 @@ *.C) obj=`basename $src .C`.o; cc='$(CXX)';; *.cxx) obj=`basename $src .cxx`.o; cc='$(CXX)';; *.cpp) obj=`basename $src .cpp`.o; cc='$(CXX)';; + *.S) obj=`basename $src .S`.o; cc='$(CC)';; # Assembly *.m) obj=`basename $src .m`.o; cc='$(CC)';; # Obj-C *) continue;; esac diff --git a/Modules/mathmodule.c b/Modules/mathmodule.c index aa93e756c6..fcf3784c2f 100644 --- a/Modules/mathmodule.c +++ b/Modules/mathmodule.c @@ -76,6 +76,10 @@ /*[clinic end generated code: output=da39a3ee5e6b4b0d input=76bc7002685dd942]*/ +#ifdef __APPLE__ +# include "TargetConditionals.h" +#endif /* __APPLE__ */ + /* sin(pi*x), giving accurate results for all finite x (especially x integral or close to an integer). This is here for use in the diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index 4015889441..b9d6633213 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -69,6 +69,8 @@ */ #if defined(__APPLE__) +#include "TargetConditionals.h" + #if defined(__has_builtin) #if __has_builtin(__builtin_available) #define HAVE_BUILTIN_AVAILABLE 1 @@ -325,6 +327,26 @@ # endif /* _MSC_VER */ #endif /* ! __WATCOMC__ || __QNX__ */ +// iOS/tvOS/watchOS *define* a number of POSIX functions, but you can't use them +// because they aren't conventional multiprocess environment. +#if TARGET_OS_IPHONE +# undef HAVE_EXECV +# undef HAVE_FORK +# undef HAVE_FORK1 +# undef HAVE_FORKPTY +# undef HAVE_GETGROUPS +# undef HAVE_POSIX_SPAWN +# undef HAVE_POSIX_SPAWNP +# undef HAVE_SCHED_H +# undef HAVE_SENDFILE +# undef HAVE_SETPRIORITY +# undef HAVE_SPAWNV +# undef HAVE_WAIT +# undef HAVE_WAIT3 +# undef HAVE_WAIT4 +# undef HAVE_WAITPID +#endif + /*[clinic input] # one of the few times we lie about this name! module os @@ -1573,7 +1595,9 @@ */ #include #elif !defined(_MSC_VER) && (!defined(__WATCOMC__) || defined(__QNX__) || defined(__VXWORKS__)) +# if !TARGET_OS_TV && !TARGET_OS_WATCH extern char **environ; +# endif #endif /* !_MSC_VER */ static PyObject * @@ -1589,6 +1613,7 @@ d = PyDict_New(); if (d == NULL) return NULL; +#if !TARGET_OS_TV && !TARGET_OS_WATCH #ifdef MS_WINDOWS /* _wenviron must be initialized in this way if the program is started through main() instead of wmain(). */ @@ -1642,6 +1667,7 @@ Py_DECREF(k); Py_DECREF(v); } +#endif return d; } @@ -4931,6 +4957,9 @@ /*[clinic end generated code: output=290fc437dd4f33a0 input=86a58554ba6094af]*/ { long result; +#if TARGET_OS_IPHONE + result = -1; +#else const char *bytes = PyBytes_AsString(command); if (PySys_Audit("os.system", "(O)", command) < 0) { @@ -4940,6 +4969,7 @@ Py_BEGIN_ALLOW_THREADS result = system(bytes); Py_END_ALLOW_THREADS +#endif return result; } #endif @@ -13693,6 +13723,7 @@ int is_symlink; int need_stat; #endif +#if !TARGET_OS_TV && !TARGET_OS_WATCH #ifdef MS_WINDOWS unsigned long dir_bits; #endif @@ -13753,6 +13784,7 @@ #endif return result; +#endif error: Py_XDECREF(st_mode); diff --git a/Modules/pwdmodule.c b/Modules/pwdmodule.c index a757380bd0..5a20864a1c 100644 --- a/Modules/pwdmodule.c +++ b/Modules/pwdmodule.c @@ -1,6 +1,10 @@ /* UNIX password file access module */ +#ifdef __APPLE__ +# include "TargetConditionals.h" +#endif /* __APPLE__ */ + #include "Python.h" #include "posixmodule.h" @@ -182,6 +186,22 @@ if (nomem == 1) { return PyErr_NoMemory(); } + +// iPhone has a "user" with UID 501, username "mobile"; but the simulator +// doesn't reflect this. Generate a simulated response. +#if TARGET_IPHONE_SIMULATOR + if (uid == 501) { + struct passwd mp; + mp.pw_name = "mobile"; + mp.pw_passwd = "/smx7MYTQIi2M"; + mp.pw_uid = 501; + mp.pw_gid = 501; + mp.pw_gecos = "Mobile User"; + mp.pw_dir = "/var/mobile"; + mp.pw_shell = "/bin/sh"; + return mkpwent(module, &mp); + } +#endif PyObject *uid_obj = _PyLong_FromUid(uid); if (uid_obj == NULL) return NULL; @@ -265,6 +285,22 @@ PyErr_NoMemory(); } else { +// iPhone has a "user" with UID 501, username "mobile"; but the simulator +// doesn't reflect this. Generate a simulated response. +#if TARGET_IPHONE_SIMULATOR + if (strcmp(name, "mobile") == 0) { + struct passwd mp; + mp.pw_name = "mobile"; + mp.pw_passwd = "/smx7MYTQIi2M"; + mp.pw_uid = 501; + mp.pw_gid = 501; + mp.pw_gecos = "Mobile User"; + mp.pw_dir = "/var/mobile"; + mp.pw_shell = "/bin/sh"; + retval = mkpwent(module, &mp); + goto out; + } +#endif PyErr_Format(PyExc_KeyError, "getpwnam(): name not found: %R", name); } diff --git a/Modules/timemodule.c b/Modules/timemodule.c index 7475ef344b..2ebafe993b 100644 --- a/Modules/timemodule.c +++ b/Modules/timemodule.c @@ -62,6 +62,11 @@ #define SEC_TO_NS (1000 * 1000 * 1000) +#ifdef __APPLE__ +# include "TargetConditionals.h" +#endif /* __APPLE__ */ + + /* Forward declarations */ static int pysleep(_PyTime_t timeout); @@ -263,11 +268,13 @@ if (_PyTime_AsTimespec(t, &tp) == -1) return NULL; +#if !TARGET_OS_IPHONE ret = clock_settime((clockid_t)clk_id, &tp); if (ret != 0) { PyErr_SetFromErrno(PyExc_OSError); return NULL; } +#endif Py_RETURN_NONE; } @@ -296,11 +303,13 @@ return NULL; } +#if !TARGET_OS_IPHONE ret = clock_settime((clockid_t)clk_id, &ts); if (ret != 0) { PyErr_SetFromErrno(PyExc_OSError); return NULL; } +#endif Py_RETURN_NONE; } diff --git a/Python/bootstrap_hash.c b/Python/bootstrap_hash.c index 3a2a731808..cb2d9e53e2 100644 --- a/Python/bootstrap_hash.c +++ b/Python/bootstrap_hash.c @@ -35,6 +35,10 @@ #endif +#ifdef __APPLE__ +# include "TargetConditionals.h" +#endif /* __APPLE__ */ + #ifdef Py_DEBUG int _Py_HashSecret_Initialized = 0; #else @@ -180,6 +184,9 @@ } #elif defined(HAVE_GETENTROPY) +// iOS, tvOS and watchOS have an incomplete definitions of getentropy +// so it is *found* by configure, but doesn't actually exist. +#elif defined(HAVE_GETENTROPY) && !TARGET_OS_IPHONE #define PY_GETENTROPY 1 /* Fill buffer with size pseudo-random bytes generated by getentropy(): diff --git a/Python/marshal.c b/Python/marshal.c index 90a4405091..65dd71d868 100644 --- a/Python/marshal.c +++ b/Python/marshal.c @@ -14,6 +14,10 @@ #include "pycore_hashtable.h" // _Py_hashtable_t #include "marshal.h" // Py_MARSHAL_VERSION +#ifdef __APPLE__ +# include "TargetConditionals.h" +#endif /* __APPLE__ */ + /*[clinic input] module marshal [clinic start generated code]*/ @@ -33,9 +37,13 @@ * #if defined(MS_WINDOWS) && defined(_DEBUG) */ #if defined(MS_WINDOWS) -#define MAX_MARSHAL_STACK_DEPTH 1000 +# define MAX_MARSHAL_STACK_DEPTH 1000 #else -#define MAX_MARSHAL_STACK_DEPTH 2000 +# if TARGET_OS_IPHONE +# define MAX_MARSHAL_STACK_DEPTH 1500 +# else +# define MAX_MARSHAL_STACK_DEPTH 2000 +# endif #endif #define TYPE_NULL '0' --- /dev/null +++ b/Tools/iOS-test/app/iOS-test/main.py @@ -0,0 +1,12 @@ +from datetime import datetime +import platform +from test import regrtest + +regrtest.start = datetime.now() +print("Testing on %s" % platform.machine()) +print("START:", regrtest.start) +regrtest.main_in_temp_cwd() +regrtest.end = datetime.now() +print("END:", regrtest.end) +print("Duration:", regrtest.end - regrtest.start) + --- /dev/null +++ b/Tools/iOS-test/app_packages/README @@ -0,0 +1 @@ +This directory exists so that 3rd party packages can be installed here. \ No newline at end of file --- /dev/null +++ b/Tools/iOS-test/iOS-test.xcodeproj/project.pbxproj @@ -0,0 +1,369 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 60796EE619190F4100A9926B /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 60796EE519190F4100A9926B /* Foundation.framework */; }; + 60796EE819190F4100A9926B /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 60796EE719190F4100A9926B /* CoreGraphics.framework */; }; + 60796EEA19190F4100A9926B /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 60796EE919190F4100A9926B /* UIKit.framework */; }; + 60796EF019190F4100A9926B /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 60796EEE19190F4100A9926B /* InfoPlist.strings */; }; + 60796EF219190F4100A9926B /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 60796EF119190F4100A9926B /* main.m */; }; + 60796EF819190F4100A9926B /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 60796EF719190F4100A9926B /* Images.xcassets */; }; + 60796F2C1919C70800A9926B /* Python.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 60796F2B1919C70800A9926B /* Python.framework */; }; + 60796F39191CDBBA00A9926B /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 60796F38191CDBBA00A9926B /* CoreFoundation.framework */; }; + 60EAF0931C26F7310003B8F5 /* libsqlite3.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 60EAF0921C26F7310003B8F5 /* libsqlite3.tbd */; }; + 60EAF0951C26F73D0003B8F5 /* libz.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 60EAF0941C26F73D0003B8F5 /* libz.tbd */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 60796EE219190F4100A9926B /* iOS-test.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "iOS-test.app"; sourceTree = BUILT_PRODUCTS_DIR; }; + 60796EE519190F4100A9926B /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; + 60796EE719190F4100A9926B /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; + 60796EE919190F4100A9926B /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; + 60796EED19190F4100A9926B /* iOS-test-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "iOS-test-Info.plist"; sourceTree = ""; }; + 60796EEF19190F4100A9926B /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; + 60796EF119190F4100A9926B /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; + 60796EF319190F4100A9926B /* iOS-test-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "iOS-test-Prefix.pch"; sourceTree = ""; }; + 60796EF719190F4100A9926B /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; + 60796F2B1919C70800A9926B /* Python.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = Python.framework; sourceTree = ""; }; + 60796F38191CDBBA00A9926B /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = System/Library/Frameworks/CoreFoundation.framework; sourceTree = SDKROOT; }; + 60DBD4B01B47DEF700068095 /* app */ = {isa = PBXFileReference; lastKnownFileType = folder; path = app; sourceTree = SOURCE_ROOT; }; + 60EAF0921C26F7310003B8F5 /* libsqlite3.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libsqlite3.tbd; path = usr/lib/libsqlite3.tbd; sourceTree = SDKROOT; }; + 60EAF0941C26F73D0003B8F5 /* libz.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libz.tbd; path = usr/lib/libz.tbd; sourceTree = SDKROOT; }; + 60F0BABF191FC868006EC268 /* app_packages */ = {isa = PBXFileReference; lastKnownFileType = folder; path = app_packages; sourceTree = SOURCE_ROOT; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 60796EDF19190F4100A9926B /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 60EAF0951C26F73D0003B8F5 /* libz.tbd in Frameworks */, + 60EAF0931C26F7310003B8F5 /* libsqlite3.tbd in Frameworks */, + 60796F39191CDBBA00A9926B /* CoreFoundation.framework in Frameworks */, + 60796F2C1919C70800A9926B /* Python.framework in Frameworks */, + 60796EE819190F4100A9926B /* CoreGraphics.framework in Frameworks */, + 60796EEA19190F4100A9926B /* UIKit.framework in Frameworks */, + 60796EE619190F4100A9926B /* Foundation.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 60796ED919190F4100A9926B = { + isa = PBXGroup; + children = ( + 60796EEB19190F4100A9926B /* iOS-test */, + 60796EE419190F4100A9926B /* Frameworks */, + 60796EE319190F4100A9926B /* Products */, + ); + sourceTree = ""; + }; + 60796EE319190F4100A9926B /* Products */ = { + isa = PBXGroup; + children = ( + 60796EE219190F4100A9926B /* iOS-test.app */, + ); + name = Products; + sourceTree = ""; + }; + 60796EE419190F4100A9926B /* Frameworks */ = { + isa = PBXGroup; + children = ( + 60EAF0941C26F73D0003B8F5 /* libz.tbd */, + 60EAF0921C26F7310003B8F5 /* libsqlite3.tbd */, + 60796F2B1919C70800A9926B /* Python.framework */, + 60796EE519190F4100A9926B /* Foundation.framework */, + 60796F38191CDBBA00A9926B /* CoreFoundation.framework */, + 60796EE719190F4100A9926B /* CoreGraphics.framework */, + 60796EE919190F4100A9926B /* UIKit.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; + 60796EEB19190F4100A9926B /* iOS-test */ = { + isa = PBXGroup; + children = ( + 60DBD4B01B47DEF700068095 /* app */, + 60F0BABF191FC868006EC268 /* app_packages */, + 60796EF719190F4100A9926B /* Images.xcassets */, + 60796EEC19190F4100A9926B /* Supporting Files */, + ); + path = "iOS-test"; + sourceTree = ""; + }; + 60796EEC19190F4100A9926B /* Supporting Files */ = { + isa = PBXGroup; + children = ( + 60796EED19190F4100A9926B /* iOS-test-Info.plist */, + 60796EEE19190F4100A9926B /* InfoPlist.strings */, + 60796EF119190F4100A9926B /* main.m */, + 60796EF319190F4100A9926B /* iOS-test-Prefix.pch */, + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 60796EE119190F4100A9926B /* iOS-test */ = { + isa = PBXNativeTarget; + buildConfigurationList = 60796F0E19190F4100A9926B /* Build configuration list for PBXNativeTarget "iOS-test" */; + buildPhases = ( + 60796F2F1919C7E700A9926B /* Refresh Python source */, + 60796EDE19190F4100A9926B /* Sources */, + 60796EDF19190F4100A9926B /* Frameworks */, + 60796EE019190F4100A9926B /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = "iOS-test"; + productName = "iOS-test"; + productReference = 60796EE219190F4100A9926B /* iOS-test.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 60796EDA19190F4100A9926B /* Project object */ = { + isa = PBXProject; + attributes = { + CLASSPREFIX = Py; + LastUpgradeCheck = 0720; + ORGANIZATIONNAME = "Python Software Foundation"; + TargetAttributes = { + 60796EE119190F4100A9926B = { + DevelopmentTeam = 383DLEZ2K4; + }; + }; + }; + buildConfigurationList = 60796EDD19190F4100A9926B /* Build configuration list for PBXProject "iOS-test" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + ); + mainGroup = 60796ED919190F4100A9926B; + productRefGroup = 60796EE319190F4100A9926B /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 60796EE119190F4100A9926B /* iOS-test */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 60796EE019190F4100A9926B /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 60796EF019190F4100A9926B /* InfoPlist.strings in Resources */, + 60796EF819190F4100A9926B /* Images.xcassets in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 60796F2F1919C7E700A9926B /* Refresh Python source */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Refresh Python source"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "mkdir -p $BUILT_PRODUCTS_DIR/$CONTENTS_FOLDER_PATH/Library/Python.framework/Resources\nmkdir -p $BUILT_PRODUCTS_DIR/$CONTENTS_FOLDER_PATH/Library/Application\\ Support/org.python.$PROJECT_NAME\nrsync -pvtrL --exclude .hg --exclude .svn --exclude .git $PROJECT_DIR/Python.framework/Resources/lib $BUILT_PRODUCTS_DIR/$CONTENTS_FOLDER_PATH/Library/Python.framework/Resources\nrsync -pvtrL --exclude .hg --exclude .svn --exclude .git $PROJECT_DIR/Python.framework/Resources/include $BUILT_PRODUCTS_DIR/$CONTENTS_FOLDER_PATH/Library/Python.framework/Resources\nrsync -pvtrL --exclude .hg --exclude .svn --exclude .git $PROJECT_DIR/app $BUILT_PRODUCTS_DIR/$CONTENTS_FOLDER_PATH/Library/Application\\ Support/org.python.$PROJECT_NAME\nrsync -pvtrL --exclude .hg --exclude .svn --exclude .git $PROJECT_DIR/app_packages/ $BUILT_PRODUCTS_DIR/$CONTENTS_FOLDER_PATH/Library/Python.framework/Resources/lib/python`readlink $PROJECT_DIR/Python.framework/Versions/Current`/site-packages/\n"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 60796EDE19190F4100A9926B /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 60796EF219190F4100A9926B /* main.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 60796EEE19190F4100A9926B /* InfoPlist.strings */ = { + isa = PBXVariantGroup; + children = ( + 60796EEF19190F4100A9926B /* en */, + ); + name = InfoPlist.strings; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 60796F0C19190F4100A9926B /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + ENABLE_BITCODE = NO; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 7.1; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 60796F0D19190F4100A9926B /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = YES; + ENABLE_BITCODE = NO; + ENABLE_NS_ASSERTIONS = NO; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 7.1; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 60796F0F19190F4100A9926B /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; + CODE_SIGN_IDENTITY = "iPhone Developer"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)", + ); + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = "iOS-test/iOS-test-Prefix.pch"; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, + "\"$(PROJECT_DIR)/Python.framework/Resources/include/python2.7\"", + ); + INFOPLIST_FILE = "iOS-test/iOS-test-Info.plist"; + PRODUCT_BUNDLE_IDENTIFIER = "org.python.$(PRODUCT_NAME:rfc1034identifier)"; + PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE = ""; + USER_HEADER_SEARCH_PATHS = include/python2.7; + WRAPPER_EXTENSION = app; + }; + name = Debug; + }; + 60796F1019190F4100A9926B /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; + CODE_SIGN_IDENTITY = "iPhone Developer"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)", + ); + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = "iOS-test/iOS-test-Prefix.pch"; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, + "\"$(PROJECT_DIR)/Python.framework/Resources/include/python2.7\"", + ); + INFOPLIST_FILE = "iOS-test/iOS-test-Info.plist"; + PRODUCT_BUNDLE_IDENTIFIER = "org.python.$(PRODUCT_NAME:rfc1034identifier)"; + PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE = ""; + USER_HEADER_SEARCH_PATHS = include/python2.7; + WRAPPER_EXTENSION = app; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 60796EDD19190F4100A9926B /* Build configuration list for PBXProject "iOS-test" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 60796F0C19190F4100A9926B /* Debug */, + 60796F0D19190F4100A9926B /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 60796F0E19190F4100A9926B /* Build configuration list for PBXNativeTarget "iOS-test" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 60796F0F19190F4100A9926B /* Debug */, + 60796F1019190F4100A9926B /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 60796EDA19190F4100A9926B /* Project object */; +} --- /dev/null +++ b/Tools/iOS-test/iOS-test/Images.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,58 @@ +{ + "images" : [ + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "3x" + }, + { + "idiom" : "ipad", + "size" : "29x29", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "40x40", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "76x76", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "76x76", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file --- /dev/null +++ b/Tools/iOS-test/iOS-test/Images.xcassets/LaunchImage.launchimage/Contents.json @@ -0,0 +1,51 @@ +{ + "images" : [ + { + "orientation" : "portrait", + "idiom" : "iphone", + "extent" : "full-screen", + "minimum-system-version" : "7.0", + "scale" : "2x" + }, + { + "orientation" : "portrait", + "idiom" : "iphone", + "subtype" : "retina4", + "extent" : "full-screen", + "minimum-system-version" : "7.0", + "scale" : "2x" + }, + { + "orientation" : "portrait", + "idiom" : "ipad", + "extent" : "full-screen", + "minimum-system-version" : "7.0", + "scale" : "1x" + }, + { + "orientation" : "landscape", + "idiom" : "ipad", + "extent" : "full-screen", + "minimum-system-version" : "7.0", + "scale" : "1x" + }, + { + "orientation" : "portrait", + "idiom" : "ipad", + "extent" : "full-screen", + "minimum-system-version" : "7.0", + "scale" : "2x" + }, + { + "orientation" : "landscape", + "idiom" : "ipad", + "extent" : "full-screen", + "minimum-system-version" : "7.0", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file --- /dev/null +++ b/Tools/iOS-test/iOS-test/en.lproj/InfoPlist.strings @@ -0,0 +1 @@ +/* Localized versions of Info.plist keys */ --- /dev/null +++ b/Tools/iOS-test/iOS-test/iOS-test-Info.plist @@ -0,0 +1,45 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleDisplayName + ${PRODUCT_NAME} + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + LSRequiresIPhoneOS + + UIRequiredDeviceCapabilities + + armv7 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + + --- /dev/null +++ b/Tools/iOS-test/iOS-test/iOS-test-Prefix.pch @@ -0,0 +1,16 @@ +// +// Prefix header +// +// The contents of this file are implicitly included at the beginning of every source file. +// + +#import + +#ifndef __IPHONE_3_0 +#warning "This project uses features only available in iOS SDK 3.0 and later." +#endif + +#ifdef __OBJC__ + #import + #import +#endif \ No newline at end of file --- /dev/null +++ b/Tools/iOS-test/iOS-test/main.m @@ -0,0 +1,149 @@ +// +// main.m +// A main module for starting Python projects under iOS. +// + +#import +#import +#include +#include + +int main(int argc, char *argv[]) { + int ret = 0; + unsigned int i; + NSString *tmp_path; + NSString *exe; + NSString *python_home; + wchar_t *wpython_home; + const char* main_script; + wchar_t** python_argv; + @autoreleasepool { + + NSString * resourcePath = [[NSBundle mainBundle] resourcePath]; + + // Special environment to avoid writing bytecode because + // the process will not have write attribute on the device. + putenv("PYTHONDONTWRITEBYTECODE=1"); + + python_home = [NSString stringWithFormat:@"%@/Library/Python.framework/Resources", resourcePath, nil]; + NSLog(@"PythonHome is: %@", python_home); + wpython_home = Py_DecodeLocale([python_home UTF8String], NULL); + Py_SetPythonHome(wpython_home); + + // iOS provides a specific directory for temp files. + tmp_path = [NSString stringWithFormat:@"TMP=%@/tmp", resourcePath, nil]; + putenv((char *)[tmp_path UTF8String]); + + // Since iOS doesn't allow dynamic linking, we have to know + // the name of the executable so that we can find the ctypes + // test objects. However, sys.argv[0] will be updated to + // reflect the script name; the TEST_EXECUTABLE environment + // variable provides the mechanism for specifying the filename. + exe = [NSString stringWithFormat:@"TEST_EXECUTABLE=%s", argv[0], nil]; + putenv((char *)[exe UTF8String]); + + NSLog(@"Initializing Python runtime..."); + Py_Initialize(); + + /******************************************************* + To tell lldb not to stop on signals, use the following commands: + process handle SIGPIPE -n true -p true -s false + process handle SIGINT -n true -p true -s false + process handle SIGXFSZ -n true -p true -s false + process handle SIGUSR1 -n true -p true -s false + process handle SIGUSR2 -n true -p true -s false + *******************************************************/ + + // Arguments to pass to test runner + char *test_args[] = { + "-j", "1", + "-u", "all,-audio,-curses,-largefile,-subprocess,-gui", +// "-v", // Verbose test output + "-W", // Display test output on failure + + "-x", // Arguments are tests to *exclude* +// Simulator failures +// "test_coroutines", // docstring not being populated +// "test_module", // docstring not being populated + +// ARM64 failures +// "test_coroutines", // docstring not being populated +// "test_ctypes", // DL loading? +// "test_module" // docstring not being populated +// "test_threading", // ctypes related; missing symbol PyThreadState_SetAsyncExc +// "test_unicode", // encoding problem + +// ARMv7 failures +// "test_cmath", // math domain error +// "test_ctypes", // DL loading? +// "test_float", // rounding? +// "test_math", // math domain error +// "test_numeric_tower", // +// "test_strtod", // +// "test_importlib", // Thread locking problem +// "test_threading", // ctypes related; missing symbol PyThreadState_SetAsyncExc + +// COMMON FAILURES + "test_bytes" // HARD CRASH ctypes related; PyBytes_FromFormat + + }; + + // Set the name of the main script + main_script = [ + [[NSBundle mainBundle] pathForResource:@"Library/Application Support/org.python.iOS-test/app/iOS-test/main" + ofType:@"py"] cStringUsingEncoding:NSUTF8StringEncoding]; + + if (main_script == NULL) { + NSLog(@"Unable to locate app/iOS-test/main.py file"); + exit(-1); + } + + // Construct argv for the interpreter + int n_test_args = sizeof(test_args) / sizeof (*test_args) + 1; + + python_argv = PyMem_RawMalloc(sizeof(wchar_t*) * n_test_args); + python_argv[0] = Py_DecodeLocale(main_script, NULL); + for (i = 1; i < n_test_args; i++) { + python_argv[i] = Py_DecodeLocale(test_args[i-1], NULL); + } + + PySys_SetArgv(n_test_args, python_argv); + + // If other modules are using thread, we need to initialize them before. + PyEval_InitThreads(); + + // Start the main.py script + NSLog(@"Running %s", main_script); + + @try { + FILE* fd = fopen(main_script, "r"); + if (fd == NULL) { + ret = 1; + NSLog(@"Unable to open main.py, abort."); + } else { + ret = PyRun_SimpleFileEx(fd, main_script, 1); + if (ret != 0) { + NSLog(@"Application quit abnormally!"); + } + } + } + @catch (NSException *exception) { + NSLog(@"Python runtime error: %@", [exception reason]); + } + @finally { + Py_Finalize(); + } + + PyMem_RawFree(wpython_home); + if (python_argv) { + for (i = 0; i < argc; i++) { + PyMem_RawFree(python_argv[i]); + } + PyMem_RawFree(python_argv); + } + NSLog(@"Leaving"); + } + + exit(ret); + return ret; +} \ No newline at end of file --- /dev/null +++ b/Tools/tvOS-test/app/README @@ -0,0 +1,3 @@ +Your application code should be placed in this directory. + +The native code will be looking for a tvOS-test/__main__.py file as the entry point. \ No newline at end of file --- /dev/null +++ b/Tools/tvOS-test/app/tvOS-test/main.py @@ -0,0 +1,14 @@ +from __future__ import print_function + +from datetime import datetime +import platform +from test import regrtest + +regrtest.start = datetime.now() +print("Testing on %s" % platform.machine()) +print("START:", regrtest.start) +regrtest.main_in_temp_cwd() +regrtest.end = datetime.now() +print("END:", regrtest.end) +print("Duration:", regrtest.end - regrtest.start) + --- /dev/null +++ b/Tools/tvOS-test/app_packages/README @@ -0,0 +1 @@ +This directory exists so that 3rd party packages can be installed here. --- /dev/null +++ b/Tools/tvOS-test/tvOS-test.xcodeproj/project.pbxproj @@ -0,0 +1,356 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 6023B2AE1C28BA7A006F2562 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 6023B2AD1C28BA7A006F2562 /* main.m */; }; + 6023B2B71C28BA7A006F2562 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 6023B2B51C28BA7A006F2562 /* Main.storyboard */; }; + 6023B2B91C28BA7A006F2562 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 6023B2B81C28BA7A006F2562 /* Assets.xcassets */; }; + 6023B2C71C28BD44006F2562 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6023B2C11C28BD44006F2562 /* CoreFoundation.framework */; }; + 6023B2C81C28BD44006F2562 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6023B2C21C28BD44006F2562 /* CoreGraphics.framework */; }; + 6023B2C91C28BD44006F2562 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6023B2C31C28BD44006F2562 /* Foundation.framework */; }; + 6023B2CA1C28BD44006F2562 /* libsqlite3.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 6023B2C41C28BD44006F2562 /* libsqlite3.tbd */; }; + 6023B2CB1C28BD44006F2562 /* libz.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 6023B2C51C28BD44006F2562 /* libz.tbd */; }; + 6023B2CC1C28BD44006F2562 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6023B2C61C28BD44006F2562 /* UIKit.framework */; }; + 6023B2D01C28BDA3006F2562 /* Python.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6023B2CE1C28BDA3006F2562 /* Python.framework */; }; + 6023B2D31C28BDB7006F2562 /* app in Resources */ = {isa = PBXBuildFile; fileRef = 6023B2D11C28BDB7006F2562 /* app */; }; + 6023B2D41C28BDB7006F2562 /* app_packages in Resources */ = {isa = PBXBuildFile; fileRef = 6023B2D21C28BDB7006F2562 /* app_packages */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 6023B2A91C28BA7A006F2562 /* tvOS-test.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "tvOS-test.app"; sourceTree = BUILT_PRODUCTS_DIR; }; + 6023B2AD1C28BA7A006F2562 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; + 6023B2B61C28BA7A006F2562 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + 6023B2B81C28BA7A006F2562 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 6023B2BA1C28BA7A006F2562 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 6023B2C11C28BD44006F2562 /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = System/Library/Frameworks/CoreFoundation.framework; sourceTree = SDKROOT; }; + 6023B2C21C28BD44006F2562 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; + 6023B2C31C28BD44006F2562 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; + 6023B2C41C28BD44006F2562 /* libsqlite3.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libsqlite3.tbd; path = usr/lib/libsqlite3.tbd; sourceTree = SDKROOT; }; + 6023B2C51C28BD44006F2562 /* libz.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libz.tbd; path = usr/lib/libz.tbd; sourceTree = SDKROOT; }; + 6023B2C61C28BD44006F2562 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; + 6023B2CD1C28BDA3006F2562 /* OpenSSL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = OpenSSL.framework; sourceTree = ""; }; + 6023B2CE1C28BDA3006F2562 /* Python.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = Python.framework; sourceTree = ""; }; + 6023B2D11C28BDB7006F2562 /* app */ = {isa = PBXFileReference; lastKnownFileType = folder; name = app; path = ../app; sourceTree = ""; }; + 6023B2D21C28BDB7006F2562 /* app_packages */ = {isa = PBXFileReference; lastKnownFileType = folder; name = app_packages; path = ../app_packages; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 6023B2A61C28BA7A006F2562 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 6023B2CB1C28BD44006F2562 /* libz.tbd in Frameworks */, + 6023B2CA1C28BD44006F2562 /* libsqlite3.tbd in Frameworks */, + 6023B2D01C28BDA3006F2562 /* Python.framework in Frameworks */, + 6023B2C71C28BD44006F2562 /* CoreFoundation.framework in Frameworks */, + 6023B2C81C28BD44006F2562 /* CoreGraphics.framework in Frameworks */, + 6023B2C91C28BD44006F2562 /* Foundation.framework in Frameworks */, + 6023B2CC1C28BD44006F2562 /* UIKit.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 6023B2A01C28BA7A006F2562 = { + isa = PBXGroup; + children = ( + 6023B2AB1C28BA7A006F2562 /* tvOS-test */, + 6023B2C01C28BD23006F2562 /* Frameworks */, + 6023B2AA1C28BA7A006F2562 /* Products */, + ); + sourceTree = ""; + }; + 6023B2AA1C28BA7A006F2562 /* Products */ = { + isa = PBXGroup; + children = ( + 6023B2A91C28BA7A006F2562 /* tvOS-test.app */, + ); + name = Products; + sourceTree = ""; + }; + 6023B2AB1C28BA7A006F2562 /* tvOS-test */ = { + isa = PBXGroup; + children = ( + 6023B2D11C28BDB7006F2562 /* app */, + 6023B2D21C28BDB7006F2562 /* app_packages */, + 6023B2B81C28BA7A006F2562 /* Assets.xcassets */, + 6023B2AC1C28BA7A006F2562 /* Supporting Files */, + ); + path = "tvOS-test"; + sourceTree = ""; + }; + 6023B2AC1C28BA7A006F2562 /* Supporting Files */ = { + isa = PBXGroup; + children = ( + 6023B2B51C28BA7A006F2562 /* Main.storyboard */, + 6023B2BA1C28BA7A006F2562 /* Info.plist */, + 6023B2AD1C28BA7A006F2562 /* main.m */, + ); + name = "Supporting Files"; + sourceTree = ""; + }; + 6023B2C01C28BD23006F2562 /* Frameworks */ = { + isa = PBXGroup; + children = ( + 6023B2C41C28BD44006F2562 /* libsqlite3.tbd */, + 6023B2C51C28BD44006F2562 /* libz.tbd */, + 6023B2CD1C28BDA3006F2562 /* OpenSSL.framework */, + 6023B2CE1C28BDA3006F2562 /* Python.framework */, + 6023B2C11C28BD44006F2562 /* CoreFoundation.framework */, + 6023B2C21C28BD44006F2562 /* CoreGraphics.framework */, + 6023B2C31C28BD44006F2562 /* Foundation.framework */, + 6023B2C61C28BD44006F2562 /* UIKit.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 6023B2A81C28BA7A006F2562 /* tvOS-test */ = { + isa = PBXNativeTarget; + buildConfigurationList = 6023B2BD1C28BA7A006F2562 /* Build configuration list for PBXNativeTarget "tvOS-test" */; + buildPhases = ( + 6023B2D61C28CB97006F2562 /* Refresh Python source */, + 6023B2A51C28BA7A006F2562 /* Sources */, + 6023B2A61C28BA7A006F2562 /* Frameworks */, + 6023B2A71C28BA7A006F2562 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = "tvOS-test"; + productName = "tvOS-test"; + productReference = 6023B2A91C28BA7A006F2562 /* tvOS-test.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 6023B2A11C28BA7A006F2562 /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 0720; + ORGANIZATIONNAME = "Python Software Foundation"; + TargetAttributes = { + 6023B2A81C28BA7A006F2562 = { + CreatedOnToolsVersion = 7.2; + }; + }; + }; + buildConfigurationList = 6023B2A41C28BA7A006F2562 /* Build configuration list for PBXProject "tvOS-test" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 6023B2A01C28BA7A006F2562; + productRefGroup = 6023B2AA1C28BA7A006F2562 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 6023B2A81C28BA7A006F2562 /* tvOS-test */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 6023B2A71C28BA7A006F2562 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 6023B2D31C28BDB7006F2562 /* app in Resources */, + 6023B2B91C28BA7A006F2562 /* Assets.xcassets in Resources */, + 6023B2B71C28BA7A006F2562 /* Main.storyboard in Resources */, + 6023B2D41C28BDB7006F2562 /* app_packages in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 6023B2D61C28CB97006F2562 /* Refresh Python source */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Refresh Python source"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "mkdir -p \"$BUILT_PRODUCTS_DIR/$CONTENTS_FOLDER_PATH/Library/Python.framework/Resources\"\nmkdir -p \"$BUILT_PRODUCTS_DIR/$CONTENTS_FOLDER_PATH/Library/Application Support/org.python.tvOS-test\"\nrsync -pvtrL --exclude .hg --exclude .svn --exclude .git \"$PROJECT_DIR/Python.framework/Resources/lib\" \"$BUILT_PRODUCTS_DIR/$CONTENTS_FOLDER_PATH/Library/Python.framework/Resources\"\nrsync -pvtrL --exclude .hg --exclude .svn --exclude .git \"$PROJECT_DIR/Python.framework/Resources/include\" \"$BUILT_PRODUCTS_DIR/$CONTENTS_FOLDER_PATH/Library/Python.framework/Resources\"\nrsync -pvtrL --exclude .hg --exclude .svn --exclude .git \"$PROJECT_DIR/app\" \"$BUILT_PRODUCTS_DIR/$CONTENTS_FOLDER_PATH/Library/Application Support/org.python.tvOS-test\"\nmkdir -p \"$BUILT_PRODUCTS_DIR/$CONTENTS_FOLDER_PATH/Library/Python.framework/Resources/lib/python`readlink $PROJECT_DIR/Python.framework/Versions/Current`/site-packages/\"\nrsync -pvtrL --exclude .hg --exclude .svn --exclude .git \"$PROJECT_DIR/app_packages/\" \"$BUILT_PRODUCTS_DIR/$CONTENTS_FOLDER_PATH/Library/Python.framework/Resources/lib/python`readlink $PROJECT_DIR/Python.framework/Versions/Current`/site-packages/\"\n"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 6023B2A51C28BA7A006F2562 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 6023B2AE1C28BA7A006F2562 /* main.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 6023B2B51C28BA7A006F2562 /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 6023B2B61C28BA7A006F2562 /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 6023B2BB1C28BA7A006F2562 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = appletvos; + TARGETED_DEVICE_FAMILY = 3; + TVOS_DEPLOYMENT_TARGET = 9.1; + }; + name = Debug; + }; + 6023B2BC1C28BA7A006F2562 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = appletvos; + TARGETED_DEVICE_FAMILY = 3; + TVOS_DEPLOYMENT_TARGET = 9.1; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 6023B2BE1C28BA7A006F2562 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = "App Icon & Top Shelf Image"; + ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)", + ); + INFOPLIST_FILE = "tvOS-test/Info.plist"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "org.python.tvOS-test"; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + 6023B2BF1C28BA7A006F2562 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = "App Icon & Top Shelf Image"; + ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)", + ); + INFOPLIST_FILE = "tvOS-test/Info.plist"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "org.python.tvOS-test"; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 6023B2A41C28BA7A006F2562 /* Build configuration list for PBXProject "tvOS-test" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 6023B2BB1C28BA7A006F2562 /* Debug */, + 6023B2BC1C28BA7A006F2562 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 6023B2BD1C28BA7A006F2562 /* Build configuration list for PBXNativeTarget "tvOS-test" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 6023B2BE1C28BA7A006F2562 /* Debug */, + 6023B2BF1C28BA7A006F2562 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 6023B2A11C28BA7A006F2562 /* Project object */; +} --- /dev/null +++ b/Tools/tvOS-test/tvOS-test/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Back.imagestacklayer/Content.imageset/Contents.json @@ -0,0 +1,13 @@ +{ + "images" : [ + { + "idiom" : "tv", + "filename" : "large.png", + "scale" : "1x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file --- /dev/null +++ b/Tools/tvOS-test/tvOS-test/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Back.imagestacklayer/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file --- /dev/null +++ b/Tools/tvOS-test/tvOS-test/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Contents.json @@ -0,0 +1,17 @@ +{ + "layers" : [ + { + "filename" : "Front.imagestacklayer" + }, + { + "filename" : "Middle.imagestacklayer" + }, + { + "filename" : "Back.imagestacklayer" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} --- /dev/null +++ b/Tools/tvOS-test/tvOS-test/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Front.imagestacklayer/Content.imageset/Contents.json @@ -0,0 +1,13 @@ +{ + "images" : [ + { + "idiom" : "tv", + "filename" : "large.png", + "scale" : "1x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file --- /dev/null +++ b/Tools/tvOS-test/tvOS-test/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Front.imagestacklayer/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file --- /dev/null +++ b/Tools/tvOS-test/tvOS-test/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Middle.imagestacklayer/Content.imageset/Contents.json @@ -0,0 +1,13 @@ +{ + "images" : [ + { + "idiom" : "tv", + "filename" : "large.png", + "scale" : "1x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file --- /dev/null +++ b/Tools/tvOS-test/tvOS-test/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Middle.imagestacklayer/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file --- /dev/null +++ b/Tools/tvOS-test/tvOS-test/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Back.imagestacklayer/Content.imageset/Contents.json @@ -0,0 +1,13 @@ +{ + "images" : [ + { + "idiom" : "tv", + "filename" : "small.png", + "scale" : "1x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file --- /dev/null +++ b/Tools/tvOS-test/tvOS-test/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Back.imagestacklayer/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file --- /dev/null +++ b/Tools/tvOS-test/tvOS-test/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Contents.json @@ -0,0 +1,17 @@ +{ + "layers" : [ + { + "filename" : "Front.imagestacklayer" + }, + { + "filename" : "Middle.imagestacklayer" + }, + { + "filename" : "Back.imagestacklayer" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} --- /dev/null +++ b/Tools/tvOS-test/tvOS-test/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Front.imagestacklayer/Content.imageset/Contents.json @@ -0,0 +1,13 @@ +{ + "images" : [ + { + "idiom" : "tv", + "filename" : "small.png", + "scale" : "1x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file --- /dev/null +++ b/Tools/tvOS-test/tvOS-test/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Front.imagestacklayer/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file --- /dev/null +++ b/Tools/tvOS-test/tvOS-test/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Middle.imagestacklayer/Content.imageset/Contents.json @@ -0,0 +1,13 @@ +{ + "images" : [ + { + "idiom" : "tv", + "filename" : "small.png", + "scale" : "1x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file --- /dev/null +++ b/Tools/tvOS-test/tvOS-test/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Middle.imagestacklayer/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file --- /dev/null +++ b/Tools/tvOS-test/tvOS-test/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Contents.json @@ -0,0 +1,26 @@ +{ + "assets" : [ + { + "size" : "1280x768", + "idiom" : "tv", + "filename" : "App Icon - Large.imagestack", + "role" : "primary-app-icon" + }, + { + "size" : "400x240", + "idiom" : "tv", + "filename" : "App Icon - Small.imagestack", + "role" : "primary-app-icon" + }, + { + "size" : "1920x720", + "idiom" : "tv", + "filename" : "Top Shelf Image.imageset", + "role" : "top-shelf-image" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file --- /dev/null +++ b/Tools/tvOS-test/tvOS-test/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image.imageset/Contents.json @@ -0,0 +1,13 @@ +{ + "images" : [ + { + "idiom" : "tv", + "filename" : "shelf.png", + "scale" : "1x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file --- /dev/null +++ b/Tools/tvOS-test/tvOS-test/Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file --- /dev/null +++ b/Tools/tvOS-test/tvOS-test/Assets.xcassets/LaunchImage.launchimage/Contents.json @@ -0,0 +1,16 @@ +{ + "images" : [ + { + "orientation" : "landscape", + "idiom" : "tv", + "filename" : "launch.png", + "extent" : "full-screen", + "minimum-system-version" : "9.0", + "scale" : "1x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file --- /dev/null +++ b/Tools/tvOS-test/tvOS-test/Base.lproj/Main.storyboard @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + --- /dev/null +++ b/Tools/tvOS-test/tvOS-test/Info.plist @@ -0,0 +1,32 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + LSRequiresIPhoneOS + + UIMainStoryboardFile + Main + UIRequiredDeviceCapabilities + + arm64 + + + --- /dev/null +++ b/Tools/tvOS-test/tvOS-test/main.m @@ -0,0 +1,149 @@ +// +// main.m +// A main module for starting Python projects under tvOS. +// + +#import +#import +#include +#include + +int main(int argc, char *argv[]) { + int ret = 0; + unsigned int i; + NSString *tmp_path; + NSString *exe; + NSString *python_home; + wchar_t *wpython_home; + const char* main_script; + wchar_t** python_argv; + @autoreleasepool { + + NSString * resourcePath = [[NSBundle mainBundle] resourcePath]; + + // Special environment to avoid writing bytecode because + // the process will not have write attribute on the device. + putenv("PYTHONDONTWRITEBYTECODE=1"); + + python_home = [NSString stringWithFormat:@"%@/Library/Python.framework/Resources", resourcePath, nil]; + NSLog(@"PythonHome is: %@", python_home); + wpython_home = Py_DecodeLocale([python_home UTF8String], NULL); + Py_SetPythonHome(wpython_home); + + // tvOS provides a specific directory for temp files. + tmp_path = [NSString stringWithFormat:@"TMP=%@/tmp", resourcePath, nil]; + putenv((char *)[tmp_path UTF8String]); + + // Since tvOS doesn't allow dynamic linking, we have to know + // the name of the executable so that we can find the ctypes + // test objects. However, sys.argv[0] will be updated to + // reflect the script name; the TEST_EXECUTABLE environment + // variable provides the mechanism for specifying the filename. + exe = [NSString stringWithFormat:@"TEST_EXECUTABLE=%s", argv[0], nil]; + putenv((char *)[exe UTF8String]); + + NSLog(@"Initializing Python runtime..."); + Py_Initialize(); + + /******************************************************* + To tell lldb not to stop on signals, use the following commands: + process handle SIGPIPE -n true -p true -s false + process handle SIGINT -n true -p true -s false + process handle SIGXFSZ -n true -p true -s false + process handle SIGUSR1 -n true -p true -s false + process handle SIGUSR2 -n true -p true -s false + *******************************************************/ + + // Arguments to pass to test runner + char *test_args[] = { + "-j", "1", + "-u", "all,-audio,-curses,-largefile,-subprocess,-gui", +// "-v", // Verbose test output + "-W", // Display test output on failure + + "-x", // Arguments are tests to *exclude* +// Simulator failures +// "test_coroutines", // docstring not being populated +// "test_module", // docstring not being populated + +// ARM64 failures +// "test_coroutines", // docstring not being populated +// "test_ctypes", // DL loading? +// "test_module" // docstring not being populated +// "test_threading", // ctypes related; missing symbol PyThreadState_SetAsyncExc +// "test_unicode", // encoding problem + +// ARMv7 failures +// "test_cmath", // math domain error +// "test_ctypes", // DL loading? +// "test_float", // rounding? +// "test_math", // math domain error +// "test_numeric_tower", // +// "test_strtod", // +// "test_importlib", // Thread locking problem +// "test_threading", // ctypes related; missing symbol PyThreadState_SetAsyncExc + +// COMMON FAILURES + "test_bytes" // HARD CRASH ctypes related; PyBytes_FromFormat + + }; + + // Set the name of the main script + main_script = [ + [[NSBundle mainBundle] pathForResource:@"Library/Application Support/org.python.tvOS-test/app/tvOS-test/main" + ofType:@"py"] cStringUsingEncoding:NSUTF8StringEncoding]; + + if (main_script == NULL) { + NSLog(@"Unable to locate app/tvOS-test/main.py file"); + exit(-1); + } + + // Construct argv for the interpreter + int n_test_args = sizeof(test_args) / sizeof (*test_args) + 1; + + python_argv = PyMem_RawMalloc(sizeof(wchar_t*) * n_test_args); + python_argv[0] = Py_DecodeLocale(main_script, NULL); + for (i = 1; i < n_test_args; i++) { + python_argv[i] = Py_DecodeLocale(test_args[i-1], NULL); + } + + PySys_SetArgv(n_test_args, python_argv); + + // If other modules are using thread, we need to initialize them before. + PyEval_InitThreads(); + + // Start the main.py script + NSLog(@"Running %s", main_script); + + @try { + FILE* fd = fopen(main_script, "r"); + if (fd == NULL) { + ret = 1; + NSLog(@"Unable to open main.py, abort."); + } else { + ret = PyRun_SimpleFileEx(fd, main_script, 1); + if (ret != 0) { + NSLog(@"Application quit abnormally!"); + } + } + } + @catch (NSException *exception) { + NSLog(@"Python runtime error: %@", [exception reason]); + } + @finally { + Py_Finalize(); + } + + PyMem_RawFree(wpython_home); + if (python_argv) { + for (i = 0; i < argc; i++) { + PyMem_RawFree(python_argv[i]); + } + PyMem_RawFree(python_argv); + } + NSLog(@"Leaving"); + } + + exit(ret); + return ret; +} diff --git a/config.sub b/config.sub index d74fb6deac..249b391d71 100755 --- a/config.sub +++ b/config.sub @@ -1723,7 +1723,7 @@ | hpux* | unos* | osf* | luna* | dgux* | auroraux* | solaris* \ | sym* | plan9* | psp* | sim* | xray* | os68k* | v88r* \ | hiux* | abug | nacl* | netware* | windows* \ - | os9* | macos* | osx* | ios* \ + | os9* | macos* | osx* | ios* | tvos* | watchos* \ | mpw* | magic* | mmixware* | mon960* | lnews* \ | amigaos* | amigados* | msdos* | newsos* | unicos* | aof* \ | aos* | aros* | cloudabi* | sortix* | twizzler* \ diff --git a/configure b/configure index b57c6f3a45..b4f2e1a026 100755 --- a/configure +++ b/configure @@ -3814,6 +3814,15 @@ *-*-cygwin*) ac_sys_system=Cygwin ;; + *-apple-ios) + ac_sys_system=iOS + ;; + *-apple-tvos) + ac_sys_system=tvOS + ;; + *-apple-watchos) + ac_sys_system=watchOS + ;; *-*-vxworks*) ac_sys_system=VxWorks ;; @@ -3870,6 +3879,15 @@ *-*-cygwin*) _host_cpu= ;; + *-apple-*) + case "$host_cpu" in + arm*) + _host_cpu=arm + ;; + *) + _host_cpu=$host_cpu + esac + ;; *-*-vxworks*) _host_cpu=$host_cpu ;; @@ -3948,6 +3966,13 @@ define_xopen_source=no;; Darwin/[12][0-9].*) define_xopen_source=no;; + # On iOS, defining _POSIX_C_SOURCE also disables platform specific features. + iOS/*) + define_xopen_source=no;; + tvOS/*) + define_xopen_source=no;; + watchOS/*) + define_xopen_source=no;; # On QNX 6.3.2, defining _XOPEN_SOURCE prevents netdb.h from # defining NI_NUMERICHOST. QNX/6.3.2) @@ -6152,6 +6177,12 @@ case $ac_sys_system in #( Darwin*) : MULTIARCH="" ;; #( + iOS*) : + MULTIARCH="" ;; #( + tvOS*) : + MULTIARCH="" ;; #( + watchOS*) : + MULTIARCH="" ;; #( FreeBSD*) : MULTIARCH="" ;; #( *) : @@ -6945,11 +6976,17 @@ fi if test "$cross_compiling" = yes; then - case "$READELF" in - readelf|:) - as_fn_error $? "readelf for the host is required for cross builds" "$LINENO" 5 - ;; - esac + case "$host" in + *-apple-*os) + # readelf not required for iOS cross builds. + ;; + *) + case "$READELF" in + readelf|:) + as_fn_error $? "readelf for the host is required for cross builds" "$LINENO" 5 + ;; + esac + esac fi @@ -14783,6 +14820,10 @@ then case $ac_sys_system/$ac_sys_release in hp*|HP*) DYNLOADFILE="dynload_hpux.o";; + # Disable dynamic loading on iOS + iOS/*) DYNLOADFILE="dynload_stub.o";; + tvOS/*) DYNLOADFILE="dynload_stub.o";; + watchOS/*) DYNLOADFILE="dynload_stub.o";; *) # use dynload_shlib.c and dlopen() if we have it; otherwise stub # out any dynamic loading @@ -26385,7 +26426,7 @@ $as_echo "$as_me: creating Modules/Setup.local" >&6;} if test ! -f Modules/Setup.local then - echo "# Edit this file for local setup changes" >Modules/Setup.local + echo "# Edit this file for local setup changes" >Modules/Setup.local fi { $as_echo "$as_me:${as_lineno-$LINENO}: creating Makefile" >&5 diff --git a/configure.ac b/configure.ac index 07b8885f1e..b660ad6475 100644 --- a/configure.ac +++ b/configure.ac @@ -500,6 +500,15 @@ *-*-cygwin*) ac_sys_system=Cygwin ;; + *-apple-ios) + ac_sys_system=iOS + ;; + *-apple-tvos) + ac_sys_system=tvOS + ;; + *-apple-watchos) + ac_sys_system=watchOS + ;; *-*-vxworks*) ac_sys_system=VxWorks ;; @@ -555,6 +564,15 @@ *-*-cygwin*) _host_cpu= ;; + *-apple-*) + case "$host_cpu" in + arm*) + _host_cpu=arm + ;; + *) + _host_cpu=$host_cpu + esac + ;; *-*-vxworks*) _host_cpu=$host_cpu ;; @@ -630,6 +648,13 @@ define_xopen_source=no;; Darwin/@<:@[12]@:>@@<:@0-9@:>@.*) define_xopen_source=no;; + # On iOS, defining _POSIX_C_SOURCE also disables platform specific features. + iOS/*) + define_xopen_source=no;; + tvOS/*) + define_xopen_source=no;; + watchOS/*) + define_xopen_source=no;; # On QNX 6.3.2, defining _XOPEN_SOURCE prevents netdb.h from # defining NI_NUMERICHOST. QNX/6.3.2) @@ -1011,6 +1036,9 @@ AC_MSG_CHECKING([for multiarch]) AS_CASE([$ac_sys_system], [Darwin*], [MULTIARCH=""], + [iOS*], [MULTIARCH=""], + [tvOS*], [MULTIARCH=""], + [watchOS*], [MULTIARCH=""], [FreeBSD*], [MULTIARCH=""], [MULTIARCH=$($CC --print-multiarch 2>/dev/null)] ) @@ -1472,11 +1500,17 @@ AC_CHECK_TOOLS([READELF], [readelf], [:]) if test "$cross_compiling" = yes; then - case "$READELF" in - readelf|:) - AC_MSG_ERROR([readelf for the host is required for cross builds]) - ;; - esac + case "$host" in + *-apple-*os) + # readelf not required for iOS cross builds. + ;; + *) + case "$READELF" in + readelf|:) + AC_MSG_ERROR([readelf for the host is required for cross builds]) + ;; + esac + esac fi AC_SUBST(READELF) @@ -4362,6 +4396,10 @@ then case $ac_sys_system/$ac_sys_release in hp*|HP*) DYNLOADFILE="dynload_hpux.o";; + # Disable dynamic loading on iOS + iOS/*) DYNLOADFILE="dynload_stub.o";; + tvOS/*) DYNLOADFILE="dynload_stub.o";; + watchOS/*) DYNLOADFILE="dynload_stub.o";; *) # use dynload_shlib.c and dlopen() if we have it; otherwise stub # out any dynamic loading @@ -6919,7 +6957,7 @@ AC_MSG_NOTICE([creating Modules/Setup.local]) if test ! -f Modules/Setup.local then - echo "# Edit this file for local setup changes" >Modules/Setup.local + echo "# Edit this file for local setup changes" >Modules/Setup.local fi AC_MSG_NOTICE([creating Makefile]) --- /dev/null +++ b/iOS/Info.plist @@ -0,0 +1,20 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + Python + CFBundleIdentifier + org.python + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + FMWK + CFBundleSignature + ???? + CFBundleVersion + xxxVERSIONxxx + + --- /dev/null +++ b/iOS/README @@ -0,0 +1,165 @@ +==================== +Python on iOS README +==================== + +:Authors: + Russell Keith-Magee (2015) + +:Version: 3.5.2 + +This document provides a overview of eccentricities of building and using +Python on iOS. + +Build instructions +================== + +The iOS build must be run on an Mac with XCode installed. To build the iOS +framework, unpack the Python sources, move into the iOS subdirectory, and +run ``make``. There are no configuration options to this build process - +it will use XCode utilities to identify the location of compilers, +resource directories, and so on. + +The build process will configure and build Python 6 times, producing: + + * A "host" version of Python + * A version of Python compiled for the x86-64 iOS Simulator + * A version of Python compiled for the i386 iOS Simulator + * A version of Python compiled for ARM64 iOS devices + * A version of Python compiled for ARMv7s iOS devices + * A version of Python compiled for ARMv7 iOS devices + +Build products will be "installed" into iOS/build. The built products will +then be combined into a single "fat" ``Python.framework`` that can be added to +an XCode project. The resulting framework will be located in the root +directory of the Python source tree. + +A ``make clean`` target also exists to clean out all build products; +``make distclean`` will clean out all user-specific files from the test and +sample projects. + +Test instructions +----------------- + +The ``Tools`` directory contains an ``iOS-Test`` project that enables you to +run the Python regression test suite. When you run ``make`` in the iOS +directory, a copy of ``Python.framework`` will also be installed into this +test project. + +To run the test project, load the project into XCode, and run (either on a +device or in the simulator). The test suite takes around 10 minutes to run on +an iPhone6S. + +.. note:: If you run the test project in debug mode, the XCode debugger will + stop whenever a signal is raised. The Python regression test suite checks + a number of signal handlers, and the test suite will stop mid-execution + when this occurs. + + To disable this signal handling, set a breakpoint at the start of + ``main.c``; when execution stops at the breakpoint, run the following + commands in the debugger (at the ``(lldb)`` prompt in the console log + window):: + + process handle SIGPIPE -n true -p true -s false + process handle SIGINT -n true -p true -s false + process handle SIGXFSZ -n true -p true -s false + process handle SIGUSR1 -n true -p true -s false + process handle SIGUSR2 -n true -p true -s false + + Unfortunately, this has to be done every time the test suite is executed. + +iOS-specific details +==================== + +* ``import sys; sys.platform`` will report as `'ios'`, regardless of whether you + are on a simulator or a real platform. + +* ``import platform; platform.machine()`` will return the device identifier. + For example, an iPhone 5S will return `'iPhone6,2'` + +* The following modules are not currently supported: + + - ``bsddb`` + - ``bz2`` + - ``curses`` + - ``dbm`` + - ``gdbm`` + - ``hotshot`` + - ``idlelib`` + - ``lzma`` + - ``nis`` + - ``ossaudiodev`` + - ``readline`` + - ``spwd`` + - ``sqlite3`` + - ``ssl`` + - ``tkinter`` + - ``turtledemo`` + - ``wsgiref`` + +* Due to limitations in using dynamic loading on iOS, binary Python modules must be + statically-linked into the executable. The framework package produced by the iOS + ``make install`` statically links all the supported standard library modules. + If you have a third-party Python binary module, you'll need to incorporate the + source files for that module into the sources for your own app. + + If you want to add or remove a binary module from the set that is included in the + Python library, you can do so by providing module setup files for each platform. + There are three default module configuration files: + + - ``Modules/Setup.iOS-aarch64`` for ARM64 iOS builds + - ``Modules/Setup.iOS-arm`` for ARMv7 iOS builds + - ``Modules/Setup.iOS-x86_64`` for x86_64 iOS simulator builds + + If you copy these files to a ``.local`` version (e.g., + ``Modules/Setup.iOS-aarch64.local``), the local version will override the + default. You can then make modifications to the modules that will be included + in the iOS framework, and the flags passed to the compiler when compiling those + modules. + +Adding Python to an iOS project +=============================== + +The iOS subdirectory contains a sample XCode 6.1 project to demonstrate how +Python can be added to an iOS project. After building the Python iOS framework, +copy it into the ``iOS/XCode-sample`` directory. You should end up with a directory +structure that looks like this:: + + XCode-sample/ + Python.framework/ - Manually copied into the project + app/ + sample/ + __init__.py + main.py - The Python script to be executed + app_packages/ - A directory that will be added to the `PYTHONPATH` at runtime + sample + Images.xcassets + en.lproj + main.c - The main() definition for the iOS application + sample-Info.plist + sample-Prefix.pch + sample.xcodeproj - The XCode project file + +If you open the project file is project and run it, you should get output +similar to the following:: + + 2015-03-14 22:15:19.595 sample[84454:22100187] PythonHome is: /Users/rkm/Library/Developer/CoreSimulator/Devices/19FE988F-E5C3-4A6C-8752-C12DE9BF079D/data/Containers/Bundle/Application/A949B323-FD20-4C76-B370-99AFF294E9D5/sample.app + 2015-03-14 22:15:19.597 sample[84454:22100187] Initializing Python runtime + 2015-03-14 22:15:19.758 sample[84454:22100187] Running /Users/rkm/Library/Developer/CoreSimulator/Devices/19FE988F-E5C3-4A6C-8752-C12DE9BF079D/data/Containers/Bundle/Application/A949B323-FD20-4C76-B370-99AFF294E9D5/sample.app/app/sample/main.py + Hello, World. + 2015-03-14 22:15:19.792 sample[84454:22100187] Leaving + +You can now modify the provide Python source code, import and use +code from the Python standard library, and add third-party modules to +app_packages. + +The sample app is a console-only app, so it isn't of any real practical use. +Python can be embedded into any Objective-C project using the normal Python +APIs for embedding; but if you want to write a full iOS app in Python, or +you want to access iOS services from within embedded code, you'll need to +bridge between the Objective-C environment and the Python environment. +This binding isn't something that Python does out of the box; you'll need +to use a third-party library like `Rubicon ObjC`_, `Pyobjus`_ or `PyObjC`_. + +.. _Rubicon ObjC: http://pybee.org/rubicon +.. _Pyobjus: http://pyobjus.readthedocs.org/ +.. _PyObjC: https://pythonhosted.org/pyobjc/ --- /dev/null +++ b/iOS/XCode-sample/app/sample/main.py @@ -0,0 +1,3 @@ + +if __name__ == '__main__': + print("Hello, World.") --- /dev/null +++ b/iOS/XCode-sample/app_packages/README @@ -0,0 +1 @@ +This directory exists so that 3rd party packages can be installed here. \ No newline at end of file --- /dev/null +++ b/iOS/XCode-sample/sample.xcodeproj/project.pbxproj @@ -0,0 +1,353 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 60796EE619190F4100A9926B /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 60796EE519190F4100A9926B /* Foundation.framework */; }; + 60796EE819190F4100A9926B /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 60796EE719190F4100A9926B /* CoreGraphics.framework */; }; + 60796EEA19190F4100A9926B /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 60796EE919190F4100A9926B /* UIKit.framework */; }; + 60796EF019190F4100A9926B /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 60796EEE19190F4100A9926B /* InfoPlist.strings */; }; + 60796EF219190F4100A9926B /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 60796EF119190F4100A9926B /* main.m */; }; + 60796EF819190F4100A9926B /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 60796EF719190F4100A9926B /* Images.xcassets */; }; + 60796F1919190FBB00A9926B /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 60796F1819190FBB00A9926B /* libz.dylib */; }; + 60796F201919174D00A9926B /* libsqlite3.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 60796F1F1919174D00A9926B /* libsqlite3.dylib */; }; + 60796F2C1919C70800A9926B /* Python.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 60796F2B1919C70800A9926B /* Python.framework */; }; + 60796F39191CDBBA00A9926B /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 60796F38191CDBBA00A9926B /* CoreFoundation.framework */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 60796EE219190F4100A9926B /* sample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = sample.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 60796EE519190F4100A9926B /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; + 60796EE719190F4100A9926B /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; + 60796EE919190F4100A9926B /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; + 60796EED19190F4100A9926B /* sample-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "sample-Info.plist"; sourceTree = ""; }; + 60796EEF19190F4100A9926B /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; + 60796EF119190F4100A9926B /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; + 60796EF319190F4100A9926B /* sample-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "sample-Prefix.pch"; sourceTree = ""; }; + 60796EF719190F4100A9926B /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; + 60796F1819190FBB00A9926B /* libz.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libz.dylib; path = usr/lib/libz.dylib; sourceTree = SDKROOT; }; + 60796F1F1919174D00A9926B /* libsqlite3.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libsqlite3.dylib; path = usr/lib/libsqlite3.dylib; sourceTree = SDKROOT; }; + 60796F2B1919C70800A9926B /* Python.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = Python.framework; sourceTree = ""; }; + 60796F38191CDBBA00A9926B /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = System/Library/Frameworks/CoreFoundation.framework; sourceTree = SDKROOT; }; + 60F0BABD191FC83F006EC268 /* app */ = {isa = PBXFileReference; lastKnownFileType = folder; path = app; sourceTree = SOURCE_ROOT; }; + 60F0BABF191FC868006EC268 /* app_packages */ = {isa = PBXFileReference; lastKnownFileType = folder; path = app_packages; sourceTree = SOURCE_ROOT; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 60796EDF19190F4100A9926B /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 60796F39191CDBBA00A9926B /* CoreFoundation.framework in Frameworks */, + 60796F2C1919C70800A9926B /* Python.framework in Frameworks */, + 60796F201919174D00A9926B /* libsqlite3.dylib in Frameworks */, + 60796F1919190FBB00A9926B /* libz.dylib in Frameworks */, + 60796EE819190F4100A9926B /* CoreGraphics.framework in Frameworks */, + 60796EEA19190F4100A9926B /* UIKit.framework in Frameworks */, + 60796EE619190F4100A9926B /* Foundation.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 60796ED919190F4100A9926B = { + isa = PBXGroup; + children = ( + 60796EEB19190F4100A9926B /* sample */, + 60796EE419190F4100A9926B /* Frameworks */, + 60796EE319190F4100A9926B /* Products */, + ); + sourceTree = ""; + }; + 60796EE319190F4100A9926B /* Products */ = { + isa = PBXGroup; + children = ( + 60796EE219190F4100A9926B /* sample.app */, + ); + name = Products; + sourceTree = ""; + }; + 60796EE419190F4100A9926B /* Frameworks */ = { + isa = PBXGroup; + children = ( + 60796F1F1919174D00A9926B /* libsqlite3.dylib */, + 60796F1819190FBB00A9926B /* libz.dylib */, + 60796F38191CDBBA00A9926B /* CoreFoundation.framework */, + 60796EE719190F4100A9926B /* CoreGraphics.framework */, + 60796EE519190F4100A9926B /* Foundation.framework */, + 60796F2B1919C70800A9926B /* Python.framework */, + 60796EE919190F4100A9926B /* UIKit.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; + 60796EEB19190F4100A9926B /* sample */ = { + isa = PBXGroup; + children = ( + 60F0BABD191FC83F006EC268 /* app */, + 60F0BABF191FC868006EC268 /* app_packages */, + 60796EF719190F4100A9926B /* Images.xcassets */, + 60796EEC19190F4100A9926B /* Supporting Files */, + ); + path = sample; + sourceTree = ""; + }; + 60796EEC19190F4100A9926B /* Supporting Files */ = { + isa = PBXGroup; + children = ( + 60796EED19190F4100A9926B /* sample-Info.plist */, + 60796EEE19190F4100A9926B /* InfoPlist.strings */, + 60796EF119190F4100A9926B /* main.m */, + 60796EF319190F4100A9926B /* sample-Prefix.pch */, + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 60796EE119190F4100A9926B /* sample */ = { + isa = PBXNativeTarget; + buildConfigurationList = 60796F0E19190F4100A9926B /* Build configuration list for PBXNativeTarget "sample" */; + buildPhases = ( + 60796F2F1919C7E700A9926B /* Refresh Python source */, + 60796EDE19190F4100A9926B /* Sources */, + 60796EDF19190F4100A9926B /* Frameworks */, + 60796EE019190F4100A9926B /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = sample; + productName = sample; + productReference = 60796EE219190F4100A9926B /* sample.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 60796EDA19190F4100A9926B /* Project object */ = { + isa = PBXProject; + attributes = { + CLASSPREFIX = Py; + LastUpgradeCheck = 0630; + ORGANIZATIONNAME = "Example Corp"; + }; + buildConfigurationList = 60796EDD19190F4100A9926B /* Build configuration list for PBXProject "sample" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + ); + mainGroup = 60796ED919190F4100A9926B; + productRefGroup = 60796EE319190F4100A9926B /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 60796EE119190F4100A9926B /* sample */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 60796EE019190F4100A9926B /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 60796EF019190F4100A9926B /* InfoPlist.strings in Resources */, + 60796EF819190F4100A9926B /* Images.xcassets in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 60796F2F1919C7E700A9926B /* Refresh Python source */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Refresh Python source"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "mkdir -p $BUILT_PRODUCTS_DIR/$CONTENTS_FOLDER_PATH/Library/Python.framework/Resources\nmkdir -p $BUILT_PRODUCTS_DIR/$CONTENTS_FOLDER_PATH/Library/Application\\ Support/org.python.$PROJECT_NAME\nrsync -pvtrL --exclude .hg --exclude .svn --exclude .git $PROJECT_DIR/Python.framework/Resources/lib $BUILT_PRODUCTS_DIR/$CONTENTS_FOLDER_PATH/Library/Python.framework/Resources\nrsync -pvtrL --exclude .hg --exclude .svn --exclude .git $PROJECT_DIR/Python.framework/Resources/include $BUILT_PRODUCTS_DIR/$CONTENTS_FOLDER_PATH/Library/Python.framework/Resources\nrsync -pvtrL --exclude .hg --exclude .svn --exclude .git $PROJECT_DIR/app $BUILT_PRODUCTS_DIR/$CONTENTS_FOLDER_PATH/Library/Application\\ Support/org.python.$PROJECT_NAME\nrsync -pvtrL --exclude .hg --exclude .svn --exclude .git $PROJECT_DIR/app_packages/ $BUILT_PRODUCTS_DIR/$CONTENTS_FOLDER_PATH/Library/Python.framework/Resources/lib/python`readlink $PROJECT_DIR/Python.framework/Versions/Current`/site-packages/\n"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 60796EDE19190F4100A9926B /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 60796EF219190F4100A9926B /* main.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 60796EEE19190F4100A9926B /* InfoPlist.strings */ = { + isa = PBXVariantGroup; + children = ( + 60796EEF19190F4100A9926B /* en */, + ); + name = InfoPlist.strings; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 60796F0C19190F4100A9926B /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 7.1; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 60796F0D19190F4100A9926B /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = YES; + ENABLE_NS_ASSERTIONS = NO; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 7.1; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 60796F0F19190F4100A9926B /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)", + ); + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = "sample/sample-Prefix.pch"; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, + "\"$(PROJECT_DIR)/Python.framework/Resources/include/python2.7\"", + ); + INFOPLIST_FILE = "sample/sample-Info.plist"; + PRODUCT_NAME = "$(TARGET_NAME)"; + USER_HEADER_SEARCH_PATHS = include/python2.7; + WRAPPER_EXTENSION = app; + }; + name = Debug; + }; + 60796F1019190F4100A9926B /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)", + ); + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = "sample/sample-Prefix.pch"; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, + "\"$(PROJECT_DIR)/Python.framework/Resources/include/python2.7\"", + ); + INFOPLIST_FILE = "sample/sample-Info.plist"; + PRODUCT_NAME = "$(TARGET_NAME)"; + USER_HEADER_SEARCH_PATHS = include/python2.7; + WRAPPER_EXTENSION = app; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 60796EDD19190F4100A9926B /* Build configuration list for PBXProject "sample" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 60796F0C19190F4100A9926B /* Debug */, + 60796F0D19190F4100A9926B /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 60796F0E19190F4100A9926B /* Build configuration list for PBXNativeTarget "sample" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 60796F0F19190F4100A9926B /* Debug */, + 60796F1019190F4100A9926B /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 60796EDA19190F4100A9926B /* Project object */; +} --- /dev/null +++ b/iOS/XCode-sample/sample/Images.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,53 @@ +{ + "images" : [ + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "29x29", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "40x40", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "76x76", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "76x76", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file --- /dev/null +++ b/iOS/XCode-sample/sample/Images.xcassets/LaunchImage.launchimage/Contents.json @@ -0,0 +1,51 @@ +{ + "images" : [ + { + "orientation" : "portrait", + "idiom" : "iphone", + "extent" : "full-screen", + "minimum-system-version" : "7.0", + "scale" : "2x" + }, + { + "orientation" : "portrait", + "idiom" : "iphone", + "subtype" : "retina4", + "extent" : "full-screen", + "minimum-system-version" : "7.0", + "scale" : "2x" + }, + { + "orientation" : "portrait", + "idiom" : "ipad", + "extent" : "full-screen", + "minimum-system-version" : "7.0", + "scale" : "1x" + }, + { + "orientation" : "landscape", + "idiom" : "ipad", + "extent" : "full-screen", + "minimum-system-version" : "7.0", + "scale" : "1x" + }, + { + "orientation" : "portrait", + "idiom" : "ipad", + "extent" : "full-screen", + "minimum-system-version" : "7.0", + "scale" : "2x" + }, + { + "orientation" : "landscape", + "idiom" : "ipad", + "extent" : "full-screen", + "minimum-system-version" : "7.0", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file --- /dev/null +++ b/iOS/XCode-sample/sample/en.lproj/InfoPlist.strings @@ -0,0 +1 @@ +/* Localized versions of Info.plist keys */ --- /dev/null +++ b/iOS/XCode-sample/sample/main.m @@ -0,0 +1,111 @@ +// +// main.m +// A main module for starting Python projects under iOS. +// + +#import +#import +#include +#include + +int main(int argc, char *argv[]) { + int ret = 0; + unsigned int i; + NSString *tmp_path; + NSString *python_home; + wchar_t *wpython_home; + const char* main_script; + wchar_t** python_argv; + + @autoreleasepool { + + NSString * resourcePath = [[NSBundle mainBundle] resourcePath]; + + // Special environment to avoid writing bytecode because + // the process will not have write attribute on the device. + putenv("PYTHONDONTWRITEBYTECODE=1"); + + python_home = [NSString stringWithFormat:@"%@/Library/Python.framework/Resources", resourcePath, nil]; + NSLog(@"PythonHome is: %@", python_home); + wpython_home = _Py_char2wchar([python_home UTF8String], NULL); + Py_SetPythonHome(wpython_home); + + // iOS provides a specific directory for temp files. + tmp_path = [NSString stringWithFormat:@"TMP=%@/tmp", resourcePath, nil]; + putenv((char *)[tmp_path UTF8String]); + + NSLog(@"Initializing Python runtime"); + Py_Initialize(); + + // Set the name of the main script + main_script = [ + [[NSBundle mainBundle] pathForResource:@"Library/Application Support/org.python.sample/app/sample/main" + ofType:@"py"] cStringUsingEncoding:NSUTF8StringEncoding]; + + if (main_script == NULL) { + NSLog(@"Unable to locate app/sample/main.py file"); + exit(-1); + } + + // Construct argv for the interpreter + python_argv = PyMem_RawMalloc(sizeof(wchar_t*) * argc); + + python_argv[0] = _Py_char2wchar(main_script, NULL); + for (i = 1; i < argc; i++) { + python_argv[i] = _Py_char2wchar(argv[i], NULL); + } + + PySys_SetArgv(argc, python_argv); + + // If other modules are using threads, we need to initialize them. + PyEval_InitThreads(); + + // Start the main.py script + NSLog(@"Running %s", main_script); + + @try { + FILE* fd = fopen(main_script, "r"); + if (fd == NULL) { + ret = 1; + NSLog(@"Unable to open main.py, abort."); + } else { + ret = PyRun_SimpleFileEx(fd, main_script, 1); + if (ret != 0) { + NSLog(@"Application quit abnormally!"); + } else { + // In a normal iOS application, the following line is what + // actually runs the application. It requires that the + // Objective-C runtime environment has a class named + // "PythonAppDelegate". This project doesn't define + // one, because Objective-C bridging isn't something + // Python does out of the box. You'll need to use + // a library like Rubicon-ObjC [1], Pyobjus [2] or + // PyObjC [3] if you want to run an *actual* iOS app. + // [1] http://pybee.org/rubicon + // [2] http://pyobjus.readthedocs.org/ + // [3] https://pythonhosted.org/pyobjc/ + + UIApplicationMain(argc, argv, nil, @"PythonAppDelegate"); + } + } + } + @catch (NSException *exception) { + NSLog(@"Python runtime error: %@", [exception reason]); + } + @finally { + Py_Finalize(); + } + + PyMem_RawFree(wpython_home); + if (python_argv) { + for (i = 0; i < argc; i++) { + PyMem_RawFree(python_argv[i]); + } + PyMem_RawFree(python_argv); + } + NSLog(@"Leaving"); + } + + exit(ret); + return ret; +} \ No newline at end of file --- /dev/null +++ b/iOS/XCode-sample/sample/sample-Info.plist @@ -0,0 +1,45 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleDisplayName + ${PRODUCT_NAME} + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + com.example.${PRODUCT_NAME:rfc1034identifier} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + LSRequiresIPhoneOS + + UIRequiredDeviceCapabilities + + armv7 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + + \ No newline at end of file --- /dev/null +++ b/iOS/XCode-sample/sample/sample-Prefix.pch @@ -0,0 +1,16 @@ +// +// Prefix header +// +// The contents of this file are implicitly included at the beginning of every source file. +// + +#import + +#ifndef __IPHONE_3_0 +#warning "This project uses features only available in iOS SDK 3.0 and later." +#endif + +#ifdef __OBJC__ + #import + #import +#endif \ No newline at end of file --- /dev/null +++ b/tvOS/Info.plist @@ -0,0 +1,20 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + Python + CFBundleIdentifier + org.python + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + FMWK + CFBundleSignature + ???? + CFBundleVersion + xxxVERSIONxxx + + --- /dev/null +++ b/tvOS/README @@ -0,0 +1,161 @@ +===================== +Python on tvOS README +===================== + +:Authors: + Russell Keith-Magee (2015) + +:Version: 3.5.2 + +This document provides a overview of eccentricities of building and using +Python on tvOS devices (i.e., AppleTV). + +Build instructions +================== + +The tvOS build must be run on an Mac with XCode installed. To build the tvOS +framework, unpack the Python sources, move into the tvOS subdirectory, and +run ``make``. There are no configuration options to this build process - +it will use XCode utilities to identify the location of compilers, +resource directories, and so on. + +The build process will configure and build Python 3 times, producing: + + * A "host" version of Python + * A version of Python compiled for the x86-64 tvOS Simulator + * A version of Python compiled for ARM64 tvOS devices + +Build products will be "installed" into tvOS/build. The built products will +then be combined into a single "fat" ``Python.framework`` that can be added to +an XCode project. The resulting framework will be located in the root +directory of the Python source tree. + +A ``make clean`` target also exists to clean out all build products; +``make distclean`` will clean out all user-specific files from the test and +sample projects. + +Test instructions +----------------- + +The ``Tools`` directory contains an ``tvOS-Test`` project that enables you to +run the Python regression test suite. When you run ``make`` in the tvOS +directory, a copy of ``Python.framework`` will also be installed into this +test project. + +To run the test project, load the project into XCode, and run (either on a +device or in the simulator). The test suite takes around 10 minutes to run on +an gen 4 AppleTV. + +.. note:: If you run the test project in debug mode, the XCode debugger will + stop whenever a signal is raised. The Python regression test suite checks + a number of signal handlers, and the test suite will stop mid-execution + when this occurs. + + To disable this signal handling, set a breakpoint at the start of + ``main.c``; when execution stops at the breakpoint, run the following + commands in the debugger (at the ``(lldb)`` prompt in the console log + window):: + + process handle SIGPIPE -n true -p true -s false + process handle SIGINT -n true -p true -s false + process handle SIGXFSZ -n true -p true -s false + process handle SIGUSR1 -n true -p true -s false + process handle SIGUSR2 -n true -p true -s false + + Unfortunately, this has to be done every time the test suite is executed. + +tvOS-specific details +==================== + +* ``import sys; sys.platform`` will report as `'tvos'`, regardless of whether you + are on a simulator or a real platform. + +* ``import platform; platform.machine()`` will return the device identifier. + For example, a Generation 4 Apple TV will return `'AppleTV5,3'` + +* The following modules are not currently supported: + + - ``bsddb`` + - ``bz2`` + - ``curses`` + - ``dbm`` + - ``gdbm`` + - ``hotshot`` + - ``idlelib`` + - ``lzma`` + - ``nis`` + - ``ossaudiodev`` + - ``readline`` + - ``spwd`` + - ``sqlite3`` + - ``ssl`` + - ``tkinter`` + - ``turtledemo`` + - ``wsgiref`` + +* Due to limitations in using dynamic loading on tvOS, binary Python modules must be + statically-linked into the executable. The framework package produced by the tvOS + ``make install`` statically links all the supported standard library modules. + If you have a third-party Python binary module, you'll need to incorporate the + source files for that module into the sources for your own app. + + If you want to add or remove a binary module from the set that is included in the + Python library, you can do so by providing module setup files for each platform. + There are two default module configuration files: + + - ``Modules/Setup.tvOS-aarch64`` for ARM64 tvOS builds + - ``Modules/Setup.tvOS-x86_64`` for x86_64 tvOS simulator builds + + If you copy these files to a ``.local`` version (e.g., + ``Modules/Setup.tvOS-aarch64.local``), the local version will override the + default. You can then make modifications to the modules that will be included + in the tvOS framework, and the flags passed to the compiler when compiling those + modules. + +Adding Python to an tvOS project +=============================== + +The tvOS subdirectory contains a sample XCode 6.1 project to demonstrate how +Python can be added to an tvOS project. After building the Python tvOS framework, +copy it into the ``tvOS/XCode-sample`` directory. You should end up with a directory +structure that looks like this:: + + XCode-sample/ + Python.framework/ - Manually copied into the project + app/ + sample/ + __init__.py + main.py - The Python script to be executed + app_packages/ - A directory that will be added to the `PYTHONPATH` at runtime + sample + Images.xcassets + en.lproj + main.c - The main() definition for the tvOS application + sample-Info.plist + sample-Prefix.pch + sample.xcodeproj - The XCode project file + +If you open the project file is project and run it, you should get output +similar to the following:: + + 2015-03-14 22:15:19.595 sample[84454:22100187] PythonHome is: /Users/rkm/Library/Developer/CoreSimulator/Devices/19FE988F-E5C3-4A6C-8752-C12DE9BF079D/data/Containers/Bundle/Application/A949B323-FD20-4C76-B370-99AFF294E9D5/sample.app + 2015-03-14 22:15:19.597 sample[84454:22100187] Initializing Python runtime + 2015-03-14 22:15:19.758 sample[84454:22100187] Running /Users/rkm/Library/Developer/CoreSimulator/Devices/19FE988F-E5C3-4A6C-8752-C12DE9BF079D/data/Containers/Bundle/Application/A949B323-FD20-4C76-B370-99AFF294E9D5/sample.app/app/sample/main.py + Hello, World. + 2015-03-14 22:15:19.792 sample[84454:22100187] Leaving + +You can now modify the provide Python source code, import and use +code from the Python standard library, and add third-party modules to +app_packages. + +The sample app is a console-only app, so it isn't of any real practical use. +Python can be embedded into any Objective-C project using the normal Python +APIs for embedding; but if you want to write a full tvOS app in Python, or +you want to access tvOS services from within embedded code, you'll need to +bridge between the Objective-C environment and the Python environment. +This binding isn't something that Python does out of the box; you'll need +to use a third-party library like `Rubicon ObjC`_, `Pyobjus`_ or `PyObjC`_. + +.. _Rubicon ObjC: http://pybee.org/rubicon +.. _Pyobjus: http://pyobjus.readthedocs.org/ +.. _PyObjC: https://pythonhosted.org/pyobjc/ --- /dev/null +++ b/tvOS/XCode-sample/app/sample/main.py @@ -0,0 +1,3 @@ + +if __name__ == '__main__': + print("Hello, World.") --- /dev/null +++ b/tvOS/XCode-sample/app_packages/README @@ -0,0 +1 @@ +This directory exists so that 3rd party packages can be installed here. \ No newline at end of file --- /dev/null +++ b/tvOS/XCode-sample/sample.xcodeproj/project.pbxproj @@ -0,0 +1,353 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 60796EE619190F4100A9926B /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 60796EE519190F4100A9926B /* Foundation.framework */; }; + 60796EE819190F4100A9926B /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 60796EE719190F4100A9926B /* CoreGraphics.framework */; }; + 60796EEA19190F4100A9926B /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 60796EE919190F4100A9926B /* UIKit.framework */; }; + 60796EF019190F4100A9926B /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 60796EEE19190F4100A9926B /* InfoPlist.strings */; }; + 60796EF219190F4100A9926B /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 60796EF119190F4100A9926B /* main.m */; }; + 60796EF819190F4100A9926B /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 60796EF719190F4100A9926B /* Images.xcassets */; }; + 60796F1919190FBB00A9926B /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 60796F1819190FBB00A9926B /* libz.dylib */; }; + 60796F201919174D00A9926B /* libsqlite3.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 60796F1F1919174D00A9926B /* libsqlite3.dylib */; }; + 60796F2C1919C70800A9926B /* Python.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 60796F2B1919C70800A9926B /* Python.framework */; }; + 60796F39191CDBBA00A9926B /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 60796F38191CDBBA00A9926B /* CoreFoundation.framework */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 60796EE219190F4100A9926B /* sample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = sample.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 60796EE519190F4100A9926B /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; + 60796EE719190F4100A9926B /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; + 60796EE919190F4100A9926B /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; + 60796EED19190F4100A9926B /* sample-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "sample-Info.plist"; sourceTree = ""; }; + 60796EEF19190F4100A9926B /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; + 60796EF119190F4100A9926B /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; + 60796EF319190F4100A9926B /* sample-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "sample-Prefix.pch"; sourceTree = ""; }; + 60796EF719190F4100A9926B /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; + 60796F1819190FBB00A9926B /* libz.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libz.dylib; path = usr/lib/libz.dylib; sourceTree = SDKROOT; }; + 60796F1F1919174D00A9926B /* libsqlite3.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libsqlite3.dylib; path = usr/lib/libsqlite3.dylib; sourceTree = SDKROOT; }; + 60796F2B1919C70800A9926B /* Python.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = Python.framework; sourceTree = ""; }; + 60796F38191CDBBA00A9926B /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = System/Library/Frameworks/CoreFoundation.framework; sourceTree = SDKROOT; }; + 60F0BABD191FC83F006EC268 /* app */ = {isa = PBXFileReference; lastKnownFileType = folder; path = app; sourceTree = SOURCE_ROOT; }; + 60F0BABF191FC868006EC268 /* app_packages */ = {isa = PBXFileReference; lastKnownFileType = folder; path = app_packages; sourceTree = SOURCE_ROOT; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 60796EDF19190F4100A9926B /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 60796F39191CDBBA00A9926B /* CoreFoundation.framework in Frameworks */, + 60796F2C1919C70800A9926B /* Python.framework in Frameworks */, + 60796F201919174D00A9926B /* libsqlite3.dylib in Frameworks */, + 60796F1919190FBB00A9926B /* libz.dylib in Frameworks */, + 60796EE819190F4100A9926B /* CoreGraphics.framework in Frameworks */, + 60796EEA19190F4100A9926B /* UIKit.framework in Frameworks */, + 60796EE619190F4100A9926B /* Foundation.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 60796ED919190F4100A9926B = { + isa = PBXGroup; + children = ( + 60796EEB19190F4100A9926B /* sample */, + 60796EE419190F4100A9926B /* Frameworks */, + 60796EE319190F4100A9926B /* Products */, + ); + sourceTree = ""; + }; + 60796EE319190F4100A9926B /* Products */ = { + isa = PBXGroup; + children = ( + 60796EE219190F4100A9926B /* sample.app */, + ); + name = Products; + sourceTree = ""; + }; + 60796EE419190F4100A9926B /* Frameworks */ = { + isa = PBXGroup; + children = ( + 60796F1F1919174D00A9926B /* libsqlite3.dylib */, + 60796F1819190FBB00A9926B /* libz.dylib */, + 60796F38191CDBBA00A9926B /* CoreFoundation.framework */, + 60796EE719190F4100A9926B /* CoreGraphics.framework */, + 60796EE519190F4100A9926B /* Foundation.framework */, + 60796F2B1919C70800A9926B /* Python.framework */, + 60796EE919190F4100A9926B /* UIKit.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; + 60796EEB19190F4100A9926B /* sample */ = { + isa = PBXGroup; + children = ( + 60F0BABD191FC83F006EC268 /* app */, + 60F0BABF191FC868006EC268 /* app_packages */, + 60796EF719190F4100A9926B /* Images.xcassets */, + 60796EEC19190F4100A9926B /* Supporting Files */, + ); + path = sample; + sourceTree = ""; + }; + 60796EEC19190F4100A9926B /* Supporting Files */ = { + isa = PBXGroup; + children = ( + 60796EED19190F4100A9926B /* sample-Info.plist */, + 60796EEE19190F4100A9926B /* InfoPlist.strings */, + 60796EF119190F4100A9926B /* main.m */, + 60796EF319190F4100A9926B /* sample-Prefix.pch */, + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 60796EE119190F4100A9926B /* sample */ = { + isa = PBXNativeTarget; + buildConfigurationList = 60796F0E19190F4100A9926B /* Build configuration list for PBXNativeTarget "sample" */; + buildPhases = ( + 60796F2F1919C7E700A9926B /* Refresh Python source */, + 60796EDE19190F4100A9926B /* Sources */, + 60796EDF19190F4100A9926B /* Frameworks */, + 60796EE019190F4100A9926B /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = sample; + productName = sample; + productReference = 60796EE219190F4100A9926B /* sample.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 60796EDA19190F4100A9926B /* Project object */ = { + isa = PBXProject; + attributes = { + CLASSPREFIX = Py; + LastUpgradeCheck = 0630; + ORGANIZATIONNAME = "Example Corp"; + }; + buildConfigurationList = 60796EDD19190F4100A9926B /* Build configuration list for PBXProject "sample" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + ); + mainGroup = 60796ED919190F4100A9926B; + productRefGroup = 60796EE319190F4100A9926B /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 60796EE119190F4100A9926B /* sample */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 60796EE019190F4100A9926B /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 60796EF019190F4100A9926B /* InfoPlist.strings in Resources */, + 60796EF819190F4100A9926B /* Images.xcassets in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 60796F2F1919C7E700A9926B /* Refresh Python source */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Refresh Python source"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "mkdir -p $BUILT_PRODUCTS_DIR/$CONTENTS_FOLDER_PATH/Library/Python.framework/Resources\nmkdir -p $BUILT_PRODUCTS_DIR/$CONTENTS_FOLDER_PATH/Library/Application\\ Support/org.python.$PROJECT_NAME\nrsync -pvtrL --exclude .hg --exclude .svn --exclude .git $PROJECT_DIR/Python.framework/Resources/lib $BUILT_PRODUCTS_DIR/$CONTENTS_FOLDER_PATH/Library/Python.framework/Resources\nrsync -pvtrL --exclude .hg --exclude .svn --exclude .git $PROJECT_DIR/Python.framework/Resources/include $BUILT_PRODUCTS_DIR/$CONTENTS_FOLDER_PATH/Library/Python.framework/Resources\nrsync -pvtrL --exclude .hg --exclude .svn --exclude .git $PROJECT_DIR/app $BUILT_PRODUCTS_DIR/$CONTENTS_FOLDER_PATH/Library/Application\\ Support/org.python.$PROJECT_NAME\nrsync -pvtrL --exclude .hg --exclude .svn --exclude .git $PROJECT_DIR/app_packages/ $BUILT_PRODUCTS_DIR/$CONTENTS_FOLDER_PATH/Library/Python.framework/Resources/lib/python`readlink $PROJECT_DIR/Python.framework/Versions/Current`/site-packages/\n"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 60796EDE19190F4100A9926B /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 60796EF219190F4100A9926B /* main.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 60796EEE19190F4100A9926B /* InfoPlist.strings */ = { + isa = PBXVariantGroup; + children = ( + 60796EEF19190F4100A9926B /* en */, + ); + name = InfoPlist.strings; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 60796F0C19190F4100A9926B /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 7.1; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 60796F0D19190F4100A9926B /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = YES; + ENABLE_NS_ASSERTIONS = NO; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 7.1; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 60796F0F19190F4100A9926B /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)", + ); + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = "sample/sample-Prefix.pch"; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, + "\"$(PROJECT_DIR)/Python.framework/Resources/include/python2.7\"", + ); + INFOPLIST_FILE = "sample/sample-Info.plist"; + PRODUCT_NAME = "$(TARGET_NAME)"; + USER_HEADER_SEARCH_PATHS = include/python2.7; + WRAPPER_EXTENSION = app; + }; + name = Debug; + }; + 60796F1019190F4100A9926B /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)", + ); + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = "sample/sample-Prefix.pch"; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, + "\"$(PROJECT_DIR)/Python.framework/Resources/include/python2.7\"", + ); + INFOPLIST_FILE = "sample/sample-Info.plist"; + PRODUCT_NAME = "$(TARGET_NAME)"; + USER_HEADER_SEARCH_PATHS = include/python2.7; + WRAPPER_EXTENSION = app; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 60796EDD19190F4100A9926B /* Build configuration list for PBXProject "sample" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 60796F0C19190F4100A9926B /* Debug */, + 60796F0D19190F4100A9926B /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 60796F0E19190F4100A9926B /* Build configuration list for PBXNativeTarget "sample" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 60796F0F19190F4100A9926B /* Debug */, + 60796F1019190F4100A9926B /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 60796EDA19190F4100A9926B /* Project object */; +} --- /dev/null +++ b/tvOS/XCode-sample/sample/Images.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,53 @@ +{ + "images" : [ + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "29x29", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "40x40", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "76x76", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "76x76", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file --- /dev/null +++ b/tvOS/XCode-sample/sample/Images.xcassets/LaunchImage.launchimage/Contents.json @@ -0,0 +1,51 @@ +{ + "images" : [ + { + "orientation" : "portrait", + "idiom" : "iphone", + "extent" : "full-screen", + "minimum-system-version" : "7.0", + "scale" : "2x" + }, + { + "orientation" : "portrait", + "idiom" : "iphone", + "subtype" : "retina4", + "extent" : "full-screen", + "minimum-system-version" : "7.0", + "scale" : "2x" + }, + { + "orientation" : "portrait", + "idiom" : "ipad", + "extent" : "full-screen", + "minimum-system-version" : "7.0", + "scale" : "1x" + }, + { + "orientation" : "landscape", + "idiom" : "ipad", + "extent" : "full-screen", + "minimum-system-version" : "7.0", + "scale" : "1x" + }, + { + "orientation" : "portrait", + "idiom" : "ipad", + "extent" : "full-screen", + "minimum-system-version" : "7.0", + "scale" : "2x" + }, + { + "orientation" : "landscape", + "idiom" : "ipad", + "extent" : "full-screen", + "minimum-system-version" : "7.0", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file --- /dev/null +++ b/tvOS/XCode-sample/sample/en.lproj/InfoPlist.strings @@ -0,0 +1 @@ +/* Localized versions of Info.plist keys */ --- /dev/null +++ b/tvOS/XCode-sample/sample/main.m @@ -0,0 +1,111 @@ +// +// main.m +// A main module for starting Python projects under iOS. +// + +#import +#import +#include +#include + +int main(int argc, char *argv[]) { + int ret = 0; + unsigned int i; + NSString *tmp_path; + NSString *python_home; + wchar_t *wpython_home; + const char* main_script; + wchar_t** python_argv; + + @autoreleasepool { + + NSString * resourcePath = [[NSBundle mainBundle] resourcePath]; + + // Special environment to avoid writing bytecode because + // the process will not have write attribute on the device. + putenv("PYTHONDONTWRITEBYTECODE=1"); + + python_home = [NSString stringWithFormat:@"%@/Library/Python.framework/Resources", resourcePath, nil]; + NSLog(@"PythonHome is: %@", python_home); + wpython_home = _Py_char2wchar([python_home UTF8String], NULL); + Py_SetPythonHome(wpython_home); + + // iOS provides a specific directory for temp files. + tmp_path = [NSString stringWithFormat:@"TMP=%@/tmp", resourcePath, nil]; + putenv((char *)[tmp_path UTF8String]); + + NSLog(@"Initializing Python runtime"); + Py_Initialize(); + + // Set the name of the main script + main_script = [ + [[NSBundle mainBundle] pathForResource:@"Library/Application Support/org.python.sample/app/sample/main" + ofType:@"py"] cStringUsingEncoding:NSUTF8StringEncoding]; + + if (main_script == NULL) { + NSLog(@"Unable to locate app/sample/main.py file"); + exit(-1); + } + + // Construct argv for the interpreter + python_argv = PyMem_RawMalloc(sizeof(wchar_t*) * argc); + + python_argv[0] = _Py_char2wchar(main_script, NULL); + for (i = 1; i < argc; i++) { + python_argv[i] = _Py_char2wchar(argv[i], NULL); + } + + PySys_SetArgv(argc, python_argv); + + // If other modules are using threads, we need to initialize them. + PyEval_InitThreads(); + + // Start the main.py script + NSLog(@"Running %s", main_script); + + @try { + FILE* fd = fopen(main_script, "r"); + if (fd == NULL) { + ret = 1; + NSLog(@"Unable to open main.py, abort."); + } else { + ret = PyRun_SimpleFileEx(fd, main_script, 1); + if (ret != 0) { + NSLog(@"Application quit abnormally!"); + } else { + // In a normal iOS application, the following line is what + // actually runs the application. It requires that the + // Objective-C runtime environment has a class named + // "PythonAppDelegate". This project doesn't define + // one, because Objective-C bridging isn't something + // Python does out of the box. You'll need to use + // a library like Rubicon-ObjC [1], Pyobjus [2] or + // PyObjC [3] if you want to run an *actual* iOS app. + // [1] http://pybee.org/rubicon + // [2] http://pyobjus.readthedocs.org/ + // [3] https://pythonhosted.org/pyobjc/ + + UIApplicationMain(argc, argv, nil, @"PythonAppDelegate"); + } + } + } + @catch (NSException *exception) { + NSLog(@"Python runtime error: %@", [exception reason]); + } + @finally { + Py_Finalize(); + } + + PyMem_RawFree(wpython_home); + if (python_argv) { + for (i = 0; i < argc; i++) { + PyMem_RawFree(python_argv[i]); + } + PyMem_RawFree(python_argv); + } + NSLog(@"Leaving"); + } + + exit(ret); + return ret; +} \ No newline at end of file --- /dev/null +++ b/tvOS/XCode-sample/sample/sample-Info.plist @@ -0,0 +1,45 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleDisplayName + ${PRODUCT_NAME} + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + com.example.${PRODUCT_NAME:rfc1034identifier} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + LSRequiresIPhoneOS + + UIRequiredDeviceCapabilities + + armv7 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + + \ No newline at end of file --- /dev/null +++ b/tvOS/XCode-sample/sample/sample-Prefix.pch @@ -0,0 +1,16 @@ +// +// Prefix header +// +// The contents of this file are implicitly included at the beginning of every source file. +// + +#import + +#ifndef __IPHONE_3_0 +#warning "This project uses features only available in iOS SDK 3.0 and later." +#endif + +#ifdef __OBJC__ + #import + #import +#endif \ No newline at end of file --- /dev/null +++ b/watchOS/Info.plist @@ -0,0 +1,20 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + Python + CFBundleIdentifier + org.python + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + FMWK + CFBundleSignature + ???? + CFBundleVersion + xxxVERSIONxxx + + --- /dev/null +++ b/watchOS/README @@ -0,0 +1,161 @@ +======================== +Python on watchOS README +======================== + +:Authors: + Russell Keith-Magee (2015) + +:Version: 3.5.2 + +This document provides a overview of eccentricities of building and using +Python on watchOS devices (i.e., AppleTV). + +Build instructions +================== + +The watchOS build must be run on an Mac with XCode installed. To build the watchOS +framework, unpack the Python sources, move into the watchOS subdirectory, and +run ``make``. There are no configuration options to this build process - +it will use XCode utilities to identify the location of compilers, +resource directories, and so on. + +The build process will configure and build Python 3 times, producing: + + * A "host" version of Python + * A version of Python compiled for the i386 watchOS Simulator + * A version of Python compiled for ARMv7k watchOS devices + +Build products will be "installed" into watchOS/build. The built products will +then be combined into a single "fat" ``Python.framework`` that can be added to +an XCode project. The resulting framework will be located in the root +directory of the Python source tree. + +A ``make clean`` target also exists to clean out all build products; +``make distclean`` will clean out all user-specific files from the test and +sample projects. + +Test instructions +----------------- + +The ``Tools`` directory contains an ``watchOS-Test`` project that enables you to +run the Python regression test suite. When you run ``make`` in the watchOS +directory, a copy of ``Python.framework`` will also be installed into this +test project. + +To run the test project, load the project into XCode, and run (either on a +device or in the simulator). The test suite takes around 10 minutes to run on +an Apple Watch. + +.. note:: If you run the test project in debug mode, the XCode debugger will + stop whenever a signal is raised. The Python regression test suite checks + a number of signal handlers, and the test suite will stop mid-execution + when this occurs. + + To disable this signal handling, set a breakpoint at the start of + ``main.c``; when execution stops at the breakpoint, run the following + commands in the debugger (at the ``(lldb)`` prompt in the console log + window):: + + process handle SIGPIPE -n true -p true -s false + process handle SIGINT -n true -p true -s false + process handle SIGXFSZ -n true -p true -s false + process handle SIGUSR1 -n true -p true -s false + process handle SIGUSR2 -n true -p true -s false + + Unfortunately, this has to be done every time the test suite is executed. + +watchOS-specific details +==================== + +* ``import sys; sys.platform`` will report as `'watchos'`, regardless of whether you + are on a simulator or a real platform. + +* ``import platform; platform.machine()`` will return the device identifier. + For example, an origianl Apple Watch will return `'Watch1,1'` + +* The following modules are not currently supported: + + - ``bsddb`` + - ``bz2`` + - ``curses`` + - ``dbm`` + - ``gdbm`` + - ``hotshot`` + - ``idlelib`` + - ``lzma`` + - ``nis`` + - ``ossaudiodev`` + - ``readline`` + - ``spwd`` + - ``sqlite3`` + - ``ssl`` + - ``tkinter`` + - ``turtledemo`` + - ``wsgiref`` + +* Due to limitations in using dynamic loading on watchOS, binary Python modules must be + statically-linked into the executable. The framework package produced by the watchOS + ``make install`` statically links all the supported standard library modules. + If you have a third-party Python binary module, you'll need to incorporate the + source files for that module into the sources for your own app. + + If you want to add or remove a binary module from the set that is included in the + Python library, you can do so by providing module setup files for each platform. + There are two default module configuration files: + + - ``Modules/Setup.watchOS-aarch64`` for ARM64 watchOS builds + - ``Modules/Setup.watchOS-x86_64`` for x86_64 watchOS simulator builds + + If you copy these files to a ``.local`` version (e.g., + ``Modules/Setup.watchOS-aarch64.local``), the local version will override the + default. You can then make modifications to the modules that will be included + in the watchOS framework, and the flags passed to the compiler when compiling those + modules. + +Adding Python to an watchOS project +=============================== + +The watchOS subdirectory contains a sample XCode 6.1 project to demonstrate how +Python can be added to an watchOS project. After building the Python watchOS framework, +copy it into the ``watchOS/XCode-sample`` directory. You should end up with a directory +structure that looks like this:: + + XCode-sample/ + Python.framework/ - Manually copied into the project + app/ + sample/ + __init__.py + main.py - The Python script to be executed + app_packages/ - A directory that will be added to the `PYTHONPATH` at runtime + sample + Images.xcassets + en.lproj + main.c - The main() definition for the watchOS application + sample-Info.plist + sample-Prefix.pch + sample.xcodeproj - The XCode project file + +If you open the project file is project and run it, you should get output +similar to the following:: + + 2015-03-14 22:15:19.595 sample[84454:22100187] PythonHome is: /Users/rkm/Library/Developer/CoreSimulator/Devices/19FE988F-E5C3-4A6C-8752-C12DE9BF079D/data/Containers/Bundle/Application/A949B323-FD20-4C76-B370-99AFF294E9D5/sample.app + 2015-03-14 22:15:19.597 sample[84454:22100187] Initializing Python runtime + 2015-03-14 22:15:19.758 sample[84454:22100187] Running /Users/rkm/Library/Developer/CoreSimulator/Devices/19FE988F-E5C3-4A6C-8752-C12DE9BF079D/data/Containers/Bundle/Application/A949B323-FD20-4C76-B370-99AFF294E9D5/sample.app/app/sample/main.py + Hello, World. + 2015-03-14 22:15:19.792 sample[84454:22100187] Leaving + +You can now modify the provide Python source code, import and use +code from the Python standard library, and add third-party modules to +app_packages. + +The sample app is a console-only app, so it isn't of any real practical use. +Python can be embedded into any Objective-C project using the normal Python +APIs for embedding; but if you want to write a full watchOS app in Python, or +you want to access watchOS services from within embedded code, you'll need to +bridge between the Objective-C environment and the Python environment. +This binding isn't something that Python does out of the box; you'll need +to use a third-party library like `Rubicon ObjC`_, `Pyobjus`_ or `PyObjC`_. + +.. _Rubicon ObjC: http://pybee.org/rubicon +.. _Pyobjus: http://pyobjus.readthedocs.org/ +.. _PyObjC: https://pythonhosted.org/pyobjc/ --- /dev/null +++ b/watchOS/XCode-sample/app/sample/main.py @@ -0,0 +1,3 @@ + +if __name__ == '__main__': + print("Hello, World.") --- /dev/null +++ b/watchOS/XCode-sample/app_packages/README @@ -0,0 +1 @@ +This directory exists so that 3rd party packages can be installed here. \ No newline at end of file --- /dev/null +++ b/watchOS/XCode-sample/sample.xcodeproj/project.pbxproj @@ -0,0 +1,353 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 60796EE619190F4100A9926B /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 60796EE519190F4100A9926B /* Foundation.framework */; }; + 60796EE819190F4100A9926B /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 60796EE719190F4100A9926B /* CoreGraphics.framework */; }; + 60796EEA19190F4100A9926B /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 60796EE919190F4100A9926B /* UIKit.framework */; }; + 60796EF019190F4100A9926B /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 60796EEE19190F4100A9926B /* InfoPlist.strings */; }; + 60796EF219190F4100A9926B /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 60796EF119190F4100A9926B /* main.m */; }; + 60796EF819190F4100A9926B /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 60796EF719190F4100A9926B /* Images.xcassets */; }; + 60796F1919190FBB00A9926B /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 60796F1819190FBB00A9926B /* libz.dylib */; }; + 60796F201919174D00A9926B /* libsqlite3.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 60796F1F1919174D00A9926B /* libsqlite3.dylib */; }; + 60796F2C1919C70800A9926B /* Python.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 60796F2B1919C70800A9926B /* Python.framework */; }; + 60796F39191CDBBA00A9926B /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 60796F38191CDBBA00A9926B /* CoreFoundation.framework */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 60796EE219190F4100A9926B /* sample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = sample.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 60796EE519190F4100A9926B /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; + 60796EE719190F4100A9926B /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; + 60796EE919190F4100A9926B /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; + 60796EED19190F4100A9926B /* sample-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "sample-Info.plist"; sourceTree = ""; }; + 60796EEF19190F4100A9926B /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; + 60796EF119190F4100A9926B /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; + 60796EF319190F4100A9926B /* sample-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "sample-Prefix.pch"; sourceTree = ""; }; + 60796EF719190F4100A9926B /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; + 60796F1819190FBB00A9926B /* libz.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libz.dylib; path = usr/lib/libz.dylib; sourceTree = SDKROOT; }; + 60796F1F1919174D00A9926B /* libsqlite3.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libsqlite3.dylib; path = usr/lib/libsqlite3.dylib; sourceTree = SDKROOT; }; + 60796F2B1919C70800A9926B /* Python.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = Python.framework; sourceTree = ""; }; + 60796F38191CDBBA00A9926B /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = System/Library/Frameworks/CoreFoundation.framework; sourceTree = SDKROOT; }; + 60F0BABD191FC83F006EC268 /* app */ = {isa = PBXFileReference; lastKnownFileType = folder; path = app; sourceTree = SOURCE_ROOT; }; + 60F0BABF191FC868006EC268 /* app_packages */ = {isa = PBXFileReference; lastKnownFileType = folder; path = app_packages; sourceTree = SOURCE_ROOT; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 60796EDF19190F4100A9926B /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 60796F39191CDBBA00A9926B /* CoreFoundation.framework in Frameworks */, + 60796F2C1919C70800A9926B /* Python.framework in Frameworks */, + 60796F201919174D00A9926B /* libsqlite3.dylib in Frameworks */, + 60796F1919190FBB00A9926B /* libz.dylib in Frameworks */, + 60796EE819190F4100A9926B /* CoreGraphics.framework in Frameworks */, + 60796EEA19190F4100A9926B /* UIKit.framework in Frameworks */, + 60796EE619190F4100A9926B /* Foundation.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 60796ED919190F4100A9926B = { + isa = PBXGroup; + children = ( + 60796EEB19190F4100A9926B /* sample */, + 60796EE419190F4100A9926B /* Frameworks */, + 60796EE319190F4100A9926B /* Products */, + ); + sourceTree = ""; + }; + 60796EE319190F4100A9926B /* Products */ = { + isa = PBXGroup; + children = ( + 60796EE219190F4100A9926B /* sample.app */, + ); + name = Products; + sourceTree = ""; + }; + 60796EE419190F4100A9926B /* Frameworks */ = { + isa = PBXGroup; + children = ( + 60796F1F1919174D00A9926B /* libsqlite3.dylib */, + 60796F1819190FBB00A9926B /* libz.dylib */, + 60796F38191CDBBA00A9926B /* CoreFoundation.framework */, + 60796EE719190F4100A9926B /* CoreGraphics.framework */, + 60796EE519190F4100A9926B /* Foundation.framework */, + 60796F2B1919C70800A9926B /* Python.framework */, + 60796EE919190F4100A9926B /* UIKit.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; + 60796EEB19190F4100A9926B /* sample */ = { + isa = PBXGroup; + children = ( + 60F0BABD191FC83F006EC268 /* app */, + 60F0BABF191FC868006EC268 /* app_packages */, + 60796EF719190F4100A9926B /* Images.xcassets */, + 60796EEC19190F4100A9926B /* Supporting Files */, + ); + path = sample; + sourceTree = ""; + }; + 60796EEC19190F4100A9926B /* Supporting Files */ = { + isa = PBXGroup; + children = ( + 60796EED19190F4100A9926B /* sample-Info.plist */, + 60796EEE19190F4100A9926B /* InfoPlist.strings */, + 60796EF119190F4100A9926B /* main.m */, + 60796EF319190F4100A9926B /* sample-Prefix.pch */, + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 60796EE119190F4100A9926B /* sample */ = { + isa = PBXNativeTarget; + buildConfigurationList = 60796F0E19190F4100A9926B /* Build configuration list for PBXNativeTarget "sample" */; + buildPhases = ( + 60796F2F1919C7E700A9926B /* Refresh Python source */, + 60796EDE19190F4100A9926B /* Sources */, + 60796EDF19190F4100A9926B /* Frameworks */, + 60796EE019190F4100A9926B /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = sample; + productName = sample; + productReference = 60796EE219190F4100A9926B /* sample.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 60796EDA19190F4100A9926B /* Project object */ = { + isa = PBXProject; + attributes = { + CLASSPREFIX = Py; + LastUpgradeCheck = 0630; + ORGANIZATIONNAME = "Example Corp"; + }; + buildConfigurationList = 60796EDD19190F4100A9926B /* Build configuration list for PBXProject "sample" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + ); + mainGroup = 60796ED919190F4100A9926B; + productRefGroup = 60796EE319190F4100A9926B /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 60796EE119190F4100A9926B /* sample */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 60796EE019190F4100A9926B /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 60796EF019190F4100A9926B /* InfoPlist.strings in Resources */, + 60796EF819190F4100A9926B /* Images.xcassets in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 60796F2F1919C7E700A9926B /* Refresh Python source */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Refresh Python source"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "mkdir -p $BUILT_PRODUCTS_DIR/$CONTENTS_FOLDER_PATH/Library/Python.framework/Resources\nmkdir -p $BUILT_PRODUCTS_DIR/$CONTENTS_FOLDER_PATH/Library/Application\\ Support/org.python.$PROJECT_NAME\nrsync -pvtrL --exclude .hg --exclude .svn --exclude .git $PROJECT_DIR/Python.framework/Resources/lib $BUILT_PRODUCTS_DIR/$CONTENTS_FOLDER_PATH/Library/Python.framework/Resources\nrsync -pvtrL --exclude .hg --exclude .svn --exclude .git $PROJECT_DIR/Python.framework/Resources/include $BUILT_PRODUCTS_DIR/$CONTENTS_FOLDER_PATH/Library/Python.framework/Resources\nrsync -pvtrL --exclude .hg --exclude .svn --exclude .git $PROJECT_DIR/app $BUILT_PRODUCTS_DIR/$CONTENTS_FOLDER_PATH/Library/Application\\ Support/org.python.$PROJECT_NAME\nrsync -pvtrL --exclude .hg --exclude .svn --exclude .git $PROJECT_DIR/app_packages/ $BUILT_PRODUCTS_DIR/$CONTENTS_FOLDER_PATH/Library/Python.framework/Resources/lib/python`readlink $PROJECT_DIR/Python.framework/Versions/Current`/site-packages/\n"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 60796EDE19190F4100A9926B /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 60796EF219190F4100A9926B /* main.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 60796EEE19190F4100A9926B /* InfoPlist.strings */ = { + isa = PBXVariantGroup; + children = ( + 60796EEF19190F4100A9926B /* en */, + ); + name = InfoPlist.strings; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 60796F0C19190F4100A9926B /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 7.1; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 60796F0D19190F4100A9926B /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = YES; + ENABLE_NS_ASSERTIONS = NO; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 7.1; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 60796F0F19190F4100A9926B /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)", + ); + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = "sample/sample-Prefix.pch"; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, + "\"$(PROJECT_DIR)/Python.framework/Resources/include/python2.7\"", + ); + INFOPLIST_FILE = "sample/sample-Info.plist"; + PRODUCT_NAME = "$(TARGET_NAME)"; + USER_HEADER_SEARCH_PATHS = include/python2.7; + WRAPPER_EXTENSION = app; + }; + name = Debug; + }; + 60796F1019190F4100A9926B /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)", + ); + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = "sample/sample-Prefix.pch"; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, + "\"$(PROJECT_DIR)/Python.framework/Resources/include/python2.7\"", + ); + INFOPLIST_FILE = "sample/sample-Info.plist"; + PRODUCT_NAME = "$(TARGET_NAME)"; + USER_HEADER_SEARCH_PATHS = include/python2.7; + WRAPPER_EXTENSION = app; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 60796EDD19190F4100A9926B /* Build configuration list for PBXProject "sample" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 60796F0C19190F4100A9926B /* Debug */, + 60796F0D19190F4100A9926B /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 60796F0E19190F4100A9926B /* Build configuration list for PBXNativeTarget "sample" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 60796F0F19190F4100A9926B /* Debug */, + 60796F1019190F4100A9926B /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 60796EDA19190F4100A9926B /* Project object */; +} --- /dev/null +++ b/watchOS/XCode-sample/sample/Images.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,53 @@ +{ + "images" : [ + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "29x29", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "40x40", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "76x76", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "76x76", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file --- /dev/null +++ b/watchOS/XCode-sample/sample/Images.xcassets/LaunchImage.launchimage/Contents.json @@ -0,0 +1,51 @@ +{ + "images" : [ + { + "orientation" : "portrait", + "idiom" : "iphone", + "extent" : "full-screen", + "minimum-system-version" : "7.0", + "scale" : "2x" + }, + { + "orientation" : "portrait", + "idiom" : "iphone", + "subtype" : "retina4", + "extent" : "full-screen", + "minimum-system-version" : "7.0", + "scale" : "2x" + }, + { + "orientation" : "portrait", + "idiom" : "ipad", + "extent" : "full-screen", + "minimum-system-version" : "7.0", + "scale" : "1x" + }, + { + "orientation" : "landscape", + "idiom" : "ipad", + "extent" : "full-screen", + "minimum-system-version" : "7.0", + "scale" : "1x" + }, + { + "orientation" : "portrait", + "idiom" : "ipad", + "extent" : "full-screen", + "minimum-system-version" : "7.0", + "scale" : "2x" + }, + { + "orientation" : "landscape", + "idiom" : "ipad", + "extent" : "full-screen", + "minimum-system-version" : "7.0", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file --- /dev/null +++ b/watchOS/XCode-sample/sample/en.lproj/InfoPlist.strings @@ -0,0 +1 @@ +/* Localized versions of Info.plist keys */ --- /dev/null +++ b/watchOS/XCode-sample/sample/main.m @@ -0,0 +1,111 @@ +// +// main.m +// A main module for starting Python projects under iOS. +// + +#import +#import +#include +#include + +int main(int argc, char *argv[]) { + int ret = 0; + unsigned int i; + NSString *tmp_path; + NSString *python_home; + char *wpython_home; + const char* main_script; + char** python_argv; + @autoreleasepool { + + NSString * resourcePath = [[NSBundle mainBundle] resourcePath]; + + // Special environment to avoid writing bytecode because + // the process will not have write attribute on the device. + putenv("PYTHONDONTWRITEBYTECODE=1"); + + python_home = [NSString stringWithFormat:@"%@/Library/Python.framework/Resources", resourcePath, nil]; + NSLog(@"PythonHome is: %@", python_home); + wpython_home = strdup([python_home UTF8String]); + Py_SetPythonHome(wpython_home); + + // iOS provides a specific directory for temp files. + tmp_path = [NSString stringWithFormat:@"TMP=%@/tmp", resourcePath, nil]; + putenv((char *)[tmp_path UTF8String]); + + NSLog(@"Initializing Python runtime"); + Py_Initialize(); + + // Set the name of the main script + main_script = [ + [[NSBundle mainBundle] pathForResource:@"Library/Application Support/org.python.sample/app/sample/main" + ofType:@"py"] cStringUsingEncoding:NSUTF8StringEncoding]; + + if (main_script == NULL) { + NSLog(@"Unable to locate app/sample/main.py file"); + exit(-1); + } + + // Construct argv for the interpreter + python_argv = PyMem_Malloc(sizeof(char *) * argc); + + + python_argv[0] = strdup(main_script); + for (i = 1; i < argc; i++) { + python_argv[i] = argv[i]; + } + + PySys_SetArgv(argc, python_argv); + + // If other modules are using threads, we need to initialize them. + PyEval_InitThreads(); + + // Start the main.py script + NSLog(@"Running %s", main_script); + + @try { + FILE* fd = fopen(main_script, "r"); + if (fd == NULL) { + ret = 1; + NSLog(@"Unable to open main.py, abort."); + } else { + ret = PyRun_SimpleFileEx(fd, main_script, 1); + if (ret != 0) { + NSLog(@"Application quit abnormally!"); + } else { + // In a normal iOS application, the following line is what + // actually runs the application. It requires that the + // Objective-C runtime environment has a class named + // "PythonAppDelegate". This project doesn't define + // one, because Objective-C bridging isn't something + // Python does out of the box. You'll need to use + // a library like Rubicon-ObjC [1], Pyobjus [2] or + // PyObjC [3] if you want to run an *actual* iOS app. + // [1] http://pybee.org/rubicon + // [2] http://pyobjus.readthedocs.org/ + // [3] https://pythonhosted.org/pyobjc/ + + UIApplicationMain(argc, argv, nil, @"PythonAppDelegate"); + } + } + } + @catch (NSException *exception) { + NSLog(@"Python runtime error: %@", [exception reason]); + } + @finally { + Py_Finalize(); + } + + PyMem_Free(wpython_home); + if (python_argv) { + for (i = 0; i < argc; i++) { + PyMem_Free(python_argv[i]); + } + PyMem_Free(python_argv); + } + NSLog(@"Leaving"); + } + + exit(ret); + return ret; +} \ No newline at end of file --- /dev/null +++ b/watchOS/XCode-sample/sample/sample-Info.plist @@ -0,0 +1,45 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleDisplayName + ${PRODUCT_NAME} + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + com.example.${PRODUCT_NAME:rfc1034identifier} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + LSRequiresIPhoneOS + + UIRequiredDeviceCapabilities + + armv7 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + + \ No newline at end of file --- /dev/null +++ b/watchOS/XCode-sample/sample/sample-Prefix.pch @@ -0,0 +1,16 @@ +// +// Prefix header +// +// The contents of this file are implicitly included at the beginning of every source file. +// + +#import + +#ifndef __IPHONE_3_0 +#warning "This project uses features only available in iOS SDK 3.0 and later." +#endif + +#ifdef __OBJC__ + #import + #import +#endif \ No newline at end of file