Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

enable testing -d:nimHasLibFFI mode #13091

Merged
merged 14 commits into from
Feb 4, 2020
4 changes: 3 additions & 1 deletion azure-pipelines.yml
Original file line number Diff line number Diff line change
Expand Up @@ -74,10 +74,12 @@ jobs:
EOF

sudo apt-fast update -qq
# `:i386` (e.g. in `libffi-dev:i386`) is needed otherwise you may get:
# `could not load: libffi.so` during dynamic loading.
DEBIAN_FRONTEND='noninteractive' \
sudo apt-fast install --no-install-recommends --allow-downgrades -yq \
g++-multilib gcc-multilib libcurl4-openssl-dev:i386 libgc-dev:i386 \
libsdl1.2-dev:i386 libsfml-dev:i386 libglib2.0-dev:i386
libsdl1.2-dev:i386 libsfml-dev:i386 libglib2.0-dev:i386 libffi-dev:i386

cat << EOF > bin/gcc
#!/bin/bash
Expand Down
6 changes: 6 additions & 0 deletions compiler/condsyms.nim
Original file line number Diff line number Diff line change
Expand Up @@ -103,3 +103,9 @@ proc initDefines*(symbols: StringTableRef) =
defineSymbol("nimNewShiftOps")
defineSymbol("nimHasCursor")
defineSymbol("nimHasExceptionsQuery")

when defined(nimHasLibFFI):
# Renaming as we can't conflate input vs output define flags; e.g. this
# will report the right thing regardless of whether user adds
# `-d:nimHasLibFFI` in his user config.
defineSymbol("nimHasLibFFIEnabled")
2 changes: 2 additions & 0 deletions compiler/evalffi.nim
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ when defined(windows):
const libcDll = "msvcrt.dll"
elif defined(linux):
const libcDll = "libc.so(.6|.5|)"
elif defined(bsd):
const libcDll = "/lib/libc.so.7"
elif defined(osx):
const libcDll = "/usr/lib/libSystem.dylib"
else:
Expand Down
11 changes: 7 additions & 4 deletions koch.nim
Original file line number Diff line number Diff line change
Expand Up @@ -485,10 +485,6 @@ proc runCI(cmd: string) =
## build nimble early on to enable remainder to depend on it if needed
kochExecFold("Build Nimble", "nimble")

when false:
execFold("nimble install -y libffi", "nimble install -y libffi")
kochExecFold("boot -d:release -d:nimHasLibFFI", "boot -d:release -d:nimHasLibFFI")

if getEnv("NIM_TEST_PACKAGES", "false") == "true":
execFold("Test selected Nimble packages", "nim c -r testament/testament cat nimble-packages")
else:
Expand All @@ -502,6 +498,13 @@ proc runCI(cmd: string) =

# main bottleneck here
execFold("Run tester", "nim c -r -d:nimCoroutines testament/testament --pedantic all -d:nimCoroutines")
block: # CT FFI
when defined(posix): # windows can be handled in future PR's
execFold("nimble install -y libffi", "nimble install -y libffi")
const nimFFI = "./bin/nim.ctffi"
# no need to bootstrap with koch boot (would be slower)
execFold("build with -d:nimHasLibFFI", "nim c -d:release -d:nimHasLibFFI -o:$1 compiler/nim.nim" % [nimFFI])
execFold("test with -d:nimHasLibFFI", "$1 c -r testament/testament --nim:$1 r tests/vm/tevalffi.nim" % [nimFFI])

execFold("Run nimdoc tests", "nim c -r nimdoc/tester")
execFold("Run nimpretty tests", "nim c -r nimpretty/tester.nim")
Expand Down
2 changes: 1 addition & 1 deletion lib/system/ansi_c.nim
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ type
CFilePtr* = ptr CFile ## The type representing a file handle.

# duplicated between io and ansi_c
const stdioUsesMacros = defined(osx) and not defined(emscripten)
const stdioUsesMacros = (defined(osx) or defined(bsd)) and not defined(emscripten)
const stderrName = when stdioUsesMacros: "__stderrp" else: "stderr"
const stdoutName = when stdioUsesMacros: "__stdoutp" else: "stdout"
const stdinName = when stdioUsesMacros: "__stdinp" else: "stdin"
Expand Down
2 changes: 1 addition & 1 deletion lib/system/io.nim
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ type
# text file handling:
when not defined(nimscript) and not defined(js):
# duplicated between io and ansi_c
const stdioUsesMacros = defined(osx) and not defined(emscripten)
const stdioUsesMacros = (defined(osx) or defined(bsd)) and not defined(emscripten)
const stderrName = when stdioUsesMacros: "__stderrp" else: "stderr"
const stdoutName = when stdioUsesMacros: "__stdoutp" else: "stdout"
const stdinName = when stdioUsesMacros: "__stdinp" else: "stdin"
Expand Down
67 changes: 67 additions & 0 deletions tests/vm/mevalffi.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
# re-enable for windows once libffi can be installed in koch.nim
# With win32 (not yet win64), libffi on windows works and this test passes.

when defined(linux) or defined(bsd):
{.passL: "-lm".} # for exp
proc c_exp(a: float64): float64 {.importc: "exp", header: "<math.h>".}

proc c_printf(frmt: cstring): cint {.importc: "printf", header: "<stdio.h>", varargs, discardable.}

const snprintfName = when defined(windows): "_snprintf" else: "snprintf"
proc c_snprintf*(buffer: pointer, buf_size: uint, format: cstring): cint {.importc: snprintfName, header: "<stdio.h>", varargs .}

proc c_malloc(size:uint):pointer {.importc:"malloc", header: "<stdlib.h>".}
proc c_free(p: pointer) {.importc:"free", header: "<stdlib.h>".}

proc fun() =
block: # c_exp
var x = 0.3
let b = c_exp(x)
let b2 = int(b*1_000_000) # avoids floating point equality
doAssert b2 == 1349858
doAssert c_exp(0.3) == c_exp(x)
const x2 = 0.3
doAssert c_exp(x2) == c_exp(x)

block: # c_printf
c_printf("foo\n")
c_printf("foo:%d\n", 100)
c_printf("foo:%d\n", 101.cint)
c_printf("foo:%d:%d\n", 102.cint, 103.cint)
let temp = 104.cint
c_printf("foo:%d:%d:%d\n", 102.cint, 103.cint, temp)
var temp2 = 105.cint
c_printf("foo:%g:%s:%d:%d\n", 0.03, "asdf", 103.cint, temp2)

block: # c_snprintf, c_malloc, c_free
let n: uint = 50
var buffer2: pointer = c_malloc(n)
var s: cstring = "foobar"
var age: cint = 25
discard c_snprintf(buffer2, n, "s1:%s s2:%s age:%d pi:%g", s, s, age, 3.14)
c_printf("ret={%s}\n", buffer2)
c_free(buffer2) # not sure it has an effect

block: # c_printf bug
var a = 123
var a2 = a.addr
#[
bug: different behavior between CT RT in this case:
at CT, shows foo2:a=123
at RT, shows foo2:a=<address as int>
]#
if false:
c_printf("foo2:a=%d\n", a2)


static:
fun()
fun()

import system/ansi_c
block:
proc fun2()=
c_fprintf(cstderr, "hello world stderr\n")
write(stderr, "hi stderr\n")
static: fun2()
fun2()
98 changes: 16 additions & 82 deletions tests/vm/tevalffi.nim
Original file line number Diff line number Diff line change
@@ -1,94 +1,28 @@
discard """
cmd: "nim c --experimental:compiletimeFFI $file"
nimout: '''
foo
foo:100
foo:101
foo:102:103
foo:102:103:104
foo:0.03:asdf:103:105
ret={s1:foobar s2:foobar age:25 pi:3.14}
joinable: false
"""

import std/[strformat,os,osproc]

proc main() =
const nim = getCurrentCompilerExe()
const file = currentSourcePath().parentDir / "mevalffi.nim"
# strangely, --hint:cc:off was needed
let cmd = fmt"{nim} c -f --experimental:compiletimeFFI --hints:off --hint:cc:off {file}"
let (output, exitCode) = execCmdEx(cmd)
let expected = """
hello world stderr
hi stderr
'''
output: '''
foo
foo:100
foo:101
foo:102:103
foo:102:103:104
foo:0.03:asdf:103:105
ret={s1:foobar s2:foobar age:25 pi:3.14}
hello world stderr
hi stderr
'''
disabled: "true"
"""
doAssert output == expected, output
doAssert exitCode == 0

# re-enable for windows once libffi can be installed in koch.nim
# With win32 (not yet win64), libffi on windows works and this test passes.

when defined(linux):
{.passL: "-lm".} # for exp
proc c_exp(a: float64): float64 {.importc: "exp", header: "<math.h>".}

proc c_printf(frmt: cstring): cint {.importc: "printf", header: "<stdio.h>", varargs, discardable.}

const snprintfName = when defined(windows): "_snprintf" else: "snprintf"
proc c_snprintf*(buffer: pointer, buf_size: uint, format: cstring): cint {.importc: snprintfName, header: "<stdio.h>", varargs .}

proc c_malloc(size:uint):pointer {.importc:"malloc", header: "<stdlib.h>".}
proc c_free(p: pointer) {.importc:"free", header: "<stdlib.h>".}

proc fun() =
block: # c_exp
var x = 0.3
let b = c_exp(x)
let b2 = int(b*1_000_000) # avoids floating point equality
doAssert b2 == 1349858
doAssert c_exp(0.3) == c_exp(x)
const x2 = 0.3
doAssert c_exp(x2) == c_exp(x)

block: # c_printf
c_printf("foo\n")
c_printf("foo:%d\n", 100)
c_printf("foo:%d\n", 101.cint)
c_printf("foo:%d:%d\n", 102.cint, 103.cint)
let temp = 104.cint
c_printf("foo:%d:%d:%d\n", 102.cint, 103.cint, temp)
var temp2 = 105.cint
c_printf("foo:%g:%s:%d:%d\n", 0.03, "asdf", 103.cint, temp2)

block: # c_snprintf, c_malloc, c_free
let n: uint = 50
var buffer2: pointer = c_malloc(n)
var s: cstring = "foobar"
var age: cint = 25
let j = c_snprintf(buffer2, n, "s1:%s s2:%s age:%d pi:%g", s, s, age, 3.14)
c_printf("ret={%s}\n", buffer2)
c_free(buffer2) # not sure it has an effect

block: # c_printf bug
var a = 123
var a2 = a.addr
#[
bug: different behavior between CT RT in this case:
at CT, shows foo2:a=123
at RT, shows foo2:a=<address as int>
]#
if false:
c_printf("foo2:a=%d\n", a2)


static:
fun()
fun()

when true:
import system/ansi_c
proc fun2()=
c_fprintf(cstderr, "hello world stderr\n")
write(stderr, "hi stderr\n")
static: fun2()
fun2()
when defined(nimHasLibFFIEnabled):
main()