Skip to content

check if cachefile dependencies can be fulfilled #21492

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Apr 24, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 27 additions & 11 deletions base/loading.jl
Original file line number Diff line number Diff line change
Expand Up @@ -699,7 +699,16 @@ function parse_cache_header(f::IO)
push!(files, (String(read(f, n)), ntoh(read(f, Float64))))
end
@assert totbytes == 4 "header of cache file appears to be corrupt"
return modules, files
# read the list of modules that are required to be present during loading
required_modules = Dict{Symbol,UInt64}()
while true
n = ntoh(read(f, Int32))
n == 0 && break
sym = Symbol(read(f, n)) # module symbol
uuid = ntoh(read(f, UInt64)) # module UUID
required_modules[sym] = uuid
end
return modules, files, required_modules
end

function parse_cache_header(cachefile::String)
Expand All @@ -713,15 +722,7 @@ function parse_cache_header(cachefile::String)
end

function cache_dependencies(f::IO)
defs, files = parse_cache_header(f)
modules = []
while true
n = ntoh(read(f, Int32))
n == 0 && break
sym = Symbol(read(f, n)) # module symbol
uuid = ntoh(read(f, UInt64)) # module UUID (mostly just a timestamp)
push!(modules, (sym, uuid))
end
defs, files, modules = parse_cache_header(f)
return modules, files
end

Expand All @@ -742,7 +743,22 @@ function stale_cachefile(modpath::String, cachefile::String)
DEBUG_LOADING[] && info("JL_DEBUG_LOADING: Rejecting cache file $cachefile due to it containing an invalid cache header.")
return true # invalid cache file
end
modules, files = parse_cache_header(io)
modules, files, required_modules = parse_cache_header(io)

# Check if transitive dependencies can be fullfilled
for mod in keys(required_modules)
if mod == :Main || mod == :Core || mod == :Base
continue
# Module is already loaded
elseif isdefined(Main, mod)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

needs a check for isbindingresolved(Main, mod) first, to avoid causing isdefined to resolve the binding

continue
end
name = string(mod)
path = find_in_node_path(name, nothing, 1)
if path === nothing
return true # Won't be able to fullfill dependency
end
end

# check if this file is going to provide one of our concrete dependencies
# or if it provides a version that conflicts with our concrete dependencies
Expand Down
41 changes: 38 additions & 3 deletions test/compile.jl
Original file line number Diff line number Diff line change
Expand Up @@ -184,13 +184,13 @@ try
@test stringmime("text/plain", Base.Docs.doc(Foo.foo)) == "foo function\n"
@test stringmime("text/plain", Base.Docs.doc(Foo.Bar.bar)) == "bar function\n"

modules, deps = Base.parse_cache_header(cachefile)
modules, deps, required_modules = Base.parse_cache_header(cachefile)
@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")]

modules, deps1 = Base.cache_dependencies(cachefile)
@test sort(modules) == Any[(s, Base.module_uuid(getfield(Foo, s))) for s in
[:Base, :Core, Foo2_module, FooBase_module, :Main]]
@test modules == Dict(s => Base.module_uuid(getfield(Foo, s)) for s in
[:Base, :Core, Foo2_module, FooBase_module, :Main])
@test deps == deps1

@test current_task()(0x01, 0x4000, 0x30031234) == 2
Expand Down Expand Up @@ -325,6 +325,41 @@ try
isa(exc, ErrorException) || rethrow(exc)
!isempty(search(exc.msg, "ERROR: LoadError: break me")) && rethrow(exc)
end

# Test transitive dependency for #21266
FooBarT_file = joinpath(dir, "FooBarT.jl")
write(FooBarT_file,
"""
__precompile__(true)
module FooBarT
end
""")
FooBarT1_file = joinpath(dir, "FooBarT1.jl")
write(FooBarT1_file,
"""
__precompile__(true)
module FooBarT1
using FooBarT
end
""")
FooBarT2_file = joinpath(dir, "FooBarT2.jl")
write(FooBarT2_file,
"""
__precompile__(true)
module FooBarT2
using FooBarT1
end
""")
Base.compilecache("FooBarT2")
write(FooBarT1_file,
"""
__precompile__(true)
module FooBarT1
end
""")
rm(FooBarT_file)
@test Base.stale_cachefile(FooBarT2_file, joinpath(dir2, "FooBarT2.ji"))
@test Base.require(:FooBarT2) === nothing
finally
splice!(Base.LOAD_CACHE_PATH, 1:2)
splice!(LOAD_PATH, 1)
Expand Down