ROS Logo
rules_perl 1.1.2.rcr.0Latest published 12h ago
MODULE.bazel
bazel_dep(name = "rules_perl", version = "1.1.2.rcr.0")
README

Build status

Perl Rules

The Perl Toolchain utilizes the portable-perl project.

Getting Started

To import rules_perl in your project, you first need to add it to your WORKSPACE file:

If you are still using WORKSPACE to manage your dependencies:

git_repository(
    name = "rules_perl",
    remote = "https://github.com/bazelbuild/rules_perl.git",
    branch = "main",
)

load("@rules_perl//perl:deps.bzl", "perl_register_toolchains", "perl_rules_dependencies")

perl_rules_dependencies()
perl_register_toolchains()

Once you've imported the rule set into your WORKSPACE, you can then load the perl rules in your BUILD files with:

load("@rules_perl//perl:perl.bzl", "perl_binary")

perl_binary(
    name = "hello_world",
    srcs = ["hello_world.pl"]
)

Please see example folder for more examples of how to include Perl scripts.

Toolchains

The toolchains are upstream Perl, built from source with ithreads, that runs from wherever Bazel unpacks it:

OS CPUs Builds
Linux x86_64, aarch64 musl-static (default), gnu (glibc ≥ 2.17), musl
macOS x86_64, aarch64 one
Windows x86_64, aarch64 msvc (default), gnu (mingw-w64 on the UCRT; x86_64 only)

--@rules_perl//perl/settings:distribution picks the vendor: perl (default) or strawberry, Strawberry Perl on Windows x86_64.

--@rules_perl//perl/settings:xs says whether the build needs a perl that can load XS modules, and on Linux picks the build. Off, the default, resolves musl-static, which is statically linked and so runs on any Linux whatever its C library (NixOS included, where the gnu build's loader is not at /lib64), but cannot load XS. A build with perl_xs turns it on in .bazelrc, which resolves the gnu build:

common --@rules_perl//perl/settings:xs=true

The static build has one more limit: it cannot read its own path, so when it is invoked by a relative path, as Bazel actions do, and the script then changes directory, @INC no longer resolves and lazily loaded modules are not found. perl_binary is unaffected, its launcher re-executes with an absolute path; a rule that runs the toolchain's interpreter directly should make @INC absolute first, as perl/private/xsubpp.pl does.

A target that needs XS can mark itself incompatible with the flag off, so that a wildcard build that leaves it off skips it, and everything depending on it:

target_compatible_with = select({
    "@rules_perl//perl/settings:xs_disabled": ["@platforms//:incompatible"],
    "//conditions:default": [],
}),

The musl build needs the host's musl loader, so until platform constraints for the C library exist (platforms_contrib is not yet released) toolchain resolution does not reach it, nor the Windows gnu build. A root module can register one ahead of rules_perl's:

register_toolchains("@rules_perl//perl:perl_x86_64_linux_musl_toolchain")

The binaries are GitHub releases of bazel-contrib/portable-perl.

Mac Support

Pure-Perl modules and, with perl_xs, XS modules both build on macOS.

Windows Support

perl_xs compiles with the resolved C toolchain, MSVC (Bazel's default) or MinGW gcc, and links against the import library of whichever Windows perl is selected. See the perl_xs documentation.

Using Perl Modules

Perl modules from CPAN can be generated using the cpan_compiler rule in conjunction with the cpan module extension.

From a cpanfile.snapshot

On a Bazel whose module extensions have facts, the extension reads Carton's cpanfile.snapshot directly:

cpan = use_extension("@rules_perl//perl/cpan:extensions.bzl", "cpan")
cpan.install(
    name = "cpan",
    lock = "//:cpanfile.snapshot",
)
use_repo(cpan, "cpan")

The snapshot names every archive but has no hashes of them, so the first evaluation fetches each archive once for its hash and remembers it in MODULE.bazel.lock as a fact; later evaluations, and builds from the repository cache, need nothing more. Check the lockfile in. A module whose consumers must not fetch anything unpinned, one published to a registry for instance, should ship the JSON lock below instead, and a Bazel without facts can only read that.

From a compiled lock

  1. Create a cpanfile per the Carton documentation.
  2. Create an empty *.json will need to be created for Bazel to use a lockfile (e.g. cpanfile.snapshot.lock.json)
  3. Define a cpan_compiler target:
load("//perl/cpan:cpan_compiler.bzl", "cpan_compiler")

cpan_compiler(
    name = "compiler",
    cpanfile = "cpanfile",
    lockfile = "cpanfile.snapshot.lock.json",
    visibility = ["//visibility:public"],
)
  1. bazel run the new target.
  2. Define a new module in MODULE.bazel pointing to the Bazel *.json lock file:
cpan = use_extension("@rules_perl//perl/cpan:extensions.bzl", "cpan")
cpan.install(
    name = "cpan",
    lock = "//perl/cpan/3rdparty:cpanfile.snapshot.lock.json",
)
use_repo(
    cpan,
    "cpan",
)

Dependencies

Once the cpan module extension is defined, dependencies will be available through the name given to the module. Using the example in the steps above, each distribution is a package of @cpan (e.g. @cpan//DateTime), and a binary from bins a target in it (bins = {"App-cloc": ["bin/cloc"]} gives @cpan//App-cloc:bin_cloc). @cpan//:DateTime and @cpan//:App-cloc_bin_cloc, the previous spellings, still resolve but are deprecated.

Each distinct archive is downloaded once and shared by every hub that pins it, across modules; a hub only decides which dependencies each distribution sees.

Note that xs dependencies are currently not supported by the cpan extension module.

Simple Pure Perl Example

Downloaded and unpacked: Test::Mock::Simple

This modules was chosen because it has no dependencies and is pure Perl.

Moved the required file to examples/cpan/Test-Mock-Simple-0.10/lib

NOTE: this location has been chosen so you can compare what is in the tar vs what as actually needed. This is a bad location! It would be better to be in cpan/lib.

Create a target for the module in your BUILD file (which resides in the cpan directory):

perl_library(
    name = "TestMockSimple",
    srcs = ["Test-Mock-Simple-0.10/lib/Test/Mock/Simple.pm"],
)

Now you can specify it as a dependency to any script that requires that module:

env = {
        "PERL5LIB": "examples/cpan/Test-Mock-Simple-0.10/lib",
    },
    deps = ["//examples/cpan:TestMockSimple"],

NOTE: at this time you need to provide the directory that Perl needs to add to @INC.

PERL5LIB includes

perl_binary (and perl_test) sets up the PERL5LIB environment variable with values for all perl_library dep's includes. The default includes are [".", "lib"].

About

Perl rules for Bazel

@bazelbuild/rules_perl@bazelbuild
Homepage
31stars
6:05 PM (12 hours ago)
#239 feat: add lyrical.2026-10-05....

Languages

Perl19.1%
Smarty2.2%
C++0.9%
Shell0.8%

Maintainers

Versions

1.1.2.rcr.0100% 42026-11-02