Say you want to use glfw (an openGL wrapper) from Julia...
ccall (dlsym (glfw, :glfwInit ), Int, ())
That's okay with glfwInit
, but what about a more complex call:
ccall (dlsym (glfw, :glCall ), ReturnType,
(Type1, Type2, Type3),
arg1, arg2, arg3)
But that's not very nice... So you could wrap it in a function:
function glfwInit ()
ccall (dlsym (glfw, :glfwInit ), Int, ())
end
glfwInit ()
Except you have to define a lot of these functions...
function glCall (arg2:: Type1 , arg2:: Type2 , arg3:: Type3 )
ccall (dlsym (glfw, :glCall ), ReturnType,
(Type1, Type2, Type3),
arg1, arg2, arg3)
end
They all look relatively similar... Macro time!
macro ccallWrap (lib, fnSym, retType, argTypes)
argTypes = eval (argTypes)
assertOp = :(sym:: Type ). head
args = [gensym () for i in 1 : length (argTypes)]
fnArgs = [Expr (assertOp, {args[i], argTypes[i]}, Any)
for i in 1 : length (argTypes)]
dlsymExpr = Expr (:call , {:dlsym , lib, fnSym}, Any)
ccallExpr = Expr (:call ,{:ccall , dlsymExpr, retType, argTypes, args... },Any)
fnBody = Expr (:block , {ccallExpr}, Any)
fnCall = Expr (:call ,{eval (fnSym), fnArgs... }, Any)
ccallFn = Expr (:function , {fnCall, fnBody}, Any)
line1 = Expr (:line , {1 }, Any)
fnBlock = Expr (:block , {line1, Expr (:global , {eval (fnSym)}, Any), ccallFn}, Any)
fnBlock
end
@ccallWrap (glfw, :glCall , ReturnType, (Type1, Type2, Type3))