Skip to content

Commit ac988cb

Browse files
committed
use @main for juliac executable entry point
add support for command line arguments
1 parent a483d90 commit ac988cb

File tree

8 files changed

+55
-41
lines changed

8 files changed

+55
-41
lines changed

contrib/juliac-buildscript.jl

Lines changed: 31 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,5 @@
11
# Script to run in the process that generates juliac's object file output
22

3-
inputfile = ARGS[1]
4-
output_type = ARGS[2]
5-
add_ccallables = ARGS[3] == "true"
6-
73
# Run the verifier in the current world (before modifications), so that error
84
# messages and types print in their usual way.
95
Core.Compiler._verify_trim_world_age[] = Base.get_world_counter()
@@ -189,13 +185,37 @@ end
189185

190186
import Base.Experimental.entrypoint
191187

192-
let mod = Base.include(Base.__toplevel__, inputfile)
193-
if !isa(mod, Module)
194-
mod = Main
195-
end
188+
# for use as C main if needed
189+
function _main(argc::Cint, argv::Ptr{Ptr{Cchar}})::Cint
190+
args = ccall(:jl_set_ARGS, Any, (Cint, Ptr{Ptr{Cchar}}), argc, argv)::Vector{String}
191+
return Main.main(args)
192+
end
193+
194+
let mod = Base.include(Main, ARGS[1])
196195
Core.@latestworld
197-
if output_type == "--output-exe" && isdefined(mod, :main) && !add_ccallables
198-
entrypoint(mod.main, ())
196+
if ARGS[2] == "--output-exe"
197+
have_cmain = false
198+
if isdefined(Main, :main)
199+
for m in methods(Main.main)
200+
if isdefined(m, :ccallable)
201+
# TODO: possibly check signature and return type
202+
have_cmain = true
203+
break
204+
end
205+
end
206+
end
207+
if !have_cmain
208+
if Base.should_use_main_entrypoint()
209+
if hasmethod(Main.main, Tuple{Vector{String}})
210+
entrypoint(_main, (Cint, Ptr{Ptr{Cchar}}))
211+
Base._ccallable("main", Cint, Tuple{typeof(_main), Cint, Ptr{Ptr{Cchar}}})
212+
else
213+
error("`@main` must accept a `Vector{String}` argument.")
214+
end
215+
else
216+
error("To generate an executable a `@main` function must be defined.")
217+
end
218+
end
199219
end
200220
#entrypoint(join, (Base.GenericIOBuffer{Memory{UInt8}}, Array{Base.SubString{String}, 1}, String))
201221
#entrypoint(join, (Base.GenericIOBuffer{Memory{UInt8}}, Array{String, 1}, Char))
@@ -204,7 +224,7 @@ let mod = Base.include(Base.__toplevel__, inputfile)
204224
entrypoint(Base.wait_forever, ())
205225
entrypoint(Base.trypoptask, (Base.StickyWorkqueue,))
206226
entrypoint(Base.checktaskempty, ())
207-
if add_ccallables
227+
if ARGS[3] == "true"
208228
ccall(:jl_add_ccallable_entrypoints, Cvoid, ())
209229
end
210230
end

contrib/juliac.jl

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,6 @@ function compile_products(enable_trim::Bool)
119119
println(stderr, "\nFailed to compile $file")
120120
exit(1)
121121
end
122-
123122
end
124123

125124
function link_products()

src/gf.c

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4642,8 +4642,6 @@ JL_DLLEXPORT void jl_extern_c(jl_value_t *name, jl_value_t *declrt, jl_tupletype
46424642
jl_error("@ccallable: function object must be a singleton");
46434643

46444644
// compute / validate return type
4645-
if (!jl_is_concrete_type(declrt) || jl_is_kind(declrt))
4646-
jl_error("@ccallable: return type must be concrete and correspond to a C type");
46474645
if (!jl_type_mappable_to_c(declrt))
46484646
jl_error("@ccallable: return type doesn't correspond to a C type");
46494647

src/jlapi.c

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -50,24 +50,28 @@ JL_DLLEXPORT int jl_is_initialized(void)
5050
* @param argc The number of command line arguments.
5151
* @param argv Array of command line arguments.
5252
*/
53-
JL_DLLEXPORT void jl_set_ARGS(int argc, char **argv)
53+
JL_DLLEXPORT jl_value_t *jl_set_ARGS(int argc, char **argv)
5454
{
55-
if (jl_core_module != NULL) {
56-
jl_array_t *args = (jl_array_t*)jl_get_global(jl_core_module, jl_symbol("ARGS"));
57-
if (args == NULL) {
58-
args = jl_alloc_vec_any(0);
59-
JL_GC_PUSH1(&args);
55+
jl_array_t *args = NULL;
56+
jl_value_t *vecstr = NULL;
57+
JL_GC_PUSH2(&args, &vecstr);
58+
if (jl_core_module != NULL)
59+
args = (jl_array_t*)jl_get_global(jl_core_module, jl_symbol("ARGS"));
60+
if (args == NULL) {
61+
vecstr = jl_apply_array_type((jl_value_t*)jl_string_type, 1);
62+
args = jl_alloc_array_1d(vecstr, 0);
63+
if (jl_core_module != NULL)
6064
jl_set_const(jl_core_module, jl_symbol("ARGS"), (jl_value_t*)args);
61-
JL_GC_POP();
62-
}
63-
assert(jl_array_nrows(args) == 0);
64-
jl_array_grow_end(args, argc);
65-
int i;
66-
for (i = 0; i < argc; i++) {
67-
jl_value_t *s = (jl_value_t*)jl_cstr_to_string(argv[i]);
68-
jl_array_ptr_set(args, i, s);
69-
}
7065
}
66+
assert(jl_array_nrows(args) == 0);
67+
jl_array_grow_end(args, argc);
68+
int i;
69+
for (i = 0; i < argc; i++) {
70+
jl_value_t *s = (jl_value_t*)jl_cstr_to_string(argv[i]);
71+
jl_array_ptr_set(args, i, s);
72+
}
73+
JL_GC_POP();
74+
return (jl_value_t*)args;
7175
}
7276

7377
JL_DLLEXPORT void jl_init_with_image_handle(void *handle) {

src/julia.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2579,7 +2579,7 @@ uint64_t parse_heap_size_hint(const char *optarg, const char *option_name);
25792579

25802580
// Set julia-level ARGS array according to the arguments provided in
25812581
// argc/argv
2582-
JL_DLLEXPORT void jl_set_ARGS(int argc, char **argv);
2582+
JL_DLLEXPORT jl_value_t *jl_set_ARGS(int argc, char **argv);
25832583

25842584
JL_DLLEXPORT int jl_generating_output(void) JL_NOTSAFEPOINT;
25852585

test/trimming/basic_jll.jl

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,10 @@
1-
module MyApp
2-
31
using Libdl
42
using Zstd_jll
53

6-
Base.@ccallable function main()::Cint
4+
function @main(args::Vector{String})::Cint
75
println(Core.stdout, "Julia! Hello, world!")
86
fptr = dlsym(Zstd_jll.libzstd_handle, :ZSTD_versionString)
97
println(Core.stdout, unsafe_string(ccall(fptr, Cstring, ())))
108
println(Core.stdout, unsafe_string(ccall((:ZSTD_versionString, libzstd), Cstring, ())))
119
return 0
1210
end
13-
14-
end

test/trimming/hello.jl

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,10 @@
1-
module MyApp
2-
31
world::String = "world!"
42
const str = OncePerProcess{String}() do
53
return "Hello, " * world
64
end
75

8-
Base.@ccallable function main()::Cint
6+
function @main(args::Vector{String})::Cint
97
println(Core.stdout, str())
8+
foreach(x->println(Core.stdout, x), args)
109
return 0
1110
end
12-
13-
end

test/trimming/trimming.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ bindir = dirname(ARGS[1])
66
let exe_suffix = splitext(Base.julia_exename())[2]
77

88
hello_exe = joinpath(bindir, "hello" * exe_suffix)
9-
@test readchomp(`$hello_exe`) == "Hello, world!"
9+
@test readchomp(`$hello_exe arg1 arg2`) == "Hello, world!\n$hello_exe\narg1\narg2"
1010
@test filesize(hello_exe) < 2_000_000
1111

1212
basic_jll_exe = joinpath(bindir, "basic_jll" * exe_suffix)

0 commit comments

Comments
 (0)