Clang.jl doesn't work for netmap (problem #ifdefs)

,

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!

Have you been able to finish this project ?