I finally wrote up a small utility to help working with initializer or declaration C/C++ macros. Many C/C++ projects provide these initializer macros for declaring variables. It's often possible to reverse engineer such C macros and is generally the solution. However sometimes this isn't feasible or requires too much effort.
This library provides a Nim macro that automates that process and ensures the proper static wrappers are used. Invoking C/C++ macros from Nim for declarations is annoying to implement. It requires using emit pragmas and static[T] types and some macro magic in the correct way. It's short but error prone.
Example:
import cdecl
proc CMacroDeclare*(name: CToken, size: static[int], otherName: CToken): array[size, int] {.
cdeclmacro: "C_MACRO_VARIABLE_DECLARER".}
CMacroDeclare(myVar, 128, someExternalCVariable) # creates myVar
As I run across more declaration type C macros I plan to add an API to handle them. Also, this is a first release so I expect there are cases that aren't properly handled. Still I've taken effort to make nice error messages for common mis-uses of the API. Issues / Bug reports / PRs welcome!
Updated the cdeclmacro macro to handle passing pragmas to the variable. This allows setting the global pragma on the Nim variable, which also emits the C code using "/VARSECTION/".
There's also the ability to define a wrapper that can pass arbitrary raw C strings. This uses the new CRawStr type.
Ok, I reworked the syntax and it covers all my use cases including single, multiple, or no variables. It also supports raw string literals or raw C string outputs.
I'm considering it basically stable except for bug fixes. Hopefully this helps other Nim users in the future with similar needs! It's already simpler for me, and nice to know the emit code is unit tested at least for the basics.
Example with some C macro that declares a variable that we want to use in Nim:
/* define example C Macro for testing */
#define C_DEFINE_VAR(NM, SZ) int32_t NM[SZ]
import cdecl
import cdecl/cdeclapi
export cdeclapi # this is needed clients to use the declared apis
proc CDefineVar*(name: CToken, size: static[int]) {.
cdeclmacro: "C_DEFINE_VAR", cdeclsVar(name -> array[size, int32]).}
Then users of the wrapper can use it like below to declare a stack local variable from C. Note that you need to be careful to make the lengths match, etc.
const cVarSz = 4
CDefineVar(myVar, cVarSz)
test "test myVar declaration":
let testVal = [1'i32,2,3,4]
myVar[0..3] = testVal
check myVar.len() == cVarSz
echo "myVar: ", repr myVar
let res = myVar == testVal
check res
Globals can be created by adding global to the pragmas cdeclmacro list.