mirror of
https://github.com/logos-messaging/nim-ffi.git
synced 2026-05-16 23:29:59 +00:00
fix Hardcoded Nim build flags in generated build files. build.rs and CMakeLists.txt both bake in --mm:orc and -d:chronicles_log_level=WARN (rust.nim:121–122, cpp.nim:463–464).
The whole point of a generic generator is decoupling — this couples every consumer of nim-ffi to one specific project's Nim build conventions. Plumb these through genBindings() parameters or a config block.
This commit is contained in:
parent
6920f22ab8
commit
1eb8f2bdf8
@ -11,6 +11,8 @@ requires "taskpools"
|
||||
requires "https://github.com/logos-messaging/nim-ffi >= 0.1.3"
|
||||
|
||||
const nimFlags = "--mm:orc -d:chronicles_log_level=WARN"
|
||||
# Flags baked into the generated build.rs / CMakeLists.txt -- see ffi.nimble.
|
||||
const genBakedFlags = "--mm:orc -d:chronicles_log_level=WARN"
|
||||
|
||||
task build, "Compile the nimtimer library":
|
||||
exec "nim c " & nimFlags &
|
||||
@ -19,9 +21,13 @@ task build, "Compile the nimtimer library":
|
||||
task genbindings_rust, "Generate Rust bindings for the nimtimer example":
|
||||
exec "nim c " & nimFlags & " --app:lib --noMain --nimMainPrefix:libnimtimer" &
|
||||
" -d:ffiGenBindings -d:targetLang=rust" & " -d:ffiOutputDir=rust_bindings" &
|
||||
" -d:ffiNimSrcRelPath=nim_timer.nim" & " -o:/dev/null nim_timer.nim"
|
||||
" -d:ffiNimSrcRelPath=nim_timer.nim" &
|
||||
" -d:ffiNimBuildFlags=\"" & genBakedFlags & "\"" &
|
||||
" -o:/dev/null nim_timer.nim"
|
||||
|
||||
task genbindings_cpp, "Generate C++ bindings for the nimtimer example":
|
||||
exec "nim c " & nimFlags & " --app:lib --noMain --nimMainPrefix:libnimtimer" &
|
||||
" -d:ffiGenBindings -d:targetLang=cpp" & " -d:ffiOutputDir=cpp_bindings" &
|
||||
" -d:ffiNimSrcRelPath=nim_timer.nim" & " -o:/dev/null nim_timer.nim"
|
||||
" -d:ffiNimSrcRelPath=nim_timer.nim" &
|
||||
" -d:ffiNimBuildFlags=\"" & genBakedFlags & "\"" &
|
||||
" -o:/dev/null nim_timer.nim"
|
||||
|
||||
10
ffi.nimble
10
ffi.nimble
@ -41,18 +41,26 @@ task genbindings_example, "Generate Rust bindings for the nim_timer example":
|
||||
exec "nim c " & nimFlagsOrc & " --app:lib --noMain --nimMainPrefix:libnimtimer -d:ffiGenBindings -o:/dev/null examples/nim_timer/nim_timer.nim"
|
||||
exec "nim c " & nimFlagsRefc & " --app:lib --noMain --nimMainPrefix:libnimtimer -d:ffiGenBindings -o:/dev/null examples/nim_timer/nim_timer.nim"
|
||||
|
||||
# Flags baked into the generated build.rs / CMakeLists.txt so downstream
|
||||
# consumers compile the Nim library with the same conventions this example
|
||||
# uses. Anything that should NOT be hardcoded into the published bindings
|
||||
# goes here, not in the generator.
|
||||
const genBakedFlags = "--mm:orc -d:chronicles_log_level=WARN"
|
||||
|
||||
task genbindings_rust, "Generate Rust bindings for the nim_timer example":
|
||||
exec "nim c " & nimFlagsOrc &
|
||||
" --app:lib --noMain --nimMainPrefix:libnimtimer" &
|
||||
" -d:ffiGenBindings -d:targetLang=rust" &
|
||||
" -d:ffiOutputDir=examples/nim_timer/rust_bindings" &
|
||||
" -d:ffiNimSrcRelPath=../nim_timer.nim" &
|
||||
" -d:ffiNimBuildFlags=\"" & genBakedFlags & "\"" &
|
||||
" -o:/dev/null examples/nim_timer/nim_timer.nim"
|
||||
exec "nim c " & nimFlagsRefc &
|
||||
" --app:lib --noMain --nimMainPrefix:libnimtimer" &
|
||||
" -d:ffiGenBindings -d:targetLang=rust" &
|
||||
" -d:ffiOutputDir=examples/nim_timer/rust_bindings" &
|
||||
" -d:ffiNimSrcRelPath=../nim_timer.nim" &
|
||||
" -d:ffiNimBuildFlags=\"" & genBakedFlags & "\"" &
|
||||
" -o:/dev/null examples/nim_timer/nim_timer.nim"
|
||||
|
||||
task genbindings_cpp, "Generate C++ bindings for the nim_timer example":
|
||||
@ -61,10 +69,12 @@ task genbindings_cpp, "Generate C++ bindings for the nim_timer example":
|
||||
" -d:ffiGenBindings -d:targetLang=cpp" &
|
||||
" -d:ffiOutputDir=examples/nim_timer/cpp_bindings" &
|
||||
" -d:ffiNimSrcRelPath=../nim_timer.nim" &
|
||||
" -d:ffiNimBuildFlags=\"" & genBakedFlags & "\"" &
|
||||
" -o:/dev/null examples/nim_timer/nim_timer.nim"
|
||||
exec "nim c " & nimFlagsRefc &
|
||||
" --app:lib --noMain --nimMainPrefix:libnimtimer" &
|
||||
" -d:ffiGenBindings -d:targetLang=cpp" &
|
||||
" -d:ffiOutputDir=examples/nim_timer/cpp_bindings" &
|
||||
" -d:ffiNimSrcRelPath=../nim_timer.nim" &
|
||||
" -d:ffiNimBuildFlags=\"" & genBakedFlags & "\"" &
|
||||
" -o:/dev/null examples/nim_timer/nim_timer.nim"
|
||||
|
||||
@ -483,10 +483,15 @@ proc generateCppHeader*(
|
||||
|
||||
result = lines.join("\n")
|
||||
|
||||
proc generateCppCMakeLists*(libName: string, nimSrcRelPath: string): string =
|
||||
proc generateCppCMakeLists*(
|
||||
libName: string, nimSrcRelPath: string, nimBuildFlags: string = ""
|
||||
): string =
|
||||
## Generates CMakeLists.txt for the C++ bindings directory.
|
||||
## CMake uses ${...} which would clash with Nim's % format operator,
|
||||
## so we build the file line by line using string concatenation.
|
||||
## nimBuildFlags is a whitespace-separated string of extra `nim c` flags
|
||||
## injected after `nim c` and before the required --app:lib / --noMain /
|
||||
## --nimMainPrefix / -o: flags.
|
||||
let src = nimSrcRelPath.replace("\\", "/")
|
||||
let cv = "${CMAKE_CURRENT_SOURCE_DIR}" # CMake variable shorthand
|
||||
let rv = "${REPO_ROOT}"
|
||||
@ -554,8 +559,8 @@ proc generateCppCMakeLists*(libName: string, nimSrcRelPath: string): string =
|
||||
L.add("add_custom_command(")
|
||||
L.add(" OUTPUT \"" & lf & "\"")
|
||||
L.add(" COMMAND \"" & nm & "\" c")
|
||||
L.add(" --mm:orc")
|
||||
L.add(" -d:chronicles_log_level=WARN")
|
||||
for tok in nimBuildFlags.splitWhitespace():
|
||||
L.add(" " & tok)
|
||||
L.add(" --app:lib")
|
||||
L.add(" --noMain")
|
||||
L.add(" \"--nimMainPrefix:lib" & libName & "\"")
|
||||
@ -601,7 +606,11 @@ proc generateCppBindings*(
|
||||
libName: string,
|
||||
outputDir: string,
|
||||
nimSrcRelPath: string,
|
||||
nimBuildFlags: string = "",
|
||||
) =
|
||||
createDir(outputDir)
|
||||
writeFile(outputDir / (libName & ".hpp"), generateCppHeader(procs, types, libName))
|
||||
writeFile(outputDir / "CMakeLists.txt", generateCppCMakeLists(libName, nimSrcRelPath))
|
||||
writeFile(
|
||||
outputDir / "CMakeLists.txt",
|
||||
generateCppCMakeLists(libName, nimSrcRelPath, nimBuildFlags),
|
||||
)
|
||||
|
||||
@ -44,3 +44,11 @@ const ffiOutputDir* {.strdefine.} = ""
|
||||
# Nim source path (relative to outputDir) embedded in generated build files;
|
||||
# set with -d:ffiNimSrcRelPath=../relative/path.nim
|
||||
const ffiNimSrcRelPath* {.strdefine.} = ""
|
||||
|
||||
# Whitespace-separated extra Nim compiler flags to bake into the generated
|
||||
# build.rs / CMakeLists.txt for the project's own `nim c` invocation. The
|
||||
# generator emits only the strictly-required flags (--app:lib, --noMain,
|
||||
# --nimMainPrefix, -o:) by default; everything else (gc choice, log level,
|
||||
# project-specific -d defines, etc.) is up to the caller. Example:
|
||||
# -d:ffiNimBuildFlags="--mm:orc -d:chronicles_log_level=WARN"
|
||||
const ffiNimBuildFlags* {.strdefine.} = ""
|
||||
|
||||
@ -81,10 +81,27 @@ tokio = { version = "1", features = ["sync"] }
|
||||
""" %
|
||||
[libName]
|
||||
|
||||
proc generateBuildRs*(libName: string, nimSrcRelPath: string): string =
|
||||
proc rustEscapeStrLit(s: string): string =
|
||||
## Escapes a string for safe embedding in a Rust string literal.
|
||||
s.replace("\\", "\\\\").replace("\"", "\\\"")
|
||||
|
||||
proc generateBuildRs*(
|
||||
libName: string, nimSrcRelPath: string, nimBuildFlags: string = ""
|
||||
): string =
|
||||
## Generates build.rs that compiles the Nim library.
|
||||
## nimSrcRelPath is relative to the output (crate) directory.
|
||||
## nimBuildFlags is a whitespace-separated string of extra `nim c` flags
|
||||
## (e.g. "--mm:orc -d:chronicles_log_level=WARN") to inject into the
|
||||
## generated `nim c` invocation, after `nim c` and before the required
|
||||
## --app:lib / --noMain / --nimMainPrefix / -o: flags.
|
||||
let escapedSrc = nimSrcRelPath.replace("\\", "\\\\")
|
||||
# Build the leading section of the cmd.arg(...) chain: the mandatory
|
||||
# `.arg("c")` plus one `.arg("...")` per caller-supplied flag, each on its
|
||||
# own line. The template then reads as `cmd$3` -- $3 is the whole leading
|
||||
# chain, so no placeholder ever sits inside a method-call expression.
|
||||
var argChain = ".arg(\"c\")"
|
||||
for tok in nimBuildFlags.splitWhitespace():
|
||||
argChain.add("\n .arg(\"" & rustEscapeStrLit(tok) & "\")")
|
||||
result =
|
||||
"""use std::path::PathBuf;
|
||||
use std::process::Command;
|
||||
@ -123,9 +140,7 @@ fn main() {
|
||||
compile_error!("nim-ffi build.rs: unsupported target OS (expected macos, linux, or windows)");
|
||||
|
||||
let mut cmd = Command::new("nim");
|
||||
cmd.arg("c")
|
||||
.arg("--mm:orc")
|
||||
.arg("-d:chronicles_log_level=WARN")
|
||||
cmd$3
|
||||
.arg("--app:lib")
|
||||
.arg("--noMain")
|
||||
.arg(format!("--nimMainPrefix:lib$2"))
|
||||
@ -140,7 +155,7 @@ fn main() {
|
||||
println!("cargo:rerun-if-changed={}", nim_src.display());
|
||||
}
|
||||
""" %
|
||||
[escapedSrc, libName]
|
||||
[escapedSrc, libName, argChain]
|
||||
|
||||
proc generateLibRs*(): string =
|
||||
result = """mod ffi;
|
||||
@ -502,13 +517,17 @@ proc generateRustCrate*(
|
||||
libName: string,
|
||||
outputDir: string,
|
||||
nimSrcRelPath: string,
|
||||
nimBuildFlags: string = "",
|
||||
) =
|
||||
## Generates a complete Rust crate in outputDir.
|
||||
createDir(outputDir)
|
||||
createDir(outputDir / "src")
|
||||
|
||||
writeFile(outputDir / "Cargo.toml", generateCargoToml(libName))
|
||||
writeFile(outputDir / "build.rs", generateBuildRs(libName, nimSrcRelPath))
|
||||
writeFile(
|
||||
outputDir / "build.rs",
|
||||
generateBuildRs(libName, nimSrcRelPath, nimBuildFlags),
|
||||
)
|
||||
writeFile(outputDir / "src" / "lib.rs", generateLibRs())
|
||||
writeFile(outputDir / "src" / "ffi.rs", generateFfiRs(procs))
|
||||
writeFile(outputDir / "src" / "types.rs", generateTypesRs(types))
|
||||
|
||||
@ -1604,6 +1604,7 @@ macro ffiDtor*(prc: untyped): untyped =
|
||||
macro genBindings*(
|
||||
outputDir: static[string] = ffiOutputDir,
|
||||
nimSrcRelPath: static[string] = ffiNimSrcRelPath,
|
||||
nimBuildFlags: static[string] = ffiNimBuildFlags,
|
||||
): untyped =
|
||||
## Emits C++ or Rust binding files from the compile-time FFI registries.
|
||||
##
|
||||
@ -1638,11 +1639,13 @@ macro genBindings*(
|
||||
case lang
|
||||
of "rust":
|
||||
generateRustCrate(
|
||||
ffiProcRegistry, ffiTypeRegistry, libName, outputDir, nimSrcRelPath
|
||||
ffiProcRegistry, ffiTypeRegistry, libName, outputDir, nimSrcRelPath,
|
||||
nimBuildFlags,
|
||||
)
|
||||
of "cpp", "c++":
|
||||
generateCppBindings(
|
||||
ffiProcRegistry, ffiTypeRegistry, libName, outputDir, nimSrcRelPath
|
||||
ffiProcRegistry, ffiTypeRegistry, libName, outputDir, nimSrcRelPath,
|
||||
nimBuildFlags,
|
||||
)
|
||||
else:
|
||||
error("genBindings: unknown targetLang '" & lang & "'. Use 'rust' or 'cpp'.")
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user