Skip to content
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
ebb3ded
juliac: log entrypoints and nonstandard typedefs
timholy Jul 27, 2025
1099753
minor Makefile improvements
timholy Jul 27, 2025
e90786b
Nicer printing
timholy Jul 28, 2025
ce0f007
Use IdSet instead of Union
timholy Jul 29, 2025
334f613
Try using the library
timholy Jul 29, 2025
612350a
Remove Array from C-friendly types
timholy Jul 30, 2025
c2dffaf
Get the shared library working
timholy Jul 30, 2025
ff8931c
Clean up after trimming tests
timholy Jul 30, 2025
52878f3
Update to JuliaLibWrapping .h file
timholy Jul 30, 2025
106868a
Split `write_logfile` into separate function
timholy Jul 30, 2025
cb068c2
Update contrib/juliac/juliac-buildscript.jl
timholy Jul 31, 2025
c0e1c3e
Export ABI metadata in JSON format
topolarity Aug 1, 2025
a1b8349
Move ABI export functionality to `abi_export.jl`
topolarity Aug 1, 2025
0a744d6
Print field / argument info more compactly
topolarity Aug 1, 2025
e1d3052
Add `--export-abi` arg to `juliac.jl`
topolarity Aug 1, 2025
d51511a
Add extra metadata for `primitive` types
topolarity Aug 1, 2025
76057d4
Minor fix-up for makefile paths
topolarity Aug 4, 2025
f5ffa0c
Merge remote-tracking branch 'julialang/master' into teh/juliac_heade…
topolarity Aug 4, 2025
0c38e91
Update header file to latest from `JuliaLibWrapping.jl`
topolarity Aug 4, 2025
6fd68ec
Adjust to `Core.MethodTable` -> `Core.methodtable`
topolarity Aug 4, 2025
77b1916
Minor fix-up for makefile paths
topolarity Aug 4, 2025
c8a0c0b
Update `test/trimming/trimming.jl` for JSON ABI format
topolarity Aug 4, 2025
af8e042
Rename `type` to `type_id`
topolarity Aug 19, 2025
6161dab
Add recursive type tests
topolarity Aug 19, 2025
cb503ee
Update contrib/juliac/abi_export.jl
timholy Aug 31, 2025
93a0557
Add isptr and isfieldatomic
timholy Aug 31, 2025
d9ea0eb
Merge branch 'master' into teh/juliac_headerlogs
timholy Aug 31, 2025
be561b7
Fix spacing
timholy Aug 31, 2025
7adc37b
Debug tests
timholy Aug 31, 2025
53b84e6
Remove project
timholy Aug 31, 2025
4dfc45b
Remove module qualification
timholy Sep 1, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 61 additions & 0 deletions contrib/juliac/juliac-buildscript.jl
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,30 @@ if Base.JLOptions().trim != 0
include(joinpath(@__DIR__, "juliac-trim-base.jl"))
end

const C_friendly_types = Union{ # a few of these are redundant to make it easier to maintain
Int8, Int16, Int32, Int64, UInt8, UInt16, UInt32, UInt64, Float32, Float64, Bool,
Cvoid, Cint, Cshort, Clong, Cuint, Cushort, Culong, Cssize_t, Csize_t,
Cchar, Cwchar_t, Cstring, Cwstring,
RawFD,
}

function is_c_friendly(@nospecialize(T::DataType))
T <: Ptr && return is_c_friendly(T.parameters[1])
return T <: C_friendly_types
end

function recursively_add_types!(types::Base.IdSet{DataType}, @nospecialize(T::DataType))
if !is_c_friendly(T)
T.name.module === Core && error("invalid type for juliac: ", T) # exclude internals (they may change)
push!(types, T)
end
for list in (T.parameters, fieldtypes(T))
for S in list
recursively_add_types!(types, S)
end
end
end

# Load user code

import Base.Experimental.entrypoint
Expand Down Expand Up @@ -73,6 +97,43 @@ let mod = Base.include(Main, ARGS[1])
if ARGS[3] == "true"
ccall(:jl_add_ccallable_entrypoints, Cvoid, ())
end

# Export info about entrypoints and structs needed to create header files
if length(ARGS) >= 4
logfile = ARGS[4]
iotmp = IOBuffer()
open(logfile, "w") do io
types = Base.IdSet{DataType}()
Base.visit(Core.GlobalMethods) do method
if isdefined(method, :ccallable)
rt, sig = method.ccallable
name = length(method.ccallable) > 2 ? Symbol(method.ccallable[3]) : method.name
print(IOContext(iotmp, :print_method_signature_only => true), method)
methodstr = String(take!(iotmp))
if name !== method.name
methodstr = replace(methodstr, String(method.name) => String(name))
end
println(io, methodstr, "::", rt)
for T in sig.parameters[2:end]
recursively_add_types!(types, T)
end
end
end
println(io) # blank line separates methods from types
for T in types
println(io, T)
dtfd = Base.DataTypeFieldDesc(T)
local fd
for i = 1:Base.datatype_nfields(T)
fd = dtfd[i]
fn = fieldname(T, i)
ft = fieldtype(T, i)
println(io, " ", fn, "::", ft, "[", fd.offset, "]")
end
println(io, fd.offset + fd.size, " bytes")
end
end
end
end

if Base.JLOptions().trim != 0
Expand Down
9 changes: 6 additions & 3 deletions test/trimming/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ JULIAC_BUILDSCRIPT := $(shell $(JULIA) -e 'print(joinpath(Sys.BINDIR, Base.DATAR

#=============================================================================

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

$(BIN)/hello-o.a: $(SRCDIR)/hello.jl $(JULIAC_BUILDSCRIPT)
$(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
Expand All @@ -42,17 +42,20 @@ $(BIN)/basic_jll-o.a: $(SRCDIR)/basic_jll.jl $(JULIAC_BUILDSCRIPT)
$(JULIA) -t 1 -J $(JULIA_LIBDIR)/julia/sys.$(SHLIB_EXT) --startup-file=no --history-file=no --project=$(SRCDIR) -e "using Pkg; Pkg.instantiate()"
$(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)/simplelib-o.a: $(SRCDIR)/simplelib.jl $(JULIAC_BUILDSCRIPT)
$(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

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

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

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

clean:
-rm -f $(BIN)/hello$(EXE) $(BIN)/basic_jll$(EXE) $(BIN)/hello-o.a $(BIN)/basic_jll-o.a
-rm -f $(BIN)/hello$(EXE) $(BIN)/basic_jll$(EXE) $(BIN)/hello-o.a $(BIN)/basic_jll-o.a $(BIN)/simplelib-o.a $(BIN)/bindinginfo_simplelib.log

.PHONY: release clean check

Expand Down
28 changes: 28 additions & 0 deletions test/trimming/simplelib.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
module SimpleLib
# Test the logging of entrypoints and types in a C-callable Julia library.

struct CVector{T}
length::Cint
data::Ptr{T}
end

struct CVectorPair{T}
from::CVector{T}
to::CVector{T}
end

Base.@ccallable "copyto_and_sum" function badname(fromto::CVectorPair{Float32})::Float32
from, to = unsafe_wrap(Array, fromto.from.data, fromto.from.length), unsafe_wrap(Array, fromto.to.data, fromto.to.length)
copyto!(to, from)
return sum(to)
end

# FIXME? varargs
# Base.@ccallable function printints(x::Cint...)::Nothing
# for i in 1:length(x)
# print(x[i], " ")
# end
# println()
# end

end
25 changes: 25 additions & 0 deletions test/trimming/trimming.jl
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,29 @@ let exe_suffix = splitext(Base.julia_exename())[2]
@test lines[2] == lines[3]
@test Base.VersionNumber(lines[2]) ≥ v"1.5.7"
@test filesize(basic_jll_exe) < filesize(unsafe_string(Base.JLOptions().image_file))/10

str = read(joinpath(bindir, "bindinginfo_simplelib.log"), String)
@test occursin("copyto_and_sum(fromto::CVectorPair{Float32})::Float32", str)
@test occursin(
"""
CVector{Float32}
length::Int32[0]
data::Ptr{Float32}[8]
16 bytes""", str
)
@test occursin(
"""
CVectorPair{Float32}
from::CVector{Float32}[0]
to::CVector{Float32}[16]
32 bytes""", str
)
# ensure that there is a blank line between methods and types
lines = split(str, '\n'; keepempty=true)
nblanks = 0
for line in lines
nblanks += isempty(line)
occursin("length", line) && break
end
@test nblanks == 1
end