Exporting (all) names from a module (Clang related)

I have the following:

module CLib

using CEnum

include("common.jl")
include("api.jl")


end

And naturally I want to automagically export everything that comes in from common and api.

Currently if i do

using CLib

Anything I try to use comes up as not defined.

I thought I would be able to figure this out looking at other C library interface module is Julia, but I can’t figure out how they are doing it. There doesn’t even seem to be an export statement to be found.

Can anyone shed a little light on exactly how this works ?

Thank you.

p.s. of course i could put in explicit export statements but there’s a LOT of names, so definitely looking for something to shortcut the process.

I prefer to add a submodule(e.g. LibClib) that exports everything using the following snippet:

module CLib
include("LibCLib")
using .LibCLib
end

In this way, for those who wanna everything being exported, they can just use using CLib.LibCLib, for those who don’t, they can use using CLib: xxx on demand.

1 Like

That looks like a nice solution.

I noticed that you are selecting base on a prefix string. What if the .h file that I am wrapping does not have a prefix of some sort, should I add a prefix to the symbols from the .h file of interest ?

Most C libraries has certain prefix to avoid function name collision. If the lib you’re wrapping dose not have one, you could use a rewriter to add a custom prefix:

function rewrite!(e::Expr)
    old_name = string(e.args[1].args[1])
    if e.head == :function
        e.args[1].args[1] = Symbol("prefix_"*old_name)
    end
    e
end
rewrite!(x) = x
rewrite(v::Vector) = map(rewrite!, v)

wc = init(; headers = [xxxx],
                  output_file = "api.jl",
                  common_file = "common.jl",
                  clang_includes = vcat(CLANG_INCLUDE),
                  clang_args = map(x->"-I"*x, find_std_headers()),
                  header_wrapped = (root, current)->root == current,
                  header_library = x->"xxxx",
                  clang_diagnostics = true,
                   rewriter=rewrite!,
)
run(wc)

Thanks very much again. The library i’m wrapping does not use prefixes. Also, I’m using Clang for the first time so examples like that are extremely helpful !

1 Like

I tried this code and it doesn’t seem to do any rewriting.

i put a debug print in the rewrite!(e::Expr) function and it is never invoked.

Any ideas ?

sorry, there is a typo here:

function rewrite!(e::Expr)
    old_name = string(e.args[1].args[1])
    if e.head == :function
        e.args[1].args[1] = Symbol("prefix_"*old_name)
    end
    e
end
rewrite!(x) = x
#shoule be `rewrite! `
rewrite!(v::Vector) = map(rewrite!, v)

wc = init(; headers = [xxxx],
                  output_file = "api.jl",
                  common_file = "common.jl",
                  clang_includes = vcat(CLANG_INCLUDE),
                  clang_args = map(x->"-I"*x, find_std_headers()),
                  header_wrapped = (root, current)->root == current,
                  header_library = x->"xxxx",
                  clang_diagnostics = true,
                   rewriter=rewrite!,
)
run(wc)

ty! i should have figured that out. when i was debugging i noticed that it was getting invoked on an array but didn’t make the connection.

Almost

===>

function rewrite!(e::Expr)
    if e.head == :function
        old_name = string(e.args[1].args[1])
        e.args[1].args[1] = Symbol("prefix_"*old_name)
    end
    e
end

I’m adding this question to the thread since it has to do with the use of rewrite in the example.

I have looked through all of the documentation for the Clang package and can’t find anything that talks about it.

I even looked through the git repo and could only find a use of it, but it wasn’t even obvious that it could be added to the clang context.

Is the documentation slightly out of date, or is this an undocumented feature ?

The reason I ask, is because I’m also looking for the thing that handles macrodefinitions, and I’m wondering if that might be handled by a similar function.

I have a macrodefinition and can’t find a way to intercept the macro definitions so that i can do the rewrite myself, since I know exactly how the macro needs to be handled.

It looks as though macro definitions are trapped very early on and possibly kept out of the processing stream.

Is my interpretation correct ?

Maybe i can define my own:

function wrap!(ctx::AbstractContext, cursor::CLMacroDefinition)

method to do the work ?

Thanks.

Yep. Clang.jl is just a thin wrapper over libclang-c API, you can build and use your own wrapper-generator, please refer to this doc for further details.

The old init-run function is for those users who don’t wanna dive into the details and the rewriter is a post-processing way to do some additional minor changes on the generated Julia code/expressions(it’s common Julia metaprogramming).

If you wanna handle some macro definitions earlier, it is right to import and overload this function: