Skip to content

Commit 9b6ffe9

Browse files
committed
Adjust to new JSON ABI format
1 parent f82ddf5 commit 9b6ffe9

File tree

6 files changed

+372
-179
lines changed

6 files changed

+372
-179
lines changed

Project.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,12 @@ authors = ["Tim Holy <[email protected]> and contributors"]
55

66
[deps]
77
Graphs = "86223c79-3864-5bf0-83f7-82e725a168b6"
8+
JSON = "682c06a0-de6a-54ab-a142-c8b1cf79cde6"
89
OrderedCollections = "bac558e1-5e72-5ebc-8fee-abe8a469f55d"
910

1011
[compat]
1112
Graphs = "1"
13+
JSON = "0.21.4"
1214
OrderedCollections = "1.8.1"
1315
julia = "1.12"
1416

src/c.jl

Lines changed: 60 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ struct CProject
33
headerbase::String
44
end
55

6-
function wrapper(dest::CProject, entrypoints, typedescs)
6+
function wrapper(dest::CProject, entrypoints, typedescs, forwarddecls)
77
# Write the header file for C
88
headerfile = joinpath(dest.dir, dest.headerbase * ".h")
99
libvar = "JULIALIB_" * uppercase(dest.headerbase) * "_H"
@@ -15,14 +15,31 @@ function wrapper(dest::CProject, entrypoints, typedescs)
1515
println(f, "#include <stdbool.h>")
1616
println(f)
1717

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, ";")
18+
typedict = Dict{Int, String}()
19+
20+
# Print forward-declarations (if any, for recursive types)
21+
for id in forwarddecls
22+
type = typedescs[id]
23+
@assert type isa StructDesc "un-expected forward declaration type"
24+
mangled_name = mangle_c!(typedict, id, typedescs)
25+
println(f, "struct ", mangled_name, ";")
26+
end
27+
28+
# Print the struct definitions
29+
for (id, type) in pairs(typedescs)
30+
if type isa StructDesc
31+
mangled_name = mangle_c!(typedict, id, typedescs)
32+
println(f, "typedef struct ", mangled_name, " {")
33+
for field in type.fields
34+
ft = mangle_c!(typedict, field.type, typedescs)
35+
println(f, " ", ft, " ", sanitize_for_c(field.name), ";")
36+
end
37+
println(f, "} ", mangled_name, ";")
38+
elseif type isa PrimitiveTypeDesc
39+
# We only rely on built-in primitive types (c.f. `ctypes`)
40+
elseif type isa PointerDesc
41+
# We emit pointer types in-line - no need for a separate typedef
2442
end
25-
println(f, "} ", mangle_c!(typedict, type.name), ";")
2643
end
2744
println(f)
2845

@@ -31,16 +48,17 @@ function wrapper(dest::CProject, entrypoints, typedescs)
3148
if !isempty(args)
3249
args = ", " * args
3350
end
34-
print(f, mangle_c!(typedict, method.return_type), " ", method.name, "(")
51+
mangled_rt = mangle_c!(typedict, method.return_type, typedescs)
52+
print(f, mangled_rt, " ", method.symbol, "(")
3553
isfirst = true
3654
for arg in method.args
3755
if isfirst
3856
isfirst = false
3957
else
4058
print(f, ", ")
4159
end
42-
ft = mangle_c!(typedict, arg.type)
43-
print(f, ft, " ", arg.name)
60+
ft = mangle_c!(typedict, arg.type, typedescs)
61+
print(f, ft, " ", sanitize_for_c(arg.name))
4462
if arg.isva
4563
print(f, "...")
4664
end
@@ -63,7 +81,16 @@ const ctypes = Dict{String, String}(
6381
"UInt64" => "uint64_t",
6482
"Float32" => "float",
6583
"Float64" => "double",
66-
"Bool" => "_Bool",
84+
"Bool" => "bool",
85+
"RawFD" => "int",
86+
87+
"Cstring" => "char *",
88+
"Cwstring" => "wchar_t *",
89+
90+
# Note: These types will never appear in an auto-exported ABI, since they are not
91+
# distinct Julia types (these are just platform-specific aliases to the types above).
92+
"Cchar" => "char",
93+
"Cwchar_t" => "wchar_t",
6794
"Cvoid" => "void",
6895
"Cint" => "int",
6996
"Cshort" => "short",
@@ -73,38 +100,29 @@ const ctypes = Dict{String, String}(
73100
"Culong" => "unsigned long",
74101
"Cssize_t" => "ssize_t",
75102
"Csize_t" => "size_t",
76-
"Cchar" => "char",
77-
"Cwchar_t" => "wchar_t",
78-
"Cstring" => "char *",
79-
"Cwstring" => "wchar_t *",
80-
"RawFD" => "int",
81103
)
82104

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
105+
function sanitize_for_c(str::AbstractString)
106+
# Replace any non alphanumeric characters with '_'
107+
return replace(str, r"[^a-zA-Z0-9_]" => "_")
108+
end
109+
110+
function mangle_c!(typedict::Dict{Int, String}, type_id::Int, typedescs::OrderedDict{Int,TypeDesc})
111+
if type_id in keys(typedict)
112+
return typedict[type_id]
98113
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
114+
115+
type = typedescs[type_id]
116+
if type isa PrimitiveTypeDesc
117+
if !in(type.name, keys(ctypes))
118+
error("unsupported primitive type: '$(type.name)'")
119+
end
120+
return ctypes[type.name]
121+
elseif type isa PointerDesc
122+
mangled = mangle_c!(typedict, type.pointee_type, typedescs) * "*"
123+
elseif type isa StructDesc
124+
mangled = sanitize_for_c(type.name)
107125
end
108-
typedict[type] = type
109-
return type
126+
typedict[type_id] = mangled
127+
return mangled
110128
end

0 commit comments

Comments
 (0)