@@ -322,6 +322,31 @@ function manifest_deps_get(env::String, where::PkgId, name::String, cache::TOMLC
322322 return nothing
323323end
324324
325+ function uuid_in_environment (project_file:: String , uuid:: UUID , cache:: TOMLCache )
326+ # First, check to see if we're looking for the environment itself
327+ proj_uuid = get (parsed_toml (cache, project_file), " uuid" , nothing )
328+ if proj_uuid != = nothing && UUID (proj_uuid) == uuid
329+ return true
330+ end
331+
332+ # Check to see if there's a Manifest.toml associated with this project
333+ manifest_file = project_file_manifest_path (project_file, cache)
334+ if manifest_file === nothing
335+ return false
336+ end
337+ manifest = parsed_toml (cache, manifest_file)
338+ for (dep_name, entries) in manifest
339+ for entry in entries
340+ entry_uuid = get (entry, " uuid" , nothing ):: Union{String, Nothing}
341+ if uuid != = nothing && UUID (entry_uuid) == uuid
342+ return true
343+ end
344+ end
345+ end
346+ # If all else fails, return `false`
347+ return false
348+ end
349+
325350function manifest_uuid_path (env:: String , pkg:: PkgId , cache:: TOMLCache ):: Union{Nothing,String}
326351 project_file = env_project_file (env)
327352 if project_file isa String
@@ -950,7 +975,7 @@ function _require(pkg::PkgId, cache::TOMLCache)
950975 if (0 == ccall (:jl_generating_output , Cint, ())) || (JLOptions (). incremental != 0 )
951976 # spawn off a new incremental pre-compile task for recursive `require` calls
952977 # or if the require search declared it was pre-compiled before (and therefore is expected to still be pre-compilable)
953- cachefile = compilecache (pkg, path)
978+ cachefile = compilecache (pkg, path, cache )
954979 if isa (cachefile, Exception)
955980 if precompilableerror (cachefile)
956981 verbosity = isinteractive () ? CoreLogging. Info : CoreLogging. Debug
@@ -1195,7 +1220,7 @@ end
11951220@assert precompile (create_expr_cache, (PkgId, String, String, typeof (_concrete_dependencies), Bool))
11961221@assert precompile (create_expr_cache, (PkgId, String, String, typeof (_concrete_dependencies), Bool))
11971222
1198- function compilecache_path (pkg:: PkgId ):: String
1223+ function compilecache_path (pkg:: PkgId , cache :: TOMLCache ):: String
11991224 entrypath, entryfile = cache_file_entry (pkg)
12001225 cachepath = joinpath (DEPOT_PATH [1 ], entrypath)
12011226 isdir (cachepath) || mkpath (cachepath)
@@ -1205,6 +1230,7 @@ function compilecache_path(pkg::PkgId)::String
12051230 crc = _crc32c (something (Base. active_project (), " " ))
12061231 crc = _crc32c (unsafe_string (JLOptions (). image_file), crc)
12071232 crc = _crc32c (unsafe_string (JLOptions (). julia_bin), crc)
1233+ crc = _crc32c (get_preferences_hash (pkg. uuid, cache), crc)
12081234 project_precompile_slug = slug (crc, 5 )
12091235 abspath (cachepath, string (entryfile, " _" , project_precompile_slug, " .ji" ))
12101236 end
@@ -1218,18 +1244,17 @@ This can be used to reduce package load times. Cache files are stored in
12181244`DEPOT_PATH[1]/compiled`. See [Module initialization and precompilation](@ref)
12191245for important notes.
12201246"""
1221- function compilecache (pkg:: PkgId , cache:: TOMLCache = TOMLCache ())
1247+ function compilecache (pkg:: PkgId , cache:: TOMLCache = TOMLCache (), show_errors :: Bool = true )
12221248 path = locate_package (pkg, cache)
12231249 path === nothing && throw (ArgumentError (" $pkg not found during precompilation" ))
1224- return compilecache (pkg, path)
1250+ return compilecache (pkg, path, cache, show_errors )
12251251end
12261252
12271253const MAX_NUM_PRECOMPILE_FILES = 10
12281254
1229- # `show_errors` is an "internal" interface for Pkg.precompile
1230- function compilecache (pkg:: PkgId , path:: String , show_errors:: Bool = true )
1255+ function compilecache (pkg:: PkgId , path:: String , cache:: TOMLCache = TOMLCache (), show_errors:: Bool = true )
12311256 # decide where to put the resulting cache file
1232- cachefile = compilecache_path (pkg)
1257+ cachefile = compilecache_path (pkg, cache )
12331258 cachepath = dirname (cachefile)
12341259 # prune the directory with cache files
12351260 if pkg. uuid != = nothing
@@ -1333,6 +1358,8 @@ function parse_cache_header(f::IO)
13331358 end
13341359 totbytes -= 4 + 4 + n2 + 8
13351360 end
1361+ prefs_hash = read (f, UInt64)
1362+ totbytes -= 8
13361363 @assert totbytes == 12 " header of cache file appears to be corrupt"
13371364 srctextpos = read (f, Int64)
13381365 # read the list of modules that are required to be present during loading
@@ -1345,7 +1372,7 @@ function parse_cache_header(f::IO)
13451372 build_id = read (f, UInt64) # build id
13461373 push! (required_modules, PkgId (uuid, sym) => build_id)
13471374 end
1348- return modules, (includes, requires), required_modules, srctextpos
1375+ return modules, (includes, requires), required_modules, srctextpos, prefs_hash
13491376end
13501377
13511378function parse_cache_header (cachefile:: String ; srcfiles_only:: Bool = false )
@@ -1354,21 +1381,21 @@ function parse_cache_header(cachefile::String; srcfiles_only::Bool=false)
13541381 ! isvalid_cache_header (io) && throw (ArgumentError (" Invalid header in cache file $cachefile ." ))
13551382 ret = parse_cache_header (io)
13561383 srcfiles_only || return ret
1357- modules, (includes, requires), required_modules, srctextpos = ret
1384+ modules, (includes, requires), required_modules, srctextpos, prefs_hash = ret
13581385 srcfiles = srctext_files (io, srctextpos)
13591386 delidx = Int[]
13601387 for (i, chi) in enumerate (includes)
13611388 chi. filename ∈ srcfiles || push! (delidx, i)
13621389 end
13631390 deleteat! (includes, delidx)
1364- return modules, (includes, requires), required_modules, srctextpos
1391+ return modules, (includes, requires), required_modules, srctextpos, prefs_hash
13651392 finally
13661393 close (io)
13671394 end
13681395end
13691396
13701397function cache_dependencies (f:: IO )
1371- defs, (includes, requires), modules = parse_cache_header (f)
1398+ defs, (includes, requires), modules, srctextpos, prefs_hash = parse_cache_header (f)
13721399 return modules, map (chi -> (chi. filename, chi. mtime), includes) # return just filename and mtime
13731400end
13741401
@@ -1383,7 +1410,7 @@ function cache_dependencies(cachefile::String)
13831410end
13841411
13851412function read_dependency_src (io:: IO , filename:: AbstractString )
1386- modules, (includes, requires), required_modules, srctextpos = parse_cache_header (io)
1413+ modules, (includes, requires), required_modules, srctextpos, prefs_hash = parse_cache_header (io)
13871414 srctextpos == 0 && error (" no source-text stored in cache file" )
13881415 seek (io, srctextpos)
13891416 return _read_dependency_src (io, filename)
@@ -1428,6 +1455,37 @@ function srctext_files(f::IO, srctextpos::Int64)
14281455 return files
14291456end
14301457
1458+ # Find the Project.toml that we should load/store to for Preferences
1459+ function get_preferences_project_path (uuid:: UUID , cache:: TOMLCache = TOMLCache ())
1460+ for env in load_path ()
1461+ project_file = env_project_file (env)
1462+ if ! isa (project_file, String)
1463+ continue
1464+ end
1465+ if uuid_in_environment (project_file, uuid, cache)
1466+ return project_file
1467+ end
1468+ end
1469+ return nothing
1470+ end
1471+
1472+ function get_preferences (uuid:: UUID , cache:: TOMLCache = TOMLCache ();
1473+ prefs_key:: String = " compile-preferences" )
1474+ project_path = get_preferences_project_path (uuid, cache)
1475+ if project_path != = nothing
1476+ preferences = get (parsed_toml (cache, project_path), prefs_key, Dict {String,Any} ())
1477+ if haskey (preferences, string (uuid))
1478+ return preferences[string (uuid)]
1479+ end
1480+ end
1481+ # Fall back to default value of "no preferences".
1482+ return Dict {String,Any} ()
1483+ end
1484+ get_preferences_hash (uuid:: UUID , cache:: TOMLCache = TOMLCache ()) = UInt64 (hash (get_preferences (uuid, cache)))
1485+ get_preferences_hash (m:: Module , cache:: TOMLCache = TOMLCache ()) = get_preferences_hash (PkgId (m). uuid, cache)
1486+ get_preferences_hash (:: Nothing , cache:: TOMLCache = TOMLCache ()) = UInt64 (hash (Dict {String,Any} ()))
1487+
1488+
14311489# returns true if it "cachefile.ji" is stale relative to "modpath.jl"
14321490# otherwise returns the list of dependencies to also check
14331491stale_cachefile (modpath:: String , cachefile:: String ) = stale_cachefile (modpath, cachefile, TOMLCache ())
@@ -1438,7 +1496,7 @@ function stale_cachefile(modpath::String, cachefile::String, cache::TOMLCache)
14381496 @debug " Rejecting cache file $cachefile due to it containing an invalid cache header"
14391497 return true # invalid cache file
14401498 end
1441- ( modules, (includes, requires), required_modules) = parse_cache_header (io)
1499+ modules, (includes, requires), required_modules, srctextpos, prefs_hash = parse_cache_header (io)
14421500 id = isempty (modules) ? nothing : first (modules). first
14431501 modules = Dict {PkgId, UInt64} (modules)
14441502
@@ -1514,6 +1572,12 @@ function stale_cachefile(modpath::String, cachefile::String, cache::TOMLCache)
15141572 end
15151573
15161574 if isa (id, PkgId)
1575+ curr_prefs_hash = get_preferences_hash (id. uuid, cache)
1576+ if prefs_hash != curr_prefs_hash
1577+ @debug " Rejecting cache file $cachefile because preferences hash does not match 0x$(string (prefs_hash, base= 16 )) != 0x$(string (curr_prefs_hash, base= 16 )) "
1578+ return true
1579+ end
1580+
15171581 get! (PkgOrigin, pkgorigins, id). cachepath = cachefile
15181582 end
15191583
0 commit comments