module Development.Shake.Language.C.Target.Android (
target
, sdkVersion
, toolChain
, abiString
, gnustl
, libcxx
, native_app_glue
) where
import Control.Category ((>>>))
import Development.Shake.FilePath
import Data.Version (Version(..), showVersion)
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 qualified System.Info as System
unsupportedArch :: Arch -> a
unsupportedArch arch = error $ "Unsupported Android target architecture " ++ show arch
toolChainPrefix :: Target -> String
toolChainPrefix x =
case targetArch x of
X86 _ -> "x86-"
Arm Arm64 -> "aarch64-linux-android-"
Arm _ -> "arm-linux-androideabi-"
arch -> unsupportedArch arch
toolPrefix_ :: Target -> String
toolPrefix_ x =
case targetArch x of
X86 _ -> "i686-linux-android-"
_ -> toolChainPrefix x
osPrefix :: String
osPrefix = System.os ++ "-" ++ cpu
where cpu = case System.arch of
"i386" -> "x86"
arch -> arch
target :: Arch -> Target
target = Target Android (Platform "android")
mkDefaultBuildFlags :: FilePath -> Version -> Arch -> BuildFlags -> BuildFlags
mkDefaultBuildFlags ndk version arch =
append compilerFlags [(Nothing, [sysroot, march])]
>>> append compilerFlags (archCompilerFlags arch)
>>> append compilerFlags [(Nothing, [
"-fpic"
, "-ffunction-sections"
, "-funwind-tables"
, "-fstack-protector"
, "-no-canonical-prefixes"])]
>>> append linkerFlags [sysroot, march]
>>> append linkerFlags (archLinkerFlags arch)
>>> append linkerFlags ["-Wl,--no-undefined", "-Wl,-z,relro", "-Wl,-z,now"]
>>> append linkerFlags ["-no-canonical-prefixes"]
>>> append archiverFlags ["crs"]
where
sysroot = "--sysroot="
++ ndk
</> "platforms"
</> "android-" ++ show (head (versionBranch version))
</> "arch-" ++ case arch of
(X86 _) -> "x86"
(Arm Arm64) -> "arm64"
(Arm _) -> "arm"
_ -> unsupportedArch arch
march = "-march=" ++ case arch of
X86 I386 -> "i386"
X86 I686 -> "i686"
X86 X86_64 -> "x86_64"
Arm Armv5 -> "armv5te"
Arm Armv6 -> "armv5te"
Arm Armv7 -> "armv7-a"
Arm Arm64 -> "armv8-a"
_ -> unsupportedArch arch
archCompilerFlags (Arm Armv7) = [(Nothing, ["-mfloat-abi=softfp", "-mfpu=neon"])]
archCompilerFlags (Arm Arm64) = []
archCompilerFlags (Arm _) = [(Nothing, ["-mtune=xscale", "-msoft-float"])]
archCompilerFlags _ = []
archLinkerFlags (Arm Armv7) = ["-Wl,--fix-cortex-a8"]
archLinkerFlags _ = []
sdkVersion :: Int -> Version
sdkVersion n = Version [n] []
gccToolChain :: FilePath -> Target -> FilePath
gccToolChain ndk target =
ndk </> "toolchains"
</> toolChainPrefix target ++ showVersion (Version [4,9] [])
</> "prebuilt"
</> osPrefix
toolChain :: FilePath
-> Version
-> ToolChainVariant
-> Target
-> ToolChain
toolChain "" _ _ _ = error "Empty NDK directory"
toolChain ndk version GCC t =
set variant GCC
$ set toolDirectory (Just (gccToolChain ndk t </> "bin"))
$ set toolPrefix (toolPrefix_ t)
$ set compilerCommand "gcc"
$ set archiverCommand "ar"
$ set linkerCommand "g++"
$ set defaultBuildFlags (return $ mkDefaultBuildFlags ndk version (targetArch t))
$ defaultToolChain
toolChain ndk version LLVM t =
set variant LLVM
$ set toolDirectory (Just (ndk </> "toolchains"
</> "llvm"
</> "prebuilt"
</> osPrefix
</> "bin"))
$ set compilerCommand "clang"
$ set archiverCommand (gccToolChain ndk t </> "bin" </> toolPrefix_ t ++ "ar")
$ set linkerCommand "clang++"
$ set defaultBuildFlags (return $
let flags = [ "-target", llvmTarget t
, "-gcc-toolchain", gccToolChain ndk t ]
in mkDefaultBuildFlags ndk version (targetArch t)
. append compilerFlags [(Nothing, flags)]
. append linkerFlags flags
)
$ defaultToolChain
where
llvmTarget x =
case targetArch x of
Arm Armv5 -> "armv5te-none-linux-androideabi"
Arm Armv7 -> "armv7-none-linux-androideabi"
Arm Arm64 -> "aarch64-none-linux-android"
X86 I386 -> "i686-none-linux-android"
arch -> unsupportedArch arch
toolChain _ _ tcVariant _ =
error $ "Unsupported toolchain variant " ++ show tcVariant
abiString :: Arch -> String
abiString (Arm Armv5) = "armeabi"
abiString (Arm Armv6) = "armeabi"
abiString (Arm Armv7) = "armeabi-v7a"
abiString (Arm Arm64) = "arm64-v8a"
abiString (X86 _) = "x86"
abiString arch = unsupportedArch arch
native_app_glue :: FilePath
-> ([FilePath], BuildFlags -> BuildFlags)
native_app_glue ndk =
( [ndk </> "sources/android/native_app_glue/android_native_app_glue.c"]
, append systemIncludes [ndk </> "sources/android/native_app_glue"] )
gnustl :: Version
-> Linkage
-> FilePath
-> Target
-> (BuildFlags -> BuildFlags)
gnustl version linkage ndk t =
append systemIncludes [stlPath </> "include", stlPath </> "libs" </> abi </> "include"]
. append libraryPath [stlPath </> "libs" </> abi]
. append libraries [lib]
where stlPath = ndk </> "sources/cxx-stl/gnu-libstdc++" </> showVersion version
abi = abiString (targetArch t)
lib = case linkage of
Static -> "gnustl_static"
Shared -> "gnustl_shared"
libcxx :: Linkage
-> FilePath
-> Target
-> (BuildFlags -> BuildFlags)
libcxx linkage ndk t =
append systemIncludes [ stl </> "llvm-libc++" </> "libcxx" </> "include"
, stl </> "llvm-libc++abi" </> "libcxxabi" </> "include"
, ndk </> "sources" </> "android" </> "support" </> "include" ]
. append compilerFlags [(Just Cpp, ["-stdlib=libc++"])]
. append libraryPath [stl </> "llvm-libc++" </> "libs" </> abi]
. prepend libraries [lib]
where stl = ndk </> "sources" </> "cxx-stl"
abi = abiString (targetArch t)
lib = case linkage of
Static -> "c++_static"
Shared -> "c++_shared"