summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--azure-pipelines.yml4
-rw-r--r--compiler/condsyms.nim6
-rw-r--r--compiler/evalffi.nim2
-rw-r--r--koch.nim11
-rw-r--r--lib/system/ansi_c.nim2
-rw-r--r--lib/system/io.nim2
-rw-r--r--tests/vm/mevalffi.nim67
-rw-r--r--tests/vm/tevalffi.nim98
8 files changed, 103 insertions, 89 deletions
diff --git a/azure-pipelines.yml b/azure-pipelines.yml
index 0898755b6..dccd0d05e 100644
--- a/azure-pipelines.yml
+++ b/azure-pipelines.yml
@@ -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
diff --git a/compiler/condsyms.nim b/compiler/condsyms.nim
index ec9b4a9f4..9a762d585 100644
--- a/compiler/condsyms.nim
+++ b/compiler/condsyms.nim
@@ -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")
diff --git a/compiler/evalffi.nim b/compiler/evalffi.nim
index 58b996e60..58c505a5b 100644
--- a/compiler/evalffi.nim
+++ b/compiler/evalffi.nim
@@ -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:
diff --git a/koch.nim b/koch.nim
index 9a35dcb59..02991d4d4 100644
--- a/koch.nim
+++ b/koch.nim
@@ -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:
@@ -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")
diff --git a/lib/system/ansi_c.nim b/lib/system/ansi_c.nim
index cb2303b61..1ff15611c 100644
--- a/lib/system/ansi_c.nim
+++ b/lib/system/ansi_c.nim
@@ -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"
diff --git a/lib/system/io.nim b/lib/system/io.nim
index 8e3acd0b9..5f4c7d6d7 100644
--- a/lib/system/io.nim
+++ b/lib/system/io.nim
@@ -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"
diff --git a/tests/vm/mevalffi.nim b/tests/vm/mevalffi.nim
new file mode 100644
index 000000000..e15ed8f74
--- /dev/null
+++ b/tests/vm/mevalffi.nim
@@ -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()
diff --git a/tests/vm/tevalffi.nim b/tests/vm/tevalffi.nim
index c2abdba5d..02374869e 100644
--- a/tests/vm/tevalffi.nim
+++ b/tests/vm/tevalffi.nim
@@ -1,17 +1,18 @@
 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
@@ -19,76 +20,9 @@ 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()