diff options
-rw-r--r-- | azure-pipelines.yml | 4 | ||||
-rw-r--r-- | compiler/condsyms.nim | 6 | ||||
-rw-r--r-- | compiler/evalffi.nim | 2 | ||||
-rw-r--r-- | koch.nim | 11 | ||||
-rw-r--r-- | lib/system/ansi_c.nim | 2 | ||||
-rw-r--r-- | lib/system/io.nim | 2 | ||||
-rw-r--r-- | tests/vm/mevalffi.nim | 67 | ||||
-rw-r--r-- | tests/vm/tevalffi.nim | 98 |
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() |