diff --git a/src/AutoBuild.jl b/src/AutoBuild.jl index 758a59e17..cd1248d8a 100644 --- a/src/AutoBuild.jl +++ b/src/AutoBuild.jl @@ -7,6 +7,7 @@ import LibGit2 import PkgLicenses const DEFAULT_JULIA_VERSION_SPEC = "1.0" +const DEFAULT_JLLWRAPPERS_VERSION_SPEC = "1.2.0" const PKG_VERSIONS = Base.VERSION >= v"1.7-" ? Pkg.Versions : Pkg.Types mutable struct BuildTimer @@ -140,10 +141,19 @@ supported ones. A few additional keyword arguments are accept: package. This can for example be used to invoke an initialization API of a shared library. +* `augment_platform_block` may be set to a string containing Julia code; if + present, this code will be inserted into the top-level of the + generated JLL package. It must define a function `augment_platform!` that + takes as a single argument, the target platform and returns the target + platform, with amended tags. This augmented platform will then be used by the + JLL wrapper to select the artifact. Note that this option requires the Julia + compatibility `julia_compat` to be 1.6 or higher. + !!! note - The `init_block` keyword argument is experimental and may be removed - in a future version of this package. Please use it sparingly. + The `init_block` and `augment_platform_block` keyword arguments are experimental + and may be removed in a future version of this package. Please use them sparingly. + """ function build_tarballs(ARGS, src_name, src_version, sources, script, platforms, products, dependencies; @@ -304,7 +314,7 @@ function build_tarballs(ARGS, src_name, src_version, sources, script, # Dependencies that must be downloaded dependencies, ) - extra_kwargs = extract_kwargs(kwargs, (:lazy_artifacts, :init_block)) + extra_kwargs = extract_kwargs(kwargs, (:lazy_artifacts, :init_block, :augment_platform_block)) if meta_json_stream !== nothing # If they've asked for the JSON metadata, by all means, give it to them! @@ -523,7 +533,13 @@ function register_jll(name, build_version, dependencies, julia_compat; gh_auth=Wizard.github_auth(;allow_anonymous=false), gh_username=gh_get_json(DEFAULT_API, "/user"; auth=gh_auth)["login"], lazy_artifacts::Bool=false, + augment_platform_block="", kwargs...) + if !isempty(augment_platform_block) && + minimum(VersionNumber(rng.lower.t) for rng in PKG_VERSIONS.semver_spec(julia_compat).ranges) < v"1.6" + error("Augmentation blocks cannot be used with Julia v1.5-.\nChange `julia_compat` to require at least Julia v1.6") + end + # Calculate tree hash of wrapper code wrapper_tree_hash = bytes2hex(Pkg.GitTools.tree_hash(code_dir)) wrapper_commit_hash = LibGit2.head(code_dir) @@ -533,7 +549,8 @@ function register_jll(name, build_version, dependencies, julia_compat; cache = RegistryTools.RegistryCache(joinpath(Pkg.depots1(), "registries_binarybuilder")) registry_url = "https://$(gh_username):$(gh_auth.token)@github.com/JuliaRegistries/General" cache.registries[registry_url] = Base.UUID("23338594-aafe-5451-b93e-139f81909106") - project = Pkg.Types.Project(build_project_dict(name, build_version, dependencies, julia_compat; lazy_artifacts=lazy_artifacts)) + jllwrappers_compat = isempty(augment_platform_block) ? DEFAULT_JLLWRAPPERS_VERSION_SPEC : "1.4.0" + project = Pkg.Types.Project(build_project_dict(name, build_version, dependencies, julia_compat; jllwrappers_compat, lazy_artifacts=lazy_artifacts)) errors = setdiff(RegistryTools.registrator_errors, [:version_less_than_all_existing]) reg_branch = RegistryTools.register( "https://github.com/$(deploy_repo).git", @@ -596,7 +613,8 @@ function get_meta_json( dependencies::Vector{<:AbstractDependency}; julia_compat::String = DEFAULT_JULIA_VERSION_SPEC, lazy_artifacts::Bool = false, - init_block::String = "") + init_block::String = "", + augment_platform_block::String = "") dict = Dict( "name" => src_name, @@ -608,6 +626,7 @@ function get_meta_json( "julia_compat" => julia_compat, "lazy_artifacts" => lazy_artifacts, "init_block" => init_block, + "augment_platform_block" => augment_platform_block, ) # Do not write the list of platforms when building only for `AnyPlatform` if platforms != [AnyPlatform()] @@ -1063,6 +1082,7 @@ function rebuild_jll_package(obj::Dict; lazy_artifacts = lazy_artifacts, julia_compat = get(obj, "julia_compat", DEFAULT_JULIA_VERSION_SPEC), init_block = get(obj, "init_block", ""), + augment_platform_block = get(obj, "augment_platform_block", ""), from_scratch = from_scratch, ) end @@ -1167,7 +1187,8 @@ function build_jll_package(src_name::String, verbose::Bool = false, julia_compat::String = DEFAULT_JULIA_VERSION_SPEC, lazy_artifacts::Bool = false, - init_block = "") + init_block = "", + augment_platform_block = "",) # Make way, for prince artifacti mkpath(joinpath(code_dir, "src", "wrappers")) @@ -1290,6 +1311,38 @@ function build_jll_package(src_name::String, end end + if !isempty(augment_platform_block) + pkg_dir = joinpath(code_dir, ".pkg") + !ispath(pkg_dir) && mkdir(pkg_dir) + open(joinpath(pkg_dir, "platform_augmentation.jl"), "w") do io + println(io, """ + $(augment_platform_block) + """) + end + + open(joinpath(pkg_dir, "select_artifacts.jl"), "w") do io + println(io, """ + push!(Base.LOAD_PATH, dirname(@__DIR__)) + + using TOML, Artifacts, Base.BinaryPlatforms + include("./platform_augmentation.jl") + artifacts_toml = joinpath(dirname(@__DIR__), "Artifacts.toml") + + # Get "target triplet" from ARGS, if given (defaulting to the host triplet otherwise) + target_triplet = get(ARGS, 1, Base.BinaryPlatforms.host_triplet()) + + # Augment this platform object with any special tags we require + platform = augment_platform!(HostPlatform(parse(Platform, target_triplet))) + + # Select all downloadable artifacts that match that platform + artifacts = select_downloadable_artifacts(artifacts_toml; platform, include_lazy=true) + + #Output the result to `stdout` as a TOML dictionary + TOML.print(stdout, artifacts) + """) + end + end + # Generate target-demuxing main source file. open(joinpath(code_dir, "src", "$(src_name)_jll.jl"), "w") do io print(io, """ @@ -1301,6 +1354,13 @@ function build_jll_package(src_name::String, if lazy_artifacts println(io, "using LazyArtifacts") end + + if !isempty(augment_platform_block) + print(io, """ + Base.include(@__MODULE__, joinpath("..", ".pkg", "platform_augmentation.jl")) + """) + end + print(io, """ import JLLWrappers @@ -1429,7 +1489,8 @@ function build_jll_package(src_name::String, # Add a Project.toml. Note: here we list _all_ runtime dependencies, including those # that may be required only for some platforms. - project = build_project_dict(src_name, build_version, dependencies, julia_compat; lazy_artifacts=lazy_artifacts) + jllwrappers_compat = isempty(augment_platform_block) ? "1.2.0" : "1.4.0" + project = build_project_dict(src_name, build_version, dependencies, julia_compat; lazy_artifacts=lazy_artifacts, jllwrappers_compat) open(joinpath(code_dir, "Project.toml"), "w") do io Pkg.TOML.print(io, project) end @@ -1502,7 +1563,12 @@ function find_uuid(ctx, pkg) """) end -function build_project_dict(name, version, dependencies::Array{Dependency}, julia_compat::String=DEFAULT_JULIA_VERSION_SPEC; lazy_artifacts::Bool=false, kwargs...) +function build_project_dict(name, version, dependencies::Array{Dependency}, + julia_compat::String=DEFAULT_JULIA_VERSION_SPEC; + jllwrappers_compat::String=DEFAULT_JLLWRAPPERS_VERSION_SPEC, + lazy_artifacts::Bool=false, + augment_platform_block="", + kwargs...) Pkg.Types.semver_spec(julia_compat) # verify julia_compat is valid project = Dict( "name" => "$(name)_jll", @@ -1511,7 +1577,7 @@ function build_project_dict(name, version, dependencies::Array{Dependency}, juli "deps" => Dict{String,Any}(), # We require at least Julia 1.3+, for Pkg.Artifacts support, but we only claim # Julia 1.0+ by default so that empty JLLs can be installed on older versions. - "compat" => Dict{String,Any}("JLLWrappers" => "1.2.0", + "compat" => Dict{String,Any}("JLLWrappers" => "$(jllwrappers_compat)", "julia" => "$(julia_compat)") ) @@ -1538,6 +1604,9 @@ function build_project_dict(name, version, dependencies::Array{Dependency}, juli if lazy_artifacts project["deps"]["LazyArtifacts"] = "4af54fe1-eca0-43a8-85a7-787d91b784e3" end + if !isempty(augment_platform_block) + project["deps"]["TOML"] = "fa267f1f-6049-4f14-aa54-33bafae1ed76" + end return project end diff --git a/test/basic.jl b/test/basic.jl index 85de9b401..7af5989cf 100644 --- a/test/basic.jl +++ b/test/basic.jl @@ -231,6 +231,10 @@ end @test_throws ErrorException build_project_dict(name, version, dependencies, "nonsense") + # Ensure passing a JLLWrappers dependency bound works + dict = build_project_dict(name, version, dependencies; jllwrappers_compat="1.4.0") + @test dict["compat"] == Dict{String,Any}("julia" => "1.0", "JLLWrappers" => "1.4.0") + # Ensure passing compat bounds works dependencies = [ Dependency(PackageSpec(name="libLLVM_jll"), compat="=9.0.0"),