1818import platform
1919import shlex
2020import subprocess
21+ import re
22+ from typing import Optional , List
2123
2224TARGET_NATIVE = "native"
2325TARGET_X86 = "x86_64"
2426TARGET_ARM64 = "arm64"
2527TARGET_UNIVERSAL = "universal"
28+ TARGET_IOS = "iOS"
29+
30+ EMBEDDED_PLATFORMS = [TARGET_IOS ]
2631
2732def GetBuildTargets ():
2833 return [TARGET_NATIVE ,
2934 TARGET_X86 ,
3035 TARGET_ARM64 ,
31- TARGET_UNIVERSAL ]
36+ TARGET_UNIVERSAL ,
37+ TARGET_IOS ]
3238
3339def GetBuildTargetDefault ():
34- return TARGET_NATIVE ;
40+ return TARGET_NATIVE
3541
3642def MacOS ():
3743 return platform .system () == "Darwin"
3844
3945def GetLocale ():
4046 return sys .stdout .encoding or locale .getdefaultlocale ()[1 ] or "UTF-8"
4147
42- def GetCommandOutput (command ):
48+ def GetCommandOutput (command , ** kwargs ):
4349 """Executes the specified command and returns output or None."""
4450 try :
45- return subprocess .check_output (
46- shlex .split (command ),
47- stderr = subprocess .STDOUT ).decode (GetLocale (), 'replace' ).strip ()
48- except subprocess .CalledProcessError :
49- pass
50- return None
51+ return subprocess .check_output (command , stderr = subprocess .STDOUT , ** kwargs ).decode (GetLocale (), 'replace' ).strip ()
52+ except :
53+ return None
5154
5255def GetTargetArmArch ():
5356 # Allows the arm architecture string to be overridden by
5457 # setting MACOS_ARM_ARCHITECTURE
5558 return os .environ .get ('MACOS_ARM_ARCHITECTURE' ) or TARGET_ARM64
5659
5760def GetHostArch ():
58- macArch = GetCommandOutput (' arch' ). strip ( )
61+ macArch = GetCommandOutput ([ " arch" ] )
5962 if macArch == "i386" or macArch == TARGET_X86 :
6063 macArch = TARGET_X86
6164 else :
6265 macArch = GetTargetArmArch ()
6366 return macArch
6467
6568def GetTargetArch (context ):
69+ if context .buildTarget in EMBEDDED_PLATFORMS :
70+ return GetTargetArmArch ()
6671 if context .targetNative :
6772 macTargets = GetHostArch ()
6873 else :
6974 if context .targetX86 :
7075 macTargets = TARGET_X86
71- if context .targetARM64 :
76+ if context .targetARM64 or context . buildTarget in EMBEDDED_PLATFORMS :
7277 macTargets = GetTargetArmArch ()
7378 if context .targetUniversal :
7479 macTargets = TARGET_X86 + ";" + GetTargetArmArch ()
@@ -89,6 +94,8 @@ def GetTargetArchPair(context):
8994 primaryArch = TARGET_X86
9095 if context .targetARM64 :
9196 primaryArch = GetTargetArmArch ()
97+ if context .buildTarget in EMBEDDED_PLATFORMS :
98+ primaryArch = GetTargetArmArch ()
9299 if context .targetUniversal :
93100 primaryArch = GetHostArch ()
94101 if (primaryArch == TARGET_X86 ):
@@ -101,18 +108,33 @@ def GetTargetArchPair(context):
101108def SupportsMacOSUniversalBinaries ():
102109 if not MacOS ():
103110 return False
104- XcodeOutput = GetCommandOutput (' /usr/bin/xcodebuild -version' )
111+ XcodeOutput = GetCommandOutput ([ " /usr/bin/xcodebuild" , " -version" ] )
105112 XcodeFind = XcodeOutput .rfind ('Xcode ' , 0 , len (XcodeOutput ))
106113 XcodeVersion = XcodeOutput [XcodeFind :].split (' ' )[1 ]
107114 return (XcodeVersion > '11.0' )
108115
116+
117+ def GetSDKRoot (context ) -> Optional [str ]:
118+ sdk = "macosx"
119+ if context .buildTarget == TARGET_IOS :
120+ sdk = "iphoneos"
121+
122+ for arg in (context .cmakeBuildArgs or '' ).split ():
123+ if "CMAKE_OSX_SYSROOT" in arg :
124+ override = arg .split ('=' )[1 ].strip ('"' ).strip ()
125+ if override :
126+ sdk = override
127+ return GetCommandOutput (["xcrun" , "--sdk" , sdk , "--show-sdk-path" ])
128+
129+
109130def SetTarget (context , targetName ):
110131 context .targetNative = (targetName == TARGET_NATIVE )
111132 context .targetX86 = (targetName == TARGET_X86 )
112133 context .targetARM64 = (targetName == GetTargetArmArch ())
113134 context .targetUniversal = (targetName == TARGET_UNIVERSAL )
135+ context .targetIos = (targetName == TARGET_IOS )
114136 if context .targetUniversal and not SupportsMacOSUniversalBinaries ():
115- self .targetUniversal = False
137+ context .targetUniversal = False
116138 raise ValueError (
117139 "Universal binaries only supported in macOS 11.0 and later." )
118140
@@ -121,7 +143,7 @@ def GetTargetName(context):
121143 TARGET_X86 if context .targetX86 else
122144 GetTargetArmArch () if context .targetARM64 else
123145 TARGET_UNIVERSAL if context .targetUniversal else
124- "" )
146+ context . buildTarget )
125147
126148devout = open (os .devnull , 'w' )
127149
@@ -133,26 +155,63 @@ def ExtractFilesRecursive(path, cond):
133155 files .append (os .path .join (r , file ))
134156 return files
135157
136- def CodesignFiles (files ):
137- SDKVersion = subprocess .check_output (
138- ['xcodebuild' , '-version' ]).strip ()[6 :10 ]
139- codeSignIDs = subprocess .check_output (
140- ['security' , 'find-identity' , '-vp' , 'codesigning' ])
158+ def _GetCodeSignStringFromTerminal ():
159+ codeSignIDs = GetCommandOutput (['security' , 'find-identity' , '-vp' , 'codesigning' ])
160+ return codeSignIDs
141161
142- codeSignID = "-"
162+ def GetCodeSignID ():
143163 if os .environ .get ('CODE_SIGN_ID' ):
144- codeSignID = os .environ .get ('CODE_SIGN_ID' )
145- elif float (SDKVersion ) >= 11.0 and \
146- codeSignIDs .find (b'Apple Development' ) != - 1 :
147- codeSignID = "Apple Development"
148- elif codeSignIDs .find (b'Mac Developer' ) != - 1 :
149- codeSignID = "Mac Developer"
164+ return os .environ .get ('CODE_SIGN_ID' )
165+
166+ codeSignIDs = _GetCodeSignStringFromTerminal ()
167+ if not codeSignIDs :
168+ return "-"
169+ for codeSignID in codeSignIDs .splitlines ():
170+ if "CSSMERR_TP_CERT_REVOKED" in codeSignID :
171+ continue
172+ if ")" not in codeSignID :
173+ continue
174+ codeSignID = codeSignID .split ()[1 ]
175+ break
176+ else :
177+ raise RuntimeError ("Could not find a valid codesigning ID" )
178+
179+ return codeSignID or "-"
180+
181+ def GetCodeSignIDHash ():
182+ codeSignIDs = _GetCodeSignStringFromTerminal ()
183+ try :
184+ return re .findall (r'\(.*?\)' , codeSignIDs )[0 ][1 :- 1 ]
185+ except :
186+ raise Exception ("Unable to parse codesign ID hash" )
187+
188+ def GetDevelopmentTeamID ():
189+ if os .environ .get ("DEVELOPMENT_TEAM" ):
190+ return os .environ .get ("DEVELOPMENT_TEAM" )
191+ codesignID = GetCodeSignIDHash ()
192+
193+ certs = subprocess .check_output (["security" , "find-certificate" , "-c" , codesignID , "-p" ])
194+ subject = GetCommandOutput (["openssl" , "x509" , "-subject" ], input = certs )
195+ subject = subject .splitlines ()[0 ]
196+
197+ # Extract the Organizational Unit (OU field) from the cert
198+ try :
199+ team = [elm for elm in subject .split (
200+ '/' ) if elm .startswith ('OU' )][0 ].split ('=' )[1 ]
201+ if team is not None and team != "" :
202+ return team
203+ except Exception as ex :
204+ raise Exception ("No development team found with exception " + ex )
205+
206+ def CodesignFiles (files ):
207+ codeSignID = GetCodeSignID ()
150208
151209 for f in files :
152210 subprocess .call (['codesign' , '-f' , '-s' , '{codesignid}'
153- .format (codesignid = codeSignID ), f ],
211+ .format (codesignid = codeSignID ), f ],
154212 stdout = devout , stderr = devout )
155213
214+
156215def Codesign (install_path , verbose_output = False ):
157216 if not MacOS ():
158217 return False
@@ -200,3 +259,19 @@ def CreateUniversalBinaries(context, libNames, x86Dir, armDir):
200259 instDir = context .instDir , libName = targetName ),
201260 outputName )
202261 return lipoCommands
262+
263+ def ConfigureCMakeExtraArgs (context , args :List [str ]) -> List [str ]:
264+ system_name = None
265+ if context .buildTarget == TARGET_IOS :
266+ system_name = "iOS"
267+
268+ if system_name :
269+ args .append (f"-DCMAKE_SYSTEM_NAME={ system_name } " )
270+ args .append (f"-DCMAKE_OSX_SYSROOT={ GetSDKRoot (context )} " )
271+
272+ # CMake gets confused trying to find things when setting the system name
273+ # See https://discourse.cmake.org/t/find-package-stops-working-when-cmake-system-name-ios/4609/8
274+ args .append (f"-DCMAKE_FIND_ROOT_PATH_MODE_PACKAGE=BOTH" )
275+ args .append (f"-DCMAKE_FIND_ROOT_PATH_MODE_INCLUDE=BOTH" )
276+ args .append (f"-DCMAKE_FIND_ROOT_PATH_MODE_LIBRARY=BOTH" )
277+ return args
0 commit comments