Skip to content

Commit ecd4439

Browse files
KristofferCtecosaur
authored andcommitted
Introduce -m/--module flag to execute a main function in a package (JuliaLang#52103)
This aims to bring similar functionality to Julia as the `-m` flag for Python which exists to directly run some function in a package and being able to pass arguments to that function. While in Python, `python -m package args` runs the file `<package>.__main__.py`, the equivalent Julia command (`julia -m Package args`) instead runs `<Package>.main(args)`. The package is assumed to be installed in the environment `julia` is run in. An example usage could be: Add the package: ```julia (@v1.11) pkg> add https://github.com/KristofferC/Rot13.jl Cloning git-repo `https://github.com/KristofferC/Rot13.jl` Updating git-repo `https://github.com/KristofferC/Rot13.jl` Resolving package versions... Updating `~/.julia/environments/v1.11/Project.toml` [43ef800a] + Rot13 v0.1.0 `https://github.com/KristofferC/Rot13.jl#master` Updating `~/.julia/environments/v1.11/Manifest.toml` [43ef800a] + Rot13 v0.1.0 `https://github.com/KristofferC/Rot13.jl#master` ``` And then it can be run (since it has a `main` function) via: ``` ❯ ./julia/julia -m Rot13 "encrypt this for me" "and this as well" rapelcg guvf sbe zr naq guvf nf jryy ``` I'm not sure if `-m/--module` is the best choice but perhaps the association to Python makes it worth it.
1 parent 1c3fb05 commit ecd4439

File tree

7 files changed

+49
-2
lines changed

7 files changed

+49
-2
lines changed

NEWS.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@ Compiler/Runtime improvements
2323
Command-line option changes
2424
---------------------------
2525

26+
* The `-m/--module` flag can be passed to run the `main` function inside a package with a set of arguments.
27+
This `main` function should be declared using `@main` to indicate that it is an entry point.
28+
2629
Multi-threading changes
2730
-----------------------
2831

base/client.jl

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -240,7 +240,7 @@ function exec_options(opts)
240240
if cmd_suppresses_program(cmd)
241241
arg_is_program = false
242242
repl = false
243-
elseif cmd == 'L'
243+
elseif cmd == 'L' || cmd == 'm'
244244
# nothing
245245
elseif cmd == 'B' # --bug-report
246246
# If we're doing a bug report, don't load anything else. We will
@@ -292,6 +292,13 @@ function exec_options(opts)
292292
elseif cmd == 'E'
293293
invokelatest(show, Core.eval(Main, parse_input_line(arg)))
294294
println()
295+
elseif cmd == 'm'
296+
@eval Main import $(Symbol(arg)).main
297+
if !should_use_main_entrypoint()
298+
error("`main` in `$arg` not declared as entry point (use `@main` to do so)")
299+
end
300+
return false
301+
295302
elseif cmd == 'L'
296303
# load file immediately on all processors
297304
if !distributed_mode

doc/man/julia.1

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,11 @@ Enable or disable usage of native code caching in the form of pkgimages
106106
-e, --eval <expr>
107107
Evaluate <expr>
108108

109+
.TP
110+
-m, --module <Package> [args]
111+
Run entry point of `Package` (`@main` function) with `args'.
112+
113+
109114
.TP
110115
-E, --print <expr>
111116
Evaluate <expr> and display the result

src/jloptions.c

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,8 @@ static const char opts[] =
128128
// actions
129129
" -e, --eval <expr> Evaluate <expr>\n"
130130
" -E, --print <expr> Evaluate <expr> and display the result\n"
131+
" -m, --module <Package> [args]\n"
132+
" Run entry point of `Package` (`@main` function) with `args'.\n"
131133
" -L, --load <file> Load <file> immediately on all processors\n\n"
132134

133135
// parallel options
@@ -271,7 +273,7 @@ JL_DLLEXPORT void jl_parse_opts(int *argcp, char ***argvp)
271273
opt_gc_threads,
272274
opt_permalloc_pkgimg
273275
};
274-
static const char* const shortopts = "+vhqH:e:E:L:J:C:it:p:O:g:";
276+
static const char* const shortopts = "+vhqH:e:E:L:J:C:it:p:O:g:m:";
275277
static const struct option longopts[] = {
276278
// exposed command line options
277279
// 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)
284286
{ "banner", required_argument, 0, opt_banner },
285287
{ "home", required_argument, 0, 'H' },
286288
{ "eval", required_argument, 0, 'e' },
289+
{ "module", required_argument, 0, 'm' },
287290
{ "print", required_argument, 0, 'E' },
288291
{ "load", required_argument, 0, 'L' },
289292
{ "bug-report", required_argument, 0, opt_bug_report },
@@ -421,6 +424,7 @@ JL_DLLEXPORT void jl_parse_opts(int *argcp, char ***argvp)
421424
case 'e': // eval
422425
case 'E': // print
423426
case 'L': // load
427+
case 'm': // module
424428
case opt_bug_report: // bug
425429
{
426430
size_t sz = strlen(optarg) + 1;
@@ -434,6 +438,10 @@ JL_DLLEXPORT void jl_parse_opts(int *argcp, char ***argvp)
434438
ncmds++;
435439
cmds[ncmds] = 0;
436440
jl_options.cmds = cmds;
441+
if (c == 'm') {
442+
optind -= 1;
443+
goto parsing_args_done;
444+
}
437445
break;
438446
}
439447
case 'J': // sysimage
@@ -886,6 +894,7 @@ JL_DLLEXPORT void jl_parse_opts(int *argcp, char ***argvp)
886894
"This is a bug, please report it.", c);
887895
}
888896
}
897+
parsing_args_done:
889898
jl_options.code_coverage = codecov;
890899
jl_options.malloc_log = malloclog;
891900
int proc_args = *argcp < optind ? *argcp : optind;

test/loading.jl

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1545,3 +1545,8 @@ end
15451545
@test_throws SystemError("opening file $(repr(file))") include(file)
15461546
end
15471547
end
1548+
1549+
@testset "-m" begin
1550+
rot13proj = joinpath(@__DIR__, "project", "Rot13")
1551+
@test readchomp(`$(Base.julia_cmd()) --startup-file=no --project=$rot13proj -m Rot13 --project nowhere ABJURER`) == "--cebwrpg abjurer NOWHERE "
1552+
end

test/project/Rot13/Project.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
name = "Rot13"
2+
uuid = "43ef800a-eac4-47f4-949b-25107b932e8f"
3+
version = "0.1.0"

test/project/Rot13/src/Rot13.jl

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
module Rot13
2+
3+
function rot13(c::Char)
4+
shft = islowercase(c) ? 'a' : 'A'
5+
isletter(c) ? c = shft + (c - shft + 13) % 26 : c
6+
end
7+
8+
rot13(str::AbstractString) = map(rot13, str)
9+
10+
function (@main)(ARGS)
11+
foreach(arg -> print(rot13(arg), " "), ARGS)
12+
return 0
13+
end
14+
15+
end # module Rot13

0 commit comments

Comments
 (0)