Following system colour scheme Selected dark colour scheme Selected light colour scheme

Python 개선 제안 한국어 번역

PEP 730 – 지원 플랫폼으로 iOS 추가

Author:
Russell Keith-Magee <russell at keith-magee.com>
Sponsor:
Ned Deily <nad at python.org>
Discussions-To:
Discourse thread
Status:
Final
Type:
Standards Track
Created:
09-Oct-2023
Python-Version:
3.13
Resolution:
Discourse message

Table of Contents

번역·라이선스 안내

이 비공식 한국어 번역은 원문 Copyright 절의 Public Domain or CC0-1.0, whichever is more permissive 조건에 따라 제공합니다. 원저자와 공식 원문은 그대로 표시합니다. 수정되지 않은 기준 원문 · 공식 최신판

Important

This PEP is a historical document. The up-to-date, canonical documentation can now be found at Using Python on iOS.

×

See PEP 1 for how to propose changes.

초록

이 PEP는 CPython에 iOS를 지원 플랫폼으로 추가할 것을 제안합니다. 초기 목표는 Python 3.13에서 Tier 3 지원을 달성하는 것입니다. 이 PEP는 iOS를 지원하는 데 필요한 변경 사항의 기술적 측면을 설명합니다. 또한 iOS를 Tier 3 플랫폼으로 도입하는 것과 관련된 프로젝트 관리상의 문제를 설명합니다.

동기

지난 15년 동안 모바일 플랫폼은 컴퓨팅 환경에서 점점 더 중요한 부분이 되었습니다. iOS는 이러한 기기의 압도적 다수를 제어하는 두 운영 체제 중 하나입니다. 그러나 CPython에는 iOS에 대한 공식 지원이 없습니다.

BeeWare ProjectKivy는 모두 거의 10년 동안 iOS를 지원해 왔습니다. 이러한 지원을 통해 iOS App Store에 게시가 승인된 애플리케이션을 생성할 수 있었습니다. 이는 iOS 지원의 기술적 실현 가능성을 보여 줍니다.

Python이라는 언어의 미래를 위해서는 널리 채택된 모든 하드웨어 또는 OS에서 Python을 사용할 수 있어야 합니다. Python을 널리 사용하는 플랫폼에서 사용할 수 없다면, 잠재적 사용자가 이러한 플랫폼을 지원하는 다른 언어를 채택하게 되므로 해당 언어의 채택에 영향을 미칩니다.

근거

개발 환경

iOS는 단일 API를 제공하지만, 서로 다른 두 ABI인 iphoneos(물리적 기기)와 iphonesimulator를 제공합니다. 이러한 ABI는 각각 여러 CPU 아키텍처에서 제공될 수 있습니다. 이 문서를 작성하는 시점에 Apple은 기기 ABI에서 arm64를 공식적으로 지원하며, 시뮬레이터 ABI에서는 arm64x86_64를 지원합니다.

macOS와 마찬가지로 iOS는 여러 CPU 아키텍처를 포함하는 “fat” 바이너리 생성을 지원합니다. 그러나 fat 바이너리는 ABI 전체에 걸칠 수 없습니다. 즉, simulator 바이너리와 device 바이너리는 각각 fat 바이너리로 만들 수 있지만, 시뮬레이터와 기기 모두의 요구 사항을 충족하는 하나의 fat “iOS” 바이너리를 만들 수는 없습니다. 단일 개발 산출물의 배포를 지원하기 위해 Apple은 공통 API를 구현하는 여러 ABI를 감싸는 래퍼인 “XCframework” 구조를 사용합니다.

iOS는 macOS와 유사한 Darwin 커널에서 실행됩니다. 그러나 iOS와 macOS 사이에는 상당한 플랫폼 차이가 있으므로, 구현 수준에서 macOS와 iOS를 구분해야 합니다.

iOS 코드는 최소 iOS 버전과의 호환성을 갖도록 컴파일됩니다.

Apple은 마케팅 자료에서 “iPadOS”라는 명칭을 자주 사용합니다. 그러나 개발 관점에서는 iPadOS와 iOS 사이에 식별 가능한 차이가 없습니다. iphoneos 또는 iphonesimulator ABI로 컴파일된 바이너리는 iPad에 배포할 수 있습니다.

tvOS, watchOS, visionOS와 같은 다른 Apple 플랫폼은 서로 다른 ABI를 사용하므로 이 PEP에서는 다루지 않습니다.

POSIX 준수

iOS는 대체로 POSIX 플랫폼입니다. 그러나 WASI/Emscripten과 마찬가지로 iOS에 존재하지만 사용할 수 없는 POSIX API와 아예 존재하지 않는 POSIX API가 있습니다.

이 중 가장 주목할 만한 점은 iOS가 어떤 형태의 다중 프로세스 지원도 제공하지 않는다는 사실입니다. forkspawn은 모두 iOS API에 존재하고 있지만, 이를 호출하면 호출한 iOS 프로세스가 중지되고 새 프로세스는 시작되지 않습니다.

WASI/Emscripten과 달리 iOS에서는 스레딩이 지원됩니다.

소켓 처리에도 상당한 제한이 있습니다. 프로세스 샌드박싱으로 인해 소켓을 통한 프로세스 간 통신을 사용할 수 없습니다. 그러나 네트워크 통신용 소켓은 사용할 수 있습니다.

동적 라이브러리

iOS의 App Store guidelines은 Objective C 또는 Swift 이외의 언어로 앱을 작성할 수 있도록 허용합니다. 그러나 배포를 위해 제출하는 앱의 구조에 대해서는 매우 엄격한 지침을 적용합니다.

iOS 앱은 동적으로 로드되는 라이브러리를 사용할 수 있지만, 동적으로 로드되는 콘텐츠를 iOS에서 사용하도록 패키징하는 방식에는 매우 엄격한 요구 사항이 있습니다.

  • 동적 바이너리 콘텐츠는 공유 객체나 바이너리 번들이 아니라 동적 라이브러리로 컴파일해야 합니다.
  • 동적 바이너리 콘텐츠는 앱 번들에 Framework로 패키징해야 합니다.
  • 각 Framework에는 하나의 동적 라이브러리만 포함할 수 있습니다.
  • 프레임워크는 반드시 iOS 앱의 Frameworks 폴더에 포함되어 있어야 합니다.
  • Framework에는 라이브러리가 아닌 콘텐츠를 포함할 수 없습니다.

이로 인해 CPython의 작동에는 몇 가지 제약이 생깁니다. lib-dynload 및/또는 site-packages 폴더에 바이너리 모듈을 저장할 수 없으며, 각 모듈을 Framework로 감싼 뒤 앱의 Frameworks 폴더에 저장해야 합니다. 이는 Python 모듈이 Python 모듈의 __file__속성을 사용하여 바이너리 모듈의 위치를 구성할 수 있다는 일반적인 가정도 더 이상 성립하지 않음을 의미합니다.

macOS와 마찬가지로, 정적으로 링크된 Python 빌드에서 접근할 수 있는 바이너리 모듈을 컴파일하려면 모든 바이너리 모듈에 libpython3.x를 링크하지 않도록 --undefined dynamic_lookup 옵션을 사용해야 합니다. 그러나 iOS에서는 이 컴파일러 플래그를 사용하면 지원 중단 경고가 발생합니다. macOS에서도 이 플래그로 인한 경고가 관찰된 바 있지만, Apple 직원들의 답변은 이 옵션을 제거하여 CPython 생태계를 깨뜨릴 의도가 없음을 시사합니다. Python은 현재 iOS에서 두드러진 입지를 차지하고 있지 않으므로, iOS에서 이 플래그를 사용하는 것이 같은 범주에 해당할지는 판단하기 어렵습니다.

콘솔 및 대화형 사용

기존 CPython REPL 또는 대화형 “python.exe”를 배포하는 것은 이 작업의 목표로 간주해서는 안 됩니다.

모바일 장치(iOS 포함)는 TTY 스타일 콘솔을 제공하지 않습니다. 모바일 장치는 stdin, stdout 또는 stderr를 제공하지 않습니다. iOS는 시스템 로그를 제공하며, 모든 stdoutstderr 콘텐츠가 시스템 로그로 리디렉션되도록 리디렉션을 설치할 수 있지만, stdin에 해당하는 기능은 없습니다.

또한 iOS는 런타임에 추가 코드를 다운로드하는 것을 제한합니다(이 동작은 App Store 심사를 우회하려는 시도와 기능적으로 구별할 수 없기 때문입니다). 따라서 기존의 “가상 환경을 만들고 pip install을 실행하는” 개발 경험은 iOS에서 실현 가능하지 않습니다.

REPL 인터페이스를 제공하는 네이티브 iOS 애플리케이션을 빌드하는 것이 가능합니다. 이는 IDLE 스타일의 사용자 경험에 더 가까울 수 있지만, iOS에서는 Tkinter를 사용할 수 없으므로 어떤 앱이든 처음부터 다시 작성해야 합니다. iOS 앱 스토어에는 이미 이 범주에 속하는 앱의 예가 여러 가지 있습니다(예: PythonistaPyto). 이 작업의 초점은 IDE 스타일의 네이티브 인터페이스에서 활용할 수 있는 임베디드 배포판을 제공하는 것이며, Python용 iOS 사용자 대상의 “앱” 인터페이스를 제공하는 것이 아닙니다.

사양

플랫폼 식별

sys

sys.platform은 시뮬레이터와 실제 장치 모두에서 "ios"로 식별됩니다.

sys.implementation._multiarch는 ABI와 CPU 아키텍처를 설명합니다.

  • ARM64 장치용 "arm64-iphoneos"
  • ARM64 시뮬레이터용 "arm64-iphonesimulator"
  • x86_64 시뮬레이터용 "x86_64-iphonesimulator"

platform

platform은 iOS 관련 세부 정보를 반환하도록 수정됩니다. platform 모듈이 반환하는 값의 대부분은 os.uname()이 반환하는 값과 일치하지만, 다음은 예외입니다.

  • platform.system()- 사용 중인 하드웨어에 따라 "iOS" 또는 iPadOS이며, "Darwin"이 아닙니다.
  • platform.release()- Darwin 커널 버전 대신 문자열인 iOS 버전 번호입니다(예: "16.6.1").

또한 platform.ios_ver()메서드가 추가됩니다. 이는 macOS 버전 정보를 제공하는 데 사용할 수 있는 platform.mac_ver()를 반영합니다. ios_ver()는 다음을 포함하는 namedtuple을 반환합니다.

  • system - 하드웨어에 따라 OS 이름(iOS 또는 iPadOS)
  • release - 문자열인 iOS 버전(예: "16.6.1")
  • model - 문자열인 장치의 모델 식별자(예: "iPhone13,2") 시뮬레이터에서는 시뮬레이터 장치에 따라 "iPhone" 또는 "iPad"를 반환합니다.
  • is_simulator - 장치가 시뮬레이터인지 나타내는 불리언

os

os.uname()은 POSIX uname()호출의 원시 결과를 반환합니다. 이에 따라 다음 값이 반환됩니다.

  • sysname - "Darwin"
  • release - Darwin 커널 버전(예: "22.6.0")

이 접근 방식에서는 os 모듈을 시스템 API에 대한 “원시” 인터페이스로, platform을 보다 일반적으로 유용한 값을 제공하는 상위 수준 API로 취급합니다.

sysconfig

sysconfig 모듈은 최소 iOS 버전을 sysconfig.get_platform()의 일부로 사용합니다(예: "ios-12.0-arm64-iphoneos"). sysconfigdata_name 및 Config 메이크파일은 식별자를 구성하기 위해 기존 플랫폼과 동일한 패턴(sys.platform, sys.implementation._multiarch 등을 사용)을 따릅니다.

서브프로세스 지원

iOS는 WASI/Emscripten에서 확립된 서브프로세스 비활성화 패턴을 활용합니다. 서브프로세스를 시작하려는 시도가 있으면 subprocess 모듈은 예외를 발생시키며, os.forkos.spawn 호출은 OSError를 발생시킵니다.

동적 모듈 로딩

iOS 동적 로딩을 지원하기 위해 importlib 부트스트랩을 확장하여 Python 바이너리 모듈 요청을 Framework 위치로 변환할 수 있는 메타패스 파인더를 추가합니다. 이 파인더는 sys.platform == "ios"인 경우에만 설치됩니다.

이 파인더는 전체 모듈 이름을 프레임워크 이름으로 사용하여 Python 모듈 이름(예: foo.bar._whiz)을 고유한 Framework 이름(즉, foo.bar._whiz.framework)으로 변환합니다. Framework는 디렉터리이며, 파인더는 해당 디렉터리에서 foo.bar._whiz라는 이름의 바이너리를 찾습니다.

컴파일

지원되는 유일한 바이너리 형식은 iOS 호환 Framework 형식으로 패키징된 동적 링크 가능 libpython3.x.dylib입니다. --undefined dynamic_lookup 컴파일러 옵션은 현재 작동하지만, 이 옵션의 장기적인 지속 가능성은 보장할 수 없습니다. 미래가 불확실한 컴파일러 플래그에 의존하는 대신, iOS의 바이너리 모듈은 libpython3.x.dylib에 링크됩니다. 이는 iOS 바이너리 모듈을 libpython3.x.a에 정적으로 링크된 실행 파일에서 로드할 수 없음을 의미합니다. 따라서 정적 libpython3.x.a iOS 라이브러리는 지원되지 않습니다. 이는 Windows의 CPython에서 사용하는 것과 동일한 패턴입니다.

iOS용 CPython을 빌드하려면 CPython의 configure 빌드 시스템에 있는 크로스 플랫폼 도구를 사용해야 합니다. 단일 configure/make/make install 패스는 하나의 ABI와 아키텍처에서 사용할 수 있는 Python.framework 아티팩트를 생성합니다.

여러 아키텍처용 Python.framework 빌드를 하나의 “fat” 라이브러리로 병합하려면 추가 도구가 필요합니다. 또한 여러 ABI를 Apple이 단일 번들에서 서로 다른 ABI용 여러 프레임워크를 배포하는 데 사용하는 XCframework 형식으로 병합하려면 도구가 필요합니다.

CPython 테스트 스위트를 실행하기 위한 Xcode 프로젝트가 제공됩니다. 테스트 스위트 바이너리를 컴파일하고, 시뮬레이터를 시작하고, 테스트 스위트를 설치하고, 실행하는 과정을 자동화하는 도구가 제공됩니다.

배포

iOS를 Tier 3 플랫폼으로 추가하려면 패치되지 않은 CPython 코드 체크아웃에서 iOS 호환 빌드를 컴파일하는 지원만 추가하면 됩니다. 최종 사용자가 사용할 공식 배포 iOS 아티팩트를 제작할 필요는 없습니다.

iOS가 Tier 2 또는 Tier 1 지원으로 승격되면, XCframework 패키지를 생성하는 데 사용되는 도구로 iOS 배포 아티팩트를 제작할 수 있습니다. 그런 다음 이를 Windows 임베디드 배포와 유사한 “embedded distribution”으로 배포하거나, Xcode 프로젝트에 추가할 수 있는 CocoaPod 또는 Swift 패키지로 배포할 수 있습니다.

CI 리소스

Anaconda는 iOS 빌드봇을 실행할 물리적 하드웨어를 제공하겠다고 제안했습니다.

GitHub Actions는 macOS 시스템에서 iOS 시뮬레이터를 호스팅할 수 있으며, iOS 시뮬레이터는 스크립팅 환경으로 제어할 수 있습니다. 무료 등급에서는 현재 x86_64 macOS 시스템만 제공하지만, ARM64 러너는 유료 플랜에서 최근 제공되기 시작했습니다. 그러나 macOS 러너 리소스가 고갈되는 것을 방지하기 위해 iOS용 GitHub Actions 실행은 표준 CI 구성의 일부로 추가되지 않습니다.

패키징

iOS에서는 “universal” 휠 형식을 제공하지 않습니다. 대신 각 ABI-아키텍처 조합에 대해 휠을 제공합니다.

iOS 휠에서는 다음 태그를 사용합니다.

  • ios_12_0_arm64_iphoneos
  • ios_12_0_arm64_iphonesimulator
  • ios_12_0_x86_64_iphonesimulator

이러한 태그에서 “12.0”은 지원되는 최소 iOS 버전입니다. macOS와 마찬가지로 태그에는 휠을 컴파일할 때 선택한 최소 iOS 버전이 포함됩니다. 최소 iOS 버전이 15.0인 휠을 컴파일하면 ios_15_0_* 태그를 사용합니다. 이 글을 작성하는 시점에 iOS 12.0은 대부분의 주요 iOS 기능을 제공하면서 기기의 거의 100%에 도달하므로, iOS 버전 일치의 하한으로 사용합니다.

이러한 휠에는 바이너리 모듈을 현 위치에 포함할 수 있습니다(즉, 데스크톱 플랫폼용 휠과 같은 방식으로 Python 소스와 같은 위치에 둘 수 있습니다). 그러나 배포를 위해 바이너리 모듈을 “Frameworks” 위치로 이동해야 하므로 사후 처리가 필요합니다. 이는 Xcode 빌드 단계로 자동화할 수 있습니다.

PEP 11 업데이트

PEP 11은 두 가지 iOS ABI를 포함하도록 업데이트됩니다.

  • arm64-apple-ios
  • arm64-apple-ios-simulator

Ned Deily가 이러한 ABI의 최초 핵심 팀 연락 담당자 역할을 맡습니다.

x86_64-apple-ios-simulator 대상은 최선의 노력에 기반하여 지원되지만, 3등급 지원 대상으로 지정되지는 않습니다. 이는 시뮬레이션 플랫폼으로서 x86_64가 곧 사용 중단될 예정이며, 현재 x86_64 macOS 하드웨어를 구축하기도 어렵기 때문입니다.

하위 호환성

새 플랫폼을 추가해도 CPython 자체에는 하위 호환성 문제가 발생하지 않습니다.

CPython 패치의 최종 형태가 해당 프로젝트에서 역사적으로 사용해 온 패치와 일치하지 않는다면, 과거에 CPython 지원을 제공해 온 프로젝트(즉, BeeWare 및 Kivy)에 일부 하위 호환성 영향이 있을 수 있습니다.

엄밀히 말해 하위 호환성 문제는 아니지만, 플랫폼 채택에 대한 고려 사항도 있습니다. CPython 자체가 iOS를 지원하더라도 iOS 호환 휠을 생성하는 방법이 명확하지 않고 cryptography, Pillow, NumPy와 같은 주요 라이브러리가 iOS 휠을 제공하지 않는다면, 커뮤니티가 iOS에서 Python을 채택할 수 있는 역량은 제한됩니다. 따라서 프로젝트에서 CI 및 릴리스 도구에 iOS 빌드를 추가하는 방법을 명확하게 문서화해야 합니다. crossenvcibuildwheel과 같은 도구에 iOS 지원을 추가하는 것이 이를 달성하는 한 가지 방법일 수 있습니다.

보안 영향

iOS를 새 플랫폼으로 추가해도 보안상의 영향은 발생하지 않습니다.

이 내용을 가르치는 방법

이 PEP와 관련된 교육 요구 사항은 최종 사용자가 자신의 Xcode 프로젝트에 iOS 지원을 추가하는 방법과 주로 관련됩니다. 이 과정에 대한 문서와 튜토리얼을 통해 이를 수행할 수 있습니다. 지원이 Tier 3에서 Tier 2 또는 Tier 1로 상향되는 경우 이 문서에 대한 필요성이 증가할 것입니다. 그러나 이 전환에는 Xcode 개발에 통합된 간소화된 배포 아티팩트(예: Cocoapod 또는 Swift 패키지)도 함께 제공되어야 합니다.

참조 구현

BeeWare의 Python-Apple-support 저장소에는 배포 가능한 아티팩트를 컴파일하기 위한 참조 패치와 빌드 도구가 포함되어 있습니다.

Briefcase는 iOS 시뮬레이터에서 테스트 스위트를 실행하는 코드의 참조 구현을 제공합니다. Toga Testbed는 GitHub Actions를 사용하여 iOS 시뮬레이터에서 실행되는 테스트 스위트의 예입니다.

거부된 아이디어

시뮬레이터 식별

이 PEP의 이전 버전에서는 코드가 디바이스에서 실행 중인지 시뮬레이터에서 실행 중인지 식별하기 위해 sys.implementation._simulator속성을 포함할 것을 제안했습니다. 공개 API에 보호된 이름을 사용하고, iOS에 특화된 세부 사항으로 sys 네임스페이스를 오염시키기 때문에 이 제안은 거부되었습니다.

논의 중에는 모든 플랫폼에서 구현할 수 있는 일반적인 platform.is_emulator()API를 포함하자는 또 다른 제안도 있었습니다. 예를 들어 ARM64 하드웨어에서 x86_64 코드를 실행하는 경우와 QEMU 또는 기타 가상화 방법에서 실행하는 경우를 구분하기 위한 것입니다. “에뮬레이터”를 일관되게 해석하는 방법이나 iOS 외부의 경우 에뮬레이터를 감지하는 방법이 명확하지 않다는 이유로 이 제안은 거부되었습니다.

이 세부 사항은 iOS에 특화된 상태로 유지하고 platform.ios_ver()API에 포함하기로 결정했습니다.

GNU 컴파일러 트리플

autoconf는 빌드 플랫폼과 호스트 플랫폼을 식별하기 위해 GNU 컴파일러 트리플을 사용해야 합니다. 그러나 autoconf 도구 모음은 iOS 시뮬레이터를 기본적으로 지원하지 않으므로, iOS 하드웨어를 GNU의 명명 체계에 어떻게 맞출지 결정해야 하는 과제가 남습니다.

이는 (config.sub를 일부 패치하면) 수행할 수 있지만, 이름 지정의 불일치를 일으키는 두 가지 주요 원인이 발생합니다.

  • 64비트 ARM 하드웨어의 식별자로 arm64aarch64중 어느 것을 사용할지
  • 시뮬레이터를 나타내는 데 어떤 식별자를 사용할지

Apple 자체 도구는 아키텍처로 arm64를 사용하지만, 일부 경우에는 aarch64도 허용하는 것으로 보입니다. 디바이스 플랫폼은 iphoneosiphonesimulator로 식별됩니다.

Rust 도구 모음은 아키텍처로 aarch64를 사용하며, 디바이스 플랫폼을 식별하는 데 aarch64-apple-iosaarch64-apple-ios-sim을 사용합니다. 그러나 x86_64 하드웨어의 iOS 시뮬레이터를 나타내는 데는 x86_64-apple-ios를 사용합니다.

다음과 같은 이유로 arm64-apple-iosarm64-apple-ios-simulator를 사용하기로 결정했습니다.

  1. autoconf 도구 모음은 이미 config.sub에 플랫폼으로서 ios를 지원합니다. 표현이 없는 것은 시뮬레이터뿐입니다.
  2. 호스트 트리플의 세 번째 부분은 sys.platform로 사용됩니다.
  3. Apple 자체 도구가 CPU 아키텍처를 참조할 때는 arm64를 사용하며, GNU 도구에서 아키텍처를 사용하는 방식은 빌드 프로세스 외부에 드러나지 않습니다.
  4. Apple 자체 도구가 OS와 독립적인 시뮬레이터 상태를 참조할 때(예: Swift 하위 모듈의 이름 지정에서) -simulator 접미사를 사용합니다.
  5. 일부 iOS 패키지는 Rust를 사용하지만, 모든 iOS 패키지는 Apple 도구를 사용합니다.

이 문서의 최초 승인 버전에서는 PEP 11 식별자로 aarch64형식을 사용했지만, 최종 확정 과정에서 이를 수정했습니다.

“Universal” 휠 형식

macOS는 현재 2개의 CPU 아키텍처를 지원합니다. 최종 사용자의 개발 경험을 돕기 위해 Python은 x86_64 및 ARM64 바이너리를 모두 포함하는 “universal2” 휠 형식을 정의합니다.

이와 유사한 “universal” iOS 휠 형식을 제공하는 것도 개념적으로는 가능합니다. 그러나 이 PEP에서는 2가지 이유로 이 접근법을 사용하지 않습니다.

첫째, macOS, 특히 수치 Python 생태계에서의 경험에 따르면 유니버설 휠은 수용하기가 매우 어려울 수 있습니다. macOS 네이티브 라이브러리는 강력한 다중 플랫폼 지원을 유지하고 있으며 Python 자체도 업데이트되었지만, 업스트림 비-Python 라이브러리의 대다수는 다중 아키텍처 빌드를 지원하지 않습니다. 그 결과 유니버설 휠을 컴파일하려면 필연적으로 여러 차례의 컴파일 과정과, 서로 다른 아키텍처에 대한 헤더 파일을 배포하는 방법에 관한 복잡한 결정이 필요합니다. 이러한 복잡성 때문에 NumPy와 Pillow를 포함한 많은 인기 프로젝트는 유니버설 휠을 전혀 제공하지 않고, 대신 ARM64 및 x86_64용 휠을 별도로 제공합니다.

둘째, 역사적 경험에 따르면 iOS에는 훨씬 더 유동적인 “universal” 정의가 필요합니다. 지난 10년 동안 iOS에 적용될 수 있는 “universal”의 해석은 at least 5가지가 서로 다르게 가능했으며, 여기에는 디바이스와 시뮬레이터에서 armv6, armv7, armv7s, arm64, x86 및 x86_64 아키텍처를 다양하게 조합하는 방식이 포함됩니다. 지금 정의한다면 “universal-iOS”에는 시뮬레이터에서 x86_64와 arm64가, 디바이스에서 arm64가 포함될 가능성이 높습니다. 그러나 예정된 x86_64 하드웨어 지원 중단으로 또 다른 해석이 추가될 것이며, 향후 새로운 디바이스 아키텍처로 arm64e를 추가해야 할 수도 있습니다. iOS 휠을 단일 플랫폼 전용으로 지정하면 Python 핵심 팀은 업데이트된 “universal” 형식에 관한 지속적인 표준화 논의를 피할 수 있습니다.

또한 휠 게시자는 어떤 플랫폼을 지원하는 것이 실현 가능한지 프로젝트별로 결정할 수 있습니다. 예를 들어 프로젝트는 x86_64 지원을 중단하거나 Python 생태계의 다른 부분보다 먼저 새로운 아키텍처를 채택할 수 있습니다. 플랫폼별 휠을 사용하면 이 결정을 개별 패키지 게시자에게 맡길 수 있습니다.

이 결정으로 인해 배포가 더 복잡해지는 대가가 발생합니다. 그러나 iOS에서의 배포는 이미 복잡한 과정이며, 도구를 사용하면 가장 효과적으로 지원할 수 있습니다. 현재는 디바이스에서 사용되는 아키텍처가 하나뿐이므로 바이너리 병합이 필요하지 않으며, 시뮬레이터 바이너리는 배포 가능한 아티팩트로 간주되지 않습니다. 따라서 시뮬레이터용 앱을 빌드하는 데는 하나의 아키텍처만 필요합니다.

정적 빌드 지원

--undefined dynamic_lookup옵션의 장기적인 지속 가능성을 보장할 수는 없지만, 이 옵션은 실제로 존재하며 작동합니다. 한 가지 방법은 지원 중단 경고를 무시하고 Apple이 지원 중단 결정을 번복하거나 지원 중단을 최종 확정하지 않기를 기대하는 것입니다.

Apple의 의사 결정 과정은 전적으로 불투명하므로 이는 기껏해야 위험한 선택입니다. 더 광범위한 iOS 개발 생태계가 프레임워크 사용을 장려한다는 사실과 함께 고려하면, 정적 라이브러리를 사용하던 레거시 사례는 고려할 필요가 없으며, 정적으로 링크된 iOS libpython3.x.a의 유일한 이점은 앱 시작 시간이 아주 조금 줄어드는 것뿐입니다. 따라서 libpython3.x의 정적 빌드 지원을 생략하는 것은 합리적인 절충안으로 보입니다.

--undefined dynamic_lookup옵션의 필요성을 없앨 수 있는 macOS에서의 링크를 위한 대안적 접근법에 관한 논의가 있었음을 언급할 필요가 있습니다. 그러나 구현상의 복잡성으로 인해 이 접근법에 관한 논의는 중단된 것으로 보입니다. 이러한 복잡성을 극복할 수 있다면, 동일한 접근 방식을 iOS에서 사용할 수 있을 가능성이 매우 높으며, 그러면 정적으로 링크된 libpython3.x.a가능해질 것입니다.

바이너리 모듈을 libpython3.x.dylib에 링크하기로 한 결정은 향후 정적 libpython3.x.a빌드의 도입을 복잡하게 만들 것입니다. 다른 바이너리 모듈 링크 방식으로 전환하려면 “동적으로 링크된” iOS 바이너리 모듈과 “정적 링크 호환” iOS 바이너리 모듈을 명확히 구별할 방법이 필요하기 때문입니다. 그러나 정적 libpython3.x.a의 실질적인 이점이 부족하다는 점을 고려하면, 이러한 변경을 해야 할 요구 사항이 생길 가능성은 낮아 보입니다.

대화형/REPL 모드

기존의 python.exe명령줄 경험은 모바일 디바이스에서는 실제로 실현 가능하지 않습니다. 모바일 디바이스에는 명령줄이 없기 때문입니다. iOS 앱에는 stdout, stderr 또는 stdin이 없으며, stdout과 stderr를 시스템 로그로 리디렉션할 수는 있지만, 매우 구체적인 사용자 대상 앱을 빌드하는 것과도 관련되지 않는 한 stdin의 입력원이 존재하지 않습니다. 이러한 앱은 IDLE 스타일의 IDE 경험에 더 가까울 것입니다. 따라서 모바일 배포의 대상으로는 “embedded mode”에만 집중하기로 결정했습니다.

x86_64 시뮬레이터 지원

Apple은 더 이상 x86_64 하드웨어를 판매하지 않습니다. 그 결과, x86_64 빌드봇을 구성하는 일이 어려울 수 있습니다. macOS 바이너리를 ARM64 하드웨어에서 x86_64 호환 모드로 실행할 수는 있지만, 테스트 목적에는 적합하지 않습니다. 따라서 x86_64 Simulator (x86_64-apple-ios-simulator)는 Tier 3 대상에 추가되지 않습니다. iOS 지원은 아무런 수정 없이 x86_64에서 작동할 가능성이 매우 높지만, 이는 official Tier 3 상태에만 영향을 줍니다.

온디바이스 테스트

시뮬레이터에서 CI 테스트는 비교적 쉽게 수행할 수 있습니다. 온디바이스 테스트는 훨씬 어렵습니다. Buildbot 또는 Github Actions 러너를 제공하도록 구성할 수 있는 디바이스 팜의 이용 가능성이 제한적이기 때문입니다.

그러나 온디바이스 테스트는 필요하지 않을 수도 있습니다. 한 가지 사례로, Apple의 Xcode Cloud 솔루션은 온디바이스 테스트를 제공하지 않습니다. Apple은 디바이스와 시뮬레이터 간 API가 일관되며 ARM64 시뮬레이터 테스트만으로도 CPU별 문제를 드러내기에 충분하다는 사실에 의존합니다.

_multiarch 태그의 순서

이 문서의 최초 승인 버전에서는 sys.implementation._multiarch(및 wheel 태그와 같은 관련 값)에 <platform>-<arch> 순서를 사용했습니다(예: iphoneos-arm64). 최종 병합 버전에서는 <arch>-<platform> 순서를 사용합니다(예: arm64-iphoneos). 이는 다른 플랫폼(특히 Linux)의 컴파일러 트리플과 일관성을 유지하기 위한 것으로, 해당 트리플은 운영 체제보다 아키텍처를 먼저 지정합니다.

platform.ios_ver()가 반환하는 값

이 문서의 최초 승인 버전에는 system 식별자가 포함되지 않았습니다. 이는 platform.system() 구현을 지원하기 위해 구현 단계에서 추가되었습니다.

이 문서의 최초 승인 버전에서는 min_releaseios_ver() 결과에서 반환된다고도 설명했습니다. 최종 버전에서는 min_release 값이 런타임에 중요하지 않으므로 생략합니다. 이는 바이너리 호환성에만 영향을 줍니다. 최소 버전은 sysconfig.get_platform()이 반환하는 값에 포함되어 있으며, 이는 휠 및 기타 바이너리의 호환성을 정의하는 데 사용되기 때문입니다.