There is a possible bug/problem with Clang.jl. I am an assistant prof working on an implementation of netmap in Julia (fast networks by bypassing the kernel for IO).
Here is the example:
This works only if I remove any “#ifdefs” from the header file. Is this a known problem with Clang.jl?
using Clang
## we assume a working directory of "/tmp/st", where we execute the following script
## furthermore, we assume only 1 header file in that directory:
##
## "https://github.com/luigirizzo/netmap/blob/master/sys/net/netmap_user.h"
##
## Note that if you use the file "netmap_user.h" as is,
## several definitions are *NOT* generated as wrappers (e.g., "nm_desc" struct is missing, several functions)
## But if you delete all the "#ifdefs", the output is correct
##
## I have netmap installed on my machine, don't know if you need that to run this code
## (e.g., netmap_user.h includes netmap.h (which is part of the installation))
const LIBCLANG_INCLUDE = "/tmp/st" ## copy only the file "netmap_user.h" into this dir
const LIBCLANG_HEADERS = [joinpath(LIBCLANG_INCLUDE, header) for header in readdir(LIBCLANG_INCLUDE) if endswith(header, ".h")]
ctx = DefaultContext()
parse_headers!(ctx,
LIBCLANG_HEADERS,
args=["-I", joinpath(LIBCLANG_INCLUDE, "..")],
includes=vcat(LIBCLANG_INCLUDE, CLANG_INCLUDE),
)
ctx.libname = "libnetmap_user"
ctx.options["is_function_strictly_typed"] = false
ctx.options["is_struct_mutable"] = false
api_file = joinpath(@__DIR__, "libnetmap_user_api.jl")
api_stream = open(api_file, "w")
## NOTE: we have only on ".h" header file in "/tmp/st", so net line works(!)
trans_unit = first(ctx.trans_units)
root_cursor = getcursor(trans_unit)
push!(ctx.cursor_stack, root_cursor)
header = spelling(root_cursor)
@info "wrapping header: $header ..."
ctx.children = children(root_cursor)
for (i, child) in enumerate(ctx.children)
child_name = name(child)
child_header = filename(child)
ctx.children_index = i
startswith(child_name, "__") && continue # skip compiler definitions
child_name in keys(ctx.common_buffer) && continue # already wrapped
child_header != header && continue # skip if cursor filename is not in the headers to be wrapped
wrap!(ctx, child)
end
@info "writing $(api_file)"
println(api_stream, "# Julia wrapper for header: $(basename(header))")
println(api_stream, "# Automatically generated using Clang.jl\n")
print_buffer(api_stream, ctx.api_buffer)
empty!(ctx.api_buffer) # clean up api_buffer for the next header
close(api_stream)
common_file = joinpath(@__DIR__, "netmap_user_common.jl")
open(common_file, "w") do f
println(f, "# Automatically generated using Clang.jl\n")
print_buffer(f, dump_to_buffer(ctx.common_buffer))
end
## NOTE:
## The resulting files should be about this big:
## 2,4K Sep 10 08:55 libnetmap_user_api.jl
## 1,9K Sep 10 08:55 netmap_user_common.jl
## If you got smaller files, there might be a bug!