diff --git a/base/loading.jl b/base/loading.jl index 20f95524c7758..7f6e6e5ace55e 100644 --- a/base/loading.jl +++ b/base/loading.jl @@ -208,9 +208,9 @@ const include_callbacks = Any[] # used to optionally track dependencies when requiring a module: const _concrete_dependencies = Any[] # these dependency versions are "set in stone", and the process should try to avoid invalidating them -const _require_dependencies = Any[] # a list of (path, mtime) tuples that are the file dependencies of the module currently being precompiled +const _require_dependencies = Any[] # a list of (mod, path, mtime) tuples that are the file dependencies of the module currently being precompiled const _track_dependencies = Ref(false) # set this to true to track the list of file dependencies -function _include_dependency(_path::AbstractString) +function _include_dependency(modstring::AbstractString, _path::AbstractString) prev = source_path(nothing) if prev === nothing path = abspath(_path) @@ -218,7 +218,7 @@ function _include_dependency(_path::AbstractString) path = joinpath(dirname(prev), _path) end if _track_dependencies[] - push!(_require_dependencies, (path, mtime(path))) + push!(_require_dependencies, (modstring, path, mtime(path))) end return path, prev end @@ -234,7 +234,7 @@ This is only needed if your module depends on a file that is not used via `inclu no effect outside of compilation. """ function include_dependency(path::AbstractString) - _include_dependency(path) + _include_dependency("__external__", path) return nothing end @@ -522,7 +522,7 @@ end include_relative(mod::Module, path::AbstractString) = include_relative(mod, String(path)) function include_relative(mod::Module, _path::String) - path, prev = _include_dependency(_path) + path, prev = _include_dependency(string(mod), _path) for callback in include_callbacks # to preserve order, must come before Core.include invokelatest(callback, mod, path) end @@ -678,13 +678,17 @@ function parse_cache_header(f::IO) end totbytes = ntoh(read(f, Int64)) # total bytes for file dependencies # read the list of files - files = Tuple{String,Float64}[] + files = Tuple{String,String,Float64}[] while true - n = ntoh(read(f, Int32)) - n == 0 && break - totbytes -= 4 + n + 8 - @assert n >= 0 "EOF while reading cache header" # probably means this wasn't a valid file to be read by Base.parse_cache_header - push!(files, (String(read(f, n)), ntoh(read(f, Float64)))) + n1 = ntoh(read(f, Int32)) + n1 == 0 && break + @assert n1 >= 0 "EOF while reading cache header" # probably means this wasn't a valid file to be read by Base.parse_cache_header + modname = String(read(f, n1)) + n2 = ntoh(read(f, Int32)) + @assert n2 >= 0 "EOF while reading cache header" # probably means this wasn't a valid file to be read by Base.parse_cache_header + filename = String(read(f, n2)) + push!(files, (modname, filename, ntoh(read(f, Float64)))) + totbytes -= 8 + n1 + n2 + 8 end @assert totbytes == 4 "header of cache file appears to be corrupt" # read the list of modules that are required to be present during loading @@ -711,7 +715,7 @@ end function cache_dependencies(f::IO) defs, files, modules = parse_cache_header(f) - return modules, files + return modules, map(mod_fl_mt -> (mod_fl_mt[2], mod_fl_mt[3]), files) # discard the module end function cache_dependencies(cachefile::String) @@ -763,11 +767,11 @@ function stale_cachefile(modpath::String, cachefile::String) end # now check if this file is fresh relative to its source files - if !samefile(files[1][1], modpath) - DEBUG_LOADING[] && info("JL_DEBUG_LOADING: Rejecting cache file $cachefile because it is for file $(files[1][1])) not file $modpath.") + if !samefile(files[1][2], modpath) + DEBUG_LOADING[] && info("JL_DEBUG_LOADING: Rejecting cache file $cachefile because it is for file $(files[1][2])) not file $modpath.") return true # cache file was compiled from a different path end - for (f, ftime_req) in files + for (_, f, ftime_req) in files # Issue #13606: compensate for Docker images rounding mtimes # Issue #20837: compensate for GlusterFS truncating mtimes to microseconds ftime = mtime(f) diff --git a/src/dump.c b/src/dump.c index 1941730083e88..4a2a13ff8fa57 100644 --- a/src/dump.c +++ b/src/dump.c @@ -1030,7 +1030,7 @@ static void write_mod_list(ios_t *s, jl_array_t *a) } // "magic" string and version header of .ji file -static const int JI_FORMAT_VERSION = 3; +static const int JI_FORMAT_VERSION = 4; static const char JI_MAGIC[] = "\373jli\r\n\032\n"; // based on PNG signature static const uint16_t BOM = 0xFEFF; // byte-order marker static void write_header(ios_t *s) @@ -1089,7 +1089,9 @@ static void write_dependency_list(ios_t *s) for (size_t i=0; i < l; i++) { jl_value_t *dep = jl_fieldref(jl_array_ptr_ref(udeps, i), 0); size_t slen = jl_string_len(dep); - total_size += 4 + slen + 8; + dep = jl_fieldref(jl_array_ptr_ref(udeps, i), 1); + slen += jl_string_len(dep); + total_size += 8 + slen + 8; } total_size += 4; } @@ -1100,11 +1102,15 @@ static void write_dependency_list(ios_t *s) size_t l = jl_array_len(udeps); for (size_t i=0; i < l; i++) { jl_value_t *deptuple = jl_array_ptr_ref(udeps, i); - jl_value_t *dep = jl_fieldref(deptuple, 0); + jl_value_t *dep = jl_fieldref(deptuple, 0); // evaluating module (as string) size_t slen = jl_string_len(dep); write_int32(s, slen); ios_write(s, jl_string_data(dep), slen); - write_float64(s, jl_unbox_float64(jl_fieldref(deptuple, 1))); + dep = jl_fieldref(deptuple, 1); // file abspath + slen = jl_string_len(dep); + write_int32(s, slen); + ios_write(s, jl_string_data(dep), slen); + write_float64(s, jl_unbox_float64(jl_fieldref(deptuple, 2))); // mtime } write_int32(s, 0); // terminator, for ease of reading } diff --git a/test/compile.jl b/test/compile.jl index a56862691f923..57a1875b92a65 100644 --- a/test/compile.jl +++ b/test/compile.jl @@ -204,8 +204,9 @@ try @test stringmime("text/plain", Base.Docs.doc(Foo.Bar.bar)) == "bar function\n" modules, deps, required_modules = Base.parse_cache_header(cachefile) + discard_module = mod_fl_mt -> (mod_fl_mt[2], mod_fl_mt[3]) @test modules == Dict(Foo_module => Base.module_uuid(Foo)) - @test map(x -> x[1], sort(deps)) == [Foo_file, joinpath(dir, "bar.jl"), joinpath(dir, "foo.jl")] + @test map(x -> x[1], sort(discard_module.(deps))) == [Foo_file, joinpath(dir, "bar.jl"), joinpath(dir, "foo.jl")] modules, deps1 = Base.cache_dependencies(cachefile) @test modules == merge(Dict(s => Base.module_uuid(getfield(Foo, s)) for s in @@ -213,7 +214,7 @@ try # plus modules included in the system image Dict(s => Base.module_uuid(Base.root_module(s)) for s in [:DelimitedFiles,:Mmap])) - @test deps == deps1 + @test discard_module.(deps) == deps1 @test current_task()(0x01, 0x4000, 0x30031234) == 2 @test nothing(0x01, 0x4000, 0x30031234) == 52