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

Code before:
task.rngState4 = 0x5502376d099035ae
uuid_tuple = (UInt64(0), UInt64(0))
ccall(:jl_set_module_uuid, Cvoid, (Any, NTuple{2, UInt64}), Base.__toplevel__, uuid_tuple)
if Base.get_bool_env("JULIA_USE_FLISP_PARSER", false) === false
    Base.JuliaSyntax.enable_in_core!()
end

if Base.JLOptions().trim != 0
    include(joinpath(@__DIR__, "juliac-trim-base.jl"))
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

Review comment (suggestion):
```suggestion
    while T <: Ptr
        T = T.parameters[1] # unwrap Ptr{...}
    end
    if T.name.module === Core && T ∉ C_friendly_types
        error("invalid type for juliac: ", T) # exclude internals (they may change)
    end
    push!(types, T)
```

Mostly just to make the logic more direct, but there is a slight behavioral difference - if we add an `isbits struct` to `C_friendly_types`, this will make sure it still gets added to `types` for translation.

Also we can probably skip export for "standard" C ABI types, but non-standard `primitive` types like `RawFD` probably do need some translation / export.

Code after:
if Base.get_bool_env("JULIA_USE_FLISP_PARSER", false) === false
    Base.JuliaSyntax.enable_in_core!()
end

include(joinpath(@__DIR__, "abi_export.jl"))

# Load user code

import Base.Experimental.entrypoint

# 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))