mirror of
https://github.com/logos-messaging/nim-ffi.git
synced 2026-07-16 13:09:24 +00:00
feat: main prefix validation (#116)
This commit is contained in:
parent
62d3c00b61
commit
c0f6f2e802
@ -226,7 +226,7 @@ task genbindings_rust, "Generate Rust bindings for the timer example":
|
||||
" -o:/dev/null examples/timer/timer.nim"
|
||||
|
||||
task genbindings_cddl, "Generate CDDL schema for the timer example":
|
||||
exec "nim c " & nimFlagsOrc & " --app:lib --noMain --nimMainPrefix:libtimer" &
|
||||
exec "nim c " & nimFlagsOrc & " --app:lib --noMain --nimMainPrefix:libmy_timer" &
|
||||
" -d:ffiGenBindings -d:targetLang=cddl" &
|
||||
" -d:ffiOutputDir=examples/timer/cddl_bindings" & " -d:ffiSrcPath=../timer.nim" &
|
||||
" -o:/dev/null examples/timer/timer.nim"
|
||||
|
||||
@ -1,10 +1,59 @@
|
||||
import std/[macros, atomics, sysatomics], strformat, chronicles, chronos
|
||||
import
|
||||
std/[macros, atomics, sysatomics, compilesettings], strformat, chronicles, chronos
|
||||
import strutils
|
||||
import ../codegen/meta
|
||||
|
||||
func nimMainPrefixOnCmdLine(cmdLine: string): tuple[found: bool, value: string] =
|
||||
## Scan the compiler command line for `--nimMainPrefix:X` (last one wins) and
|
||||
## return its value. Switch names in Nim are style-insensitive, so the name
|
||||
## is matched lowercased and with underscores stripped; the separator may be
|
||||
## `:` or `=`. Returns `(false, "")` when the flag is absent — note config.nims
|
||||
## switches may not surface here, so absence is not proof it was never set.
|
||||
var found = false
|
||||
var value = ""
|
||||
for tok in cmdLine.splitWhitespace():
|
||||
let body = tok.strip(trailing = false, chars = {'-'})
|
||||
let sep = body.find({':', '='})
|
||||
if sep < 0:
|
||||
continue
|
||||
if body[0 ..< sep].toLowerAscii().replace("_", "") == "nimmainprefix":
|
||||
found = true
|
||||
value = body[sep + 1 .. ^1]
|
||||
(found, value)
|
||||
|
||||
proc validateNimMainPrefix(libraryName: string) {.compileTime.} =
|
||||
## The Nim runtime init symbol is importc'd as `lib{libraryName}NimMain`, so
|
||||
## the build must pass `--nimMainPrefix:lib{libraryName}`; a mismatch otherwise
|
||||
## surfaces only at link time as an obscure undefined-symbol error. Absence
|
||||
## can't be an error — config.nims may set the prefix without it showing on
|
||||
## `commandLine` — so it only warrants a hint, and only for the `--app:lib`
|
||||
## build where the prefix actually matters.
|
||||
let expectedPrefix = "lib" & libraryName
|
||||
let (prefixFound, prefixValue) =
|
||||
nimMainPrefixOnCmdLine(querySetting(SingleValueSetting.commandLine))
|
||||
if prefixFound and prefixValue != expectedPrefix:
|
||||
error(
|
||||
"declareLibrary(\"" & libraryName &
|
||||
"\"): the Nim runtime init symbol is importc'd as " & expectedPrefix &
|
||||
"NimMain, so the build needs --nimMainPrefix:" & expectedPrefix &
|
||||
", but the command line passes --nimMainPrefix:" & prefixValue &
|
||||
". Change the flag to --nimMainPrefix:" & expectedPrefix &
|
||||
" (it must be \"lib\" followed by the declareLibrary name)."
|
||||
)
|
||||
elif not prefixFound and compileOption("app", "lib"):
|
||||
hint(
|
||||
"declareLibrary(\"" & libraryName & "\"): pass --nimMainPrefix:" & expectedPrefix &
|
||||
" so the Nim runtime init symbol " & expectedPrefix &
|
||||
"NimMain resolves; without it the build may fail with an undefined-symbol" &
|
||||
" link error (ignore this hint if the prefix is set in config.nims)."
|
||||
)
|
||||
|
||||
macro declareLibraryBase*(libraryName: static[string]): untyped =
|
||||
# Record the library name for binding generation
|
||||
currentLibName = libraryName
|
||||
|
||||
validateNimMainPrefix(libraryName)
|
||||
|
||||
var res = newStmtList()
|
||||
|
||||
## Generate {.pragma: exported, exportc, cdecl, raises: [].}
|
||||
|
||||
5
tests/unit/mainprefix_fixture.nim
Normal file
5
tests/unit/mainprefix_fixture.nim
Normal file
@ -0,0 +1,5 @@
|
||||
import ffi
|
||||
|
||||
type MpFixture = object
|
||||
|
||||
declareLibrary("mpfixture", MpFixture)
|
||||
23
tests/unit/test_main_prefix_validation.nim
Normal file
23
tests/unit/test_main_prefix_validation.nim
Normal file
@ -0,0 +1,23 @@
|
||||
import std/[os, strutils]
|
||||
import unittest2
|
||||
|
||||
# The validation only fires when --nimMainPrefix is on the command line, so we
|
||||
# capture a real `nim check` of the fixture at this test's compile time.
|
||||
# `mainprefix_fixture.nim` deliberately lacks the `test_` prefix so the nimble
|
||||
# runner never compiles it standalone.
|
||||
const
|
||||
nimExe = getCurrentCompilerExe()
|
||||
fixture = currentSourcePath.parentDir / "mainprefix_fixture.nim"
|
||||
checkCmd = nimExe & " check --hints:off --colors:off "
|
||||
wrongPrefixOutput = staticExec(checkCmd & "--nimMainPrefix:libWRONG " & fixture)
|
||||
rightPrefixOutput = staticExec(checkCmd & "--nimMainPrefix:libmpfixture " & fixture)
|
||||
|
||||
suite "compile-time --nimMainPrefix validation":
|
||||
test "a mismatched prefix errors and names the expected flag":
|
||||
check "Error:" in wrongPrefixOutput
|
||||
# naming the expected flag is what distinguishes our error from any other
|
||||
# compile failure, so assert on it rather than the bare "Error:".
|
||||
check "needs --nimMainPrefix:libmpfixture" in wrongPrefixOutput
|
||||
|
||||
test "the matching prefix compiles without error":
|
||||
check "Error:" notin rightPrefixOutput
|
||||
Loading…
x
Reference in New Issue
Block a user