Yes, you can do this. You need to store proc address somewhere and it's args in simple case.
Essentially, you need to wrap this code into nice macro: proc testProc(abc: int, bca: int) {.cdecl.} = echo "testProc: ", abc, ", ", bca var testProcAddr = cast[pointer](testProc) var testProcCall = cast[proc(a: int, b: int) {.cdecl.}](testProcAddr) testProcCall(6, 7) I created this sample macro for you. This isn't ideal, actually this is pretty crappy but you get an idea how it works. Code doesn't support any argument types other than int and requires cdecl calling convention. callProc proc is actually should be generated by macro. import macros, strutils type ProcInfo = ref object name: string procAddr: pointer args: seq[string] # callConv: int var procInfos: seq[ProcInfo] = @[] proc anotherTestProc(abc: int) {.cdecl.} = echo "anotherTestProc: ", abc proc testProc(abc: int, bca: int) {.cdecl.} = echo "testProc: ", abc, ", ", bca macro registerProc(p: typed): typed = let impl = getImpl(p.symbol) #echo impl.treeRepr var xprocName = impl[0].symbol.`$` var xprocArgs: seq[string] = @[] for formalParam in impl.findChild(it.kind == nnkFormalParams): if formalParam.kind != nnkIdentDefs: continue var argSym = formalParam[1] xprocArgs.add(argSym.symbol.`$`) result = parseStmt(""" block: var prcInfo = new(ProcInfo) prcInfo.name = "$1" prcInfo.args = @$2 prcInfo.procAddr = cast[pointer]($3) procInfos.add(prcInfo) """ % [xprocName, xProcArgs.repr, xprocName]) #echo result.treeRepr proc findProcInfo(procName: string, argCount: int): ProcInfo = for procInfo in procInfos: if procInfo.name == procName and procInfo.args.len == argCount: return procInfo return nil proc callProc(procName: string, args: varargs[int]) = var p = findProcInfo(procName, args.len) assert(p != nil) case args.len: of 0: var procToCall = cast[proc() {.cdecl.}](p.procAddr) procToCall() of 1: var procToCall = cast[proc(a: int) {.cdecl.}](p.procAddr) procToCall(args[0]) of 2: var procToCall = cast[proc(a: int, b: int) {.cdecl.}](p.procAddr) procToCall(args[0], args[1]) else: discard registerProc(testProc) registerProc(anotherTestProc) callProc("testProc", 123, 321) callProc("anotherTestProc", 666)