module Development.Shake.Language.C.Target.OSX (
DeveloperPath
, getSDKRoot
, macOSX
, iPhoneOS
, iPhoneSimulator
, target
, sdkVersion
, toolChain
, getPlatformVersions
, macosx_version_min
, iphoneos_version_min
, universalBinary
) where
import Data.List (stripPrefix)
import Data.List.Split (splitOn)
import Data.Maybe
import Data.Version (Version(..), showVersion)
import Development.Shake as Shake
import Development.Shake.FilePath
import Development.Shake.Language.C.BuildFlags
import Development.Shake.Language.C.Target
import Development.Shake.Language.C.Label
import Development.Shake.Language.C.ToolChain
import System.Process (readProcess)
import Text.Read (readMaybe)
archString :: Arch -> String
archString arch =
case arch of
X86 I386 -> "i386"
X86 I686 -> "i686"
X86 X86_64 -> "x86_64"
Arm Armv5 -> "armv5"
Arm Armv6 -> "armv6"
Arm Armv7 -> "armv7"
Arm Armv7s -> "armv7s"
Arm Arm64 -> "arm64"
_ -> error $ "Unsupported OSX target architecture " ++ show arch
archFlags :: Target -> [String]
archFlags t = ["-arch", archString (targetArch t)]
newtype DeveloperPath = DeveloperPath FilePath
deriving (Show)
getSDKRoot :: Action DeveloperPath
getSDKRoot = liftIO $
(DeveloperPath . head . splitOn "\n")
<$> readProcess "xcode-select" ["--print-path"] ""
macOSX :: Platform
macOSX = Platform "MacOSX"
iPhoneOS :: Platform
iPhoneOS = Platform "iPhoneOS"
iPhoneSimulator :: Platform
iPhoneSimulator = Platform "iPhoneSimulator"
target :: Platform -> Arch -> Target
target = Target OSX
sdkDirectory :: FilePath -> Platform -> FilePath
sdkDirectory sdkRoot platform =
sdkRoot
</> "Platforms"
</> (platformName platform ++ ".platform")
</> "Developer"
</> "SDKs"
platformSDKPath :: FilePath -> Platform -> Version -> FilePath
platformSDKPath sdkRoot platform version =
sdkDirectory sdkRoot platform
</> platformName platform ++ showVersion version ++ ".sdk"
getPlatformVersionsWithRoot :: Platform -> DeveloperPath -> Action [Version]
getPlatformVersionsWithRoot platform (DeveloperPath sdkRoot) = do
dirs <- getDirectoryDirs (sdkDirectory sdkRoot platform)
case mapMaybe (\x -> parseVersion =<< stripPrefix name (dropExtension x)) dirs of
[] -> error $ "No SDK found for " ++ name
xs -> return xs
where name = platformName platform
parseVersion "" = Nothing
parseVersion str =
flip Version [] <$> mapM readMaybe (splitOn "." str)
getPlatformVersions :: Platform -> Action [Version]
getPlatformVersions platform =
getPlatformVersionsWithRoot platform =<< getSDKRoot
sdkVersion :: Int -> Int -> Version
sdkVersion major minor = Version [major, minor] []
toolChain :: DeveloperPath
-> Version
-> Target
-> ToolChain
toolChain (DeveloperPath sdkRoot) version t =
set variant LLVM
$ set toolDirectory (Just (sdkRoot </> "Toolchains/XcodeDefault.xctoolchain/usr/bin"))
$ set compilerCommand "clang"
$ set archiverCommand "libtool"
$ set archiver (\tc flags inputs output -> do
need inputs
command_ [] (tool tc archiverCommand)
$ get archiverFlags flags
++ ["-static"]
++ ["-o", output]
++ inputs
)
$ set linkerCommand "clang++"
$ set linker (\lr tc ->
case lr of
Executable -> defaultLinker tc
SharedLibrary -> defaultLinker tc . prepend linkerFlags ["-dynamiclib"]
LoadableLibrary -> defaultLinker tc . prepend linkerFlags ["-bundle"]
)
$ set defaultBuildFlags
( return $
append preprocessorFlags [ "-isysroot", sysRoot ]
. append compilerFlags [(Nothing, archFlags t)]
. append linkerFlags (archFlags t ++ [ "-isysroot", sysRoot ]) )
$ defaultToolChain
where sysRoot = platformSDKPath sdkRoot (targetPlatform t) version
macosx_version_min :: Version -> BuildFlags -> BuildFlags
macosx_version_min version =
append compilerFlags [(Nothing, ["-mmacosx-version-min=" ++ showVersion version])]
iphoneos_version_min :: Version -> BuildFlags -> BuildFlags
iphoneos_version_min version =
append compilerFlags [(Nothing, ["-miphoneos-version-min=" ++ showVersion version])]
universalBinary :: [FilePath]
-> FilePath
-> Action ()
universalBinary inputs output = do
need inputs
command_ [] "lipo" $ ["-create", "-output", output] ++ inputs