mirror of
https://github.com/logos-messaging/nim-ffi.git
synced 2026-05-17 07:39:34 +00:00
fix Cross-file FFI exports silently disappear from bindings. genBindings() only sees procs registered in modules that were imported transitively before its call. A downstream
user who adds {.ffi.} in a sub-module that isn't pulled into the root file gets a successful build with missing methods. The README warns about this, but there's no
compile-time diagnostic — the registry could at least error if genBindings() is called and the count looks suspicious, or expose a way to assert "I expect N exports."
This commit is contained in:
parent
b598255f74
commit
e6c09d25b1
@ -70,7 +70,10 @@ proc nimtimerComplex*(
|
||||
# the compiler processes the AST. genBindings() reads those registries to emit
|
||||
# the binding files, so placing it any earlier would produce incomplete output.
|
||||
# In a multi-file library, import all sub-modules first and call genBindings()
|
||||
# once, at the bottom of the top-level compilation-root file.
|
||||
# once, at the bottom of the top-level compilation-root file. For multi-file
|
||||
# libraries it's strongly recommended to pin `expectedExports = N`: a sub-
|
||||
# module that isn't imported here would silently disappear from the bindings,
|
||||
# and the pin turns that into a loud compile error.
|
||||
# This call is a no-op unless -d:ffiGenBindings is passed to the compiler.
|
||||
genBindings() # reads -d:ffiOutputDir, -d:ffiNimSrcRelPath, -d:targetLang from compile flags
|
||||
|
||||
|
||||
@ -1605,6 +1605,7 @@ macro genBindings*(
|
||||
outputDir: static[string] = ffiOutputDir,
|
||||
nimSrcRelPath: static[string] = ffiNimSrcRelPath,
|
||||
nimBuildFlags: static[string] = ffiNimBuildFlags,
|
||||
expectedExports: static[int] = -1,
|
||||
): untyped =
|
||||
## Emits C++ or Rust binding files from the compile-time FFI registries.
|
||||
##
|
||||
@ -1622,6 +1623,14 @@ macro genBindings*(
|
||||
## -d:ffiNimSrcRelPath, or can be passed as explicit arguments.
|
||||
## This macro is a no-op unless -d:ffiGenBindings is set.
|
||||
##
|
||||
## expectedExports: optional pin on the number of registered procs. The
|
||||
## generator can only see {.ffi.} / {.ffiCtor.} annotations from modules
|
||||
## the compilation root has *imported* by the time genBindings is called;
|
||||
## a sub-module that isn't pulled in produces silently-incomplete bindings.
|
||||
## Set this to your known export count and the macro fails loudly when the
|
||||
## tally drifts (typical cause: a new export landed in an unimported file).
|
||||
## Default -1 disables the pin (only the zero-procs sanity check applies).
|
||||
##
|
||||
## Example (all via compile flags):
|
||||
## genBindings()
|
||||
## # nim c -d:ffiGenBindings -d:targetLang=rust \
|
||||
@ -1641,6 +1650,23 @@ macro genBindings*(
|
||||
" registered. The library name cannot be safely derived from proc names" &
|
||||
" (e.g. \"nim_timer_create\" is ambiguous between \"nim\" and \"nim_timer\")."
|
||||
)
|
||||
if ffiProcRegistry.len == 0:
|
||||
error(
|
||||
"genBindings: zero {.ffi.} / {.ffiCtor.} procs registered. The most" &
|
||||
" common cause is calling genBindings() from a file that hasn't" &
|
||||
" imported the modules that declare the exports -- the registry only" &
|
||||
" sees annotations from code the compilation root has transitively" &
|
||||
" imported. Move the call to the root file, or import the relevant" &
|
||||
" sub-modules above it."
|
||||
)
|
||||
if expectedExports >= 0 and ffiProcRegistry.len != expectedExports:
|
||||
error(
|
||||
"genBindings: expected " & $expectedExports & " FFI export(s), found " &
|
||||
$ffiProcRegistry.len & ". A {.ffi.} / {.ffiCtor.} annotation may have" &
|
||||
" landed in a module the compilation root doesn't import (silently" &
|
||||
" omitted), or the expectedExports pin is stale. Update the pin or" &
|
||||
" add the missing import."
|
||||
)
|
||||
let lang = targetLang.toLowerAscii()
|
||||
let libName = deriveLibName(ffiProcRegistry)
|
||||
case lang
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user