@@ -322,6 +322,31 @@ function manifest_deps_get(env::String, where::PkgId, name::String, cache::TOMLC
322
322
return nothing
323
323
end
324
324
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
+
325
350
function manifest_uuid_path (env:: String , pkg:: PkgId , cache:: TOMLCache ):: Union{Nothing,String}
326
351
project_file = env_project_file (env)
327
352
if project_file isa String
@@ -950,7 +975,7 @@ function _require(pkg::PkgId, cache::TOMLCache)
950
975
if (0 == ccall (:jl_generating_output , Cint, ())) || (JLOptions (). incremental != 0 )
951
976
# spawn off a new incremental pre-compile task for recursive `require` calls
952
977
# 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 )
954
979
if isa (cachefile, Exception)
955
980
if precompilableerror (cachefile)
956
981
verbosity = isinteractive () ? CoreLogging. Info : CoreLogging. Debug
@@ -1195,7 +1220,7 @@ end
1195
1220
@assert precompile (create_expr_cache, (PkgId, String, String, typeof (_concrete_dependencies), Bool))
1196
1221
@assert precompile (create_expr_cache, (PkgId, String, String, typeof (_concrete_dependencies), Bool))
1197
1222
1198
- function compilecache_path (pkg:: PkgId ):: String
1223
+ function compilecache_path (pkg:: PkgId , cache :: TOMLCache ):: String
1199
1224
entrypath, entryfile = cache_file_entry (pkg)
1200
1225
cachepath = joinpath (DEPOT_PATH [1 ], entrypath)
1201
1226
isdir (cachepath) || mkpath (cachepath)
@@ -1205,6 +1230,7 @@ function compilecache_path(pkg::PkgId)::String
1205
1230
crc = _crc32c (something (Base. active_project (), " " ))
1206
1231
crc = _crc32c (unsafe_string (JLOptions (). image_file), crc)
1207
1232
crc = _crc32c (unsafe_string (JLOptions (). julia_bin), crc)
1233
+ crc = _crc32c (get_preferences_hash (pkg. uuid, cache), crc)
1208
1234
project_precompile_slug = slug (crc, 5 )
1209
1235
abspath (cachepath, string (entryfile, " _" , project_precompile_slug, " .ji" ))
1210
1236
end
@@ -1218,18 +1244,17 @@ This can be used to reduce package load times. Cache files are stored in
1218
1244
`DEPOT_PATH[1]/compiled`. See [Module initialization and precompilation](@ref)
1219
1245
for important notes.
1220
1246
"""
1221
- function compilecache (pkg:: PkgId , cache:: TOMLCache = TOMLCache ())
1247
+ function compilecache (pkg:: PkgId , cache:: TOMLCache = TOMLCache (), show_errors :: Bool = true )
1222
1248
path = locate_package (pkg, cache)
1223
1249
path === nothing && throw (ArgumentError (" $pkg not found during precompilation" ))
1224
- return compilecache (pkg, path)
1250
+ return compilecache (pkg, path, cache, show_errors )
1225
1251
end
1226
1252
1227
1253
const MAX_NUM_PRECOMPILE_FILES = 10
1228
1254
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 )
1231
1256
# decide where to put the resulting cache file
1232
- cachefile = compilecache_path (pkg)
1257
+ cachefile = compilecache_path (pkg, cache )
1233
1258
cachepath = dirname (cachefile)
1234
1259
# prune the directory with cache files
1235
1260
if pkg. uuid != = nothing
@@ -1333,6 +1358,8 @@ function parse_cache_header(f::IO)
1333
1358
end
1334
1359
totbytes -= 4 + 4 + n2 + 8
1335
1360
end
1361
+ prefs_hash = read (f, UInt64)
1362
+ totbytes -= 8
1336
1363
@assert totbytes == 12 " header of cache file appears to be corrupt"
1337
1364
srctextpos = read (f, Int64)
1338
1365
# read the list of modules that are required to be present during loading
@@ -1345,7 +1372,7 @@ function parse_cache_header(f::IO)
1345
1372
build_id = read (f, UInt64) # build id
1346
1373
push! (required_modules, PkgId (uuid, sym) => build_id)
1347
1374
end
1348
- return modules, (includes, requires), required_modules, srctextpos
1375
+ return modules, (includes, requires), required_modules, srctextpos, prefs_hash
1349
1376
end
1350
1377
1351
1378
function parse_cache_header (cachefile:: String ; srcfiles_only:: Bool = false )
@@ -1354,21 +1381,21 @@ function parse_cache_header(cachefile::String; srcfiles_only::Bool=false)
1354
1381
! isvalid_cache_header (io) && throw (ArgumentError (" Invalid header in cache file $cachefile ." ))
1355
1382
ret = parse_cache_header (io)
1356
1383
srcfiles_only || return ret
1357
- modules, (includes, requires), required_modules, srctextpos = ret
1384
+ modules, (includes, requires), required_modules, srctextpos, prefs_hash = ret
1358
1385
srcfiles = srctext_files (io, srctextpos)
1359
1386
delidx = Int[]
1360
1387
for (i, chi) in enumerate (includes)
1361
1388
chi. filename ∈ srcfiles || push! (delidx, i)
1362
1389
end
1363
1390
deleteat! (includes, delidx)
1364
- return modules, (includes, requires), required_modules, srctextpos
1391
+ return modules, (includes, requires), required_modules, srctextpos, prefs_hash
1365
1392
finally
1366
1393
close (io)
1367
1394
end
1368
1395
end
1369
1396
1370
1397
function 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)
1372
1399
return modules, map (chi -> (chi. filename, chi. mtime), includes) # return just filename and mtime
1373
1400
end
1374
1401
@@ -1383,7 +1410,7 @@ function cache_dependencies(cachefile::String)
1383
1410
end
1384
1411
1385
1412
function 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)
1387
1414
srctextpos == 0 && error (" no source-text stored in cache file" )
1388
1415
seek (io, srctextpos)
1389
1416
return _read_dependency_src (io, filename)
@@ -1428,6 +1455,37 @@ function srctext_files(f::IO, srctextpos::Int64)
1428
1455
return files
1429
1456
end
1430
1457
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
+
1431
1489
# returns true if it "cachefile.ji" is stale relative to "modpath.jl"
1432
1490
# otherwise returns the list of dependencies to also check
1433
1491
stale_cachefile (modpath:: String , cachefile:: String ) = stale_cachefile (modpath, cachefile, TOMLCache ())
@@ -1438,7 +1496,7 @@ function stale_cachefile(modpath::String, cachefile::String, cache::TOMLCache)
1438
1496
@debug " Rejecting cache file $cachefile due to it containing an invalid cache header"
1439
1497
return true # invalid cache file
1440
1498
end
1441
- ( modules, (includes, requires), required_modules) = parse_cache_header (io)
1499
+ modules, (includes, requires), required_modules, srctextpos, prefs_hash = parse_cache_header (io)
1442
1500
id = isempty (modules) ? nothing : first (modules). first
1443
1501
modules = Dict {PkgId, UInt64} (modules)
1444
1502
@@ -1514,6 +1572,12 @@ function stale_cachefile(modpath::String, cachefile::String, cache::TOMLCache)
1514
1572
end
1515
1573
1516
1574
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
+
1517
1581
get! (PkgOrigin, pkgorigins, id). cachepath = cachefile
1518
1582
end
1519
1583
0 commit comments