3535import platform
3636import shlex
3737import subprocess
38+ import re
39+ from typing import Optional , List
3840
3941TARGET_NATIVE = "native"
4042TARGET_X86 = "x86_64"
4143TARGET_ARM64 = "arm64"
4244TARGET_UNIVERSAL = "universal"
45+ TARGET_IOS = "ios"
46+
47+ EMBEDDED_PLATFORMS = [TARGET_IOS ]
4348
4449def GetBuildTargets ():
4550 return [TARGET_NATIVE ,
4651 TARGET_X86 ,
4752 TARGET_ARM64 ,
48- TARGET_UNIVERSAL ]
53+ TARGET_UNIVERSAL ,
54+ TARGET_IOS ]
4955
5056def GetBuildTargetDefault ():
51- return TARGET_NATIVE ;
57+ return TARGET_NATIVE
5258
5359def MacOS ():
5460 return platform .system () == "Darwin"
5561
5662def GetLocale ():
5763 return sys .stdout .encoding or locale .getdefaultlocale ()[1 ] or "UTF-8"
5864
59- def GetCommandOutput (command ):
60- """Executes the specified command and returns output or None."""
65+ def GetCommandOutput (command , ** kwargs ):
6166 try :
62- return subprocess .check_output (
63- shlex .split (command ),
64- stderr = subprocess .STDOUT ).decode (GetLocale (), 'replace' ).strip ()
65- except subprocess .CalledProcessError :
66- pass
67- return None
67+ return subprocess .check_output (command , stderr = subprocess .STDOUT , ** kwargs ).decode (GetLocale (), 'replace' ).strip ()
68+ except :
69+ return None
6870
6971def GetTargetArmArch ():
7072 # Allows the arm architecture string to be overridden by
7173 # setting MACOS_ARM_ARCHITECTURE
7274 return os .environ .get ('MACOS_ARM_ARCHITECTURE' ) or TARGET_ARM64
7375
7476def GetHostArch ():
75- macArch = GetCommandOutput (' arch' ). strip ( )
77+ macArch = GetCommandOutput ([ " arch" ] )
7678 if macArch == "i386" or macArch == TARGET_X86 :
7779 macArch = TARGET_X86
7880 else :
@@ -85,7 +87,7 @@ def GetTargetArch(context):
8587 else :
8688 if context .targetX86 :
8789 macTargets = TARGET_X86
88- if context .targetARM64 :
90+ if context .targetARM64 or context . buildTarget in EMBEDDED_PLATFORMS :
8991 macTargets = GetTargetArmArch ()
9092 if context .targetUniversal :
9193 macTargets = TARGET_X86 + ";" + GetTargetArmArch ()
@@ -106,6 +108,8 @@ def GetTargetArchPair(context):
106108 primaryArch = TARGET_X86
107109 if context .targetARM64 :
108110 primaryArch = GetTargetArmArch ()
111+ if context .targetIos :
112+ primaryArch = TARGET_IOS
109113 if context .targetUniversal :
110114 primaryArch = GetHostArch ()
111115 if (primaryArch == TARGET_X86 ):
@@ -118,18 +122,33 @@ def GetTargetArchPair(context):
118122def SupportsMacOSUniversalBinaries ():
119123 if not MacOS ():
120124 return False
121- XcodeOutput = GetCommandOutput (' /usr/bin/xcodebuild -version' )
125+ XcodeOutput = GetCommandOutput ([ " /usr/bin/xcodebuild" , " -version" ] )
122126 XcodeFind = XcodeOutput .rfind ('Xcode ' , 0 , len (XcodeOutput ))
123127 XcodeVersion = XcodeOutput [XcodeFind :].split (' ' )[1 ]
124128 return (XcodeVersion > '11.0' )
125129
130+
131+ def GetSDKRoot (context ) -> Optional [str ]:
132+ sdk = "macosx"
133+ if context .buildTarget == TARGET_IOS :
134+ sdk = "iphoneos"
135+
136+ for arg in (context .cmakeBuildArgs or '' ).split ():
137+ if "CMAKE_OSX_SYSROOT" in arg :
138+ override = arg .split ('=' )[1 ].strip ('"' ).strip ()
139+ if override :
140+ sdk = override
141+ return GetCommandOutput (["xcrun" , "--sdk" , sdk , "--show-sdk-path" ])
142+
143+
126144def SetTarget (context , targetName ):
127145 context .targetNative = (targetName == TARGET_NATIVE )
128146 context .targetX86 = (targetName == TARGET_X86 )
129147 context .targetARM64 = (targetName == GetTargetArmArch ())
130148 context .targetUniversal = (targetName == TARGET_UNIVERSAL )
149+ context .targetIos = (targetName == TARGET_IOS )
131150 if context .targetUniversal and not SupportsMacOSUniversalBinaries ():
132- self .targetUniversal = False
151+ context .targetUniversal = False
133152 raise ValueError (
134153 "Universal binaries only supported in macOS 11.0 and later." )
135154
@@ -150,26 +169,63 @@ def ExtractFilesRecursive(path, cond):
150169 files .append (os .path .join (r , file ))
151170 return files
152171
153- def CodesignFiles (files ):
154- SDKVersion = subprocess .check_output (
155- ['xcodebuild' , '-version' ]).strip ()[6 :10 ]
156- codeSignIDs = subprocess .check_output (
157- ['security' , 'find-identity' , '-vp' , 'codesigning' ])
172+ def _GetCodeSignStringFromTerminal ():
173+ codeSignIDs = GetCommandOutput (['security' , 'find-identity' , '-vp' , 'codesigning' ])
174+ return codeSignIDs
158175
159- codeSignID = "-"
176+ def GetCodeSignID ():
160177 if os .environ .get ('CODE_SIGN_ID' ):
161- codeSignID = os .environ .get ('CODE_SIGN_ID' )
162- elif float (SDKVersion ) >= 11.0 and \
163- codeSignIDs .find (b'Apple Development' ) != - 1 :
164- codeSignID = "Apple Development"
165- elif codeSignIDs .find (b'Mac Developer' ) != - 1 :
166- codeSignID = "Mac Developer"
178+ return os .environ .get ('CODE_SIGN_ID' )
179+
180+ codeSignIDs = _GetCodeSignStringFromTerminal ()
181+ if not codeSignIDs :
182+ return "-"
183+ for codeSignID in codeSignIDs .splitlines ():
184+ if "CSSMERR_TP_CERT_REVOKED" in codeSignID :
185+ continue
186+ if ")" not in codeSignID :
187+ continue
188+ codeSignID = codeSignID .split ()[1 ]
189+ break
190+ else :
191+ raise RuntimeError ("Could not find a valid codesigning ID" )
192+
193+ return codeSignID or "-"
194+
195+ def GetCodeSignIDHash ():
196+ codeSignIDs = _GetCodeSignStringFromTerminal ()
197+ try :
198+ return re .findall (r'\(.*?\)' , codeSignIDs )[0 ][1 :- 1 ]
199+ except :
200+ raise Exception ("Unable to parse codesign ID hash" )
201+
202+ def GetDevelopmentTeamID ():
203+ if os .environ .get ("DEVELOPMENT_TEAM" ):
204+ return os .environ .get ("DEVELOPMENT_TEAM" )
205+ codesignID = GetCodeSignIDHash ()
206+
207+ certs = subprocess .check_output (["security" , "find-certificate" , "-c" , codesignID , "-p" ])
208+ subject = GetCommandOutput (["openssl" , "x509" , "-subject" ], input = certs )
209+ subject = subject .splitlines ()[0 ]
210+
211+ # Extract the Organizational Unit (OU field) from the cert
212+ try :
213+ team = [elm for elm in subject .split (
214+ '/' ) if elm .startswith ('OU' )][0 ].split ('=' )[1 ]
215+ if team is not None and team != "" :
216+ return team
217+ except Exception as ex :
218+ raise Exception ("No development team found with exception " + ex )
219+
220+ def CodesignFiles (files ):
221+ codeSignID = GetCodeSignID ()
167222
168223 for f in files :
169224 subprocess .call (['codesign' , '-f' , '-s' , '{codesignid}'
170- .format (codesignid = codeSignID ), f ],
225+ .format (codesignid = codeSignID ), f ],
171226 stdout = devout , stderr = devout )
172227
228+
173229def Codesign (install_path , verbose_output = False ):
174230 if not MacOS ():
175231 return False
@@ -217,3 +273,12 @@ def CreateUniversalBinaries(context, libNames, x86Dir, armDir):
217273 instDir = context .instDir , libName = targetName ),
218274 outputName )
219275 return lipoCommands
276+
277+ def ConfigureCMakeExtraArgs (context , args :List [str ]) -> List [str ]:
278+ system_name = None
279+ if context .buildTarget == TARGET_IOS :
280+ system_name = "iOS"
281+
282+ if system_name :
283+ args .append (f"-DCMAKE_SYSTEM_NAME={ system_name } " )
284+ return args
0 commit comments