toolchain_ios.py #7

  • //
  • guest/
  • brandon_m_bare/
  • csbuild/
  • brandon_m_bare/
  • csbuild/
  • toolchain_ios.py
  • View
  • Commits
  • Open Download .zip Download (12 KB)
# Copyright (C) 2013 Jaedyn K. Draper
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the "Software"),
# to deal in the Software without restriction, including without limitation
# the rights to use, copy, modify, merge, publish, distribute, sublicense,
# and/or sell copies of the Software, and to permit persons to whom the
# Software is furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.

"""
Contains a plugin class for building iOS projects.
"""

import csbuild
import os
import subprocess
import sys

from . import toolchain_gcc
from . import toolchain_gcc_darwin


HAS_RUN_XCRUN = False
DEFAULT_DEVICE_SDK_DIR = None
DEFAULT_SIMULATOR_SDK_DIR = None
DEFAULT_DEVICE_SDK_VERSION = None
DEFAULT_SIMULATOR_SDK_VERSION = None
DEFAULT_XCODE_ACTIVE_DEV_DIR = None
DEFAULT_XCODE_TOOLCHAIN_DIR = None


class iOSArchitecture( object ):
	DEVICE_ARMV7 =   "device-armv7"
	DEVICE_ARM64 =   "device-arm64"
	SIMULATOR_I386 = "simulator-i386"
	SIMULATOR_X64 =  "simulator-x64"


class iOSBase( object ):
	def __init__( self ):
		global HAS_RUN_XCRUN
		if not HAS_RUN_XCRUN:
			global DEFAULT_DEVICE_SDK_DIR
			global DEFAULT_SIMULATOR_SDK_DIR
			global DEFAULT_DEVICE_SDK_VERSION
			global DEFAULT_SIMULATOR_SDK_VERSION
			global DEFAULT_XCODE_ACTIVE_DEV_DIR
			global DEFAULT_XCODE_TOOLCHAIN_DIR

			try:
				DEFAULT_DEVICE_SDK_DIR = subprocess.check_output(["xcrun", "--sdk", "iphoneos", "--show-sdk-path"])
				DEFAULT_SIMULATOR_SDK_DIR = subprocess.check_output(["xcrun", "--sdk", "iphonesimulator", "--show-sdk-path"])
				DEFAULT_XCODE_ACTIVE_DEV_DIR = subprocess.check_output( ["xcode-select", "-p"] )
			except:
				DEFAULT_DEVICE_SDK_DIR = "/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk"
				DEFAULT_SIMULATOR_SDK_DIR = "/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk"
				DEFAULT_XCODE_ACTIVE_DEV_DIR = "/Applications/Xcode.app/Contents/Developer"

				# In Python3, these will need to be bytes rather than strings for the decoding below.
				if sys.version_info >= (3, 0):
					DEFAULT_DEVICE_SDK_DIR = DEFAULT_DEVICE_SDK_DIR.encode("utf-8")
					DEFAULT_SIMULATOR_SDK_DIR = DEFAULT_SIMULATOR_SDK_DIR.encode("utf-8")
					DEFAULT_XCODE_ACTIVE_DEV_DIR = DEFAULT_XCODE_ACTIVE_DEV_DIR.encode( "utf-8" )

			try:
				DEFAULT_DEVICE_SDK_VERSION = subprocess.check_output(["xcrun", "--sdk", "iphoneos", "--show-sdk-version"])
				DEFAULT_SIMULATOR_SDK_VERSION = subprocess.check_output(["xcrun", "--sdk", "iphonesimulator", "--show-sdk-version"])
			except:
				DEFAULT_DEVICE_SDK_VERSION = ""
				DEFAULT_SIMULATOR_SDK_VERSION = ""

				# In Python3, these will need to be bytes rather than strings for the decoding below.
				if sys.version_info >= (3, 0):
					DEFAULT_DEVICE_SDK_VERSION = DEFAULT_DEVICE_SDK_VERSION.encode("utf-8")
					DEFAULT_SIMULATOR_SDK_VERSION = DEFAULT_SIMULATOR_SDK_VERSION.encode("utf-8")

			if sys.version_info >= (3, 0):
				DEFAULT_DEVICE_SDK_DIR = DEFAULT_DEVICE_SDK_DIR.decode("utf-8")
				DEFAULT_SIMULATOR_SDK_DIR = DEFAULT_SIMULATOR_SDK_DIR.decode("utf-8")
				DEFAULT_DEVICE_SDK_VERSION = DEFAULT_DEVICE_SDK_VERSION.decode("utf-8")
				DEFAULT_SIMULATOR_SDK_VERSION = DEFAULT_SIMULATOR_SDK_VERSION.decode("utf-8")
				DEFAULT_XCODE_ACTIVE_DEV_DIR = DEFAULT_XCODE_ACTIVE_DEV_DIR.decode( "utf-8" )

			DEFAULT_DEVICE_SDK_DIR = DEFAULT_DEVICE_SDK_DIR.strip("\n")
			DEFAULT_SIMULATOR_SDK_DIR = DEFAULT_SIMULATOR_SDK_DIR.strip("\n")
			DEFAULT_DEVICE_SDK_VERSION = DEFAULT_DEVICE_SDK_VERSION.strip("\n")
			DEFAULT_SIMULATOR_SDK_VERSION = DEFAULT_SIMULATOR_SDK_VERSION.strip("\n")
			DEFAULT_XCODE_ACTIVE_DEV_DIR = DEFAULT_XCODE_ACTIVE_DEV_DIR.strip( "\n" )
			DEFAULT_XCODE_TOOLCHAIN_DIR = os.path.join( DEFAULT_XCODE_ACTIVE_DEV_DIR, "Toolchains", "XcodeDefault.xctoolchain" )

			HAS_RUN_XCRUN = True

		self.shared._deviceSdkDir = DEFAULT_DEVICE_SDK_DIR
		self.shared._simulatorSdkDir = DEFAULT_SIMULATOR_SDK_DIR
		self.shared._targetDeviceVersion = DEFAULT_DEVICE_SDK_VERSION
		self.shared._targetSimulatorVersion = DEFAULT_SIMULATOR_SDK_VERSION


	def _copyTo( self, other ):
		other.shared._deviceSdkDir = self.shared._deviceSdkDir
		other.shared._simulatorSdkDir = self.shared._simulatorSdkDir
		other.shared._targetDeviceVersion = self.shared._targetDeviceVersion
		other.shared._targetSimulatorVersin = self.shared._targetSimulatorVersion


	@staticmethod
	def AdditionalArgs( parser ):
		parser.add_argument( "--ios-target-version", help="Version of iOS to build against.", type=str, default=None )


	def _setTargetVersion( self ):
		cmdLineVer = csbuild.GetOption( "ios_target_version" )

		if cmdLineVer:
			self.SetTargetDeviceVersion( cmdLineVer )
			self.SetTargetSimulatorVersion( cmdLineVer )


	def GetDefaultArchitecture( self ) :
		return iOSArchitecture.SIMULATOR_X64


	def GetValidArchitectures( self ):
		return [iOSArchitecture.DEVICE_ARMV7, iOSArchitecture.DEVICE_ARM64, iOSArchitecture.SIMULATOR_I386, iOSArchitecture.SIMULATOR_X64]


	def SetTargetDeviceVersion( self, version ):
		"""
		Set the target device version to compile against.

		:param version: Target device version.
		:type version: str
		"""
		self.shared._deviceSdkDir = "{}/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS{}.sdk".format( DEFAULT_XCODE_ACTIVE_DEV_DIR, version )
		self.shared._targetDeviceVersion = version

		assert os.access( self.shared._deviceSdkDir, os.F_OK ), "SDK does not exist: {}".format( self.shared._deviceSdkDir )


	def SetTargetSimulatorVersion( self, version ):
		"""
		Set the target simulator version to compile against.

		:param version: Target simulator version.
		:type version: str
		"""
		self.shared._simulatorSdkDir = "{}/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator{}.sdk".format( DEFAULT_XCODE_ACTIVE_DEV_DIR, version )
		self.shared._targetSimulatorVersion = version

		assert os.access( self.shared._simulatorSdkDir, os.F_OK ), "SDK does not exist: {}".format( self.shared._simulatorSdkDir )


	def GetTargetDeviceVersion( self ):
		return self.shared._targetDeviceVersion


	def GetTargetSimulatorVersion( self ):
		return self.shared._targetSimulatorVersion


	def _getMinVersionArg( self, arch ):
		argumentMap = {
			iOSArchitecture.DEVICE_ARMV7:   "-miphoneos-version-min={} ".format( self.shared._targetDeviceVersion ) if self.shared._targetDeviceVersion else "",
			iOSArchitecture.DEVICE_ARM64:   "-miphoneos-version-min={} ".format( self.shared._targetDeviceVersion ) if self.shared._targetDeviceVersion else "",
			iOSArchitecture.SIMULATOR_I386: "-mios-simulator-version-min={} ".format( self.shared._targetSimulatorVersion ) if self.shared._targetSimulatorVersin else "",
			iOSArchitecture.SIMULATOR_X64:  "-mios-simulator-version-min={} ".format( self.shared._targetSimulatorVersion ) if self.shared._targetSimulatorVersin else "",
		}
		return argumentMap[arch]


	def _getArchitectureArg( self, arch ):
		argumentMap = {
			iOSArchitecture.DEVICE_ARMV7:   "armv7",
			iOSArchitecture.DEVICE_ARM64:   "arm64",
			iOSArchitecture.SIMULATOR_I386: "i386",
			iOSArchitecture.SIMULATOR_X64:  "x86_64",
		}
		return "-arch {} ".format( argumentMap[arch] )


	def _getAugmentedCommand( self, originalCmd, project ):
		return "{} {}{}".format(
			originalCmd,
			self._getMinVersionArg( project.outputArchitecture ),
			self._getArchitectureArg( project.outputArchitecture ),
		)


	def _setSysRoot( self, arch ):
		sysRootMap = {
			iOSArchitecture.DEVICE_ARMV7:   self.shared._deviceSdkDir,
			iOSArchitecture.DEVICE_ARM64:   self.shared._deviceSdkDir,
			iOSArchitecture.SIMULATOR_I386: self.shared._simulatorSdkDir,
			iOSArchitecture.SIMULATOR_X64:  self.shared._simulatorSdkDir,
		}
		self.shared._sysroot = sysRootMap[arch]


class iOSCompiler( iOSBase, toolchain_gcc_darwin.GccCompilerDarwin ):
	def __init__( self, shared ):
		toolchain_gcc_darwin.GccCompilerDarwin.__init__( self, shared )
		iOSBase.__init__( self )


	def copy( self, shared ):
		ret = toolchain_gcc_darwin.GccCompilerDarwin.copy( self, shared )
		iOSBase._copyTo( self, ret )
		return ret


	def _getArchFlag( self, project ):
		# iOS builds should not receive the -m32 or -m64 flags when compiling for iOS.
		return ""


	def _getBaseCommand( self, compiler, project, isCpp ):
		return "{} ".format( toolchain_gcc_darwin.GccCompilerDarwin._getBaseCommand( self, compiler, project, isCpp ) )


	def GetBaseCcCommand( self, project ):
		self._setSysRoot( project.outputArchitecture )
		originalCmd = toolchain_gcc.GccCompiler.GetBaseCcCommand( self, project )
		return self._getAugmentedCommand( originalCmd, project )


	def GetBaseCxxCommand( self, project ):
		self._setSysRoot( project.outputArchitecture )
		originalCmd = toolchain_gcc.GccCompiler.GetBaseCxxCommand( self, project )
		return self._getAugmentedCommand( originalCmd, project )


class iOSLinker( iOSBase, toolchain_gcc_darwin.GccLinkerDarwin ):
	def __init__( self, shared ):
		toolchain_gcc_darwin.GccLinkerDarwin.__init__( self, shared )
		iOSBase.__init__( self )


	def copy( self, shared ):
		ret = toolchain_gcc_darwin.GccLinkerDarwin.copy( self, shared )
		iOSBase._copyTo( self, ret )
		return ret


	def _getArchFlag( self, project ):
		# iOS builds should not receive the -m32 or -m64 flags.
		return ""


	def GetLinkCommand( self, project, outputFile, objList ):
		self._setSysRoot( project.outputArchitecture )
		originalCmd = toolchain_gcc_darwin.GccLinkerDarwin.GetLinkCommand( self, project, outputFile, objList )
		if project.type != csbuild.ProjectType.StaticLibrary:
			ret =  "{} -Xlinker -no_implicit_dylibs ".format( self._getAugmentedCommand( originalCmd, project ) )
		else:
			ret = originalCmd
		return ret



	def GetAppBundleRootPath( self, appBundlePath ):
		"""
		Get the root directory under the app bundle. All files contained in the bundles must be somewhere under the root directory.

		:param appBundlePath: Path the to the .app directory.
		:type appBundlePath: str

		:return: str
		"""
		return appBundlePath


	def GetAppBundleExePath( self, appBundlePath ):
		"""
		Get the app bundle directory where application executables are stored.

		:param appBundlePath: Path the to the .app directory.
		:type appBundlePath: str

		:return: str
		"""
		return appBundlePath


	def GetAppBundleResourcePath( self, appBundlePath ):
		"""
		Get the app bundle directory where application resources (such as images, NIBs, or localization files) are typically stored.

		:param appBundlePath: Path the to the .app directory.
		:type appBundlePath: str

		:return: str
		"""
		return appBundlePath


	def GetAppBundleFrameworksPath( self, appBundlePath ):
		"""
		Get the app bundle directory where required application frameworks are stored.  These are private frameworks required
		for the application to work and will override frameworks installed on the running system.

		:param appBundlePath: Path the to the .app directory.
		:type appBundlePath: str

		:return: str
		"""
		return appBundlePath


	def GetAppBundlePlugInsPath( self, appBundlePath ):
		"""
		Get the app bundle directory where loadable modules are typically stored.

		:param appBundlePath: Path the to the .app directory.
		:type appBundlePath: str

		:return: str
		"""
		return appBundlePath


	def GetAppBundleSharedSupportPath( self, appBundlePath ):
		"""
		Get the app bundle directory where support files are typically stored.  These are files that supplement the application
		in some way, but are not required for the application to run.

		:param appBundlePath: Path the to the .app directory.
		:type appBundlePath: str

		:return: str
		"""
		return appBundlePath
# Change User Description Committed
#7 16488 brandon_m_bare -- Added additional command line arguments for osx and ios for overriding the target versions to compile against.
-- Added assertions on setting the target version for osx and ios to validate the selected version is actually installed.

#review-16363
@ShadauxCat
#6 14792 brandon_m_bare -- Fixed a "raise" in the ios toolchain that was supposed to be a "return".
-- Added a string member in the plist generator to contain the resolved file path rather than reusing the same member object that held the temporary data.  This fixes an exception when building mulitple architectures/targets in a single build for osx/ios that references an external plist.

#review-14793
@ShadauxCat
#5 13943 brandon_m_bare -- Reorganized how plist generation works so it's now completely encapsulated within the plist generator plugin.
-- Cleaned up the app bundle generation process for the gcc_darwin toolchain.
-- Added functions in gcc_darwin to get the proper base paths inside an app bundle (overrode those functions for the ios toolchain since the paths need to be different there).
-- Added a utility function to completely remove a directory tree.  Like shutil.rmtree(), but this one actually works.
-- Fixed Objective-C/C++ files getting chunked when they shouldn't have been.
-- Added dSYM generation for osx and ios (only occurs when an app bundle is also generated).
-- Added the default active development directory and toolchain directory to the gcc_darwin and ios toochains.
-- Added code in gcc_darwin to copy shared libraries and loadable modules into app bundles.
#4 12544 brandon_m_bare Fixed a Python3 error when the ios toolchain's device/simulator default paths are used.
#3 12345 brandon_m_bare -- Cleaned up the gcc_darwin toolchain so that the SDK path and version are automatically retrieved only once in the entire execution of a make script.
-- Similarly updated the ios toolchain so it's SDK paths and version are automatically retrieved.
-- Cleaned up the sys path modification in the HelloLibraries makefile.

#review-12337
@ShadauxCat
#2 12080 brandon_m_bare -- Fixed a few instances in the iOS toolchain where we weren't accessing the new shared members.
-- Fixed the android toolchain not using self.shared.isClang.
-- Removed the vsgen option to select a platform because that's done using the options for selecting toolchain and architecture now.
#1 11832 brandon_m_bare Integration from csbuild Mainline.
//guest/brandon_m_bare/csbuild/brandon_m_bare/toolchain_ios.py
#1 11504 brandon_m_bare Seeding branch of csbuild.
//guest/ShadauxCat/csbuild/Mainline/toolchain_ios.py
#1 11496 ShadauxCat Initial checkin: Current states for csbuild and libSprawl