Skip to content

Commit 06f44bf

Browse files
committed
Generate a .h file
1 parent 4811d62 commit 06f44bf

File tree

3 files changed

+138
-1
lines changed

3 files changed

+138
-1
lines changed

src/JuliaLibWrapping.jl

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,10 @@ module JuliaLibWrapping
33
using OrderedCollections
44
using Graphs
55

6-
export parselog
6+
export parselog, wrapper
7+
export CProject
78

89
include("parselog.jl")
10+
include("c.jl")
911

1012
end

src/c.jl

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
struct CProject
2+
dir::String
3+
headerbase::String
4+
end
5+
6+
function wrapper(dest::CProject, entrypoints, typedescs)
7+
# Write the header file for C
8+
headerfile = joinpath(dest.dir, dest.headerbase * ".h")
9+
libvar = "JULIALIB_" * uppercase(dest.headerbase) * "_H"
10+
open(headerfile, "w") do f
11+
println(f, "#ifndef $libvar")
12+
println(f, "#define $libvar")
13+
println(f, "#include <stddef.h>")
14+
println(f, "#include <stdint.h>")
15+
println(f, "#include <stdbool.h>")
16+
println(f)
17+
18+
typedict = Dict{String, String}()
19+
for type in values(typedescs)
20+
println(f, "typedef struct {")
21+
for field in type.fields
22+
ft = mangle_c!(typedict, field.type)
23+
println(f, " ", ft, " ", field.name, ";")
24+
end
25+
println(f, "} ", mangle_c!(typedict, type.name), ";")
26+
end
27+
println(f)
28+
29+
for method in entrypoints
30+
args = join(method.args, ", ")
31+
if !isempty(args)
32+
args = ", " * args
33+
end
34+
print(f, mangle_c!(typedict, method.return_type), " ", method.name, "(")
35+
isfirst = true
36+
for arg in method.args
37+
if isfirst
38+
isfirst = false
39+
else
40+
print(f, ", ")
41+
end
42+
ft = mangle_c!(typedict, arg.type)
43+
print(f, ft, " ", arg.name)
44+
if arg.isva
45+
print(f, "...")
46+
end
47+
end
48+
print(f, ");\n")
49+
end
50+
51+
println(f, "#endif // $libvar")
52+
end
53+
end
54+
55+
const ctypes = Dict{String, String}(
56+
"Int8" => "int8_t",
57+
"Int16" => "int16_t",
58+
"Int32" => "int32_t",
59+
"Int64" => "int64_t",
60+
"UInt8" => "uint8_t",
61+
"UInt16" => "uint16_t",
62+
"UInt32" => "uint32_t",
63+
"UInt64" => "uint64_t",
64+
"Float32" => "float",
65+
"Float64" => "double",
66+
"Bool" => "_Bool",
67+
"Cvoid" => "void",
68+
"Cint" => "int",
69+
"Cshort" => "short",
70+
"Clong" => "long",
71+
"Cuint" => "unsigned int",
72+
"Cushort" => "unsigned short",
73+
"Culong" => "unsigned long",
74+
"Cssize_t" => "ssize_t",
75+
"Csize_t" => "size_t",
76+
"Cchar" => "char",
77+
"Cwchar_t" => "wchar_t",
78+
"Cstring" => "char *",
79+
"Cwstring" => "wchar_t *",
80+
"RawFD" => "int",
81+
)
82+
83+
function mangle_c!(typedict::Dict{String, String}, type::AbstractString)
84+
ft = get(typedict, type, nothing)
85+
ft !== nothing && return ft
86+
ft = get(ctypes, type, nothing)
87+
ft !== nothing && return ft
88+
idxbad = findfirst(r"[^a-zA-Z0-9_\{\}]", type)
89+
if idxbad !== nothing
90+
error("Invalid type name: ", type, " (invalid character at position ", idxbad, ")")
91+
end
92+
m = match(r"^Ptr\{(.+)\}$", type)
93+
if m !== nothing
94+
inner_type = m.captures[1]
95+
result = mangle_c!(typedict, inner_type) * "*"
96+
typedict[type] = result
97+
return result
98+
end
99+
m = match(r"^(.+)\{(.+)\}$", type)
100+
if m !== nothing
101+
basename, params = m.captures
102+
params = split(params, ",")
103+
params = join(map(p -> mangle_c!(typedict, p), params), "_")
104+
result = basename * "_" * params * "_"
105+
typedict[type] = result
106+
return result
107+
end
108+
typedict[type] = type
109+
return type
110+
end

test/runtests.jl

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,4 +73,29 @@ end
7373
@test occursin("CVectorPair{Float32}(from::CVector{Float32}[0], to::CVector{Float32}[16]) (32 bytes)", str)
7474
@test occursin("CVector{Float32}(length::Int32[0], data::Ptr{Float32}[8]) (16 bytes)", str)
7575
end
76+
77+
@testset "C wrapper" begin
78+
mktempdir() do path
79+
mkpath(path)
80+
dest = CProject(path, "libsimple")
81+
entrypoints, typedescs = parselog("bindinginfo_libsimple.log")
82+
wrapper(dest, entrypoints, typedescs)
83+
84+
headerfile = joinpath(dest.dir, dest.headerbase * ".h")
85+
@test isfile(headerfile)
86+
content = read(headerfile, String)
87+
@test occursin("#ifndef JULIALIB_LIBSIMPLE_H", content)
88+
@test occursin("#define JULIALIB_LIBSIMPLE_H", content)
89+
@test occursin("#include <stddef.h>", content)
90+
@test occursin("#include <stdint.h>", content)
91+
@test occursin("#include <stdbool.h>", content)
92+
@test occursin("typedef struct {", content)
93+
@test occursin(" int32_t length;", content)
94+
@test occursin(" float* data;", content)
95+
@test occursin("CVector_float_ from;", content)
96+
@test occursin("CVector_float_ to;", content)
97+
@test occursin("float copyto_and_sum(CVectorPair_float_ fromto);", content)
98+
@test occursin("int32_t countsame(MyTwoVec* list, int32_t n);", content)
99+
end
100+
end
76101
end

0 commit comments

Comments
 (0)