I’m trying to write a macro that takes a function, creates a wrapper for it, passes the wrapper to @cfunction
and finally passes the function pointer to an external C library.
To further clarify the use-case here: I want to create a type-stable wrapper of the function and pass this to the C-Library. The wrapper should extract the arguments from a C pointer and then call the function, all without runtime dispatch.
I tried several things, that dont work, see below.
My question:
How can this could be done? Is this even possible?
Approach 1: Defining wrapper and passing to @cfunction
.
macro _test_macro_func_wrapped_1(func)
func_esc = esc(func) # must be escaped, because macro lives in package
quote
wrapped = function ()
println("Execute Wrapper")
r = $func_esc()
return println("Execute Wrapper result: ", r)
end
wrapped() # works
# ERROR HERE - "wrapped" not defined
ptr = @cfunction(wrapped, Cvoid, ())
@info "Function ptr:" ptr
ptr
end
end
Approach 2:
Try to avoid macro hygiene (but not working)
macro _test_macro_func_wrapped_2(func)
func_esc = esc(func) # escape the function
wrapper_name = :wrapper
println("Wrapper name: ", wrapper_name)
quote
# Try to avoid auto generated name, but somehow its still generated
function ($wrapper_name)()
println("Execute Wrapper")
r = $func_esc(10)
return println("Execute Wrapper result: ", r)
end
($wrapper_name)() # works
$wrapper_name # works
@info "Method:" $wrapper_name # Works
# ERROR HERE: "wrapper" not defined in Main (but also not in the package)
ptr = @cfunction($wrapper_name, Cvoid, ())
@info "Function ptr:" ptr
ptr
end
end
Approach 3:
Avoid macro hygiene and force definition of the wrapper via eval
. But fails, because of an “syntax error” if esc()
is used, or if esc()
is not used, then the outer function cannot be referenced.
macro _test_macro_func_wrapped_3(func)
func_esc = esc(func) # escape the function
wrapper_name = :wrapper
package_name = @__MODULE__
package_wrapper_expr = Expr(:., package_name, :(:wrapper))
println("Wrapper name: ", wrapper_name)
println("Package wrapper expr: ", package_wrapper_expr)
wrapper_def = quote
function ($wrapper_name)()
println("Execute Wrapper")
r = $(func)(10)
return println("Execute Wrapper result: ", r)
end
end
# ERROR here: LoadError: syntax: invalid syntax (escape (outerref my_scalar_function))
# or if esc() is ommited: UndefVarError: `my_scalar_function` not defined in `package`
eval(wrapper_def)
quote
($package_wrapper_expr)()
$package_wrapper_expr
@info "Method:" $package_wrapper_expr
ptr = @cfunction($package_wrapper_expr, Cvoid, ())
@info "Function ptr:" ptr
ptr
end
end