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))