diff --git a/NEWS.md b/NEWS.md index 56a2ffb8d539d6..432211ba003f4e 100644 --- a/NEWS.md +++ b/NEWS.md @@ -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 ----------------------- diff --git a/base/client.jl b/base/client.jl index 31a3016489dcd0..087efe3d3b99c6 100644 --- a/base/client.jl +++ b/base/client.jl @@ -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 @@ -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 diff --git a/doc/man/julia.1 b/doc/man/julia.1 index afde0326e49523..a7d16abe3f85cf 100644 --- a/doc/man/julia.1 +++ b/doc/man/julia.1 @@ -106,6 +106,11 @@ Enable or disable usage of native code caching in the form of pkgimages -e, --eval Evaluate +.TP +-m, --module [args] +Run entry point of `Package` (`@main` function) with `args'. + + .TP -E, --print Evaluate and display the result diff --git a/src/jloptions.c b/src/jloptions.c index 570d021351104e..2ba5174e5c7307 100644 --- a/src/jloptions.c +++ b/src/jloptions.c @@ -128,6 +128,8 @@ static const char opts[] = // actions " -e, --eval Evaluate \n" " -E, --print Evaluate and display the result\n" + " -m, --module [args]\n" + " Run entry point of `Package` (`@main` function) with `args'.\n" " -L, --load Load immediately on all processors\n\n" // parallel options @@ -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 @@ -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 }, @@ -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; @@ -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 @@ -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; diff --git a/test/loading.jl b/test/loading.jl index 4a72a0f8060ad2..8ba2cf3026120f 100644 --- a/test/loading.jl +++ b/test/loading.jl @@ -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 diff --git a/test/project/Rot13/Project.toml b/test/project/Rot13/Project.toml new file mode 100644 index 00000000000000..eb03cb84d588e5 --- /dev/null +++ b/test/project/Rot13/Project.toml @@ -0,0 +1,3 @@ +name = "Rot13" +uuid = "43ef800a-eac4-47f4-949b-25107b932e8f" +version = "0.1.0" diff --git a/test/project/Rot13/src/Rot13.jl b/test/project/Rot13/src/Rot13.jl new file mode 100644 index 00000000000000..0672799d61f242 --- /dev/null +++ b/test/project/Rot13/src/Rot13.jl @@ -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