Skip to content

Commit 28dcc8a

Browse files
committed
[Dependencies] Require compat argument for runtime dependencies
1 parent 944f07c commit 28dcc8a

File tree

3 files changed

+54
-69
lines changed

3 files changed

+54
-69
lines changed

src/BinaryBuilderBase.jl

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ export HostPlatform, platform_dlext, valid_dl_path, arch, libc,
1414
Platform, AnyPlatform
1515

1616
export AbstractSource, AbstractDependency, SetupSource, PatchSource,
17-
resolve_jlls, coerce_dependency, coerce_source, Runner,
17+
resolve_jlls, coerce_source, Runner,
1818
generate_compiler_wrappers!, preferred_runner, CompilerShard, UserNSRunner,
1919
DockerRunner, choose_shards, exeext, preferred_libgfortran_version,
2020
preferred_cxxstring_abi, gcc_version, available_gcc_builds, getversion,

src/Dependencies.jl

+17-22
Original file line numberDiff line numberDiff line change
@@ -85,10 +85,8 @@ the latest version of the package compatible with the environment will be
8585
automatically chosen by the package resolver, unless `compat` is specified, see
8686
below.
8787
88-
The optional keyword argument `compat` can be used to specify a string for use
89-
in the `Project.toml` of the generated Julia package. If `compat` is non-empty
90-
and `build_version` is not passed, the latter defaults to the minimum version
91-
compatible with the `compat` specifier.
88+
The keyword argument `compat` must be used to specify a string for use in the `Project.toml` of the generated Julia package.
89+
If `build_version` is not passed, the minimum version compatible with the `compat` specifier is used as build version.
9290
9391
The optional keyword argument `platforms` is a vector of `AbstractPlatform`s
9492
which indicates for which platforms the dependency should be used. By default
@@ -123,9 +121,12 @@ struct Dependency <: AbstractDependency
123121
if build_version spec
124122
throw(ArgumentError("build_version and compat for $(pkg) are incompatible"))
125123
end
126-
if pkg.version != PKG_VERSIONS.VersionSpec("*") && !(pkg.version in spec)
127-
throw(ArgumentError("PackageSpec version and compat for $(pkg) are incompatible"))
124+
if pkg.version != PKG_VERSIONS.VersionSpec("*")
125+
compatible_p = pkg.version isa PKG_VERSIONS.VersionSpec ? !isempty(intersect(pkg.version, spec)) : (pkg.version in spec)
126+
compatible_p || throw(ArgumentError("""PackageSpec version and compat ("$(compat)") for $(pkg) are incompatible"""))
128127
end
128+
else
129+
throw(ArgumentError("""Dependency("$(getname(pkg))") must have a non-empty compat bound."""))
129130
end
130131
if top_level
131132
@warn("Dependency(\"$(getname(pkg))\") was defined as top-level but this is deprecated, use `RuntimeDependency` instead")
@@ -154,8 +155,7 @@ Define a binary dependency that is only listed as dependency of the generated JL
154155
but its artifact is not installed in the prefix during the build. The `dep` argument can be
155156
either a string with the name of the JLL package or a `Pkg.PackageSpec`.
156157
157-
The optional keyword argument `compat` can be used to specify a string for use
158-
in the `Project.toml` of the generated Julia package.
158+
The keyword argument `compat` must be used to specify a string for use in the `Project.toml` of the generated Julia package.
159159
160160
The optional keyword argument `platforms` is a vector of `AbstractPlatform`s which indicates
161161
for which platforms the dependency should be used. By default `platforms=[AnyPlatform()]`,
@@ -176,9 +176,12 @@ struct RuntimeDependency <: AbstractDependency
176176
top_level::Bool=false)
177177
if !isempty(compat)
178178
spec = PKG_VERSIONS.semver_spec(compat) # verify compat is valid
179-
if pkg.version != PKG_VERSIONS.VersionSpec("*") && !(pkg.version in spec)
180-
throw(ArgumentError("PackageSpec version and compat for $(pkg) are incompatible"))
179+
if pkg.version != PKG_VERSIONS.VersionSpec("*")
180+
compatible_p = pkg.version isa PKG_VERSIONS.VersionSpec ? !isempty(intersect(pkg.version, spec)) : (pkg.version in spec)
181+
compatible_p || throw(ArgumentError("""PackageSpec version and compat ("$(compat)") for $(pkg) are incompatible"""))
181182
end
183+
else
184+
throw(ArgumentError("""RuntimeDependency("$(getname(pkg))") must have a non-empty compat bound."""))
182185
end
183186
if top_level
184187
if !(isempty(platforms) || all(==(AnyPlatform()), platforms))
@@ -276,7 +279,9 @@ filter_platforms(deps::AbstractVector{<:AbstractDependency}, p::AbstractPlatform
276279
function registry_resolve!(ctx, dependencies::Vector{<:AbstractDependency})
277280
resolved_dependencies = Pkg.Types.registry_resolve!(ctx.registries, getpkg.(dependencies))
278281
for idx in eachindex(dependencies)
279-
dependencies[idx] = typeof(dependencies[idx])(resolved_dependencies[idx]; platforms=dependencies[idx].platforms)
282+
dependencies[idx] = typeof(dependencies[idx])(resolved_dependencies[idx];
283+
compat=dependencies[idx].compat,
284+
platforms=dependencies[idx].platforms)
280285
end
281286
return dependencies
282287
end
@@ -300,8 +305,7 @@ function resolve_jlls(dependencies::Vector; ctx = Pkg.Types.Context(), outs=stdo
300305
end
301306

302307
# Don't clobber caller
303-
# XXX: Coercion is needed as long as we support old-style dependencies.
304-
dependencies = deepcopy(coerce_dependency.(dependencies))
308+
dependencies = deepcopy(dependencies)
305309

306310
# If all dependencies already have a UUID, return early
307311
if all(x->getpkg(x).uuid !== nothing, dependencies)
@@ -378,12 +382,3 @@ function dependencify(d::Dict)
378382
end
379383
error("Cannot convert to dependency")
380384
end
381-
382-
383-
# XXX: compatibility functions. These are needed until we support old-style
384-
# dependencies.
385-
coerce_dependency(dep::AbstractDependency) = dep
386-
function coerce_dependency(dep)
387-
@warn "Using PackageSpec or string as dependency is deprecated, use Dependency instead"
388-
Dependency(dep)
389-
end

test/dependencies.jl

+36-46
Original file line numberDiff line numberDiff line change
@@ -22,44 +22,48 @@ end
2222

2323
@testset "Dependencies" begin
2424
name = "Foo_jll"
25-
dep = Dependency(PackageSpec(; name = name); platforms=supported_platforms(; experimental=true, exclude=!Sys.isapple))
26-
@test Dependency(name) dep
25+
dep = Dependency(PackageSpec(; name = name); compat="0", platforms=supported_platforms(; experimental=true, exclude=!Sys.isapple))
26+
@test Dependency(name; compat="0") dep
2727
@test !is_host_dependency(dep)
2828
@test is_target_dependency(dep)
2929
@test is_build_dependency(dep)
3030
@test is_runtime_dependency(dep)
3131
@test !is_top_level_dependency(dep)
3232
@test getname(dep) == name
3333
@test getname(PackageSpec(; name = name)) == name
34-
@test getpkg(dep) == PackageSpec(; name = name)
35-
@test getcompat(dep) == ""
34+
@test getpkg(dep) == PackageSpec(; name = name, version = PKG_VERSIONS.VersionSpec(v"0"))
35+
@test getcompat(dep) == "0"
3636

3737
build_version = v"1.2.3"
38-
dep_buildver = Dependency(PackageSpec(; name = name), build_version)
39-
@test Dependency(name, build_version) == dep_buildver
38+
dep_buildver = Dependency(PackageSpec(; name = name), build_version; compat = "~1.2")
39+
@test Dependency(name, build_version; compat="~1.2") == dep_buildver
4040
@test getname(dep_buildver) == name
4141
@test getpkg(dep_buildver) == PackageSpec(; name = name, version = PKG_VERSIONS.VersionSpec(build_version))
42-
@test getcompat(dep_buildver) == ""
42+
@test getcompat(dep_buildver) == "~1.2"
4343

44-
# the same but with compat info
44+
# the same but with platforms argument
4545
dep_buildver = Dependency(PackageSpec(; name = name), build_version; compat = "~1.2", platforms=[Platform("x86_64", "linux"; cxxstring_abi="cxx11")])
46-
@test Dependency(name, build_version) dep_buildver
46+
@test Dependency(name, build_version; compat="~1.2") dep_buildver
4747
@test getname(dep_buildver) == name
4848
@test getpkg(dep_buildver) == PackageSpec(; name = name, version = PKG_VERSIONS.VersionSpec(build_version))
4949
@test getcompat(dep_buildver) == "~1.2"
5050

5151
# the same but only with compat specifier
5252
dep_compat = Dependency(PackageSpec(; name); compat = "2, ~$(build_version)")
53-
@test Dependency(name, build_version) dep_compat
53+
@test Dependency(name, build_version; compat="2, ~$(build_version)") dep_compat
5454
@test getname(dep_compat) == name
5555
@test getpkg(dep_compat) == PackageSpec(; name, version = PKG_VERSIONS.VersionSpec(build_version))
5656
@test getcompat(dep_compat) == "2, ~$(build_version)"
5757

5858
# if build_version and compat don't match, an error should be thrown
5959
@test_throws ArgumentError Dependency(PackageSpec(; name = name), build_version; compat = "2.0")
6060

61+
# Runtime dependencies without compat bounds should throw an error
62+
@test_throws ArgumentError Dependency(name)
63+
@test_throws ArgumentError RuntimeDependency(name)
64+
6165
run_dep = RuntimeDependency(PackageSpec(; name); compat="3.14")
62-
@test RuntimeDependency(name) run_dep
66+
@test RuntimeDependency(name; compat="3.14") run_dep
6367
@test !is_host_dependency(run_dep)
6468
@test is_target_dependency(run_dep)
6569
@test !is_build_dependency(run_dep)
@@ -72,8 +76,8 @@ end
7276
# We should be able to convert a `Vector{RuntimeDependency}` to `Vector{Dependency}`
7377
@test Dependency[RuntimeDependency(name; compat="~1.8", platforms=[Platform("aarch64", "macos"; cxxstring_abi="cxx03")])] ==
7478
[Dependency(name; compat="~1.8", platforms=[Platform("aarch64", "macos"; cxxstring_abi="cxx03")])]
75-
@test @test_logs((:warn, r"was defined as top-level"), Dependency[RuntimeDependency(name; top_level=true)]) ==
76-
[@test_logs((:warn, r"was defined as top-level"), Dependency(name; top_level=true))]
79+
@test @test_logs((:warn, r"was defined as top-level"), Dependency[RuntimeDependency(name; compat="1", top_level=true)]) ==
80+
[@test_logs((:warn, r"was defined as top-level"), Dependency(name; compat="1", top_level=true))]
7781
# If the version in the PackageSpec and the compat don't match, an error should be thrown
7882
@test_throws ArgumentError RuntimeDependency(PackageSpec(; name, version=v"1.2.3"); compat = "2.0")
7983

@@ -102,12 +106,12 @@ end
102106
@test getpkg(host_dep) == PackageSpec(; name = host_name)
103107

104108
top_level_name = "MPIPreferences"
105-
@test_logs (:warn, r"deprecated") @test_throws ArgumentError Dependency(PackageSpec(; name=top_level_name); platforms=supported_platforms(; exclude=!Sys.isapple), top_level=true)
106-
@test_throws ArgumentError RuntimeDependency(PackageSpec(; name=top_level_name); platforms=supported_platforms(; exclude=!Sys.isapple), top_level=true)
109+
@test_logs (:warn, r"deprecated") @test_throws ArgumentError Dependency(PackageSpec(; name=top_level_name); compat="0", platforms=supported_platforms(; exclude=!Sys.isapple), top_level=true)
110+
@test_throws ArgumentError RuntimeDependency(PackageSpec(; name=top_level_name); compat="1", platforms=supported_platforms(; exclude=!Sys.isapple), top_level=true)
107111

108-
top_level_dep = @test_logs (:warn, r"deprecated") Dependency(PackageSpec(; name = top_level_name); top_level=true)
112+
top_level_dep = @test_logs (:warn, r"deprecated") Dependency(PackageSpec(; name = top_level_name); compat="1", top_level=true)
109113
@test is_top_level_dependency(top_level_dep)
110-
top_level_dep = RuntimeDependency(PackageSpec(; name = top_level_name); top_level=true)
114+
top_level_dep = RuntimeDependency(PackageSpec(; name = top_level_name); compat="1", top_level=true)
111115
@test is_top_level_dependency(top_level_dep)
112116

113117
@testset "Filter dependencies by platform" begin
@@ -117,7 +121,7 @@ end
117121

118122
@testset "JSON (de)serialization" begin
119123
jdep = JSON.lower(dep)
120-
@test jdep == Dict("type" => "dependency", "name" => name, "uuid" => nothing, "compat" => "", "version-major" => 0x0, "version-minor" => 0x0, "version-patch" => 0x0, "platforms" => ["x86_64-apple-darwin", "aarch64-apple-darwin"], "top_level" => false)
124+
@test jdep == Dict("type" => "dependency", "name" => name, "uuid" => nothing, "compat" => "0", "version-major" => 0x0, "version-minor" => 0x0, "version-patch" => 0x0, "platforms" => ["x86_64-apple-darwin", "aarch64-apple-darwin"], "top_level" => false)
121125
@test dependencify(jdep) == dep
122126

123127
jrun_dep = JSON.lower(run_dep)
@@ -137,14 +141,14 @@ end
137141
@test jhost_dep == Dict("type" => "hostdependency", "name" => host_name, "uuid" => nothing, "compat" => "", "version-major" => 0x0, "version-minor" => 0x0, "version-patch" => 0x0, "platforms" => ["any"], "top_level" => false)
138142
@test dependencify(jhost_dep) == host_dep
139143

140-
full_dep = Dependency(PackageSpec(; name = "Baz_jll", uuid = "00000000-1111-2222-3333-444444444444", version = PKG_VERSIONS.VersionSpec("3.1.4")))
144+
full_dep = Dependency(PackageSpec(; name = "Baz_jll", uuid = "00000000-1111-2222-3333-444444444444", version = PKG_VERSIONS.VersionSpec("3.1.4")); compat="3")
141145
jfull_dep = JSON.lower(full_dep)
142-
@test jfull_dep == Dict("type" => "dependency", "name" => "Baz_jll", "uuid" => "00000000-1111-2222-3333-444444444444", "compat" => "", "version-major" => 0x3, "version-minor" => 0x1, "version-patch" => 0x4, "platforms" => ["any"], "top_level" => false)
146+
@test jfull_dep == Dict("type" => "dependency", "name" => "Baz_jll", "uuid" => "00000000-1111-2222-3333-444444444444", "compat" => "3", "version-major" => 0x3, "version-minor" => 0x1, "version-patch" => 0x4, "platforms" => ["any"], "top_level" => false)
143147
@test dependencify(jfull_dep) == full_dep
144148
@test_throws ErrorException dependencify(Dict("type" => "git"))
145149

146150
jtop_level_dep = JSON.lower(top_level_dep)
147-
@test jtop_level_dep == Dict("type" => "runtimedependency", "name" => "MPIPreferences", "uuid" => nothing, "compat" => "", "version-major" => 0x0, "version-minor" => 0x0, "version-patch" => 0x0, "platforms" => ["any"], "top_level" => true)
151+
@test jtop_level_dep == Dict("type" => "runtimedependency", "name" => "MPIPreferences", "uuid" => nothing, "compat" => "1", "version-major" => 0x0, "version-minor" => 0x0, "version-patch" => 0x0, "platforms" => ["any"], "top_level" => true)
148152
@test dependencify(jtop_level_dep) == top_level_dep
149153
end
150154

@@ -164,7 +168,7 @@ end
164168
with_temp_project() do dir
165169
prefix = Prefix(dir)
166170
dependencies = [
167-
Dependency("Zlib_jll")
171+
Dependency("Zlib_jll"; compat="1.2.12")
168172
]
169173
platform = HostPlatform()
170174
ap = @test_logs setup_dependencies(prefix, getpkg.(dependencies), platform)
@@ -199,7 +203,7 @@ end
199203
with_temp_project() do dir
200204
prefix = Prefix(dir)
201205
dependencies = [
202-
Dependency("LibCURL_jll")
206+
Dependency("LibCURL_jll"; compat="7, 8")
203207
]
204208
platform = HostPlatform()
205209
ap = @test_logs setup_dependencies(prefix, getpkg.(dependencies), platform)
@@ -222,7 +226,7 @@ end
222226
with_temp_project() do dir
223227
prefix = Prefix(dir)
224228
dependencies = [
225-
Dependency("LibOSXUnwind_jll")
229+
Dependency("LibOSXUnwind_jll"; compat="0.0.7")
226230
]
227231
platform = Platform("i686", "linux"; libc="musl")
228232
@test_logs (:warn, r"Dependency LibOSXUnwind_jll does not have a mapping for artifact LibOSXUnwind for platform i686-linux-musl") begin
@@ -234,7 +238,7 @@ end
234238
# Test setup of dependencies that depend on the Julia version
235239
with_temp_project() do dir
236240
prefix = Prefix(dir)
237-
dependencies = [Dependency("GMP_jll")]
241+
dependencies = [Dependency("GMP_jll"; compat="6.1.2")]
238242
platform = Platform("x86_64", "linux"; julia_version=v"1.5")
239243

240244
# Test that a particular version of GMP is installed
@@ -245,7 +249,7 @@ end
245249
# Next, test on Julia v1.6
246250
with_temp_project() do dir
247251
prefix = Prefix(dir)
248-
dependencies = [Dependency("GMP_jll")]
252+
dependencies = [Dependency("GMP_jll"; compat="6.2.1")]
249253
platform = Platform("x86_64", "linux"; julia_version=v"1.6")
250254

251255
# Test that a particular version of GMP is installed
@@ -257,8 +261,8 @@ end
257261
with_temp_project() do dir
258262
prefix = Prefix(dir)
259263
dependencies = [
260-
Dependency("GMP_jll", v"6.1.2"),
261-
Dependency("MPFR_jll",v"4.1.0"),
264+
Dependency("GMP_jll"; compat="6.1.2"),
265+
Dependency("MPFR_jll"; compat="4.1.0"),
262266
]
263267

264268
# Test that this is not instantiatable with either Julia v1.5 or v1.6
@@ -348,30 +352,16 @@ end
348352
end
349353

350354
@testset "resolve_jlls" begin
351-
# Deps given by name::String
352-
dependencies = ["OpenSSL_jll",]
353-
@test_logs (:warn, r"use Dependency instead") begin
354-
truefalse, resolved_deps = resolve_jlls(dependencies)
355-
@test truefalse
356-
@test all(x->getpkg(x).uuid !== nothing, resolved_deps)
357-
end
358-
# Deps given by name::PackageSpec
359-
@test_logs (:warn, r"use Dependency instead") begin
360-
dependencies = [PackageSpec(name="OpenSSL_jll"),]
361-
truefalse, resolved_deps = resolve_jlls(dependencies)
362-
@test truefalse
363-
@test all(x->getpkg(x).uuid !== nothing, resolved_deps)
364-
end
365355
# Deps given by (name,uuid)::PackageSpec
366-
dependencies = [Dependency(PackageSpec(name="OpenSSL_jll", uuid="458c3c95-2e84-50aa-8efc-19380b2a3a95")),]
356+
dependencies = [Dependency(PackageSpec(name="OpenSSL_jll", uuid="458c3c95-2e84-50aa-8efc-19380b2a3a95"); compat="3.0.3"),]
367357
truefalse, resolved_deps = resolve_jlls(dependencies)
368358
@test truefalse
369359
@test all(x->getpkg(x).uuid !== nothing, resolved_deps)
370360
# Deps given by combination of name::String, name::PackageSpec and (name,uuid)::PackageSpec
371361
dependencies = [
372-
Dependency("Zlib_jll"),
373-
Dependency(PackageSpec(name="Bzip2_jll")),
374-
Dependency(PackageSpec(name="OpenSSL_jll", uuid="458c3c95-2e84-50aa-8efc-19380b2a3a95")),
362+
Dependency("Zlib_jll"; compat="1.2.13"),
363+
Dependency(PackageSpec(name="Bzip2_jll"); compat="1.0.8"),
364+
Dependency(PackageSpec(name="OpenSSL_jll", uuid="458c3c95-2e84-50aa-8efc-19380b2a3a95"); compat="3.0.3"),
375365
]
376366
truefalse, resolved_deps = resolve_jlls(dependencies)
377367
@test truefalse

0 commit comments

Comments
 (0)