Repository: JuliaLang/julia
File: contrib/juliac/juliac-buildscript.jl (Julia)

Code before:
end

const C_friendly_types = Base.IdSet{Any}([    # 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 recursively_add_types!(types::Base.IdSet{DataType}, @nospecialize(T::DataType))
    if T ∉ C_friendly_types
        if T <: Ptr
            return recursively_add_types!(types, T.parameters[1])
        end
        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
    return types
end

function write_logfile(io::IO)
    iotmp = IOBuffer()
    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)

Review comment (suggestion):
My KISS instinct would be to use a standard serialization format like JSON to print out the type information

Also do we need the `offset` info? No problem with adding it so I'm mostly asking for understanding - IIUC the offsets should be implied by the C ABI on a particular platform

Code after:

# for use as C main if needed
function _main(argc::Cint, argv::Ptr{Ptr{Cchar}})::Cint
    args = ccall(:jl_set_ARGS, Any, (Cint, Ptr{Ptr{Cchar}}), argc, argv)::Vector{String}
    setglobal!(Base, :PROGRAM_FILE, args[1])
    popfirst!(args)
    append!(Base.ARGS, args)
    return Main.main(args)
end

let include_result = Base.include(Main, ARGS[1])
    Core.@latestworld
    if ARGS[2] == "--output-exe"
        have_cmain = false
        if isdefined(Main, :main)
            for m in methods(Main.main)
                if isdefined(m, :ccallable)
                    # TODO: possibly check signature and return type
                    have_cmain = true
                    break
                end
            end
        elseif include_result isa Module && isdefined(include_result, :main)
            error("""
                  The `main` function must be defined in `Main`. If you are defining it inside a
                  module, try adding `import .$(nameof(include_result)).main` to $(ARGS[1]).
                  """)
        end
        if !have_cmain
            if Base.should_use_main_entrypoint()
                if hasmethod(Main.main, Tuple{Vector{String}})
                    entrypoint(_main, (Cint, Ptr{Ptr{Cchar}}))
                    Base._ccallable("main", Cint, Tuple{typeof(_main), Cint, Ptr{Ptr{Cchar}}})
                else
                    error("`@main` must accept a `Vector{String}` argument.")
                end
            else
                error("To generate an executable a `@main` function must be defined in the `Main` module.")
            end
        end
    end
    #entrypoint(join, (Base.GenericIOBuffer{Memory{UInt8}}, Array{Base.SubString{String}, 1}, String))
    #entrypoint(join, (Base.GenericIOBuffer{Memory{UInt8}}, Array{String, 1}, Char))
    entrypoint(Base.task_done_hook, (Task,))
    entrypoint(Base.wait, ())
    entrypoint(Base.wait_forever, ())
    entrypoint(Base.trypoptask, (Base.StickyWorkqueue,))
    entrypoint(Base.checktaskempty, ())
    if ARGS[3] == "true"
        Base.Compiler.add_ccallable_entrypoints!()
    end