Skip to content

Commit

Permalink
Haiku support for Nim (#8542)
Browse files Browse the repository at this point in the history
* posix_other: Haiku now has spawn.h

This is added per https://dev.haiku-os.org/ticket/13446

* posix_other: Add Haiku specific Dirent members

* cpuinfo: Add an implementation for Haiku

* distros: Add basic Haiku support

* encodings: update Haiku support

* fenv, math: Haiku now provides libm

* times: Add Haiku struct members

* ansi_c, osalloc: Add Haiku constants

* threads: Add Haiku support

* testament: Haiku uses LIBRARY_PATH

* nim.cfg: Update Haiku support

libnetwork should only be linked if network functions are used

* threads: Haiku does not support -pthread switch

* tworkingdir: Haiku's env is in /bin

* posix_other: add SIGKILLTHR for Haiku

* sockets: link with libnetwork on Haiku

* coro: correct ucontext.h location

http://pubs.opengroup.org/onlinepubs/009696699/basedefs/ucontext.h.html

* coro: ucontext backend is not available on Haiku

Haiku doesn't provide the <ucontext.h> header, as it was removed from POSIX

* coro: fix setjmp backend

The compiler does not allow statements after a noreturn function

* nativesockets: Haiku doesn't support AI_V4MAPPED

* system: hostOS can contains "haiku"

* os: add support for Haiku's packagefs

packagefs is read-only, but there are writable holes to the underlying
file system as well

* os: update constant for Haiku
  • Loading branch information
alaviss authored and Araq committed Aug 14, 2018
1 parent feda366 commit 7ef2682
Show file tree
Hide file tree
Showing 19 changed files with 114 additions and 29 deletions.
16 changes: 9 additions & 7 deletions config/nim.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -82,19 +82,21 @@ path="$lib/pure"
clang.cpp.options.linker = "-ldl"
tcc.options.linker = "-ldl"
@end
@if bsd or haiku:
@if bsd:
# BSD got posix_spawn only recently, so we deactivate it for osproc:
define:useFork
# at least NetBSD has problems with thread local storage:
tlsEmulation:on
@end
@if haiku:
# -fopenmp
gcc.options.linker = "-lroot -lnetwork"
gcc.cpp.options.linker = "-lroot -lnetwork"
clang.options.linker = "-lroot -lnetwork"
clang.cpp.options.linker = "-lroot -lnetwork"
tcc.options.linker = "-lroot -lnetwork"
# Haiku currently have problems with TLS
# https://dev.haiku-os.org/ticket/14342
tlsEmulation:on
gcc.options.linker = "-Wl,--as-needed -lnetwork"
gcc.cpp.options.linker = "-Wl,--as-needed -lnetwork"
clang.options.linker = "-Wl,--as-needed -lnetwork"
clang.cpp.options.linker = "-Wl,--as-needed -lnetwork"
tcc.options.linker = "-Wl,--as-needed -lnetwork"
@end
@end

Expand Down
2 changes: 2 additions & 0 deletions lib/deprecated/pure/sockets.nim
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ include "system/inclrtl"

when hostOS == "solaris":
{.passl: "-lsocket -lnsl".}
elif hostOS == "haiku":
{.passl: "-lnetwork".}

import os, parseutils
from times import epochTime
Expand Down
12 changes: 11 additions & 1 deletion lib/posix/posix_other.nim
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
{.deadCodeElim: on.} # dce option deprecated

const
hasSpawnH = not defined(haiku) # should exist for every Posix system nowadays
hasSpawnH = true # should exist for every Posix system nowadays
hasAioH = defined(linux)

when defined(linux) and not defined(android):
Expand Down Expand Up @@ -43,6 +43,9 @@ type

Dirent* {.importc: "struct dirent",
header: "<dirent.h>", final, pure.} = object ## dirent_t struct
when defined(haiku):
d_dev*: Dev ## Device (not POSIX)
d_pdev*: Dev ## Parent device (only for queries) (not POSIX)
d_ino*: Ino ## File serial number.
when defined(dragonfly):
# DragonflyBSD doesn't have `d_reclen` field.
Expand All @@ -54,6 +57,9 @@ type
## (not POSIX)
when defined(linux) or defined(openbsd):
d_off*: Off ## Not an offset. Value that ``telldir()`` would return.
elif defined(haiku):
d_pino*: Ino ## Parent inode (only for queries) (not POSIX)
d_reclen*: cushort ## Length of this record. (not POSIX)

d_name*: array[0..255, char] ## Name of entry.

Expand Down Expand Up @@ -599,6 +605,10 @@ else:
MSG_NOSIGNAL* {.importc, header: "<sys/socket.h>".}: cint
## No SIGPIPE generated when an attempt to send is made on a stream-oriented socket that is no longer connected.

when defined(haiku):
const
SIGKILLTHR* = 21 ## BeOS specific: Kill just the thread, not team

when hasSpawnH:
when defined(linux):
# better be safe than sorry; Linux has this flag, macosx doesn't, don't
Expand Down
12 changes: 12 additions & 0 deletions lib/pure/concurrency/cpuinfo.nim
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,14 @@ when defined(genode):
proc affinitySpaceTotal(env: GenodeEnvPtr): cuint {.
importcpp: "@->cpu().affinity_space().total()".}

when defined(haiku):
{.emit: "#include <OS.h>".}
type
SystemInfo {.importc: "system_info", bycopy.} = object
cpuCount {.importc: "cpu_count".}: uint32

proc getSystemInfo(info: ptr SystemInfo): int32 {.importc: "get_system_info".}

proc countProcessors*(): int {.rtl, extern: "ncpi$1".} =
## returns the numer of the processors/cores the machine has.
## Returns 0 if it cannot be detected.
Expand Down Expand Up @@ -86,6 +94,10 @@ proc countProcessors*(): int {.rtl, extern: "ncpi$1".} =
result = sysconf(SC_NPROC_ONLN)
elif defined(genode):
result = runtimeEnv.affinitySpaceTotal().int
elif defined(haiku):
var sysinfo: SystemInfo
if getSystemInfo(addr sysinfo) == 0:
result = sysinfo.cpuCount.int
else:
result = sysconf(SC_NPROCESSORS_ONLN)
if result <= 0: result = 0
18 changes: 11 additions & 7 deletions lib/pure/coro.nim
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@ when defined(windows):
{.warning: "ucontext coroutine backend is not available on windows, defaulting to fibers.".}
when defined(nimCoroutinesSetjmp):
{.warning: "setjmp coroutine backend is not available on windows, defaulting to fibers.".}
elif defined(haiku):
const coroBackend = CORO_BACKEND_SETJMP
when defined(nimCoroutinesUcontext):
{.warning: "ucontext coroutine backend is not available on haiku, defaulting to setjmp".}
elif defined(nimCoroutinesSetjmp) or defined(nimCoroutinesSetjmpBundled):
const coroBackend = CORO_BACKEND_SETJMP
else:
Expand All @@ -55,21 +59,21 @@ when coroBackend == CORO_BACKEND_FIBERS:

elif coroBackend == CORO_BACKEND_UCONTEXT:
type
stack_t {.importc, header: "<sys/ucontext.h>".} = object
stack_t {.importc, header: "<ucontext.h>".} = object
ss_sp: pointer
ss_flags: int
ss_size: int

ucontext_t {.importc, header: "<sys/ucontext.h>".} = object
ucontext_t {.importc, header: "<ucontext.h>".} = object
uc_link: ptr ucontext_t
uc_stack: stack_t

Context = ucontext_t

proc getcontext(context: var ucontext_t): int32 {.importc, header: "<sys/ucontext.h>".}
proc setcontext(context: var ucontext_t): int32 {.importc, header: "<sys/ucontext.h>".}
proc swapcontext(fromCtx, toCtx: var ucontext_t): int32 {.importc, header: "<sys/ucontext.h>".}
proc makecontext(context: var ucontext_t, fn: pointer, argc: int32) {.importc, header: "<sys/ucontext.h>", varargs.}
proc getcontext(context: var ucontext_t): int32 {.importc, header: "<ucontext.h>".}
proc setcontext(context: var ucontext_t): int32 {.importc, header: "<ucontext.h>".}
proc swapcontext(fromCtx, toCtx: var ucontext_t): int32 {.importc, header: "<ucontext.h>".}
proc makecontext(context: var ucontext_t, fn: pointer, argc: int32) {.importc, header: "<ucontext.h>", varargs.}

elif coroBackend == CORO_BACKEND_SETJMP:
proc coroExecWithStack*(fn: pointer, stack: pointer) {.noreturn, importc: "narch_$1", fastcall.}
Expand Down Expand Up @@ -190,7 +194,7 @@ proc switchTo(current, to: CoroutinePtr) =
elif to.state == CORO_CREATED:
# Coroutine is started.
coroExecWithStack(runCurrentTask, to.stack.bottom)
doAssert false
#doAssert false
else:
{.error: "Invalid coroutine backend set.".}
# Execution was just resumed. Restore frame information and set active stack.
Expand Down
6 changes: 6 additions & 0 deletions lib/pure/distros.nim
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,8 @@ type
OpenBSD
DragonFlyBSD

Haiku


const
LacksDevPackages* = {Distribution.Gentoo, Distribution.Slackware,
Expand Down Expand Up @@ -166,6 +168,8 @@ proc detectOsImpl(d: Distribution): bool =
of Distribution.Solaris:
let uname = toLowerAscii(uname())
result = ("sun" in uname) or ("solaris" in uname)
of Distribution.Haiku:
result = defined(haiku)
else:
let dd = toLowerAscii($d)
result = dd in toLowerAscii(uname()) or dd in toLowerAscii(release())
Expand Down Expand Up @@ -224,6 +228,8 @@ proc foreignDepInstallCmd*(foreignPackageName: string): (string, bool) =
result = ("pacman -S " & p, true)
else:
result = ("<your package manager here> install " & p, true)
elif defined(haiku):
result = ("pkgman install " & p, true)
else:
result = ("brew install " & p, false)

Expand Down
4 changes: 3 additions & 1 deletion lib/pure/encodings.nim
Original file line number Diff line number Diff line change
Expand Up @@ -255,7 +255,7 @@ when defined(windows):

else:
when defined(haiku):
const iconvDll = "(libc.so.6|libiconv.so|libtextencoding.so)"
const iconvDll = "libiconv.so"
elif defined(macosx):
const iconvDll = "libiconv.dylib"
else:
Expand All @@ -272,6 +272,8 @@ else:
const EILSEQ = 86.cint
elif defined(solaris):
const EILSEQ = 88.cint
elif defined(haiku):
const EILSEQ = -2147454938.cint

var errno {.importc, header: "<errno.h>".}: cint

Expand Down
2 changes: 1 addition & 1 deletion lib/pure/fenv.nim
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@

{.deadCodeElim: on.} # dce option deprecated

when defined(Posix) and not defined(haiku):
when defined(Posix):
{.passl: "-lm".}

var
Expand Down
2 changes: 1 addition & 1 deletion lib/pure/math.nim
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ proc fac*(n: int): int =

{.push checks:off, line_dir:off, stack_trace:off.}

when defined(Posix) and not defined(haiku):
when defined(Posix):
{.passl: "-lm".}

const
Expand Down
5 changes: 3 additions & 2 deletions lib/pure/nativesockets.nim
Original file line number Diff line number Diff line change
Expand Up @@ -248,9 +248,10 @@ proc getAddrInfo*(address: string, port: Port, domain: Domain = AF_INET,
hints.ai_socktype = toInt(sockType)
hints.ai_protocol = toInt(protocol)
# OpenBSD doesn't support AI_V4MAPPED and doesn't define the macro AI_V4MAPPED.
# FreeBSD doesn't support AI_V4MAPPED but defines the macro.
# FreeBSD, Haiku don'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) and not defined(android):
# https://dev.haiku-os.org/ticket/14323
when not defined(freebsd) and not defined(openbsd) and not defined(netbsd) and not defined(android) and not defined(haiku):
if domain == AF_INET6:
hints.ai_flags = AI_V4MAPPED
var gaiResult = getaddrinfo(address, $port, addr(hints), result)
Expand Down
13 changes: 12 additions & 1 deletion lib/pure/os.nim
Original file line number Diff line number Diff line change
Expand Up @@ -615,7 +615,10 @@ proc copyFile*(source, dest: string) {.rtl, extern: "nos$1",

when not declared(ENOENT) and not defined(Windows):
when NoFakeVars:
const ENOENT = cint(2) # 2 on most systems including Solaris
when not defined(haiku):
const ENOENT = cint(2) # 2 on most systems including Solaris
else:
const ENOENT = cint(-2147459069)
else:
var ENOENT {.importc, header: "<errno.h>".}: cint

Expand Down Expand Up @@ -972,6 +975,14 @@ proc rawCreateDir(dir: string): bool =
result = false
else:
raiseOSError(osLastError(), dir)
elif defined(haiku):
let res = mkdir(dir, 0o777)
if res == 0'i32:
result = true
elif errno == EEXIST or errno == EROFS:
result = false
else:
raiseOSError(osLastError(), dir)
elif defined(posix):
let res = mkdir(dir, 0o777)
if res == 0'i32:
Expand Down
2 changes: 1 addition & 1 deletion lib/pure/times.nim
Original file line number Diff line number Diff line change
Expand Up @@ -892,7 +892,7 @@ else:
weekday {.importc: "tm_wday".},
yearday {.importc: "tm_yday".},
isdst {.importc: "tm_isdst".}: cint
when defined(linux) and defined(amd64):
when defined(linux) and defined(amd64) or defined(haiku):
gmtoff {.importc: "tm_gmtoff".}: clong
zone {.importc: "tm_zone".}: cstring
type
Expand Down
2 changes: 1 addition & 1 deletion lib/system.nim
Original file line number Diff line number Diff line change
Expand Up @@ -1365,7 +1365,7 @@ const
hostOS* {.magic: "HostOS".}: string = ""
## a string that describes the host operating system. Possible values:
## "windows", "macosx", "linux", "netbsd", "freebsd", "openbsd", "solaris",
## "aix", "standalone".
## "aix", "haiku", "standalone".

hostCPU* {.magic: "HostCPU".}: string = ""
## a string that describes the host CPU. Possible values:
Expand Down
11 changes: 11 additions & 0 deletions lib/system/ansi_c.nim
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,15 @@ elif defined(macosx) or defined(linux) or defined(freebsd) or
SIGSEGV = cint(11)
SIGTERM = cint(15)
SIGPIPE = cint(13)
elif defined(haiku):
const
SIGABRT = cint(6)
SIGFPE = cint(8)
SIGILL = cint(4)
SIGINT = cint(2)
SIGSEGV = cint(11)
SIGTERM = cint(15)
SIGPIPE = cint(7)
else:
when NoFakeVars:
{.error: "SIGABRT not ported to your platform".}
Expand All @@ -74,6 +83,8 @@ else:

when defined(macosx):
const SIGBUS = cint(10)
elif defined(haiku):
const SIGBUS = cint(30)
else:
template SIGBUS: untyped = SIGSEGV

Expand Down
3 changes: 3 additions & 0 deletions lib/system/osalloc.nim
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,9 @@ elif defined(posix):
# some arches like mips and alpha use different values
const MAP_ANONYMOUS = 0x20
const MAP_PRIVATE = 0x02 # Changes are private
elif defined(haiku):
const MAP_ANONYMOUS = 0x08
const MAP_PRIVATE = 0x02
else:
var
MAP_ANONYMOUS {.importc: "MAP_ANONYMOUS", header: "<sys/mman.h>".}: cint
Expand Down
16 changes: 14 additions & 2 deletions lib/system/threads.nim
Original file line number Diff line number Diff line change
Expand Up @@ -162,10 +162,12 @@ elif defined(genode):
mainTls

else:
when not defined(macosx):
when not (defined(macosx) or defined(haiku)):
{.passL: "-pthread".}

{.passC: "-pthread".}
when not defined(haiku):
{.passC: "-pthread".}

const
schedh = "#define _GNU_SOURCE\n#include <sched.h>"
pthreadh = "#define _GNU_SOURCE\n#include <pthread.h>"
Expand Down Expand Up @@ -714,3 +716,13 @@ elif defined(solaris):
if threadId == 0:
threadId = int(thr_self())
result = threadId

elif defined(haiku):
type thr_id {.importc: "thread_id", header: "<OS.h>".} = distinct int32
proc find_thread(name: cstring): thr_id {.importc, header: "<OS.h>".}

proc getThreadId*(): int =
## get the ID of the currently running thread.
if threadId == 0:
threadId = int(find_thread(nil))
result = threadId
5 changes: 4 additions & 1 deletion tests/osproc/texitsignal.nim
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,12 @@ if paramCount() == 0:
# windows kill happens using TerminateProcess(h, 0), so we should get a
# 0 here
echo p.waitForExit() == 0
elif defined(haiku):
# on Haiku, the program main thread receive SIGKILLTHR
echo p.waitForExit() == 128 + SIGKILLTHR
else:
# on posix (non-windows), kill sends SIGKILL
echo p.waitForExit() == 128 + SIGKILL

else:
sleep(5000) # should get killed before this
sleep(5000) # should get killed before this
2 changes: 2 additions & 0 deletions tests/osproc/tworkingdir.nim
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ else:
var process: Process
when defined(android):
process = startProcess("/system/bin/env", "/system/bin", ["true"])
elif defined(haiku):
process = startProcess("/bin/env", "/bin", ["true"])
else:
process = startProcess("/usr/bin/env", "/usr/bin", ["true"])
let dir2 = getCurrentDir()
Expand Down
10 changes: 7 additions & 3 deletions tests/testament/categories.nim
Original file line number Diff line number Diff line change
Expand Up @@ -109,10 +109,14 @@ proc runBasicDLLTest(c, r: var TResults, cat: Category, options: string) =
safeCopyFile("lib" / nimrtlDll, "tests/dll" / nimrtlDll)
else:
# posix relies on crappy LD_LIBRARY_PATH (ugh!):
var libpath = getEnv"LD_LIBRARY_PATH".string
const libpathenv = when defined(haiku):
"LIBRARY_PATH"
else:
"LD_LIBRARY_PATH"
var libpath = getEnv(libpathenv).string
# Temporarily add the lib directory to LD_LIBRARY_PATH:
putEnv("LD_LIBRARY_PATH", "tests/dll" & (if libpath.len > 0: ":" & libpath else: ""))
defer: putEnv("LD_LIBRARY_PATH", libpath)
putEnv(libpathenv, "tests/dll" & (if libpath.len > 0: ":" & libpath else: ""))
defer: putEnv(libpathenv, libpath)
var nimrtlDll = DynlibFormat % "nimrtl"
safeCopyFile("lib" / nimrtlDll, "tests/dll" / nimrtlDll)

Expand Down

0 comments on commit 7ef2682

Please sign in to comment.