In my game I'm using {.emit.} to achieve some things that are currently difficult in Nim.
Unfortunately, {.emit.}'d variables are awkward... When using {.importc.} to bring them back into Nim:
Here's a minimal example:
# mymodule.nim
{.emit:"""
const char* foo = "Hello world!";
""".}
var foo* {.importc.}: cstring
# main.nim
import mymodule
echo foo
Result:
/home/exelotl/nim/test/emit/nimcache/@mmymodule.nim.c:35:17: error: conflicting types for ‘foo’
35 | extern NCSTRING foo;
| ^~~
/home/exelotl/nim/test/emit/nimcache/@mmymodule.nim.c:31:13: note: previous definition of ‘foo’ was here
31 | const char* foo = "Hello world!";
| ^~~
If we edit the declaration of foo:
var foo* {.importc, nodecl.}: cstring
Result:
/home/exelotl/nim/test/emit/nimcache/@mmain.nim.c: In function ‘NimMainModule’:
/home/exelotl/nim/test/emit/nimcache/@mmain.nim.c:152:24: error: ‘foo’ undeclared (first use in this function)
152 | T1_[0] = cstrToNimstr(foo);
| ^~~
Workaround:
Use {.nodecl.} and then {.importc.} the variable in every place where it's used.
# main.nim
import mymodule
var foo {.importc, nodecl.}: cstring
echo foo
This is what I'm doing now... It's not ideal, but it works.
Does anybody know a solution that would allow me use an {.emit.}'d variable from another module without resorting to this?
What would that look like?
Is there a way to ensure different codegendecl output depending on whether the variable is being accessed in mymodule.nim or main.nim?
I've settled on the following solution of using a helper module which emits the symbol to be importc'd
(thanks to @clyybber for the idea!)
# main.nim
import mymodule
echo foo # Works!
import helper # Add helper to the build.
# mymodule.nim
# This module defines the data for foo:
{.emit:"""
const char foo_data[13] = "Hello world!";
""".}
# And it imports the pointer to foo, but the pointer itself is defined in the helper unit.
let foo* {.importc.}: cstring
# helper.nim
# This module defines the pointer to foo.
# It only needs to be added to the build.
{.emit:"""
extern const char foo_data[13];
const char * const foo = &foo;
""".}