diff --git a/contrib/juliac-buildscript.jl b/contrib/juliac-buildscript.jl index 4bfbfd2272220..1697ed3fd1f03 100644 --- a/contrib/juliac-buildscript.jl +++ b/contrib/juliac-buildscript.jl @@ -1,9 +1,5 @@ # Script to run in the process that generates juliac's object file output -inputfile = ARGS[1] -output_type = ARGS[2] -add_ccallables = ARGS[3] == "true" - # Run the verifier in the current world (before modifications), so that error # messages and types print in their usual way. Core.Compiler._verify_trim_world_age[] = Base.get_world_counter() @@ -189,13 +185,37 @@ end import Base.Experimental.entrypoint -let mod = Base.include(Base.__toplevel__, inputfile) - if !isa(mod, Module) - mod = Main - end +# 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} + return Main.main(args) +end + +let mod = Base.include(Main, ARGS[1]) Core.@latestworld - if output_type == "--output-exe" && isdefined(mod, :main) && !add_ccallables - entrypoint(mod.main, ()) + 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 + 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.") + 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)) @@ -204,7 +224,7 @@ let mod = Base.include(Base.__toplevel__, inputfile) entrypoint(Base.wait_forever, ()) entrypoint(Base.trypoptask, (Base.StickyWorkqueue,)) entrypoint(Base.checktaskempty, ()) - if add_ccallables + if ARGS[3] == "true" ccall(:jl_add_ccallable_entrypoints, Cvoid, ()) end end diff --git a/src/gf.c b/src/gf.c index 436b4c84347dc..5a960c33ef503 100644 --- a/src/gf.c +++ b/src/gf.c @@ -4642,8 +4642,6 @@ JL_DLLEXPORT void jl_extern_c(jl_value_t *name, jl_value_t *declrt, jl_tupletype jl_error("@ccallable: function object must be a singleton"); // compute / validate return type - if (!jl_is_concrete_type(declrt) || jl_is_kind(declrt)) - jl_error("@ccallable: return type must be concrete and correspond to a C type"); if (!jl_type_mappable_to_c(declrt)) jl_error("@ccallable: return type doesn't correspond to a C type"); diff --git a/src/jlapi.c b/src/jlapi.c index 47d5b84fa5606..b27c01d9e0f1a 100644 --- a/src/jlapi.c +++ b/src/jlapi.c @@ -50,24 +50,28 @@ JL_DLLEXPORT int jl_is_initialized(void) * @param argc The number of command line arguments. * @param argv Array of command line arguments. */ -JL_DLLEXPORT void jl_set_ARGS(int argc, char **argv) +JL_DLLEXPORT jl_value_t *jl_set_ARGS(int argc, char **argv) { - if (jl_core_module != NULL) { - jl_array_t *args = (jl_array_t*)jl_get_global(jl_core_module, jl_symbol("ARGS")); - if (args == NULL) { - args = jl_alloc_vec_any(0); - JL_GC_PUSH1(&args); + jl_array_t *args = NULL; + jl_value_t *vecstr = NULL; + JL_GC_PUSH2(&args, &vecstr); + if (jl_core_module != NULL) + args = (jl_array_t*)jl_get_global(jl_core_module, jl_symbol("ARGS")); + if (args == NULL) { + vecstr = jl_apply_array_type((jl_value_t*)jl_string_type, 1); + args = jl_alloc_array_1d(vecstr, 0); + if (jl_core_module != NULL) jl_set_const(jl_core_module, jl_symbol("ARGS"), (jl_value_t*)args); - JL_GC_POP(); - } - assert(jl_array_nrows(args) == 0); - jl_array_grow_end(args, argc); - int i; - for (i = 0; i < argc; i++) { - jl_value_t *s = (jl_value_t*)jl_cstr_to_string(argv[i]); - jl_array_ptr_set(args, i, s); - } } + assert(jl_array_nrows(args) == 0); + jl_array_grow_end(args, argc); + int i; + for (i = 0; i < argc; i++) { + jl_value_t *s = (jl_value_t*)jl_cstr_to_string(argv[i]); + jl_array_ptr_set(args, i, s); + } + JL_GC_POP(); + return (jl_value_t*)args; } JL_DLLEXPORT void jl_init_with_image_handle(void *handle) { diff --git a/src/julia.h b/src/julia.h index 4cb4f18d30c8e..c7b19fb8b4530 100644 --- a/src/julia.h +++ b/src/julia.h @@ -2579,7 +2579,7 @@ uint64_t parse_heap_size_hint(const char *optarg, const char *option_name); // Set julia-level ARGS array according to the arguments provided in // argc/argv -JL_DLLEXPORT void jl_set_ARGS(int argc, char **argv); +JL_DLLEXPORT jl_value_t *jl_set_ARGS(int argc, char **argv); JL_DLLEXPORT int jl_generating_output(void) JL_NOTSAFEPOINT; diff --git a/test/trimming/basic_jll.jl b/test/trimming/basic_jll.jl index fc0137dd4eab2..334b5466343d0 100644 --- a/test/trimming/basic_jll.jl +++ b/test/trimming/basic_jll.jl @@ -1,14 +1,10 @@ -module MyApp - using Libdl using Zstd_jll -Base.@ccallable function main()::Cint +function @main(args::Vector{String})::Cint println(Core.stdout, "Julia! Hello, world!") fptr = dlsym(Zstd_jll.libzstd_handle, :ZSTD_versionString) println(Core.stdout, unsafe_string(ccall(fptr, Cstring, ()))) println(Core.stdout, unsafe_string(ccall((:ZSTD_versionString, libzstd), Cstring, ()))) return 0 end - -end diff --git a/test/trimming/hello.jl b/test/trimming/hello.jl index fef25f9e8558f..579ef4e18de38 100644 --- a/test/trimming/hello.jl +++ b/test/trimming/hello.jl @@ -1,13 +1,10 @@ -module MyApp - world::String = "world!" const str = OncePerProcess{String}() do return "Hello, " * world end -Base.@ccallable function main()::Cint +function @main(args::Vector{String})::Cint println(Core.stdout, str()) + foreach(x->println(Core.stdout, x), args) return 0 end - -end diff --git a/test/trimming/trimming.jl b/test/trimming/trimming.jl index 0f6d452c25c9b..5d55ed62b03a8 100644 --- a/test/trimming/trimming.jl +++ b/test/trimming/trimming.jl @@ -6,7 +6,7 @@ bindir = dirname(ARGS[1]) let exe_suffix = splitext(Base.julia_exename())[2] hello_exe = joinpath(bindir, "hello" * exe_suffix) - @test readchomp(`$hello_exe`) == "Hello, world!" + @test readchomp(`$hello_exe arg1 arg2`) == "Hello, world!\n$hello_exe\narg1\narg2" @test filesize(hello_exe) < 2_000_000 basic_jll_exe = joinpath(bindir, "basic_jll" * exe_suffix)