@@ -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 " Failed to load $path_to_try because $(restored. msg) "
@@ -178,7 +215,7 @@ const package_callbacks = Any[]
178215const include_callbacks = Any[]
179216
180217# used to optionally track dependencies when requiring a module:
181- const _concrete_dependencies = Any [] # these dependency versions are "set in stone", and the process should try to avoid invalidating them
218+ const _concrete_dependencies = Pair{Symbol, UInt64} [] # these dependency versions are "set in stone", and the process should try to avoid invalidating them
182219const _require_dependencies = Any[] # a list of (mod, path, mtime) tuples that are the file dependencies of the module currently being precompiled
183220const _track_dependencies = Ref (false ) # set this to true to track the list of file dependencies
184221function _include_dependency (modstring:: AbstractString , _path:: AbstractString )
@@ -358,14 +395,6 @@ function unreference_module(key)
358395 end
359396end
360397
361- function register_all (a)
362- for m in a
363- if module_parent (m) === m
364- register_root_module (module_name (m), m)
365- end
366- end
367- end
368-
369398function _require (mod:: Symbol )
370399 # dependency-tracking is only used for one top-level include(path),
371400 # and is not applied recursively to imported modules:
@@ -390,13 +419,13 @@ function _require(mod::Symbol)
390419 if path === nothing
391420 throw (ArgumentError (" Module $name not found in current path.\n Run `Pkg.add(\" $name \" )` to install the $name package." ))
392421 end
422+ path = String (path)
393423
394424 # attempt to load the module file via the precompile cache locations
395425 doneprecompile = false
396426 if JLOptions (). use_compiled_modules != 0
397427 doneprecompile = _require_search_from_serialized (mod, path)
398428 if ! isa (doneprecompile, Bool)
399- register_all (doneprecompile)
400429 return
401430 end
402431 end
@@ -423,7 +452,6 @@ function _require(mod::Symbol)
423452 @warn " The call to compilecache failed to create a usable precompiled cache file for module $name " exception= m
424453 # fall-through, TODO : disable __precompile__(true) error so that the normal include will succeed
425454 else
426- register_all (m)
427455 return
428456 end
429457 end
@@ -446,7 +474,6 @@ function _require(mod::Symbol)
446474 # TODO : disable __precompile__(true) error and do normal include instead of error
447475 error (" Module $mod declares __precompile__(true) but require failed to create a usable precompiled cache file." )
448476 end
449- register_all (m)
450477 end
451478 finally
452479 toplevel_load[] = last
@@ -539,7 +566,7 @@ function evalfile(path::AbstractString, args::Vector{String}=String[])
539566end
540567evalfile (path:: AbstractString , args:: Vector ) = evalfile (path, String[args... ])
541568
542- function create_expr_cache (input:: String , output:: String , concrete_deps:: Vector{Any} )
569+ function create_expr_cache (input:: String , output:: String , concrete_deps:: typeof (_concrete_dependencies) )
543570 rm (output, force= true ) # Remove file if it exists
544571 code_object = """
545572 while !eof(STDIN)
@@ -606,12 +633,12 @@ function compilecache(name::String)
606633 if ! isdir (cachepath)
607634 mkpath (cachepath)
608635 end
609- cachefile:: String = abspath (cachepath, name * " .ji" )
636+ cachefile:: String = abspath (cachepath, " $name .ji" )
610637 # build up the list of modules that we want the precompile process to preserve
611638 concrete_deps = copy (_concrete_dependencies)
612- for (key,mod) in loaded_modules
639+ for (key, mod) in loaded_modules
613640 if ! (mod === Main || mod === Core || mod === Base)
614- push! (concrete_deps, ( key, module_uuid (mod) ))
641+ push! (concrete_deps, key => module_uuid (mod))
615642 end
616643 end
617644 # run the expression and cache the result
@@ -637,13 +664,13 @@ module_uuid(m::Module) = ccall(:jl_module_uuid, UInt64, (Any,), m)
637664isvalid_cache_header (f:: IOStream ) = 0 != ccall (:jl_read_verify_header , Cint, (Ptr{Void},), f. ios)
638665
639666function parse_cache_header (f:: IO )
640- modules = Dict { Symbol,UInt64} ()
667+ modules = Vector {Pair{ Symbol, UInt64} } ()
641668 while true
642669 n = ntoh (read (f, Int32))
643670 n == 0 && break
644671 sym = Symbol (read (f, n)) # module symbol
645672 uuid = ntoh (read (f, UInt64)) # module UUID (mostly just a timestamp)
646- modules[ sym] = uuid
673+ push! ( modules, sym => uuid)
647674 end
648675 totbytes = ntoh (read (f, Int64)) # total bytes for file dependencies
649676 # read the list of files
@@ -662,13 +689,13 @@ function parse_cache_header(f::IO)
662689 @assert totbytes == 12 " header of cache file appears to be corrupt"
663690 srctextpos = ntoh (read (f, Int64))
664691 # read the list of modules that are required to be present during loading
665- required_modules = Dict { Symbol,UInt64} ()
692+ required_modules = Vector {Pair{ Symbol, UInt64} } ()
666693 while true
667694 n = ntoh (read (f, Int32))
668695 n == 0 && break
669696 sym = Symbol (read (f, n)) # module symbol
670697 uuid = ntoh (read (f, UInt64)) # module UUID
671- required_modules[ sym] = uuid
698+ push! ( required_modules, sym => uuid)
672699 end
673700 return modules, files, required_modules, srctextpos
674701end
@@ -729,6 +756,8 @@ function read_dependency_src(cachefile::String, filename::AbstractString)
729756 end
730757end
731758
759+ # returns true if it "cachefile.ji" is stale relative to "modpath.jl"
760+ # otherwise returns the list of dependencies to also check
732761function stale_cachefile (modpath:: String , cachefile:: String )
733762 io = open (cachefile, " r" )
734763 try
@@ -737,13 +766,12 @@ function stale_cachefile(modpath::String, cachefile::String)
737766 return true # invalid cache file
738767 end
739768 modules, files, required_modules = parse_cache_header (io)
769+ modules = Dict {Symbol, UInt64} (modules)
740770
741771 # Check if transitive dependencies can be fullfilled
742- for mod in keys (required_modules)
743- if mod == :Main || mod == :Core || mod == :Base
744- continue
772+ for (mod, uuid_req) in required_modules
745773 # Module is already loaded
746- elseif root_module_exists (mod)
774+ if root_module_exists (mod)
747775 continue
748776 end
749777 name = string (mod)
@@ -761,7 +789,7 @@ function stale_cachefile(modpath::String, cachefile::String)
761789 uuid = get (modules, mod, UInt64 (0 ))
762790 if uuid != = UInt64 (0 )
763791 if uuid === uuid_req
764- return false # this is the file we want
792+ return required_modules # this is the file we want
765793 end
766794 @debug " Rejecting cache file $cachefile because it provides the wrong uuid (got $uuid ) for $mod (want $uuid_req )"
767795 return true # cachefile doesn't provide the required version of the dependency
@@ -790,7 +818,7 @@ function stale_cachefile(modpath::String, cachefile::String)
790818 return true
791819 end
792820
793- return false # fresh cachefile
821+ return required_modules # fresh cachefile
794822 finally
795823 close (io)
796824 end
0 commit comments