Skip to content

Commit ebb3ded

Browse files
committed
juliac: log entrypoints and nonstandard typedefs
To facilitate creating bindings for other programming languages, this adds logging to the `juliac` buildscript, optionally outputting a logfile that describes the entrypoints (signatures and return types) and nonstandard typedefs that appear in the entrypoint specifications.
1 parent 2afae11 commit ebb3ded

File tree

4 files changed

+108
-5
lines changed

4 files changed

+108
-5
lines changed

contrib/juliac/juliac-buildscript.jl

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,37 @@ if Base.JLOptions().trim != 0
2727
include(joinpath(@__DIR__, "juliac-trim-base.jl"))
2828
end
2929

30+
const C_friendly_types = Union{ # a few of these are redundant to make it easier to maintain
31+
Int8, Int16, Int32, Int64, UInt8, UInt16, UInt32, UInt64, Float32, Float64, Bool,
32+
Cvoid, Cint, Cshort, Clong, Cuint, Cushort, Culong, Cssize_t, Csize_t,
33+
Cchar, Cwchar_t, Cstring, Cwstring,
34+
RawFD,
35+
}
36+
37+
function is_c_friendly(@nospecialize(T::DataType))
38+
T <: Ptr && return is_c_friendly(T.parameters[1])
39+
return T <: C_friendly_types
40+
end
41+
42+
function recursively_add_types!(types::Base.IdSet{DataType}, @nospecialize(T::DataType))
43+
if !is_c_friendly(T)
44+
T.name.module === Core && error("invalid type for juliac: ", T) # exclude internals (they may change)
45+
push!(types, T)
46+
end
47+
for list in (T.parameters, fieldtypes(T))
48+
for S in list
49+
recursively_add_types!(types, S)
50+
end
51+
end
52+
end
53+
54+
function mangle_name(@nospecialize(T::DataType))
55+
is_c_friendly(T) && return string(T)
56+
pname = isempty(T.parameters) ? String(nameof(T)) :
57+
join(pushfirst!(map(mangle_name, T.parameters), String(nameof(T)), "_"))
58+
return "_" * pname * "_"
59+
end
60+
3061
# Load user code
3162

3263
import Base.Experimental.entrypoint
@@ -73,6 +104,38 @@ let mod = Base.include(Main, ARGS[1])
73104
if ARGS[3] == "true"
74105
ccall(:jl_add_ccallable_entrypoints, Cvoid, ())
75106
end
107+
108+
# Export info about entrypoints and structs needed to create header files
109+
if length(ARGS) >= 4
110+
logfile = ARGS[4]
111+
open(logfile, "w") do io
112+
types = Base.IdSet{DataType}()
113+
Base.visit(Core.GlobalMethods) do method
114+
if isdefined(method, :ccallable)
115+
rt, sig = method.ccallable
116+
name = length(method.ccallable) > 2 ? Symbol(method.ccallable[3]) : method.name
117+
Base.show_tuple_as_call(io, name, sig)
118+
println(io, "::", rt)
119+
for T in sig.parameters[2:end]
120+
recursively_add_types!(types, T)
121+
end
122+
end
123+
end
124+
println(io)
125+
for T in types
126+
println(io, mangle_name(T))
127+
dtfd = Base.DataTypeFieldDesc(T)
128+
local fd
129+
for i = 1:Base.datatype_nfields(T)
130+
fd = dtfd[i]
131+
fn = fieldname(T, i)
132+
ft = fieldtype(T, i)
133+
println(io, " ", fn, "::", mangle_name(ft), "[", fd.offset, "]")
134+
end
135+
println(io, fd.offset + fd.size, " bytes")
136+
end
137+
end
138+
end
76139
end
77140

78141
if Base.JLOptions().trim != 0

test/trimming/Makefile

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -33,26 +33,29 @@ JULIAC_BUILDSCRIPT := $(shell $(JULIA) -e 'print(joinpath(Sys.BINDIR, Base.DATAR
3333

3434
#=============================================================================
3535

36-
release: $(BIN)/hello$(EXE) $(BIN)/basic_jll$(EXE)
36+
release: $(BIN)/hello$(EXE) $(BIN)/basic_jll$(EXE) $(BIN)/simplelib-o.a
3737

3838
$(BIN)/hello-o.a: $(SRCDIR)/hello.jl $(JULIAC_BUILDSCRIPT)
39-
$(JULIA) -t 1 -J $(JULIA_LIBDIR)/julia/sys.$(SHLIB_EXT) --startup-file=no --history-file=no --output-o $@ --output-incremental=no --strip-ir --strip-metadata --experimental --trim $(JULIAC_BUILDSCRIPT) $< --output-exe true
39+
$(JULIA) -t 1 -J $(JULIA_LIBDIR)/julia/sys.$(SHLIB_EXT) --startup-file=no --history-file=no --output-o $@ --output-incremental=no --strip-ir --strip-metadata --experimental --trim $(JULIAC_BUILDSCRIPT) $< --output-exe true $(BIN)/bindinginfo_hello.log
4040

4141
$(BIN)/basic_jll-o.a: $(SRCDIR)/basic_jll.jl $(JULIAC_BUILDSCRIPT)
4242
$(JULIA) -t 1 -J $(JULIA_LIBDIR)/julia/sys.$(SHLIB_EXT) --startup-file=no --history-file=no --project=$(SRCDIR) -e "using Pkg; Pkg.instantiate()"
43-
$(JULIA) -t 1 -J $(JULIA_LIBDIR)/julia/sys.$(SHLIB_EXT) --startup-file=no --history-file=no --project=$(SRCDIR) --output-o $@ --output-incremental=no --strip-ir --strip-metadata --experimental --trim $(JULIAC_BUILDSCRIPT) $< --output-exe true
43+
$(JULIA) -t 1 -J $(JULIA_LIBDIR)/julia/sys.$(SHLIB_EXT) --startup-file=no --history-file=no --project=$(SRCDIR) --output-o $@ --output-incremental=no --strip-ir --strip-metadata --experimental --trim $(JULIAC_BUILDSCRIPT) $< --output-exe true $(BIN)/bindinginfo_basic_jll.log
44+
45+
$(BIN)/simplelib-o.a: $(SRCDIR)/simplelib.jl $(JULIAC_BUILDSCRIPT)
46+
$(JULIA) -t 1 -J $(JULIA_LIBDIR)/julia/sys.$(SHLIB_EXT) --startup-file=no --history-file=no --output-o $@ --output-incremental=no --strip-ir --strip-metadata --experimental --trim $(JULIAC_BUILDSCRIPT) $< --output-lib true $(BIN)/bindinginfo_simplelib.log
4447

4548
$(BIN)/hello$(EXE): $(BIN)/hello-o.a
4649
$(CC) -o $@ $(WHOLE_ARCHIVE) $< $(NO_WHOLE_ARCHIVE) $(CPPFLAGS_ADD) $(CPPFLAGS) $(CFLAGS_ADD) $(CFLAGS) $(LDFLAGS_ADD) $(LDFLAGS)
4750

4851
$(BIN)/basic_jll$(EXE): $(BIN)/basic_jll-o.a
4952
$(CC) -o $@ $(WHOLE_ARCHIVE) $< $(NO_WHOLE_ARCHIVE) $(CPPFLAGS_ADD) $(CPPFLAGS) $(CFLAGS_ADD) $(CFLAGS) $(LDFLAGS_ADD) $(LDFLAGS)
5053

51-
check: $(BIN)/hello$(EXE) $(BIN)/basic_jll$(EXE)
54+
check: $(BIN)/hello$(EXE) $(BIN)/basic_jll$(EXE) $(BIN)/simplelib-o.a
5255
$(JULIA) --depwarn=error $(SRCDIR)/trimming.jl $<
5356

5457
clean:
55-
-rm -f $(BIN)/hello$(EXE) $(BIN)/basic_jll$(EXE) $(BIN)/hello-o.a $(BIN)/basic_jll-o.a
58+
-rm -f $(BIN)/hello$(EXE) $(BIN)/basic_jll$(EXE) $(BIN)/hello-o.a $(BIN)/basic_jll-o.a $(BIN)/simplelib-o.a
5659

5760
.PHONY: release clean check
5861

test/trimming/simplelib.jl

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
module SimpleLib
2+
# Test the logging of entrypoints and types in a C-callable Julia library.
3+
4+
struct CVector{T}
5+
length::Cint
6+
data::Ptr{T}
7+
end
8+
9+
struct CVectorPair{T}
10+
from::CVector{T}
11+
to::CVector{T}
12+
end
13+
14+
Base.@ccallable function copyto_and_sum(fromto::CVectorPair{Float32})::Float32
15+
from, to = unsafe_wrap(Array, fromto.from.data, fromto.from.length), unsafe_wrap(Array, fromto.to.data, fromto.to.length)
16+
copyto!(to, from)
17+
return sum(to)
18+
end
19+
20+
end

test/trimming/trimming.jl

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,21 @@ let exe_suffix = splitext(Base.julia_exename())[2]
1515
@test lines[2] == lines[3]
1616
@test Base.VersionNumber(lines[2]) v"1.5.7"
1717
@test filesize(basic_jll_exe) < filesize(unsafe_string(Base.JLOptions().image_file))/10
18+
19+
str = read(joinpath(bindir, "bindinginfo_simplelib.log"), String)
20+
@test occursin("copyto_and_sum(::CVectorPair{Float32})::Float32", str)
21+
@test occursin(
22+
"""
23+
_CVector_Float32_
24+
length::Int32[0]
25+
data::Ptr{Float32}[8]
26+
16 bytes""", str
27+
)
28+
@test occursin(
29+
"""
30+
_CVectorPair_Float32_
31+
from::_CVector_Float32_[0]
32+
to::_CVector_Float32_[16]
33+
32 bytes""", str
34+
)
1835
end

0 commit comments

Comments
 (0)