diff --git a/base/binaryplatforms.jl b/base/binaryplatforms.jl index 39348891c83a6..d59b6397b1f73 100644 --- a/base/binaryplatforms.jl +++ b/base/binaryplatforms.jl @@ -1067,12 +1067,20 @@ function select_platform(download_info::Dict, platform::AbstractPlatform = HostP return nothing end - # At this point, we may have multiple possibilities. E.g. if, in the future, - # Julia can be built without a direct dependency on libgfortran, we may match - # multiple tarballs that vary only within their libgfortran ABI. To narrow it - # down, we just sort by triplet, then pick the last one. This has the effect - # of generally choosing the latest release (e.g. a `libgfortran5` tarball - # rather than a `libgfortran3` tarball) + # 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] end diff --git a/test/binaryplatforms.jl b/test/binaryplatforms.jl index 793a9b1f06a41..54154f492168f 100644 --- a/test/binaryplatforms.jl +++ b/test/binaryplatforms.jl @@ -315,8 +315,9 @@ end P("x86_64", "linux"; libgfortran_version=v"5") => "linux8", # Ambiguity test - P("aarch64", "linux"; libgfortran_version=v"3") => "linux4", + P("aarch64", "linux"; libgfortran_version=v"3") => "linux3", P("aarch64", "linux"; libgfortran_version=v"3", libstdcxx_version=v"3.4.18") => "linux5", + P("aarch64", "linux"; libgfortran_version=v"3", libstdcxx_version=v"3.4.18", foo="bar") => "linux9", # OS test P("x86_64", "macos"; libgfortran_version=v"3") => "mac4", @@ -327,8 +328,10 @@ end @test select_platform(platforms, P("x86_64", "linux"; libgfortran_version=v"4")) == "linux7" # Ambiguity test - @test select_platform(platforms, P("aarch64", "linux")) == "linux5" - @test select_platform(platforms, P("aarch64", "linux"; libgfortran_version=v"3")) == "linux5" + @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"4")) === nothing @test select_platform(platforms, P("x86_64", "macos")) == "mac4" @@ -339,6 +342,14 @@ 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: + platforms = Dict( + # Typical binning test + P("x86_64", "linux") => "good", + P("x86_64", "linux"; sanitize="memory") => "bad", + ) + @test select_platform(platforms, P("x86_64", "linux")) == "good" end @testset "Custom comparators" begin