Pkg.jl

repository·master·Indexed 20 days ago

https://github.com/julialang/pkg.jl

The official package manager for the Julia programming language, shipped as a standard library since v1.0. Pkg.jl handles dependency resolution, environment management, and package installation. It includes APIs for managing artifacts via Pkg.Artifacts, handling complex requirements with PackageSpec and RegistrySpec, and experimental support for Julia Apps—standalone programs defined with a @main entry point and configured in Project.toml.

Tokens
26.8K
Snippets
90
Records
138
Agent score
71%

What's inside Pkg.jl

  1. Define weak dependencies

    master

    A weak dependency is a dependency that is not automatically installed when your package is installed, but you can still control which versions are allowed if the user chooses to install it. This is primarily used for Extensions (requires Julia 1.9+).

    To define weak dependencies, list them under the [weakdeps] section in your Project.toml, and then define their version constraints in the [compat] section.

    [weakdeps]
    SomePackage = "b3785f31-9d33-4cdf-bc73-f646780f1739"
    
    [compat]
    SomePackage = "1.2"
  2. How version specifiers handle leading zeros (pre-1.0 versions)

    master

    Julia's handling of semantic versioning (semver) differs for versions with a major version of 0:

    1. 0.0.x versions: Versions where both major and minor are zero (e.g., 0.0.1 and 0.0.2) are considered incompatible.
    2. 0.a.b versions (where a != 0): A version with a non-zero minor version is considered compatible with versions having the same minor version and smaller or equal patch versions (0.a.c where c <= b).
    3. Different minor versions: Versions with different minor versions (e.g., 0.2.0 vs 0.3.0) are considered incompatible.

    Examples:

    • Example = "0.0.1" results in the range [0.0.1, 0.0.2) (effectively only version 0.0.1).
    • Example = "0.2.1" results in the range [0.2.1, 0.3.0).
    [compat]
    Example = "0.0.1" # Range: [0.0.1, 0.0.2)
    Example = "0.2.1" # Range: [0.2.1, 0.3.0)
  3. Understand Project and Manifest files

    master

    A project is defined by two primary files located in its root directory:

    • Project file (Project.toml or JuliaProject.toml): Describes project metadata, including name, UUID (for packages), authors, license, and a list of dependencies (names and UUIDs).
    • Manifest file (Manifest.toml or JuliaManifest.toml): Describes the complete, exact dependency graph. It records the specific versions of every package and library used.

    Version-specific Manifests: You can suffix the manifest file with -v{major}.{minor}.toml (e.g., Manifest-v1.10.toml). Julia prefers the manifest that matches the current VERSION, allowing you to maintain different environments for different Julia versions.

  4. Understand the difference between a Package and a Module

    master

    It is important to distinguish between the distributable unit and the code namespace:

    • Package: The distributable unit managed by Pkg. It is a source tree containing a Project.toml file.
    • Module: A Julia language construct (defined with the module keyword) that provides a namespace for code.

    Typically, a package contains a module with the same name (e.g., the DataFrames package contains a DataFrames module). You interact with the module using import or using, but Pkg manages the package.

  5. Manage monorepos using the `[workspace]` section

    master

    A workspace allows you to group multiple projects together. When resolving dependencies, Pkg considers the requirements of all projects in the workspace and records the compatible versions in a single shared manifest file located next to the base project file.

    Key Characteristics

    • Monorepo Support: Ideal for managing many unregistered packages.
    • Shared Resolution: All projects in the workspace are resolved together.
    • Nesting: Workspaces can be nested; merged workspaces use a single manifest stored alongside the 'root project'.
    • Isolation: Dependencies of the root package are not automatically available in child projects; children must declare their own [deps].
    [workspace]
    projects = ["test", "docs", "benchmarks", "PrivatePackage"]
  6. How environments work in Pkg

    master

    An environment is a collection of specific package versions. The active environment is the one currently being modified by Pkg commands like add, rm, and up.

    • The default environment is typically identified by the Julia version (e.g., (@v1.10)).
    • Environments are lightweight; if multiple environments use the same package version, it is only stored once on disk.
    • Each environment is defined by a project file (Project.toml) which tracks explicitly installed packages.
  7. Reproduce environments using Materialize

    master
    To ensure reproducibility across different machines, you can materialize an environment. When you run the instantiate command in Pkg, it materializes the environment by downloading and installing the exact package versions specified in the Manifest.toml file.
  8. What are package extensions and when to use them

    master

    A package extension is a module that is automatically loaded only when a specific set of other packages are loaded into the Julia session.

    Why use extensions?

    Use extensions to avoid making packages unconditional dependencies. This prevents increased load times and unnecessary dependency overhead for users who do not use the specific functionality provided by the secondary package. For example, a Plotting package can provide specialized plotting methods for a Contour package via an extension, but users of Plotting who don't use Contour won't have to load Contour automatically.

    Key Requirements

    • Requires Julia 1.9+.
    • Extensions are defined in a separate module (usually in an ext/ directory) and registered in the parent package's Project.toml.
  9. Define a public API using `export` and `public`

    master

    A package's public API consists of symbols that are explicitly made public. There are two ways to do this:

    1. export symbol: Makes the symbol available in the global namespace when a user calls using YourPackage.
    2. public symbol: Makes the symbol part of the public API (meaning changes to its behavior require a version bump), but the user must still access it via qualification (e.g., YourPackage.symbol) when using using YourPackage.

    Versioning Note: When you change the behavior of a public symbol such that it no longer conforms to its previous documentation/specification, you must increment the major version number according to Julia's SemVer variant.

    module HelloWorld
    
    export greet
    # greet is available via 'using HelloWorld'
    
    public greet_alien
    # greet_alien is public API, but requires 'HelloWorld.greet_alien()'
    
    import Random
    
    "Writes a friendly message."
    greet() = print("Hello World!")
    
    "Greet an alien."
    greet_alien() = print("Hello ", Random.randstring(8))
    
    end # module
  10. Understand the Pkg Protocol for resource retrieval

    master

    The Pkg Protocol is used by Pkg Clients to retrieve resources from Pkg Servers, such as registry versions, package source trees, and artifacts.

    Key features include:

    • Diffing: A system to request diffs of resources from previous versions to minimize download size during updates.
    • Bundling: A mechanism to request and receive multiple resources in a single request.
    • Caching: While /registries changes frequently, individual resources like /registry/$uuid/$hash, /package/$uuid/$hash, and /artifact/$hash can be cached indefinitely based on HTTP headers.
    • Compression: Supports zstd (preferred) and gzip via the Accept-Encoding header.