From c39e2029762387d05f7b3d81490c6129703c1b60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20H=C3=B8is=C3=A6ther=20Rasch?= Date: Sun, 6 Aug 2017 02:18:15 +0200 Subject: [PATCH] Introduce first class support for Android (#5772) --- compiler/condsyms.nim | 5 +++- compiler/installer.ini | 1 + compiler/platform.nim | 8 +++++-- config/nim.cfg | 10 ++++++++ doc/nimc.rst | 9 +++++++ lib/posix/posix.nim | 2 +- lib/posix/posix_other.nim | 2 +- lib/pure/nativesockets.nim | 2 +- lib/pure/ospaths.nim | 19 +++++++++++++-- lib/pure/osproc.nim | 3 ++- lib/system/platforms.nim | 4 +++- tests/osproc/tworkingdir.nim | 6 ++++- tests/testament/categories.nim | 2 +- tools/niminst/buildsh.tmpl | 44 ++++++++++++++++++++++++++++++++-- tools/niminst/makefile.tmpl | 6 +++++ 15 files changed, 109 insertions(+), 14 deletions(-) diff --git a/compiler/condsyms.nim b/compiler/condsyms.nim index a4f47ac729..dc97e36489 100644 --- a/compiler/condsyms.nim +++ b/compiler/condsyms.nim @@ -41,7 +41,10 @@ proc isDefined*(symbol: string): bool = result = targetOS in {osLinux, osMorphos, osSkyos, osIrix, osPalmos, osQnx, osAtari, osAix, osHaiku, osVxWorks, osSolaris, osNetbsd, - osFreebsd, osOpenbsd, osDragonfly, osMacosx} + osFreebsd, osOpenbsd, osDragonfly, osMacosx, + osAndroid} + of "linux": + result = targetOS in {osLinux, osAndroid} of "bsd": result = targetOS in {osNetbsd, osFreebsd, osOpenbsd, osDragonfly} of "emulatedthreadvars": diff --git a/compiler/installer.ini b/compiler/installer.ini index 680a5f9d58..979cfa3a1d 100644 --- a/compiler/installer.ini +++ b/compiler/installer.ini @@ -14,6 +14,7 @@ Platforms: """ openbsd: i386;amd64 dragonfly: i386;amd64 haiku: i386;amd64 + android: i386;arm;arm64 """ Authors: "Andreas Rumpf" diff --git a/compiler/platform.nim b/compiler/platform.nim index e8b80ab9c2..01ddba23ea 100644 --- a/compiler/platform.nim +++ b/compiler/platform.nim @@ -21,8 +21,8 @@ type # conditionals to condsyms (end of module). osNone, osDos, osWindows, osOs2, osLinux, osMorphos, osSkyos, osSolaris, osIrix, osNetbsd, osFreebsd, osOpenbsd, osDragonfly, osAix, osPalmos, osQnx, - osAmiga, osAtari, osNetware, osMacos, osMacosx, osHaiku, osVxworks, osGenode - osJS, osNimrodVM, osStandalone + osAmiga, osAtari, osNetware, osMacos, osMacosx, osHaiku, osAndroid, osVxworks + osGenode, osJS, osNimrodVM, osStandalone type TInfoOSProp* = enum @@ -143,6 +143,10 @@ const objExt: ".o", newLine: "\x0A", pathSep: ":", dirSep: "/", scriptExt: ".sh", curDir: ".", exeExt: "", extSep: ".", props: {ospNeedsPIC, ospPosix, ospLacksThreadVars}), + (name: "Android", parDir: "..", dllFrmt: "lib$1.so", altDirSep: "/", + objExt: ".o", newLine: "\x0A", pathSep: ":", dirSep: "/", + scriptExt: ".sh", curDir: ".", exeExt: "", extSep: ".", + props: {ospNeedsPIC, ospPosix}), (name: "VxWorks", parDir: "..", dllFrmt: "lib$1.so", altDirSep: "/", objExt: ".o", newLine: "\x0A", pathSep: ";", dirSep: "\\", scriptExt: ".sh", curDir: ".", exeExt: ".vxe", extSep: ".", diff --git a/config/nim.cfg b/config/nim.cfg index 291d2a3bcb..042a94eaa8 100644 --- a/config/nim.cfg +++ b/config/nim.cfg @@ -90,6 +90,16 @@ path="$lib/pure" @end @end +@if android: + cc = clang + gcc.options.linker = "-landroid-glob" + gcc.cpp.options.linker = "-landroid-glob" + clang.options.linker = "-landroid-glob" + clang.cpp.options.linker = "-landroid-glob" + tcc.options.linker = "-landroid-glob" + define:"useShPath:/system/bin/sh" +@end + # Configuration for the Intel C/C++ compiler: @if windows: icl.options.speed = "/Ox /arch:SSE2" diff --git a/doc/nimc.rst b/doc/nimc.rst index 387b7a1b72..e949df69c8 100644 --- a/doc/nimc.rst +++ b/doc/nimc.rst @@ -278,6 +278,15 @@ Define Effect what's in the Nim file with what's in the C header (requires a C compiler with _Static_assert support, like any C11 compiler) +``tempDir`` This symbol takes a string as its value, like + ``--define:tempDir:/some/temp/path`` to override the + temporary directory returned by ``os.getTempDir()``. + The value **should** end with a directory separator + character. (Relevant for the Android platform) +``useShPath`` This symbol takes a string as its value, like + ``--define:useShPath:/opt/sh/bin/sh`` to override the + path for the ``sh`` binary, in cases where it is not + located in the default location ``/bin/sh`` ================== ========================================================= diff --git a/lib/posix/posix.nim b/lib/posix/posix.nim index 55d1dd2ebd..b635c0b0b1 100644 --- a/lib/posix/posix.nim +++ b/lib/posix/posix.nim @@ -92,7 +92,7 @@ else: # There used to be this name in posix.nim a long time ago, not sure why! {.deprecated: [cSIG_HOLD: SIG_HOLD].} -when not defined(macosx): +when not defined(macosx) and not defined(android): proc st_atime*(s: Stat): Time {.inline.} = ## Second-granularity time of last access result = s.st_atim.tv_sec diff --git a/lib/posix/posix_other.nim b/lib/posix/posix_other.nim index 9629b399e8..7738d710cc 100644 --- a/lib/posix/posix_other.nim +++ b/lib/posix/posix_other.nim @@ -215,7 +215,7 @@ type ## For a typed memory object, the length in bytes. ## For other file types, the use of this field is ## unspecified. - when defined(macosx): + when defined(macosx) or defined(android): st_atime*: Time ## Time of last access. st_mtime*: Time ## Time of last data modification. st_ctime*: Time ## Time of last status change. diff --git a/lib/pure/nativesockets.nim b/lib/pure/nativesockets.nim index 7568408a6c..1a62c0bf6e 100644 --- a/lib/pure/nativesockets.nim +++ b/lib/pure/nativesockets.nim @@ -233,7 +233,7 @@ proc getAddrInfo*(address: string, port: Port, domain: Domain = AF_INET, # OpenBSD doesn't support AI_V4MAPPED and doesn't define the macro AI_V4MAPPED. # FreeBSD doesn't support AI_V4MAPPED but defines the macro. # https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=198092 - when not defined(freebsd) and not defined(openbsd) and not defined(netbsd): + when not defined(freebsd) and not defined(openbsd) and not defined(netbsd) and not defined(android): if domain == AF_INET6: hints.ai_flags = AI_V4MAPPED var gaiResult = getaddrinfo(address, $port, addr(hints), result) diff --git a/lib/pure/ospaths.nim b/lib/pure/ospaths.nim index fa5342fcf3..769fa9872b 100644 --- a/lib/pure/ospaths.nim +++ b/lib/pure/ospaths.nim @@ -528,11 +528,26 @@ when declared(getEnv) or defined(nimscript): elif getEnv("XDG_CONFIG_DIR"): return string(getEnv("XDG_CONFIG_DIR")) & "/" else: return string(getEnv("HOME")) & "/.config/" + when defined(android): + {.pragma: getTempDirEffects, tags: [ReadEnvEffect, ReadIOEffect, WriteDirEffect].} + elif defined(windows): + {.pragma: getTempDirEffects, tags: [ReadEnvEffect, ReadIOEffect].} + else: + {.pragma: getTempDirEffects, tags: [ReadIOEffect].} + proc getTempDir*(): string {.rtl, extern: "nos$1", - tags: [ReadEnvEffect, ReadIOEffect].} = + getTempDirEffects.} = ## Returns the temporary directory of the current user for applications to ## save temporary files in. - when defined(windows): return string(getEnv("TEMP")) & "\\" + when defined(tempDir): + const tempDir {.strdefine.}: string = nil + return tempDir + elif defined(windows): return string(getEnv("TEMP")) & "\\" + elif defined(android): + let tempDir = getHomeDir() / "nimtempfs" + try: createDir(tempDir) + except OSError: discard + return tempDir else: return "/tmp/" proc expandTilde*(path: string): string {. diff --git a/lib/pure/osproc.nim b/lib/pure/osproc.nim index 23c8546c4c..3635aecc16 100644 --- a/lib/pure/osproc.nim +++ b/lib/pure/osproc.nim @@ -762,7 +762,8 @@ elif not defined(useNimRtl): var sysCommand: string var sysArgsRaw: seq[string] if poEvalCommand in options: - sysCommand = "/bin/sh" + const useShPath {.strdefine.} = "/bin/sh" + sysCommand = useShPath sysArgsRaw = @[sysCommand, "-c", command] assert args.len == 0, "`args` has to be empty when using poEvalCommand." else: diff --git a/lib/system/platforms.nim b/lib/system/platforms.nim index 9bdbbaa590..8939615cd5 100644 --- a/lib/system/platforms.nim +++ b/lib/system/platforms.nim @@ -35,7 +35,8 @@ type OsPlatform* {.pure.} = enum ## the OS this program will run on. none, dos, windows, os2, linux, morphos, skyos, solaris, irix, netbsd, freebsd, openbsd, aix, palmos, qnx, amiga, - atari, netware, macos, macosx, haiku, js, nimVM, standalone + atari, netware, macos, macosx, haiku, android, js, nimVM, + standalone const targetOS* = when defined(windows): OsPlatform.windows @@ -58,6 +59,7 @@ const elif defined(macosx): OsPlatform.macosx elif defined(macos): OsPlatform.macos elif defined(haiku): OsPlatform.haiku + elif defined(android): OsPlatform.android elif defined(js): OsPlatform.js elif defined(nimrodVM): OsPlatform.nimVM elif defined(standalone): OsPlatform.standalone diff --git a/tests/osproc/tworkingdir.nim b/tests/osproc/tworkingdir.nim index 84ba3375c1..eeed9240d0 100644 --- a/tests/osproc/tworkingdir.nim +++ b/tests/osproc/tworkingdir.nim @@ -9,7 +9,11 @@ when defined(windows): discard else: let dir1 = getCurrentDir() - var process = startProcess("/usr/bin/env", "/usr/bin", ["true"]) + var process: Process + when defined(android): + process = startProcess("/system/bin/env", "/system/bin", ["true"]) + else: + process = startProcess("/usr/bin/env", "/usr/bin", ["true"]) let dir2 = getCurrentDir() discard process.waitForExit() process.close() diff --git a/tests/testament/categories.nim b/tests/testament/categories.nim index 4ba07cd212..7b1dd0df01 100644 --- a/tests/testament/categories.nim +++ b/tests/testament/categories.nim @@ -139,7 +139,7 @@ proc gcTests(r: var TResults, cat: Category, options: string) = " -d:release --gc:markAndSweep", cat, actionRun) template test(filename: untyped) = testWithoutBoehm filename - when not defined(windows): + when not defined(windows) and not defined(android): # AR: cannot find any boehm.dll on the net, right now, so disabled # for windows: testSpec r, makeTest("tests/gc" / filename, options & diff --git a/tools/niminst/buildsh.tmpl b/tools/niminst/buildsh.tmpl index 956c5ead84..faa8a47d08 100644 --- a/tools/niminst/buildsh.tmpl +++ b/tools/niminst/buildsh.tmpl @@ -1,4 +1,4 @@ -#? stdtmpl(subsChar='?') | standard +#? stdtmpl(subsChar='?') | standard #proc generateBuildShellScript(c: ConfigData): string = # result = "#! /bin/sh\n# Generated from niminst\n" & # "# Template is in tools/niminst/buildsh.tmpl\n" & @@ -9,6 +9,18 @@ set -e while : do case "$1" in + --os) + optos=$2 + shift 2 + ;; + --cpu) + optcpu=$2 + shift 2 + ;; + --osname) + optosname=$2 + shift 2 + ;; --extraBuildArgs) extraBuildArgs=" $2" shift 2 @@ -35,6 +47,7 @@ PS4="" # add(result, "# platform detection\n") ucpu=`uname -m` uos=`uname` +uosname=`uname -o` # add(result, "# bin dir detection\n") binDir=?{firstBinPath(c).toUnix} @@ -46,9 +59,21 @@ if [ ! -d $binDir ]; then mkdir $binDir fi +# add(result, "# override OS, CPU and OS Name with command-line arguments\n") +if [ -n "$optos" ]; then + uos="$optos" +fi +if [ -n "$optcpu" ]; then + ucpu="$optcpu" +fi +if [ -n "$optcpu" ]; then + uosname="$optosname" +fi + # add(result, "# convert to lower case:\n") ucpu=`echo $ucpu | tr "[:upper:]" "[:lower:]"` uos=`echo $uos | tr "[:upper:]" "[:lower:]"` +uosname=`echo $uosname | tr "[:upper:]" "[:lower:]"` case $uos in *linux* ) @@ -97,6 +122,11 @@ case $uos in *mingw* ) myos="windows" ;; + *android* ) + myos="android" + LINK_FLAGS="$LINK_FLAGS -ldl -lm -lrt" + LINK_FLAGS="$LINK_FLAGS -landroid-glob" + ;; *) echo 2>&1 "Error: unknown operating system: $uos" exit 1 @@ -132,7 +162,7 @@ case $ucpu in exit 1 esac ;; - *arm*|*armv6l* ) + *arm*|*armv6l*|*armv71* ) mycpu="arm" ;; *aarch64* ) mycpu="arm64" ;; @@ -142,7 +172,17 @@ case $ucpu in ;; esac +case $uosname in + *android* ) + LINK_FLAGS="$LINK_FLAGS -landroid-glob" + myosname="android" + myos="android" + ;; +esac + # add(result, "# call the compiler:\n") +echo \# OS: $myos +echo \# CPU: $mycpu case $myos in # for osA in 1..c.oses.len: diff --git a/tools/niminst/makefile.tmpl b/tools/niminst/makefile.tmpl index 2203d05e9c..4a20680e00 100644 --- a/tools/niminst/makefile.tmpl +++ b/tools/niminst/makefile.tmpl @@ -17,6 +17,7 @@ endif ucpu := $(shell sh -c 'uname -m | tr "[:upper:]" "[:lower:]"') uos := $(shell sh -c 'uname | tr "[:upper:]" "[:lower:]"') +uosname := $(shell sh -c 'uname -o | tr "[:upper:]" "[:lower:]"') ifeq ($(uos),linux) myos = linux @@ -68,6 +69,11 @@ ifndef uos $(error unknown operating system: $(uos)) endif +ifeq ($(uosname),android) + myos = android + LINK_FLAGS += -landroid-glob +endif + ifeq ($(ucpu),i386) mycpu = i386 endif