Skip to content
Closed
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
37 changes: 22 additions & 15 deletions base/binaryplatforms.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1068,21 +1068,28 @@ function select_platform(download_info::Dict, platform::AbstractPlatform = HostP
end

# At this point, we may have multiple possibilities. We now engage a multi-
# stage selection algorithm, where we first choose simpler matches over more
# complex matches. We define a simpler match as one that has fewer tags
# overall. As these candidate matches have already been filtered to match
# the given platform, the only other tags that exist are ones that are in
# addition to the tags declared by the platform. Hence, selecting the
# minimum in number of tags is equivalent to selecting the closest match.
min_tag_count = minimum(length(tags(p)) for p in ps)
filter!(p -> length(tags(p)) == min_tag_count, ps)

# Now we _still_ may continue to have multiple matches, so we now simply sort
# the candidate matches by their triplets and take the last one, so as to
# generally choose the latest release (e.g. a `libgfortran5` tarball over a
# `libgfortran3` tarball).
p = last(sort(ps, by = p -> triplet(p)))
return download_info[p]
# stage selection algorithm, where we first sort the matches by how complete
# the match is, e.g. preferring matches where the intersection of tags is
# equal to the union of the tags:
function match_loss(a, b)
a_tags = Set(keys(tags(a)))
b_tags = Set(keys(tags(b)))
return length(union(a_tags, b_tags)) - length(intersect(a_tags, b_tags))
end

# We prefer these better matches, and secondarily reverse-sort by triplet so
# as to generally choose the latest release (e.g. a `libgfortran5` tarball
# over a `libgfortran3` tarball).
ps = sort(ps, lt = (a, b) -> begin
loss_a = match_loss(a, platform)
loss_b = match_loss(b, platform)
if loss_a != loss_b
return loss_a < loss_b
end
return triplet(a) > triplet(b)
end)

return download_info[first(ps)]
end

# precompiles to reduce latency (see https://github.com/JuliaLang/julia/pull/43990#issuecomment-1025692379)
Expand Down
21 changes: 14 additions & 7 deletions test/binaryplatforms.jl
Original file line number Diff line number Diff line change
Expand Up @@ -330,8 +330,7 @@ end
# Ambiguity test
@test select_platform(platforms, P("aarch64", "linux")) == "linux3"
@test select_platform(platforms, P("aarch64", "linux"; libgfortran_version=v"3")) == "linux3"
# This one may be surprising, but we still match `linux3`, and since linux3 is shorter, we choose it.
@test select_platform(platforms, P("aarch64", "linux"; libgfortran_version=v"3", libstdcxx_version=v"3.4.18")) === "linux3"
@test select_platform(platforms, P("aarch64", "linux"; libgfortran_version=v"3", libstdcxx_version=v"3.4.18")) === "linux5"
@test select_platform(platforms, P("aarch64", "linux"; libgfortran_version=v"4")) === nothing

@test select_platform(platforms, P("x86_64", "macos")) == "mac4"
Expand All @@ -343,13 +342,21 @@ end
# Sorry, Alex. ;)
@test select_platform(platforms, P("x86_64", "freebsd")) === nothing

# The new "prefer shortest matching" algorithm is meant to be used to resolve ambiguities such as the following:
# The new "most complete match" algorithm deals with ambiguities as follows:
platforms = Dict(
# Typical binning test
P("x86_64", "linux") => "good",
P("x86_64", "linux"; sanitize="memory") => "bad",
P("x86_64", "linux") => "normal",
P("x86_64", "linux"; sanitize="memory") => "sanitized",
)
@test select_platform(platforms, P("x86_64", "linux")) == "normal"
@test select_platform(platforms, P("x86_64", "linux"; sanitize="memory")) == "sanitized"

# Ties are broken by reverse-sorting by triplet:
platforms = Dict(
P("x86_64", "linux"; libgfortran_version=v"3") => "libgfortran3",
P("x86_64", "linux"; libgfortran_version=v"4") => "libgfortran4",
)
@test select_platform(platforms, P("x86_64", "linux")) == "good"
@test select_platform(platforms, P("x86_64", "linux")) == "libgfortran4"
@test select_platform(platforms, P("x86_64", "linux"; libgfortran_version=v"3")) == "libgfortran3"
end

@testset "Custom comparators" begin
Expand Down