For some reason, I want to compile my package into binaries with PackageCompiler
. It generally works fine, but compiled directories always include something like libgit2
, which should be of no use to my package.
After some digging, I find the main reason to be the dependency on Pkg
, which comes from many xxx_jll
packages.
Let’s first have a look at how many dependencies Pkg
with introduce:
[[deps.Pkg]]
deps = ["Artifacts", "Dates", "Downloads", "LibGit2", "Libdl", "Logging", "Markdown", "Printf", "REPL", "Random", "SHA", "Serialization", "TOML", "Tar", "UUIDs", "p7zip_jll"]
uuid = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f"
It can be understood that seems I want to compile my package into binaries to deliver, dependencies like Downloads
(which then depends on LibCURL
), LibGit2
, REPL
, p7zip_jll
and so on are generally useless.
Besides, these dependencies will introduce vulnerabilities, like I have reported last year in this post. LibCURL
and LibGit2
will both introduce vulnerabilities, like CVE-2021-22945, CVE-2018-25032, and so on. Yes, the latter is a zlib bug, but libgit2 depends on that. These vulnerabilities sometimes can be solved by simply remove the related files, but why we ever have them, when we don’t need them at all?
Then, the reason for this.
It seems that these packages are created by JLLWrappers
, (through Yggdrasil
, I suppose?) and are relevant with following codes:
macro generate_main_file_header(src_name)
return excat(
# Declare this module as interpreted
generate_compiler_options(src_name),
# import Artifacts module
generate_imports(src_name),
)
end
macro generate_main_file(src_name, pkg_uuid)
return excat(
# `is_available()` forward declaration, `PATH_list` and `LIBPATH_list` forward definitions,
# `find_artifact_dir()` definition.
generate_toplevel_definitions(src_name, __source__),
# Select and load the best wrapper file
generate_wrapper_load(src_name, pkg_uuid, __source__),
)
end
Digging further, I find the following:
function generate_imports(src_name)
# We lie a bit in the registry that JLL packages are usable on Julia 1.0-1.2.
# This is to allow packages that might want to support Julia 1.0 to get the
# benefits of a JLL package on 1.3 (requiring them to declare a dependence on
# the JLL package in their Project.toml) but engage in heroic hacks to do
# something other than actually use a JLL package on 1.0-1.2. By allowing
# this package to be installed (but not loaded) on 1.0-1.2, we enable users
# to avoid splitting their package versions into pre-1.3 and post-1.3 branches
# if they are willing to engage in the kinds of hoop-jumping they might need
# to in order to install binaries in a JLL-compatible way on 1.0-1.2. One
# example of this hoop-jumping being to express a dependency on this JLL
# package, then import it within a `VERSION >= v"1.3"` conditional, and use
# the deprecated `build.jl` mechanism to download the binaries through e.g.
# `BinaryProvider.jl`. This should work well for the simplest packages, and
# require greater and greater heroics for more and more complex packages.
@static if VERSION < v"1.3.0-rc4"
return quote
error("Unable to use $($(src_name))_jll on Julia versions older than 1.3!")
end
elseif VERSION < v"1.6.0-DEV"
# Use slow Pkg-based Artifacts
return quote
using Libdl, Pkg, Pkg.BinaryPlatforms, Pkg.Artifacts
using Pkg.Artifacts: load_artifacts_toml, unpack_platform
using Pkg.BinaryPlatforms: triplet, select_platform
HostPlatform() = platform_key_abi()
end
else
# Use fast stdlib-based Artifacts + Preferences
return quote
using Libdl, Artifacts, JLLWrappers.Preferences, Base.BinaryPlatforms
using Artifacts: load_artifacts_toml, unpack_platform
using Base.BinaryPlatforms: triplet, select_platform
end
end
end
Thus, Pkg
seems to be required for pre-1.6.0 versions only? However, because of the considerations of backward compatibility, we will always have Pkg
as a dependency, at least before we move to julia 2.x?
Besides, some xxx_jll
packages need LazyArtifacts
, which in turn depends on Pkg
. This also is of no meaning for compiled binaries, I suppose?