@@ -118,22 +118,58 @@ end
118118
119119# these return either the array of modules loaded from the path / content given
120120# or an Exception that describes why it couldn't be loaded
121- function _include_from_serialized (content:: Vector{UInt8} )
122- return ccall (:jl_restore_incremental_from_buf , Any, (Ptr{UInt8}, Int), content, sizeof (content))
121+ function _include_from_serialized (content:: Vector{UInt8} , depmods :: Vector{Module} )
122+ return ccall (:jl_restore_incremental_from_buf , Any, (Ptr{UInt8}, Int, Any ), content, sizeof (content), depmods )
123123end
124- function _include_from_serialized (path:: String )
125- return ccall (:jl_restore_incremental , Any, (Cstring,), path)
124+ function _include_from_serialized (path:: String , depmods :: Vector{Module} )
125+ return ccall (:jl_restore_incremental , Any, (Cstring, Any ), path, depmods )
126126end
127127
128128# returns an array of modules loaded, or an Exception that describes why it failed
129129# and it reconnects the Base.Docs.META
130130function _require_from_serialized (mod:: Symbol , path_to_try:: String )
131- restored = _include_from_serialized (path_to_try)
131+ return _require_from_serialized (mod, path_to_try, parse_cache_header (path_to_try)[3 ])
132+ end
133+ function _require_from_serialized (mod:: Symbol , path_to_try:: String , depmodnames:: Vector{Pair{Symbol, UInt64}} )
134+ # load all of the dependent modules
135+ ndeps = length (depmodnames)
136+ depmods = Vector {Module} (uninitialized, ndeps)
137+ for i in 1 : ndeps
138+ modname, uuid = depmodnames[i]
139+ if root_module_exists (modname)
140+ M = root_module (modname)
141+ if module_name (M) === modname && module_uuid (M) === uuid
142+ depmods[i] = M
143+ end
144+ else
145+ modpath = find_package (string (modname))
146+ modpath === nothing && return ErrorException (" Required dependency $modname not found in current path." )
147+ mod = _require_search_from_serialized (modname, String (modpath))
148+ if ! isa (mod, Bool)
149+ for M in mod:: Vector{Any}
150+ if module_name (M) === modname && module_uuid (M) === uuid
151+ depmods[i] = M
152+ break
153+ end
154+ end
155+ for callback in package_callbacks
156+ invokelatest (callback, modname)
157+ end
158+ end
159+ end
160+ isassigned (depmods, i) || return ErrorException (" Required dependency $modname failed to load from a cache file." )
161+ end
162+ # now load the path_to_try.ji file
163+ restored = _include_from_serialized (path_to_try, depmods)
132164 if ! isa (restored, Exception)
133165 for M in restored:: Vector{Any}
166+ M = M:: Module
134167 if isdefined (M, Base. Docs. META)
135168 push! (Base. Docs. modules, M)
136169 end
170+ if module_parent (M) === M
171+ register_root_module (module_name (M), M)
172+ end
137173 end
138174 end
139175 return restored
@@ -145,12 +181,13 @@ end
145181function _require_search_from_serialized (mod:: Symbol , sourcepath:: String )
146182 paths = find_all_in_cache_path (mod)
147183 for path_to_try in paths:: Vector{String}
148- if stale_cachefile (sourcepath, path_to_try)
184+ deps = stale_cachefile (sourcepath, path_to_try)
185+ if deps === true
149186 continue
150187 end
151- restored = _require_from_serialized (mod, path_to_try)
188+ restored = _require_from_serialized (mod, path_to_try, deps )
152189 if isa (restored, Exception)
153- if isa (restored, ErrorException) && endswith (restored . msg, " uuid did not match cache file. " )
190+ if isa (restored, ErrorException)
154191 # can't use this cache due to a module uuid mismatch,
155192 # defer reporting error until after trying all of the possible matches
156193 DEBUG_LOADING[] && info (" JL_DEBUG_LOADING: Failed to load $path_to_try because $(restored. msg) " )
@@ -183,7 +220,7 @@ const package_callbacks = Any[]
183220const include_callbacks = Any[]
184221
185222# used to optionally track dependencies when requiring a module:
186- const _concrete_dependencies = Any [] # these dependency versions are "set in stone", and the process should try to avoid invalidating them
223+ const _concrete_dependencies = Pair{Symbol, UInt64} [] # these dependency versions are "set in stone", and the process should try to avoid invalidating them
187224const _require_dependencies = Any[] # a list of (mod, path, mtime) tuples that are the file dependencies of the module currently being precompiled
188225const _track_dependencies = Ref (false ) # set this to true to track the list of file dependencies
189226function _include_dependency (modstring:: AbstractString , _path:: AbstractString )
@@ -363,14 +400,6 @@ function unreference_module(key)
363400 end
364401end
365402
366- function register_all (a)
367- for m in a
368- if module_parent (m) === m
369- register_root_module (module_name (m), m)
370- end
371- end
372- end
373-
374403function _require (mod:: Symbol )
375404 # dependency-tracking is only used for one top-level include(path),
376405 # and is not applied recursively to imported modules:
@@ -396,13 +425,13 @@ function _require(mod::Symbol)
396425 if path === nothing
397426 throw (ArgumentError (" Module $name not found in current path.\n Run `Pkg.add(\" $name \" )` to install the $name package." ))
398427 end
428+ path = String (path)
399429
400430 # attempt to load the module file via the precompile cache locations
401431 doneprecompile = false
402432 if JLOptions (). use_compiled_modules != 0
403433 doneprecompile = _require_search_from_serialized (mod, path)
404434 if ! isa (doneprecompile, Bool)
405- register_all (doneprecompile)
406435 return
407436 end
408437 end
@@ -430,7 +459,6 @@ function _require(mod::Symbol)
430459 warn (m, prefix= " WARNING: " )
431460 # fall-through, TODO : disable __precompile__(true) error so that the normal include will succeed
432461 else
433- register_all (m)
434462 return
435463 end
436464 end
@@ -452,7 +480,6 @@ function _require(mod::Symbol)
452480 # TODO : disable __precompile__(true) error and do normal include instead of error
453481 error (" Module $mod declares __precompile__(true) but require failed to create a usable precompiled cache file." )
454482 end
455- register_all (m)
456483 end
457484 finally
458485 toplevel_load[] = last
@@ -545,7 +572,7 @@ function evalfile(path::AbstractString, args::Vector{String}=String[])
545572end
546573evalfile (path:: AbstractString , args:: Vector ) = evalfile (path, String[args... ])
547574
548- function create_expr_cache (input:: String , output:: String , concrete_deps:: Vector{Any} )
575+ function create_expr_cache (input:: String , output:: String , concrete_deps:: typeof (_concrete_dependencies) )
549576 rm (output, force= true ) # Remove file if it exists
550577 code_object = """
551578 while !eof(STDIN)
@@ -612,12 +639,12 @@ function compilecache(name::String)
612639 if ! isdir (cachepath)
613640 mkpath (cachepath)
614641 end
615- cachefile:: String = abspath (cachepath, name * " .ji" )
642+ cachefile:: String = abspath (cachepath, " $name .ji" )
616643 # build up the list of modules that we want the precompile process to preserve
617644 concrete_deps = copy (_concrete_dependencies)
618- for (key,mod) in loaded_modules
645+ for (key, mod) in loaded_modules
619646 if ! (mod === Main || mod === Core || mod === Base)
620- push! (concrete_deps, ( key, module_uuid (mod) ))
647+ push! (concrete_deps, key => module_uuid (mod))
621648 end
622649 end
623650 # run the expression and cache the result
@@ -644,13 +671,13 @@ module_uuid(m::Module) = ccall(:jl_module_uuid, UInt64, (Any,), m)
644671isvalid_cache_header (f:: IOStream ) = 0 != ccall (:jl_read_verify_header , Cint, (Ptr{Void},), f. ios)
645672
646673function parse_cache_header (f:: IO )
647- modules = Dict { Symbol,UInt64} ()
674+ modules = Vector {Pair{ Symbol, UInt64} } ()
648675 while true
649676 n = ntoh (read (f, Int32))
650677 n == 0 && break
651678 sym = Symbol (read (f, n)) # module symbol
652679 uuid = ntoh (read (f, UInt64)) # module UUID (mostly just a timestamp)
653- modules[ sym] = uuid
680+ push! ( modules, sym => uuid)
654681 end
655682 totbytes = ntoh (read (f, Int64)) # total bytes for file dependencies
656683 # read the list of files
@@ -669,13 +696,13 @@ function parse_cache_header(f::IO)
669696 @assert totbytes == 12 " header of cache file appears to be corrupt"
670697 srctextpos = ntoh (read (f, Int64))
671698 # read the list of modules that are required to be present during loading
672- required_modules = Dict { Symbol,UInt64} ()
699+ required_modules = Vector {Pair{ Symbol, UInt64} } ()
673700 while true
674701 n = ntoh (read (f, Int32))
675702 n == 0 && break
676703 sym = Symbol (read (f, n)) # module symbol
677704 uuid = ntoh (read (f, UInt64)) # module UUID
678- required_modules[ sym] = uuid
705+ push! ( required_modules, sym => uuid)
679706 end
680707 return modules, files, required_modules, srctextpos
681708end
@@ -736,6 +763,8 @@ function read_dependency_src(cachefile::String, filename::AbstractString)
736763 end
737764end
738765
766+ # returns true if it "cachefile.ji" is stale relative to "modpath.jl"
767+ # otherwise returns the list of dependencies to also check
739768function stale_cachefile (modpath:: String , cachefile:: String )
740769 io = open (cachefile, " r" )
741770 try
@@ -744,13 +773,12 @@ function stale_cachefile(modpath::String, cachefile::String)
744773 return true # invalid cache file
745774 end
746775 modules, files, required_modules = parse_cache_header (io)
776+ modules = Dict {Symbol, UInt64} (modules)
747777
748778 # Check if transitive dependencies can be fullfilled
749- for mod in keys (required_modules)
750- if mod == :Main || mod == :Core || mod == :Base
751- continue
779+ for (mod, uuid_req) in required_modules
752780 # Module is already loaded
753- elseif root_module_exists (mod)
781+ if root_module_exists (mod)
754782 continue
755783 end
756784 name = string (mod)
@@ -768,7 +796,7 @@ function stale_cachefile(modpath::String, cachefile::String)
768796 uuid = get (modules, mod, UInt64 (0 ))
769797 if uuid != = UInt64 (0 )
770798 if uuid === uuid_req
771- return false # this is the file we want
799+ return required_modules # this is the file we want
772800 end
773801 DEBUG_LOADING[] && info (" JL_DEBUG_LOADING: Rejecting cache file $cachefile because it provides the wrong uuid (got $uuid ) for $mod (want $uuid_req )." )
774802 return true # cachefile doesn't provide the required version of the dependency
@@ -797,7 +825,7 @@ function stale_cachefile(modpath::String, cachefile::String)
797825 return true
798826 end
799827
800- return false # fresh cachefile
828+ return required_modules # fresh cachefile
801829 finally
802830 close (io)
803831 end
0 commit comments