-
-
Notifications
You must be signed in to change notification settings - Fork 5.5k
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
Standardize the entry-point for Julia execution #50974
Changes from 5 commits
19a3061
e6bf018
61df2d9
1567a0f
edb89c5
cc4108b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -228,11 +228,8 @@ incomplete_tag(exc::Meta.ParseError) = incomplete_tag(exc.detail) | |
|
||
cmd_suppresses_program(cmd) = cmd in ('e', 'E') | ||
function exec_options(opts) | ||
quiet = (opts.quiet != 0) | ||
startup = (opts.startupfile != 2) | ||
history_file = (opts.historyfile != 0) | ||
color_set = (opts.color != 0) # --color!=auto | ||
global have_color = color_set ? (opts.color == 1) : nothing # --color=on | ||
global have_color = (opts.color != 0) ? (opts.color == 1) : nothing # --color=on | ||
global is_interactive = (opts.isinteractive != 0) | ||
|
||
# pre-process command line argument list | ||
|
@@ -323,15 +320,8 @@ function exec_options(opts) | |
end | ||
end | ||
end | ||
if repl || is_interactive::Bool | ||
b = opts.banner | ||
auto = b == -1 | ||
banner = b == 0 || (auto && !interactiveinput) ? :no : | ||
b == 1 || (auto && interactiveinput) ? :yes : | ||
:short # b == 2 | ||
run_main_repl(interactiveinput, quiet, banner, history_file, color_set) | ||
end | ||
nothing | ||
|
||
return repl || is_interactive::Bool | ||
end | ||
|
||
function _global_julia_startup_file() | ||
|
@@ -548,13 +538,28 @@ function _start() | |
append!(ARGS, Core.ARGS) | ||
# clear any postoutput hooks that were saved in the sysimage | ||
empty!(Base.postoutput_hooks) | ||
local ret = 0 | ||
try | ||
exec_options(JLOptions()) | ||
should_run_repl = exec_options(JLOptions()) | ||
if should_run_repl | ||
if isassigned(REPL_MODULE_REF) | ||
ret = REPL_MODULE_REF[].main(ARGS) | ||
end | ||
elseif isdefined(Main, :main) | ||
if Core.Compiler.generating_sysimg() | ||
precompile(Main.main, (typeof(ARGS),)) | ||
else | ||
ret = invokelatest(Main.main, ARGS) | ||
end | ||
end | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I thought the triage discussion was to have it call There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So the concern is in particular if Main.main is defined, but There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yep |
||
ret === nothing && (ret = 0) | ||
ret = Cint(ret) | ||
catch | ||
ret = Cint(1) | ||
invokelatest(display_error, scrub_repl_backtrace(current_exceptions())) | ||
exit(1) | ||
end | ||
if is_interactive && get(stdout, :color, false) | ||
print(color_normal) | ||
end | ||
return ret | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -39,6 +39,58 @@ $ julia --color=yes -O -- script.jl arg1 arg2.. | |
|
||
See also [Scripting](@ref man-scripting) for more information on writing Julia scripts. | ||
|
||
## The `Main.main` entry point | ||
|
||
At the conclusion of executing a script or expression, `julia` will attempt to execute the function | ||
`Main.main(ARGS)` (if such a function has been defined). This feature is intended to aid in the unification | ||
of compiled and interactive workflows. In compiled workflows, loading the code that defines the `main` | ||
function may be spatially and temporally separated from the invocation. However, for interactive workflows, | ||
the behavior is equivalent to explicitly calling `exit(main(ARGS))` at the end of the evaluated script or | ||
expression. | ||
|
||
!!! compat "Julia 1.11" | ||
The special entry point `Main.main` was added in Julia 1.11. For compatibility with prior julia versions, | ||
add an explicit `VERSION < v"1.11" && exit(main(ARGS))` at the end of your scripts. | ||
|
||
To see this feature in action, consider the following definition, which will execute the print function despite there being no explicit call to `main`: | ||
|
||
``` | ||
$ julia -e 'main(ARGS) = println("Hello World!")' | ||
Hello World! | ||
$ | ||
``` | ||
|
||
Only the `main` binding in the `Main`, module has this special behavior. For example, using `hello` | ||
instead of `main` will result in the `hello` function not executing: | ||
|
||
``` | ||
$ julia -e 'hello(ARGS) = println("Hello World!")' | ||
$ | ||
``` | ||
|
||
The `main` binding may be imported from a package. A hello package defined as | ||
|
||
``` | ||
module Hello | ||
|
||
export main | ||
main(ARGS) = println("Hello from the package!") | ||
|
||
end | ||
``` | ||
|
||
may be used as: | ||
|
||
``` | ||
$ julia -e 'using Hello' | ||
Hello from the package! | ||
$ julia -e 'import Hello' # N.B.: Execution depends on the binding not whether the package is loaded | ||
$ | ||
``` | ||
|
||
However, note that the current best practice recommendation is to not mix application and reusable library | ||
code in the same package. Helper applications may be distributed as separate pacakges or as scripts with | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks for the catch, but commenting on old (merged and subsequently reverted PRs doesn't really help). If the issue is present in current documentation, please submit a new PR. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sorry about that. I checked |
||
separate `main` entry points in a package's `bin` folder. | ||
JeffBezanson marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
## Parallel mode | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Testing
isdefined
will cause theMain.main
binding to become resolved (in the precompile process, if exported by a package), which may cause problems for people who want to add their ownMain.main
later? Binding resolution time is one of the less well-defined semantics unfortunately for this. Maybe we should checkisbindingresolved
?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I do want to resolve the inputs for actually executing the thing, but I can see the case for allowing the binding to be unresolved during precompile. I'll tweak this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've changed my mind on this - I do think you want to resolve the binding in the precompile process, so you get your warning if there's conflicts and the
-e using
pattern works without surprises. If you don't want a package'smain
function, just import it.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You don't even need to
import
the package - if there's already an existingmain
, that one will still be resolved correctly. As far as I can tell, the conflict just doesn't make the modules'main
available at all:The message could be tweaked/special cased for
main
, but that can be done later together with improving the warning for two packages trying to bring amain
into the namespace. I'm not sure what the consequences of that warning are for precompilation though.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is probably a moot point anyways. I was noticing that the export main pattern actually may be going to be discouraged, looking at the example here of REPL, so that explicit import of the intended module is needed anyways. And incremental compile packages are not permitted to change the set of usings for Main anyways, so they shouldn't add a binding there. So seems fine.