Skip to content

Commit a56e0ca

Browse files
authored
Merge pull request #173 from JuliaLang/sd-pgkcompile
get back compile_package
2 parents 0dd40aa + b0beea6 commit a56e0ca

File tree

8 files changed

+165
-154
lines changed

8 files changed

+165
-154
lines changed

REQUIRE

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
11
julia 0.7
22
ArgParse
3-
SnoopCompile
43
@windows WinRPM

src/PackageCompiler.jl

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
module PackageCompiler
22

3-
using Libdl, SnoopCompile
3+
using Libdl
44

55
include("compiler_flags.jl")
66
include("static_julia.jl")
@@ -111,15 +111,15 @@ use a toml instead.
111111
function compile_package(
112112
packages::Tuple{String, String}...;
113113
force = false, reuse = false, debug = false, cpu_target = nothing,
114-
additional_packages = Symbol[]
114+
additional_packages = Symbol[], verbose = false
115115
)
116116
userimg = sysimg_folder("precompile.jl")
117117
if !reuse
118118
snoop_userimg(userimg, packages...; additional_packages = additional_packages)
119119
end
120120
!isfile(userimg) && reuse && error("Nothing to reuse. Please run `compile_package(reuse = true)`")
121121
image_path = sysimg_folder()
122-
build_sysimg(image_path, userimg, cpu_target=cpu_target)
122+
build_sysimg(image_path, userimg, cpu_target=cpu_target, verbose = verbose)
123123
imgfile = joinpath(image_path, "sys.$(Libdl.dlext)")
124124
syspath = joinpath(default_sysimg_path(debug), "sys.$(Libdl.dlext)")
125125
if force

src/compiler_flags.jl

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -226,14 +226,20 @@ function run_julia(code::String; kw...)
226226
end
227227

228228
function jl_command(flag, value)
229-
isempty(value) && return ""
229+
(value === nothing || isempty(value)) && return ""
230230
if is_short_flag(flag)
231231
string("-", flag, value)
232232
else
233233
string("--", flag, "=", value)
234234
end
235235
end
236236

237+
238+
function push_command!(cmd, flag, value)
239+
command = jl_command(flag, value)
240+
isempty(command) || push!(cmd.exec, command)
241+
end
242+
237243
function julia_code_cmd(
238244
code::String, jl_options = Base.JLOptions();
239245
kw...
@@ -244,13 +250,12 @@ function julia_code_cmd(
244250
for (k, v) in kw
245251
jl_key = jl_option_key(k)
246252
flag = jl_options_to_flag[jl_key]
247-
push!(cmd.exec, jl_command(flag, v))
253+
push_command!(cmd, flag, v)
248254
end
249255
# add remaining commands from JLOptions
250256
for key in setdiff(keys(jl_options_to_flag), keys(kw))
251257
flag = jl_options_to_flag[key]
252-
command = jl_command(flag, jl_option_value(jl_options, key))
253-
isempty(command) || push!(cmd.exec, command)
258+
push_command!(cmd, flag, jl_option_value(jl_options, key))
254259
end
255260
# for better debug, let's not make a tmp file which would get lost!
256261
file = sysimg_folder("run_julia_code.jl")

src/incremental.jl

Lines changed: 15 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ Init basic C libraries
44
function InitBase()
55
"""
66
Base.__init__()
7+
Sys.__init__() #fix https://github.com/JuliaLang/julia/issues/30479
78
"""
89
end
910

@@ -17,17 +18,6 @@ function InitREPL()
1718
"""
1819
end
1920

20-
"""
21-
Fix for https://github.com/JuliaLang/julia/issues/30479
22-
"""
23-
function Fix30479()
24-
"""
25-
_bindir = ccall(:jl_get_julia_bindir, Any, ())::String
26-
@eval(Sys, BINDIR = \$(_bindir))
27-
@eval(Sys, STDLIB = joinpath(\$_bindir, "..", "share", "julia", "stdlib", string('v', (VERSION.major), '.', VERSION.minor)))
28-
"""
29-
end
30-
3121
function Include(path)
3222
"""
3323
M = Module()
@@ -61,7 +51,7 @@ end
6151
The command to pass to julia --output-o, that runs the julia code in `path` during compilation.
6252
"""
6353
function PrecompileCommand(path)
64-
ExitHooksStart() * InitBase() * Fix30479() * InitREPL() * Include(path) * ExitHooksEnd()
54+
ExitHooksStart() * InitBase() * InitREPL() * Include(path) * ExitHooksEnd()
6555
end
6656

6757

@@ -87,6 +77,7 @@ function compile_incremental(
8777
debug = false, cc_flags = nothing
8878
)
8979
precompiles = package_folder("incremental_precompile.jl")
80+
9081
if snoopfile == nothing && precompile_file != nothing
9182
# we directly got a precompile_file
9283
isfile(precompile_file) || error("Need to pass an existing file to precompile_file. Found: $(repr(precompile_file))")
@@ -96,7 +87,7 @@ function compile_incremental(
9687
elseif snoopfile == nothing && precompile_file == nothing
9788
# reuse precompiles
9889
else
99-
snoop(toml_path, snoopfile, precompiles)
90+
snoop(nothing, toml_path, snoopfile, precompiles)
10091
end
10192
systemp = sysimg_folder("sys.a")
10293
sysout = sysimg_folder("sys.$(Libdl.dlext)")
@@ -138,19 +129,17 @@ function compile_incremental(packages::Symbol...; kw...)
138129
"compat" => Dict(),
139130
)
140131
precompiles_all = package_folder("incremental_precompile.jl")
141-
open(precompiles_all, "w") do io
142-
println(io, "# Precompile file for $(join(packages, " "))")
143-
end
144-
for package in packages
145-
precompiles = package_folder(string(package), "incremental_precompile.jl")
146-
toml, testfile = package_toml(package)
147-
snoop(toml, testfile, precompiles)
148-
pkg_toml = TOML.parsefile(toml)
149-
merge!(finaltoml["deps"], get(pkg_toml, "deps", Dict()))
150-
merge!(finaltoml["compat"], get(pkg_toml, "compat", Dict()))
151-
open(precompiles_all, "a") do io
152-
println(io)
153-
write(io, read(precompiles))
132+
open(precompiles_all, "w") do compile_io
133+
println(compile_io, "# Precompile file for $(join(packages, " "))")
134+
for package in packages
135+
precompiles = package_folder(string(package), "incremental_precompile.jl")
136+
toml, testfile = package_toml(package)
137+
snoop(package, toml, testfile, precompiles)
138+
pkg_toml = TOML.parsefile(toml)
139+
merge!(finaltoml["deps"], get(pkg_toml, "deps", Dict()))
140+
merge!(finaltoml["compat"], get(pkg_toml, "compat", Dict()))
141+
println(compile_io)
142+
write(compile_io, read(precompiles))
154143
end
155144
end
156145
toml = package_folder("Project.toml")

src/pkg.jl

Lines changed: 0 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -25,54 +25,6 @@ function in_manifest(name::AbstractString, manifest::Dict = current_manifest())
2525
end
2626

2727

28-
"""
29-
require_uninstalled(name::AbstractString, mod = Main)
30-
31-
Loads a package, even if it isn't installed.
32-
Call this only in a precompile file used for incremental compilation!
33-
"""
34-
function require_uninstalled(name::AbstractString, mod = Main)
35-
pkg = Base.PkgId(package_uuid(name), name)
36-
psym = Symbol(name)
37-
@eval mod begin
38-
if !isdefined($mod, $(QuoteNode(psym)))
39-
const $psym = Base.require($pkg)
40-
# we need to call the __init__ because of
41-
# https://github.com/JuliaLang/julia/issues/22910
42-
if isdefined($psym, :__init__)
43-
$psym.__init__()
44-
end
45-
else
46-
@warn(string($name, " already defined"))
47-
end
48-
end
49-
end
50-
51-
52-
function extract_used_packages(file::String)
53-
scope_regex = r"([\u00A0-\uFFFF\w_!´]*@?[\u00A0-\uFFFF\w_!´]+)\."
54-
namespaces = unique(getindex.(eachmatch(scope_regex, read(file, String)), 1))
55-
# only use names that are also in current manifest
56-
return filter(in_manifest, namespaces)
57-
end
58-
59-
60-
"""
61-
Extracts using statements from a julia file.
62-
"""
63-
function extract_using(path, usings = Set{String}())
64-
src = read(path, String)
65-
regex = r"using ([\u00A0-\uFFFF\w_!´]+)(,[ \u00A0-\uFFFF\w_!´]+)?"
66-
for match in eachmatch(regex, src)
67-
push!(usings, match[1])
68-
if match[2] !== nothing
69-
pkgs = strip.(split(match[2], ',', keepempty = false))
70-
union!(usings, pkgs)
71-
end
72-
end
73-
return usings
74-
end
75-
7628
#=
7729
genfile & create_project_from_require have been taken from the PR
7830
https://github.com/JuliaLang/PkgDev.jl/pull/144

src/snooping.jl

Lines changed: 68 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,19 @@
11
using Pkg, Serialization
22

33

4-
function snoop(tomlpath, snoopfile, outputfile, reuse = false)
5-
packages = extract_using(snoopfile)
4+
function snoop(package, tomlpath, snoopfile, outputfile, reuse = false)
5+
66
command = """
77
using Pkg, PackageCompiler
88
"""
9+
910
if tomlpath != nothing
1011
command *= """
1112
Pkg.activate($(repr(tomlpath)))
1213
Pkg.instantiate()
1314
"""
1415
end
16+
1517
command *= """
1618
# let's wrap the snoop file in a try catch...
1719
# This way we still do some snooping even if there is an error in the tests!
@@ -24,29 +26,48 @@ function snoop(tomlpath, snoopfile, outputfile, reuse = false)
2426

2527
# let's use a file in the PackageCompiler dir,
2628
# so it doesn't get lost if later steps fail
27-
tmp_file = sysimg_folder("precompile_tmp.jl")
29+
tmp_file = package_folder("precompile_tmp.jl")
2830
if !reuse
2931
run_julia(command, compile = "all", O = 0, g = 1, trace_compile = tmp_file)
3032
end
31-
actually_used = extract_used_packages(tmp_file)
33+
used_packages = Set{String}() # e.g. from test/REQUIRE
34+
if package != nothing
35+
push!(used_packages, string(package))
36+
end
3237
if tomlpath != nothing
3338
# add toml packages, in case extract_used_packages misses a package
3439
deps = get(TOML.parsefile(tomlpath), "deps", Dict{String, Any}())
35-
union!(actually_used, string.(keys(deps)))
40+
union!(used_packages, string.(keys(deps)))
41+
end
42+
usings = if isempty(used_packages)
43+
""
44+
else
45+
packages = join(used_packages, ", ")
46+
"""
47+
using $packages
48+
for Mod in [$packages]
49+
isdefined(Mod, :__init__) && Mod.__init__()
50+
end
51+
"""
3652
end
3753

3854
line_idx = 0; missed = 0
3955
open(outputfile, "w") do io
4056
println(io, """
41-
# We need to use all used packages in the precompile file for maximum
42-
# usage of the precompile statements.
43-
# Since this can be any recursive dependency of the package we AOT compile,
44-
# we decided to just use them without installing them. An added
45-
# benefit is, that we can call __init__ this way more easily, since
46-
# incremental sysimage compilation won't call __init__ on `using`
47-
# https://github.com/JuliaLang/julia/issues/22910
48-
using PackageCompiler
49-
PackageCompiler.require_uninstalled.($(repr(actually_used)), (@__MODULE__,))
57+
# We need to use all used packages in the precompile file for maximum
58+
# usage of the precompile statements.
59+
# Since this can be any recursive dependency of the package we AOT compile,
60+
# we decided to just use them without installing them. An added
61+
# benefit is, that we can call __init__ this way more easily, since
62+
# incremental sysimage compilation won't call __init__ on `using`
63+
# https://github.com/JuliaLang/julia/issues/22910
64+
$usings
65+
# bring recursive dependencies of used packages and standard libraries into namespace
66+
for Mod in Base.loaded_modules_array()
67+
if !Core.isdefined(@__MODULE__, nameof(Mod))
68+
Core.eval(@__MODULE__, Expr(:const, Expr(:(=), nameof(Mod), Mod)))
69+
end
70+
end
5071
""")
5172
for line in eachline(tmp_file)
5273
line_idx += 1
@@ -61,17 +82,47 @@ function snoop(tomlpath, snoopfile, outputfile, reuse = false)
6182
if expr.head != :incomplete
6283
# after all this, we still need to wrap into try catch,
6384
# since some anonymous symbols won't be found...
64-
println(io, "try;", line, "; catch e; @warn \"couldn't precompile statement $line_idx\" exception = e; end")
85+
println(io, "try;", line, "; catch e; @debug \"couldn't precompile statement $line_idx\" exception = e; end")
6586
else
6687
missed += 1
67-
@warn "Incomplete line in precompile file: $line"
88+
@debug "Incomplete line in precompile file: $line"
6889
end
6990
catch e
7091
missed += 1
71-
@warn "Parse error in precompile file: $line" exception=e
92+
@debug "Parse error in precompile file: $line" exception=e
7293
end
7394
end
7495
end
7596
@info "used $(line_idx - missed) out of $line_idx precompile statements"
7697
outputfile
7798
end
99+
100+
101+
"""
102+
snoop_userimg(userimg, packages::Tuple{String, String}...)
103+
104+
Traces all function calls in packages and writes out `precompile` statements into the file `userimg`
105+
"""
106+
function snoop_userimg(userimg, packages::Tuple{String, String}...; additional_packages = Symbol[])
107+
snooped_precompiles = map(packages) do package_snoopfile
108+
package, snoopfile = package_snoopfile
109+
module_name = Symbol(package)
110+
toml, runtests = package_toml(module_name)
111+
pkg_root = normpath(joinpath(dirname(runtests), ".."))
112+
file2snoop = if isfile(pkg_root, snoopfile)
113+
joinpath(pkg_root, snoopfile)
114+
else
115+
joinpath(pkg_root, snoopfile)
116+
end
117+
precompile_file = package_folder(package, "precompile.jl")
118+
snoop(package, toml, file2snoop, precompile_file)
119+
return precompile_file
120+
end
121+
# merge all of the temporary files into a single output
122+
open(userimg, "w") do output
123+
for path in snooped_precompiles
124+
open(input -> write(output, input), path)
125+
end
126+
end
127+
nothing
128+
end

0 commit comments

Comments
 (0)