Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introduce -m/--module flag to execute a main function in a package #52103

Merged
merged 5 commits into from
Feb 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
3 changes: 3 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ Compiler/Runtime improvements
Command-line option changes
---------------------------

* The `-m/--module` flag can be passed to run the `main` function inside a package with a set of arguments.
This `main` function should be declared using `@main` to indicate that it is an entry point.

Multi-threading changes
-----------------------

Expand Down
9 changes: 8 additions & 1 deletion base/client.jl
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,7 @@ function exec_options(opts)
if cmd_suppresses_program(cmd)
arg_is_program = false
repl = false
elseif cmd == 'L'
elseif cmd == 'L' || cmd == 'm'
# nothing
elseif cmd == 'B' # --bug-report
# If we're doing a bug report, don't load anything else. We will
Expand Down Expand Up @@ -292,6 +292,13 @@ function exec_options(opts)
elseif cmd == 'E'
invokelatest(show, Core.eval(Main, parse_input_line(arg)))
println()
elseif cmd == 'm'
@eval Main import $(Symbol(arg)).main
if !should_use_main_entrypoint()
error("`main` in `$arg` not declared as entry point (use `@main` to do so)")
end
return false

elseif cmd == 'L'
# load file immediately on all processors
if !distributed_mode
Expand Down
5 changes: 5 additions & 0 deletions doc/man/julia.1
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,11 @@ Enable or disable usage of native code caching in the form of pkgimages
-e, --eval <expr>
Evaluate <expr>

.TP
-m, --module <Package> [args]
Run entry point of `Package` (`@main` function) with `args'.


.TP
-E, --print <expr>
Evaluate <expr> and display the result
Expand Down
11 changes: 10 additions & 1 deletion src/jloptions.c
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,8 @@ static const char opts[] =
// actions
" -e, --eval <expr> Evaluate <expr>\n"
" -E, --print <expr> Evaluate <expr> and display the result\n"
" -m, --module <Package> [args]\n"
" Run entry point of `Package` (`@main` function) with `args'.\n"
" -L, --load <file> Load <file> immediately on all processors\n\n"

// parallel options
Expand Down Expand Up @@ -271,7 +273,7 @@ JL_DLLEXPORT void jl_parse_opts(int *argcp, char ***argvp)
opt_gc_threads,
opt_permalloc_pkgimg
};
static const char* const shortopts = "+vhqH:e:E:L:J:C:it:p:O:g:";
static const char* const shortopts = "+vhqH:e:E:L:J:C:it:p:O:g:m:";
static const struct option longopts[] = {
// exposed command line options
// NOTE: This set of required arguments need to be kept in sync
Expand All @@ -284,6 +286,7 @@ JL_DLLEXPORT void jl_parse_opts(int *argcp, char ***argvp)
{ "banner", required_argument, 0, opt_banner },
{ "home", required_argument, 0, 'H' },
{ "eval", required_argument, 0, 'e' },
{ "module", required_argument, 0, 'm' },
{ "print", required_argument, 0, 'E' },
{ "load", required_argument, 0, 'L' },
{ "bug-report", required_argument, 0, opt_bug_report },
Expand Down Expand Up @@ -421,6 +424,7 @@ JL_DLLEXPORT void jl_parse_opts(int *argcp, char ***argvp)
case 'e': // eval
case 'E': // print
case 'L': // load
case 'm': // module
case opt_bug_report: // bug
{
size_t sz = strlen(optarg) + 1;
Expand All @@ -434,6 +438,10 @@ JL_DLLEXPORT void jl_parse_opts(int *argcp, char ***argvp)
ncmds++;
cmds[ncmds] = 0;
jl_options.cmds = cmds;
if (c == 'm') {
optind -= 1;
goto parsing_args_done;
}
break;
}
case 'J': // sysimage
Expand Down Expand Up @@ -886,6 +894,7 @@ JL_DLLEXPORT void jl_parse_opts(int *argcp, char ***argvp)
"This is a bug, please report it.", c);
}
}
parsing_args_done:
jl_options.code_coverage = codecov;
jl_options.malloc_log = malloclog;
int proc_args = *argcp < optind ? *argcp : optind;
Expand Down
5 changes: 5 additions & 0 deletions test/loading.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1545,3 +1545,8 @@ end
@test_throws SystemError("opening file $(repr(file))") include(file)
end
end

@testset "-m" begin
rot13proj = joinpath(@__DIR__, "project", "Rot13")
@test readchomp(`$(Base.julia_cmd()) --startup-file=no --project=$rot13proj -m Rot13 --project nowhere ABJURER`) == "--cebwrpg abjurer NOWHERE "
end
3 changes: 3 additions & 0 deletions test/project/Rot13/Project.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
name = "Rot13"
uuid = "43ef800a-eac4-47f4-949b-25107b932e8f"
version = "0.1.0"
15 changes: 15 additions & 0 deletions test/project/Rot13/src/Rot13.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
module Rot13

function rot13(c::Char)
shft = islowercase(c) ? 'a' : 'A'
isletter(c) ? c = shft + (c - shft + 13) % 26 : c
end

rot13(str::AbstractString) = map(rot13, str)

function (@main)(ARGS)
foreach(arg -> print(rot13(arg), " "), ARGS)
return 0
end

end # module Rot13