Skip to content

Commit 29a5a8c

Browse files
committed
Move startup code to new Client.jl stdlib
1 parent ebe1a37 commit 29a5a8c

File tree

10 files changed

+616
-191
lines changed

10 files changed

+616
-191
lines changed

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,7 @@ $(build_depsbindir)/stringreplace: $(JULIAHOME)/contrib/stringreplace.c | $(buil
184184
@$(call PRINT_CC, $(HOSTCC) -o $(build_depsbindir)/stringreplace $(JULIAHOME)/contrib/stringreplace.c)
185185

186186
julia-base-cache: julia-sysimg-$(JULIA_BUILD_MODE) | $(DIRS) $(build_datarootdir)/julia
187-
@JULIA_BINDIR=$(call cygpath_w,$(build_bindir)) WINEPATH="$(call cygpath_w,$(build_bindir));$$WINEPATH" \
187+
@JULIA_BINDIR=$(call cygpath_w,$(build_bindir)) JULIA_MINIMAL_CLIENT=1 WINEPATH="$(call cygpath_w,$(build_bindir));$$WINEPATH" \
188188
$(call spawn, $(JULIA_EXECUTABLE) --startup-file=no $(call cygpath_w,$(JULIAHOME)/etc/write_base_cache.jl) \
189189
$(call cygpath_w,$(build_datarootdir)/julia/base.cache))
190190

base/client.jl

Lines changed: 16 additions & 179 deletions
Original file line numberDiff line numberDiff line change
@@ -227,13 +227,12 @@ end
227227
incomplete_tag(exc::Meta.ParseError) = incomplete_tag(exc.detail)
228228

229229
cmd_suppresses_program(cmd) = cmd in ('e', 'E')
230+
231+
# Minimal exec_options for precompilation
230232
function exec_options(opts)
231233
quiet = (opts.quiet != 0)
232-
startup = (opts.startupfile != 2)
233-
history_file = (opts.historyfile != 0)
234-
color_set = (opts.color != 0) # --color!=auto
235-
global have_color = color_set ? (opts.color == 1) : nothing # --color=on
236-
global is_interactive = (opts.isinteractive != 0)
234+
global have_color = false
235+
global is_interactive = false
237236

238237
# pre-process command line argument list
239238
arg_is_program = !isempty(ARGS)
@@ -245,13 +244,6 @@ function exec_options(opts)
245244
repl = false
246245
elseif cmd == 'L'
247246
# nothing
248-
elseif cmd == 'B' # --bug-report
249-
# If we're doing a bug report, don't load anything else. We will
250-
# spawn a child in which to execute these options.
251-
let InteractiveUtils = load_InteractiveUtils()
252-
InteractiveUtils.report_bug(arg)
253-
end
254-
return nothing
255247
else
256248
@warn "Unexpected command -$cmd'$arg'"
257249
end
@@ -260,30 +252,6 @@ function exec_options(opts)
260252
# remove filename from ARGS
261253
global PROGRAM_FILE = arg_is_program ? popfirst!(ARGS) : ""
262254

263-
# Load Distributed module only if any of the Distributed options have been specified.
264-
distributed_mode = (opts.worker == 1) || (opts.nprocs > 0) || (opts.machine_file != C_NULL)
265-
if distributed_mode
266-
let Distributed = require(PkgId(UUID((0x8ba89e20_285c_5b6f, 0x9357_94700520ee1b)), "Distributed"))
267-
Core.eval(Main, :(const Distributed = $Distributed))
268-
Core.eval(Main, :(using .Distributed))
269-
end
270-
271-
invokelatest(Main.Distributed.process_opts, opts)
272-
end
273-
274-
interactiveinput = (repl || is_interactive::Bool) && isa(stdin, TTY)
275-
is_interactive::Bool |= interactiveinput
276-
277-
# load ~/.julia/config/startup.jl file
278-
if startup
279-
try
280-
load_julia_startup()
281-
catch
282-
invokelatest(display_error, scrub_repl_backtrace(current_exceptions()))
283-
!(repl || is_interactive::Bool) && exit(1)
284-
end
285-
end
286-
287255
# process cmds list
288256
for (cmd, arg) in cmds
289257
if cmd == 'e'
@@ -292,24 +260,13 @@ function exec_options(opts)
292260
invokelatest(show, Core.eval(Main, parse_input_line(arg)))
293261
println()
294262
elseif cmd == 'L'
295-
# load file immediately on all processors
296-
if !distributed_mode
297-
include(Main, arg)
298-
else
299-
# TODO: Move this logic to Distributed and use a callback
300-
@sync for p in invokelatest(Main.procs)
301-
@async invokelatest(Main.remotecall_wait, include, p, Main, arg)
302-
end
303-
end
263+
include(Main, arg)
304264
end
305265
end
306266

307267
# load file
308268
if arg_is_program
309-
# program
310-
if !is_interactive::Bool
311-
exit_on_sigint(true)
312-
end
269+
exit_on_sigint(true)
313270
try
314271
if PROGRAM_FILE == "-"
315272
include_string(Main, read(stdin, String), "stdin")
@@ -318,52 +275,12 @@ function exec_options(opts)
318275
end
319276
catch
320277
invokelatest(display_error, scrub_repl_backtrace(current_exceptions()))
321-
if !is_interactive::Bool
322-
exit(1)
323-
end
278+
exit(1)
324279
end
325280
end
326-
if repl || is_interactive::Bool
327-
b = opts.banner
328-
auto = b == -1
329-
banner = b == 0 || (auto && !interactiveinput) ? :no :
330-
b == 1 || (auto && interactiveinput) ? :yes :
331-
:short # b == 2
332-
run_main_repl(interactiveinput, quiet, banner, history_file, color_set)
333-
end
334281
nothing
335282
end
336283

337-
function _global_julia_startup_file()
338-
# If the user built us with a specific Base.SYSCONFDIR, check that location first for a startup.jl file
339-
# If it is not found, then continue on to the relative path based on Sys.BINDIR
340-
BINDIR = Sys.BINDIR
341-
SYSCONFDIR = Base.SYSCONFDIR
342-
if !isempty(SYSCONFDIR)
343-
p1 = abspath(BINDIR, SYSCONFDIR, "julia", "startup.jl")
344-
isfile(p1) && return p1
345-
end
346-
p2 = abspath(BINDIR, "..", "etc", "julia", "startup.jl")
347-
isfile(p2) && return p2
348-
return nothing
349-
end
350-
351-
function _local_julia_startup_file()
352-
if !isempty(DEPOT_PATH)
353-
path = abspath(DEPOT_PATH[1], "config", "startup.jl")
354-
isfile(path) && return path
355-
end
356-
return nothing
357-
end
358-
359-
function load_julia_startup()
360-
global_file = _global_julia_startup_file()
361-
(global_file !== nothing) && include(Main, global_file)
362-
local_file = _local_julia_startup_file()
363-
(local_file !== nothing) && include(Main, local_file)
364-
return nothing
365-
end
366-
367284
const repl_hooks = []
368285

369286
"""
@@ -388,96 +305,9 @@ function __atreplinit(repl)
388305
end
389306
_atreplinit(repl) = invokelatest(__atreplinit, repl)
390307

391-
function load_InteractiveUtils(mod::Module=Main)
392-
# load interactive-only libraries
393-
if !isdefined(mod, :InteractiveUtils)
394-
try
395-
let InteractiveUtils = require(PkgId(UUID(0xb77e0a4c_d291_57a0_90e8_8db25a27a240), "InteractiveUtils"))
396-
Core.eval(mod, :(const InteractiveUtils = $InteractiveUtils))
397-
Core.eval(mod, :(using .InteractiveUtils))
398-
return InteractiveUtils
399-
end
400-
catch ex
401-
@warn "Failed to import InteractiveUtils into module $mod" exception=(ex, catch_backtrace())
402-
end
403-
return nothing
404-
end
405-
return getfield(mod, :InteractiveUtils)
406-
end
407-
308+
# set by Client.jl
408309
global active_repl
409310

410-
# run the requested sort of evaluation loop on stdio
411-
function run_main_repl(interactive::Bool, quiet::Bool, banner::Symbol, history_file::Bool, color_set::Bool)
412-
load_InteractiveUtils()
413-
414-
if interactive && isassigned(REPL_MODULE_REF)
415-
invokelatest(REPL_MODULE_REF[]) do REPL
416-
term_env = get(ENV, "TERM", @static Sys.iswindows() ? "" : "dumb")
417-
global current_terminfo = load_terminfo(term_env)
418-
term = REPL.Terminals.TTYTerminal(term_env, stdin, stdout, stderr)
419-
banner == :no || Base.banner(term, short=banner==:short)
420-
if term.term_type == "dumb"
421-
repl = REPL.BasicREPL(term)
422-
quiet || @warn "Terminal not fully functional"
423-
else
424-
repl = REPL.LineEditREPL(term, get(stdout, :color, false), true)
425-
repl.history_file = history_file
426-
end
427-
global active_repl = repl
428-
# Make sure any displays pushed in .julia/config/startup.jl ends up above the
429-
# REPLDisplay
430-
pushdisplay(REPL.REPLDisplay(repl))
431-
_atreplinit(repl)
432-
REPL.run_repl(repl, backend->(global active_repl_backend = backend))
433-
end
434-
else
435-
# otherwise provide a simple fallback
436-
if interactive && !quiet
437-
@warn "REPL provider not available: using basic fallback"
438-
end
439-
banner == :no || Base.banner(short=banner==:short)
440-
let input = stdin
441-
if isa(input, File) || isa(input, IOStream)
442-
# for files, we can slurp in the whole thing at once
443-
ex = parse_input_line(read(input, String))
444-
if Meta.isexpr(ex, :toplevel)
445-
# if we get back a list of statements, eval them sequentially
446-
# as if we had parsed them sequentially
447-
for stmt in ex.args
448-
eval_user_input(stderr, stmt, true)
449-
end
450-
body = ex.args
451-
else
452-
eval_user_input(stderr, ex, true)
453-
end
454-
else
455-
while isopen(input) || !eof(input)
456-
if interactive
457-
print("julia> ")
458-
flush(stdout)
459-
end
460-
try
461-
line = ""
462-
ex = nothing
463-
while !eof(input)
464-
line *= readline(input, keep=true)
465-
ex = parse_input_line(line)
466-
if !(isa(ex, Expr) && ex.head === :incomplete)
467-
break
468-
end
469-
end
470-
eval_user_input(stderr, ex, true)
471-
catch err
472-
isa(err, InterruptException) ? print("\n\n") : rethrow()
473-
end
474-
end
475-
end
476-
end
477-
end
478-
nothing
479-
end
480-
481311
# MainInclude exists to hide Main.include and eval from `names(Main)`.
482312
baremodule MainInclude
483313
using ..Base
@@ -549,7 +379,14 @@ function _start()
549379
# clear any postoutput hooks that were saved in the sysimage
550380
empty!(Base.postoutput_hooks)
551381
try
552-
exec_options(JLOptions())
382+
if Base.generating_output() || parse(Bool, get(ENV, "JULIA_MINIMAL_CLIENT", "0"))
383+
exec_options(JLOptions())
384+
else
385+
let Client = require(PkgId(UUID((0x22d9f1f7_1f08_4fdd, 0xa466_30825a29bd37)), "Client"))
386+
Core.eval(Main, :(const Client = $Client))
387+
invokelatest(Client.exec_options, JLOptions())
388+
end
389+
end
553390
catch
554391
invokelatest(display_error, scrub_repl_backtrace(current_exceptions()))
555392
exit(1)

contrib/generate_precompile.jl

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -127,8 +127,7 @@ precompile_script = """
127127

128128
julia_exepath() = joinpath(Sys.BINDIR, Base.julia_exename())
129129

130-
have_repl = haskey(Base.loaded_modules,
131-
Base.PkgId(Base.UUID("3fa0cd96-eef1-5676-8a61-b3b8758bbffb"), "REPL"))
130+
have_repl = false
132131
if have_repl
133132
hardcoded_precompile_statements *= """
134133
precompile(Tuple{typeof(getproperty), REPL.REPLBackend, Symbol})
@@ -153,9 +152,7 @@ if Artifacts !== nothing
153152
"""
154153
end
155154

156-
Pkg = get(Base.loaded_modules,
157-
Base.PkgId(Base.UUID("44cfe95a-1eb2-52ea-b672-e2afdf69b78f"), "Pkg"),
158-
nothing)
155+
Pkg = nothing
159156

160157
if Pkg !== nothing
161158
# TODO: Split Pkg precompile script into REPL and script part
@@ -182,9 +179,7 @@ if Libdl !== nothing
182179
"""
183180
end
184181

185-
InteractiveUtils = get(Base.loaded_modules,
186-
Base.PkgId(Base.UUID("b77e0a4c-d291-57a0-90e8-8db25a27a240"), "InteractiveUtils"),
187-
nothing)
182+
InteractiveUtils = nothing
188183
if InteractiveUtils !== nothing
189184
repl_script *= """
190185
@time_imports using Random
@@ -240,7 +235,8 @@ procenv = Dict{String,Any}(
240235
"JULIA_PROJECT" => nothing, # remove from environment
241236
"JULIA_LOAD_PATH" => "@stdlib",
242237
"JULIA_DEPOT_PATH" => Sys.iswindows() ? ";" : ":",
243-
"TERM" => "")
238+
"TERM" => "",
239+
"JULIA_MINIMAL_CLIENT" => "true")
244240

245241
generate_precompile_statements() = try # Make sure `ansi_enablecursor` is printed
246242
start_time = time_ns()

pkgimage.mk

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ export JULIA_LOAD_PATH := @stdlib
1111
unexport JULIA_PROJECT :=
1212
unexport JULIA_BINDIR :=
1313

14+
export JULIA_MINIMAL_CLIENT := true
15+
1416
default: release
1517
release: all-release
1618
debug: all-debug
@@ -22,7 +24,7 @@ $(JULIA_DEPOT_PATH):
2224
print-depot-path:
2325
@$(call PRINT_JULIA, $(call spawn,$(JULIA_EXECUTABLE)) --startup-file=no -e '@show Base.DEPOT_PATH')
2426

25-
STDLIBS := ArgTools Artifacts Base64 CRC32c FileWatching Libdl NetworkOptions SHA Serialization \
27+
STDLIBS := ArgTools Artifacts Base64 Client CRC32c FileWatching Libdl NetworkOptions SHA Serialization \
2628
GMP_jll LLVMLibUnwind_jll LibUV_jll LibUnwind_jll MbedTLS_jll OpenLibm_jll PCRE2_jll \
2729
Zlib_jll dSFMT_jll libLLVM_jll libblastrampoline_jll OpenBLAS_jll Printf Random Tar \
2830
LibSSH2_jll MPFR_jll LinearAlgebra Dates Distributed Future LibGit2 Profile SparseArrays UUIDs \
@@ -129,6 +131,7 @@ $(eval $(call sysimg_builder,Pkg,Dates LibGit2 Libdl Logging Printf Random SHA U
129131

130132
# 7-depth packages
131133
$(eval $(call pkgimg_builder,LazyArtifacts,Artifacts Pkg))
134+
$(eval $(call pkgimg_builder,Client,Distributed REPL InteractiveUtils Pkg))
132135

133136
$(eval $(call pkgimg_builder,SparseArrays,Libdl LinearAlgebra Random Serialization))
134137
$(eval $(call pkgimg_builder,Statistics,LinearAlgebra SparseArrays))

stdlib/Client/Project.toml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
name = "Client"
2+
uuid = "22d9f1f7-1f08-4fdd-a466-30825a29bd37"
3+
version = "1.11.0"
4+
5+
[deps]
6+
Distributed = "8ba89e20-285c-5b6f-9357-94700520ee1b"
7+
InteractiveUtils = "b77e0a4c-d291-57a0-90e8-8db25a27a240"
8+
Pkg = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f"
9+
REPL = "3fa0cd96-eef1-5676-8a61-b3b8758bbffb"

0 commit comments

Comments
 (0)