diff --git a/NEWS.md b/NEWS.md index 244d8c3c4f3e1b..bd22382cec8968 100644 --- a/NEWS.md +++ b/NEWS.md @@ -158,6 +158,8 @@ New language features * `@__LINE__` special macro now available to reflect invocation source line number ([#12727]). + * `PROGRAM_FILE` global is now available for determining the name of the running script ([#14114]). + Language changes ---------------- @@ -1734,14 +1736,17 @@ Too numerous to mention. [#12727]: https://github.com/JuliaLang/julia/issues/12727 [#12739]: https://github.com/JuliaLang/julia/issues/12739 [#13062]: https://github.com/JuliaLang/julia/issues/13062 +[#13232]: https://github.com/JuliaLang/julia/issues/13232 [#13338]: https://github.com/JuliaLang/julia/issues/13338 [#13387]: https://github.com/JuliaLang/julia/issues/13387 [#13440]: https://github.com/JuliaLang/julia/issues/13440 [#13465]: https://github.com/JuliaLang/julia/issues/13465 -[#13496]: https://github.com/JuliaLang/julia/issues/13496 [#13480]: https://github.com/JuliaLang/julia/issues/13480 [#13496]: https://github.com/JuliaLang/julia/issues/13496 [#13542]: https://github.com/JuliaLang/julia/issues/13542 [#13680]: https://github.com/JuliaLang/julia/issues/13680 [#13681]: https://github.com/JuliaLang/julia/issues/13681 +[#13780]: https://github.com/JuliaLang/julia/issues/13780 [#13824]: https://github.com/JuliaLang/julia/issues/13824 +[#13897]: https://github.com/JuliaLang/julia/issues/13897 +[#14114]: https://github.com/JuliaLang/julia/issues/14114 diff --git a/base/client.jl b/base/client.jl index 70aacb8610913a..a5d7a4db1a0f57 100644 --- a/base/client.jl +++ b/base/client.jl @@ -177,10 +177,9 @@ end # try to include() a file, ignoring if not found try_include(path::AbstractString) = isfile(path) && include(path) -function process_options(opts::JLOptions, args::Vector{UTF8String}) - if !isempty(args) - arg = first(args) - idxs = find(x -> x == "--", args) +function process_options(opts::JLOptions) + if !isempty(ARGS) + idxs = find(x -> x == "--", ARGS) if length(idxs) > 1 println(STDERR, "julia: redundant option terminator `--`") exit(1) @@ -234,15 +233,15 @@ function process_options(opts::JLOptions, args::Vector{UTF8String}) eval(Main, parse_input_line(bytestring(opts.postboot))) end # load file - if !isempty(args) && !isempty(args[1]) + if !isempty(ARGS) && !isempty(ARGS[1]) # program repl = false # remove filename from ARGS - shift!(ARGS) + global PROGRAM_FILE = UTF8String(shift!(ARGS)) if !is_interactive ccall(:jl_exit_on_sigint, Void, (Cint,), 1) end - include(args[1]) + include(PROGRAM_FILE) end break end @@ -298,7 +297,7 @@ function _start() append!(ARGS, Core.ARGS) opts = JLOptions() try - (quiet,repl,startup,color_set,history_file) = process_options(opts,copy(ARGS)) + (quiet,repl,startup,color_set,history_file) = process_options(opts) local term global active_repl diff --git a/base/docs/helpdb/Base.jl b/base/docs/helpdb/Base.jl index 50700fded25fa2..849c80193b27a6 100644 --- a/base/docs/helpdb/Base.jl +++ b/base/docs/helpdb/Base.jl @@ -8477,8 +8477,9 @@ graphemes """ @__FILE__ -> AbstractString -`@__FILE__` expands to a string with the absolute path and file name of the script being -run. Returns `nothing` if run from a REPL or an empty string if evaluated by `julia -e `. +`@__FILE__` expands to a string with the absolute file path of the file containing the +macro. Returns `nothing` if run from a REPL or an empty string if evaluated by +`julia -e `. Alternatively see [`PROGRAM_FILE`](:data:`PROGRAM_FILE`). """ :@__FILE__ diff --git a/base/exports.jl b/base/exports.jl index e05c856bd9a3f0..814868ac45fc25 100644 --- a/base/exports.jl +++ b/base/exports.jl @@ -182,6 +182,7 @@ export JULIA_HOME, LOAD_PATH, OS_NAME, + PROGRAM_FILE, STDERR, STDIN, STDOUT, diff --git a/base/initdefs.jl b/base/initdefs.jl index 01d0cd6496be33..e5cc9706c9de83 100644 --- a/base/initdefs.jl +++ b/base/initdefs.jl @@ -2,6 +2,7 @@ ## initdefs.jl - initialization and runtime management definitions +PROGRAM_FILE = UTF8String("") const ARGS = UTF8String[] exit(n) = ccall(:jl_exit, Void, (Int32,), n) diff --git a/doc/manual/getting-started.rst b/doc/manual/getting-started.rst index 14c42585bd075c..89a91854951fee 100644 --- a/doc/manual/getting-started.rst +++ b/doc/manual/getting-started.rst @@ -51,19 +51,22 @@ argument to the julia command:: As the example implies, the following command-line arguments to julia are taken as command-line arguments to the program ``script.jl``, passed -in the global constant ``ARGS``. ``ARGS`` is also set when script code -is given using the ``-e`` option on the command line (see the ``julia`` -help output below). For example, to just print the arguments given to a -script, you could do this:: +in the global constant ``ARGS``. The name of the script itself is passed +in as the global ``PROGRAM_FILE``. Note that ``ARGS`` is also set when script +code is given using the ``-e`` option on the command line (see the ``julia`` +help output below) but ``PROGRAM_FILE`` will be empty. For example, to just +print the arguments given to a script, you could do this:: + + $ julia -e 'println(PROGRAM_FILE); for x in ARGS; println(x); end' foo bar - $ julia -e 'for x in ARGS; println(x); end' foo bar foo bar Or you could put that code into a script and run it:: - $ echo 'for x in ARGS; println(x); end' > script.jl + $ echo 'println(PROGRAM_FILE); for x in ARGS; println(x); end' > script.jl $ julia script.jl foo bar + script.jl foo bar diff --git a/doc/stdlib/constants.rst b/doc/stdlib/constants.rst index 2577ce6fbb5cab..2ee60422d030a9 100644 --- a/doc/stdlib/constants.rst +++ b/doc/stdlib/constants.rst @@ -14,6 +14,11 @@ Constants A symbol representing the name of the operating system. Possible values are ``:Linux``, ``:Darwin`` (OS X), or ``:Windows``. +.. data:: PROGRAM_FILE + + A string containing the script name passed to Julia from the command line. Note that the + script name remains unchanged from within included files. Alternatively see :data:`@__FILE__`. + .. data:: ARGS An array of the command line arguments passed to Julia, as strings. diff --git a/doc/stdlib/file.rst b/doc/stdlib/file.rst index fb868008227971..51501c5867d262 100644 --- a/doc/stdlib/file.rst +++ b/doc/stdlib/file.rst @@ -337,7 +337,7 @@ .. Docstring generated from Julia source - ``@__FILE__`` expands to a string with the absolute path and file name of the script being run. Returns ``nothing`` if run from a REPL or an empty string if evaluated by ``julia -e ``\ . + ``@__FILE__`` expands to a string with the absolute file path of the file containing the macro. Returns ``nothing`` if run from a REPL or an empty string if evaluated by ``julia -e ``. Alternatively see :data:`PROGRAM_FILE`. .. function:: @__LINE__ -> Int diff --git a/test/cmdlineargs.jl b/test/cmdlineargs.jl index 13bf36386be2d5..598b4642f62a2b 100644 --- a/test/cmdlineargs.jl +++ b/test/cmdlineargs.jl @@ -209,21 +209,44 @@ let exename = `$(joinpath(JULIA_HOME, Base.julia_exename())) --precompiled=yes` # test passing arguments let testfile = tempname() try - # write a julia source file that just prints ARGS to STDOUT and exits + # write a julia source file that just prints ARGS to STDOUT open(testfile, "w") do io println(io, "println(ARGS)") - println(io, "exit(0)") end - @test readchomp(`$exename $testfile foo -bar --baz`) == "UTF8String[\"foo\",\"-bar\",\"--baz\"]" - @test readchomp(`$exename $testfile -- foo -bar --baz`) == "UTF8String[\"foo\",\"-bar\",\"--baz\"]" - @test readchomp(`$exename -L $testfile -- foo -bar --baz`) == "UTF8String[\"foo\",\"-bar\",\"--baz\"]" + @test readchomp(`$exename $testfile foo -bar --baz`) == "UTF8String[\"foo\",\"-bar\",\"--baz\"]" + @test readchomp(`$exename $testfile -- foo -bar --baz`) == "UTF8String[\"foo\",\"-bar\",\"--baz\"]" + @test readchomp(`$exename -L $testfile -e 'exit(0)' -- foo -bar --baz`) == "UTF8String[\"foo\",\"-bar\",\"--baz\"]" + @test split(readchomp(`$exename -L $testfile $testfile`), '\n') == ["UTF8String[\"$testfile\"]", "UTF8String[]"] @test !success(`$exename --foo $testfile`) - @test !success(`$exename -L $testfile -- foo -bar -- baz`) + @test !success(`$exename -L $testfile -e 'exit(0)' -- foo -bar -- baz`) finally rm(testfile) end end + # test the script name + let a = tempname(), b = tempname() + try + open(a, "w") do io + println(io, "println(@__FILE__)") + println(io, "println(PROGRAM_FILE)") + println(io, "println(length(ARGS))") + println(io, "include(\"$b\")") + end + open(b, "w") do io + println(io, "println(@__FILE__)") + println(io, "println(PROGRAM_FILE)") + println(io, "println(length(ARGS))") + end + @test split(readchomp(`$exename $a`), '\n') == ["$a", "$a", "0", "$b", "$a", "0"] + @test split(readchomp(`$exename -L $b -e 'exit(0)'`), '\n') == ["$(realpath(b))", "", "0"] + @test split(readchomp(`$exename -L $b $a`), '\n') == ["$(realpath(b))", "", "1", "$a", "$a", "0", "$b", "$a", "0"] + finally + rm(a) + rm(b) + end + end + # issue #10562 @test readchomp(`$exename -e 'println(ARGS);' ''`) == "UTF8String[\"\"]"