Bazel rules for Emacs Lisp

Table of Contents


1 Introduction

This repository provides a Bazel integration for Emacs Lisp; see the Bazel homepage for more information about Bazel, and see the Emacs Lisp manual. It is modeled after the rules definitions for other languages, like the C++ rules.

This is not an officially supported Google product.


2 Requirements

To use rules_elisp, you need Bazel. For installation instructions, see Installing Bazel. This repository supports all full Bazel releases starting with Bazel 7.2.1. You’ll also need a recent C/C++ compiler (GCC or Clang on GNU/Linux and macOS, Visual C++ 2019 on Windows) and at least Python 3.12. For further instructions how to use Bazel on Windows, see Installing Bazel on Windows.

This repository generally supports the two most recent major versions of Emacs. Currently, the supported versions are Emacs 29 and Emacs 30. Once Emacs 31 is released, support for Emacs 29 will be dropped.


3 Usage

Add a snippet like the following to your MODULE.bazel file:

bazel_dep(name = "phst_rules_elisp")
git_override(
    module_name = "phst_rules_elisp",
    remote = "https://github.com/phst/rules_elisp.git",
    commit = "10054ee512b7087eb53d92f4f85857b778e53357",
)

See the Bzlmod documentation for background information. Then you can use the elisp_library, elisp_cc_module, elisp_binary, and elisp_test rules. See the rule documentation below and the examples in the examples directory for details. Note that the C++ code used by rules_elisp requires at least C++17, but Bazel still compiles with C++11 by default. See the Abseil FAQ how to correctly change the C++ standard for your project.

Rule: elisp_library (name, [fatal_warnings], srcs, [outs], [data], [load_path], [deps])
load("@phst_rules_elisp//elisp:elisp_library.bzl", "elisp_library")

Byte-compiles Emacs Lisp source files and makes the compiled output available to dependencies. All sources are byte-compiled. elisp_library, elisp_binary, and elisp_test rules depending on this binary can then use load or require to load them.

By default, libraries need to be loaded using a filename relative to the repository root, i.e., package/​file. If you want to add further elements to the load path, use the load_path attribute.

If there are multiple source files specified in srcs, these source files can also load each other. However, it’s often preferable to only have one elisp_library target per source file to make dependencies more obvious and ensure that files get only loaded in their byte-compiled form.

The source files in srcs can also list shared objects. The rule treats them as Emacs modules and doesn’t try to byte-compile them. You can use e.g. cc_binary with linkshared = True to create shared objects.

The elisp_library rule supports the following attributes:

name

A unique name for this target. Name; mandatory.

fatal_warnings

If True (the default), then byte compile warnings should be treated as errors. If False, they still show up in the output, but don’t cause the compilation to fail. Most targets should leave this attribute as True, because otherwise important issues might remain undetected. Set this attribute to False only for integrating third-party libraries that don’t compile cleanly and that you don’t control. Boolean; optional; default: True.

srcs

List of source files. These must either be Emacs Lisp files ending in .el, or module objects ending in .so, .dylib, or .dll. List of labels; mandatory.

outs

List of byte-compiled Emacs Lisp files to be made available as targets. List of output files; optional; default: [].

data

List of files to be made available at runtime. List of labels; optional; default: [].

load_path

List of additional load path elements. The elements are directory names, which can be either relative or absolute. Relative names are relative to the current package. Absolute names are relative to the repository root. To add a load path entry for the current package, specify . here. List of strings; optional; default: [].

deps

List of elisp_library dependencies. List of labels; optional; default: []; required providers: EmacsLispInfo.

Rule: elisp_cc_module (name, [srcs], [deps], [data], [copts], [linkopts], [local_defines])
load("@phst_rules_elisp//elisp:elisp_cc_module.bzl", "elisp_cc_module")

Builds an Emacs dynamic module from C and C+​+​ source files. For background on Emacs modules, see Emacs Dynamic Modules, and see Writing Dynamically-Loaded Modules. The emacs_module rule is similar to cc_library, but it always builds a dynamic library (shared object) that can be loaded into Emacs. The module can also be used directly as dependency for elisp_library, elisp_binary, and elisp_test rules. The dynamic library will only export the symbols necessary for Emacs modules, plugin_is_GPL_compatible and emacs_module_init; see Module Initialization Code. The file name of the dynamic library will be name.extension, where name is the rule name as specified in the name attribute, and extension is the correct extension for dynamic libraries for the target operating system. The file name will not be prefixed with lib.

The library code in srcs can include a recent version of emacs-module.h using

#include "emacs-module.h"

to implement module functions.

The elisp_cc_module rule supports the following attributes:

name

A unique name for this target. Name; mandatory.

srcs

C and C+​+​ source files for the module. See the corresponding attribute for cc_library. List of labels; optional; default: [].

deps

cc_library targets that the module depends on. See the corresponding attribute for cc_library. List of labels; optional; default: []; required providers: CcInfo.

data

Data dependencies to make available at runtime. See the corresponding attribute for cc_library. List of labels; optional; default: [].

copts

Additional options to pass to the C/​C+​+​ compiler. See the corresponding attribute for cc_library. List of strings; optional; default: [].

linkopts

Additional options to pass to the C/​C+​+​ linker. See the corresponding attribute for cc_library. List of strings; optional; default: [].

local_defines

Additional preprocessor definitions to pass to the C/​C+​+​ compiler. See the corresponding attribute for cc_library. List of strings; optional; default: [].

Rule: elisp_binary (name, [fatal_warnings], src, [data], [deps], [interactive], [input_args], [output_args])
load("@phst_rules_elisp//elisp:elisp_binary.bzl", "elisp_binary")

Binary rule that loads a single Emacs Lisp file. The source file is byte-compiled. At runtime, the compiled version is loaded in batch mode unless interactive is True.

The elisp_binary rule supports the following attributes:

name

A unique name for this target. Name; mandatory.

fatal_warnings

If True (the default), then byte compile warnings should be treated as errors. If False, they still show up in the output, but don’t cause the compilation to fail. Most targets should leave this attribute as True, because otherwise important issues might remain undetected. Set this attribute to False only for integrating third-party libraries that don’t compile cleanly and that you don’t control. Boolean; optional; default: True.

src

Source file to load. Label; mandatory.

data

List of files to be made available at runtime. List of labels; optional; default: [].

deps

List of elisp_library dependencies. List of labels; optional; default: []; required providers: EmacsLispInfo.

interactive

Run Emacs in interactive instead of batch mode. Boolean; optional; default: False.

input_args

Indices of command-line arguments that represent input filenames. These numbers specify indices into the argv array. Negative indices are interpreted as counting from the end of the array. For example, the index 2 stands for argv[2], and the index -2 stands for argv[argc - 2]. When passing arguments to an emacs_binary program on the command line, the corresponding arguments are treated as filenames for input files and added to the inputFiles field of the manifest. This only has an effect for toolchains that specify wrap = True. List of integers; optional; default: [].

output_args

Indices of command-line arguments that represent output filenames. These numbers specify indices into the argv array. Negative indices are interpreted as counting from the end of the array. For example, the index 2 stands for argv[2], and the index -2 stands for argv[argc - 2]. When passing arguments to an emacs_binary program on the command line, the corresponding arguments are treated as filenames for output files and added to the outputFiles field of the manifest. This only has an effect for toolchains that specify wrap = True. List of integers; optional; default: [].

Rule: elisp_test (name, [fatal_warnings], srcs, [data], [deps], [skip_tests], [skip_tags])
load("@phst_rules_elisp//elisp:elisp_test.bzl", "elisp_test")

Runs ERT tests that are defined in the source files. The given source files should contain ERT tests defined with ert-deftest. For details, see How to Write Tests. The generated test binary loads all source files and executes all tests like ert-run-tests-batch-and-exit.

You can restrict the tests to be run using the --test_filter option. If set, the value of --test_filter must be a Lisp expression usable as an ERT test selector; see Test Selectors. You can also restrict the tests to be run using the skip_tests and skip_tags rule attributes. These restrictions are additive, i.e., a test only runs if it’s not suppressed by either facility.

In coverage mode (i.e., when run under bazel coverage), all tests tagged with the :nocover tag are also skipped. You can use this tag to skip tests that normally pass, but don’t work under coverage for some reason.

Test files can access additional command-line arguments passed via the args attribute or the --test_arg Bazel option via the command-line-args-left variable. After processing known arguments, test files must remove them from command-line-args-left so that it’s empty after all test files are loaded. Emacs will not automatically process these arguments using command-switch-alist or command-line-functions.

The elisp_test rule supports the following attributes:

name

A unique name for this target. Name; mandatory.

fatal_warnings

If True (the default), then byte compile warnings should be treated as errors. If False, they still show up in the output, but don’t cause the compilation to fail. Most targets should leave this attribute as True, because otherwise important issues might remain undetected. Set this attribute to False only for integrating third-party libraries that don’t compile cleanly and that you don’t control. Boolean; optional; default: True.

srcs

List of source files to load. List of labels; mandatory.

data

List of files to be made available at runtime. List of labels; optional; default: [].

deps

List of elisp_library dependencies. List of labels; optional; default: []; required providers: EmacsLispInfo.

skip_tests

List of tests to skip. This attribute contains a list of ERT test symbols; when running the test rule, these tests are skipped. Most of the time, you should use the skip-unless macro instead; see Tests and Their Environment. The skip_tests attribute is mainly useful for third-party code that you don’t control. List of strings; optional; default: [].

skip_tags

List of test tags to skip. This attribute contains a list of tag names; if a test is tagged with one of the tags from this list, it is skipped. This can be useful to e.g. skip tests that are flaky or only work in interactive mode. Use the :tags keyword argument to ert-deftest to tag tests. List of strings; optional; default: [].


4 Load path management

The Emacs Lisp rules by default only add the repository root directories to the load path; see (elisp)Library Search. However, many Emacs Lisp libraries assume that their immediate parent directory is present in the load path. To support such libraries, the elisp_library rule supports an optional load_path attribute. You can specify additional load path directories using this attribute. Relative directories are relative to the Bazel package directory; absolute directories are relative to the repository root. A typical use case is to specify load_path = ["."] to add the current package to the load path.


5 Runfiles

This repository also includes a library to access runfiles; see the Bazel documentation on runfiles. To use it, add a build dependency on @phst_rules_elisp//elisp/runfiles.

Use the function elisp/runfiles/rlocation to map a runfile name to a filename in the local filesystem. For more advanced use cases, see the class elisp/runfiles/runfiles.

The library also provides a file name handler for runfiles, elisp/runfiles/file-handler. It uses the prefix ‘/bazel-runfile:’.


6 Protocol buffers

By defining elisp_proto_library rules, you can use protocol buffers in Emacs Lisp; see https://developers.google.com/protocol-buffers. To make a protocol buffer definition available to Emacs Lisp, you first need a proto_library rule; see https://bazel.build/reference/be/protocol-buffer#proto_library. You can either use an existing proto_library rule or add your own. Then, add an elisp_proto_library rule that references the proto_library rule. Normally, the name of the proto_library rule ends in ‘_proto’, and the name of the corresponding elisp_proto_library rule has the same prefix and ends in ‘_elisp_proto’. For example:

load("@phst_rules_elisp//elisp/proto:elisp_proto_library.bzl", "elisp_proto_library")
load("@protobuf//bazel:proto_library.bzl", "proto_library")

proto_library(
    name = "my_proto",
    srcs = ["my.proto"],
)

elisp_proto_library(
    name = "my_elisp_proto",
    deps = [":my_proto"],
)

You can then use the elisp_proto_library rule in the same way as a normal elisp_library rule, i.e., depend on it in other elisp_library, elisp_binary, or elisp_test rules. The name of the Emacs Lisp feature for the library is the same as the name of the original ‘.proto’ file, relative to its repository root. For example, if the above BUILD file is in a package named ‘mypackage’, you would load the protocol buffer library using (require 'mypackage/my.proto).

Rule: elisp_proto_library (name, deps)
load("@phst_rules_elisp//elisp/proto:elisp_proto_library.bzl", "elisp_proto_library")

Generates Emacs bindings for a protocol buffer library. By convention, for a proto_library rule named prefix_​proto there should be a corresponding elisp_proto_library rule named prefix_​elisp_​proto. Other elisp_library, elisp_binary, and elisp_test rules can then depend on this rule. This rule generates and byte-compiles Emacs Lisp representations of the protocol buffer definitions listed in the deps attribute and all their direct and indirect dependencies. The feature symbol for require is the filename of the original .proto file listed in the proto_library rule, relative to its repository root.

The elisp_proto_library rule supports the following attributes:

name

A unique name for this target. Name; mandatory.

deps

List of exactly one proto_library rule. List of labels; mandatory; required providers: ProtoInfo.

Emacs Lisp protocol buffer bindings contain Emacs Lisp equivalents for all message and enumeration types defined in the underlying protocol buffer definition files. Because Emacs Lisp doesn’t have namespaces, the names of all defined entities are the full names of the corresponding protocol buffer descriptors, including the protocol buffer package name (which is often different from the Bazel package name), but with dots (‘.’) replaced with slashes (‘/’), because dots are special characters in Emacs Lisp; see (elisp)Symbol Type. For example, the Lisp name of the protocol buffer message type google.protobuf.Duration is google/protobuf/Duration, and the Lisp name of the protocol buffer enumeration value google.protobuf.FieldDescriptorProto.TYPE_BOOL is google/protobuf/FieldDescriptorProto/TYPE_BOOL.

When accessing protocol buffer message fields, Emacs translates field values to and from Lisp data types; see (elisp)Programming Types. For scalar types, the translation uses appropriate matching types, i.e., numbers and strings. Boolean values are translated to either nil or t. The bytes type is represented using unibyte strings; see (elisp)Text Representations. Accessing string and byte fields always creates copies; this means that changing the return value using aset will not modify the original protocol buffer message.

The situation is a bit more complex for submessage fields, repeated fields, and map fields. Emacs represents values of these fields using specialized types. For submessage fields, these types are again generated protocol buffer message types. For repeated and map fields, Emacs uses the types elisp/proto/array and elisp/proto/map, respectively. Message, array, and map objects can be mutable or immutable; attempting to modify an immutable object signals an error. The Lisp representations of these types are opaque structure-like types. Their implementation is maintained internally, and you shouldn’t try to access or modify it directly. Rather, the Emacs Lisp library elisp/proto/proto contains the following facilities to use and manipulate these types.

Type: elisp/proto/message

The base type for all message types. This is an abstract type; you can’t instantiate it directly.

Function: elisp/proto/message-p object

This predicate returns whether the given object is a protocol buffer message object.

Function: elisp/proto/message-mutable-p object

This predicate returns whether the given protocol buffer message object is mutable.

Type: elisp/proto/array

A type that represents repeated protocol buffer message fields. You can’t instantiate this type directly; instead, you obtain instances of this type by accessing repeated message fields.

Protocol buffer arrays are generalized sequences. This means you can use the functions from the seq.el library with them. See (elisp)Sequence Functions.

Function: elisp/proto/array-p object

This predicate returns whether the given object is a protocol buffer array object.

Function: elisp/proto/array-mutable-p object

This predicate returns whether the given protocol buffer array is mutable.

Type: elisp/proto/map

A type that represents protocol buffer map fields. You can’t instantiate this type directly; instead, you obtain instances of this type by accessing repeated message fields. See https://developers.google.com/protocol-buffers/docs/proto3#maps.

Protocol buffer maps are generalized maps. This means you can use the functions from the map.el library with them. See the comments in map.el for details.

Function: elisp/proto/map-p object

This predicate returns whether the given object is a protocol buffer map object.

Function: elisp/proto/map-mutable-p object

This predicate returns whether the given protocol buffer map is mutable.

It should be noted that protocol buffer arrays and maps are not “full” types. You can’t use them as replacement types for vectors or hash tables because there’s no way to create objects of these types from scratch. You can only obtain new objects by accessing protocol buffer message fields. This is also the reason why these types don’t provide implementations of seq-into, seq-concatenate or map-into that would return new protocol buffer arrays and maps.

Another important difference between these types and the standard Emacs Lisp types is that protocol buffer arrays and maps are strongly-typed: all their elements have the same type, which is determined when creating the object. For example, you can’t add a string value to a protocol buffer array holding integers.

The Lisp representation of protocol buffer enumerations are plain Lisp constants. See (elisp)Defining Variables. Their values are just the integral values of the corresponding enumerators.

Whenever Emacs needs to convert a Lisp value to a protocol buffer field value, an array element, or a map key or value, it accepts values that are compatible with the destination type. For example, you can use an integer to set a floating-point protocol buffer message field. Setting a Boolean field accepts any non-nil value as true. Setting a repeated field accepts lists, vectors, and any other generalized sequence type. Setting a map field accepts hash-tables, association lists, and any other generalized map type.

Function: elisp/proto/make type [fields...]

This function creates and initializes a new protocol buffer message object. The type must be a symbol denoting an existing protocol buffer message type, using the conventions described above (i.e., periods replaced with slashes). Before calling this function for a given type, you have to require the generated library that defines the type, otherwise the function will fail. The fields are keyword-value pairs of the form :field value that are used to initialize the fields. If a field isn’t mentioned in fields, it’s not set in the resulting message. For example, the following code creates a new protocol buffer message object of type google.protobuf.Duration:

(require 'elisp/proto/proto)
(require 'duration_proto)
(elisp/proto/make 'google/protobuf/Duration :seconds 3600)

The nanos field remains uninitialized.

For every protocol buffer message type, the generated library will also contain a function type-new that you can use as a shorthand for elisp/proto/make. For example, you could also write the above example as

(require 'duration_proto)
(google/protobuf/Duration-new :seconds 3600)

To check whether an object is a protocol buffer message object of a given type, the generated libraries contain predicate functions like type-p. For example, to test whether an object is a duration protocol buffer message, you can write

(require 'duration_proto)
(google/protobuf/Duration-p object)

You can also use the Common Lisp type predicates like cl-typep or cl-check-type with protocol buffer message objects. See (cl)Type Predicates.


6.1 Accessing protocol buffer message fields

The functions described in this section retrieve and manipulate message fields. They all accept a message object as first argument and a field name as second argument. The field name is a plain symbol denoting the unqualified field name.

Function: elisp/proto/has-field message field

This function returns whether the given field is present in the message object. If the field doesn’t have a notion of presence (e.g., it’s a repeated field), an error is signaled.

Function: elisp/proto/field message field

This function returns the value of the given field within the message object. If the field isn’t set in the message, then the return value depends on the type of the field. If the field is scalar, its default value is returned. If the field is a submessage, repeated, or map field, nil is returned. For non-scalar fields, the return value is immutable, i.e., trying to change it will signal an error.

If the field is a string or byte array field, the return value is a newly-allocated string. This implies that it’s often a good idea to bind the return value to a local variable instead of retrieving the value many times.

pcase pattern: elisp/proto type [fields...]

As a more compact alternative to type predicates and field access using elisp/proto/field, you can use elisp/proto patterns in pcase form. See (elisp)Pattern-Matching Conditional. The elisp/proto form takes an unquoted protocol buffer type and a list of fields. For example, the following form extracts the fields of a duration message:

(pcase message
  ((elisp/proto google/protobuf/Duration seconds nanos)
   (message "Duration with %d seconds and %d nanoseconds"
            seconds nanos))
  (_ (message "Some other thing")))

Instead of specifying plain field names, you can also specify (field pattern) pairs. These match the field value against pattern, which is again a pcase pattern. For example, the following code tests whether a duration is strictly positive:

(pcase message
  ((or (elisp/proto google/protobuf/Duration
                    (seconds (and (pred cl-plusp) seconds))
                    nanos)
       (elisp/proto google/protobuf/Duration
                    (seconds (and 0 seconds))
                    (nanos (and (pred cl-plusp) nanos))))
   (message "Duration with %d seconds and %d nanoseconds is positive"
            seconds nanos)))

A field construct that is a plain symbol is thus the same as (field field).

Function: elisp/proto/set-field message field value

This function sets the field to a new value. It signals an error if the message object is immutable, or if the new value isn’t compatible with the field type.


6.2 Parsing and serializing protocol buffer messages

The primary purpose of protocol buffers is data serialization. The Emacs Lisp protocol buffer bindings support all three major forms of protocol buffer serialization: binary, JSON, and text. However, currently the textual protocol buffer representation can only be generated, not parsed. Since none of the serialized forms are self-describing, you have to explicitly pass the desired message type to the parsing functions.

You can customize the behavior of the parsing and serialization functions to some extend with optional keyword arguments. These are the most common keyword arguments:

:allow-partial

This keyword argument affects how missing required fields are handled: by default, they cause an error to be signaled, but if the keyword argument is non-nil, they are silently ignored, and the result might not be fully initialized.

:discard-unknown

This keyword argument affects how unknown fields are handled: by default, they cause an error to be signaled, but if the keyword argument is non-nil, they are silently ignored.

:deterministic

If this keyword argument is non-nil, serialization functions attempt to produce slightly more deterministic output; however, this attempt is best-effort, since protocol buffer serialization is not guaranteed to be deterministic.

Other keyword arguments are described in the main body of the function definitions below.

Function: elisp/proto/parse type serialized [:allow-partial]

This function parses a protocol buffer message from its binary serialization form. The serialized argument must be a unibyte string containing the binary serialization of a protocol buffer message of type type. The type is again a symbol denoting a protocol buffer message type.

Function: elisp/proto/parse-json type serialized [:discard-unknown]

This function is like elisp/proto/parse, but it expects the JSON serialization instead of the binary serialization.

Function: elisp/proto/serialize message [:allow-partial] [:discard-unknown] [:deterministic]

This function is the inverse of elisp/proto/parse, producing the binary serialization of the message as a unibyte string.

Function: elisp/proto/serialize-text message [:compact] [:discard-unknown] [:deterministic]

This function is the inverse of elisp/proto/parse, producing the binary serialization of the message as a unibyte string. If the :compact keyword argument is non-nil, the output is a bit more compact, with less vertical whitespace; however, you shouldn’t rely on any specific output format in any case.

Function: elisp/proto/serialize-json message [:emit-defaults] [:proto-names]

This function is the inverse of elisp/proto/parse-json, producing the JSON serialization of the message as a string. If the :emit-defaults keyword argument is non-nil, the result will also include fields whose value equals their default value; normally such fields are left out. The :proto-names keyword argument determines the naming style for field names: by default, camel-case versions of the names are used, but if the keyword argument is non-nil, the names from the protocol buffer definition are used verbatim.

You can print a human-readable representation of protocol buffer messages, arrays, and maps using the functions cl-prin1, cl-prin1-to-string, or cl-print-to-string-with-limit. However, these objects don’t have a read syntax; see (elisp)Printed Representation. Using plain Emacs functions like print will result in a representation that’s not very human-readable; see (elisp)Read and Print.


6.3 Well-known protocol buffer types

The Emacs Lisp protocol buffer bindings contain some dedicated support for a few well-known message types. These are predefined types which are used frequently; see https://developers.google.com/protocol-buffers/docs/reference/google.protobuf.

Function: elisp/proto/timestamp message
Function: elisp/proto/duration message

These functions convert protocol buffer messages of type google.protobuf.Timestamp and google.protobuf.Duration to Lisp timestamps. See (elisp)Time of Day, for the definition of a Lisp timestamp.

Function: elisp/proto/make-timestamp time
Function: elisp/proto/make-duration time

These functions perform the opposite conversion, creating google.protobuf.Timestamp and google.protobuf.Duration messages from Lisp time values. See (elisp)Time of Day, for the definition of a Lisp time value.

Function: elisp/proto/set-timestamp message time
Function: elisp/proto/set-duration message time

These functions are similar, but they change message objects in place instead of creating new ones. The message arguments must be mutable. As an alternative to calling these functions directly, you can also use elisp/proto/timestamp and elisp/proto/duration as generalized variables; see (elisp)Generalized Variables.

Function: elisp/proto/pack-any message

This function returns a new protocol buffer message of type google.protobuf.Any that wraps the given message.

Function: elisp/proto/unpack-any any

This function unpacks the given protocol buffer message of type google.protobuf.Any. The return type depends on the type_url field. Even though this allows you to handle message types dynamically, you still need to load the generated bindings for the dynamic type for unpacking to work.

Function: elisp/proto/any-type-name any

This function extracts the full type name from the type_url field of the given protocol buffer message of type google.protobuf.Any. The return name is the full name of the type of the message packed in any as a string.


6.4 Specialized array and map functions

This section describes a few additional functions that deal with arrays and maps.

Function: elisp/proto/array-length array
Function: elisp/proto/map-length map

These functions return the number of elements in the given array or map.

Function: elisp/proto/do-array function array

This function calls function for each element in array in ascending order. function has to accept a single argument.

Function: elisp/proto/do-map function map

This function calls function for each entry in map. function has to accept two arguments, the key and the value. The iteration order is arbitrary.

Function: elisp/proto/append-array array value

This function adds value as a new element to the end of array.

Function: elisp/proto/extend-array dest source

This function appends all elements in the source sequence to the end of dest. The source must be a generalized sequence.

Function: elisp/proto/update-map dest source

This function inserts all entries in the source map into map. The source must be a generalized map. If a given key already exists, the corresponding value is overwritten.

Function: elisp/proto/copy-array array
Function: elisp/proto/copy-map map

These functions return a shallow copy of the given array or map. The returned copy is mutable, but its elements might still be immutable.

Function: elisp/proto/clear-array array
Function: elisp/proto/clear-map map

These functions remove all elements from the given array or map.

Function: elisp/proto/replace-array dest source
Function: elisp/proto/replace-map dest source

These functions first remove all elements from dest and then add elements from source. After the operation finishes successfully, dest will have the same number of elements as source. Elements in source are converted to the element type of dest as necessary.

Function: elisp/proto/map-put map key value
Function: elisp/proto/map-set map key value

These two functions perform an “upsert” operation: if key is already present in map, they update its value to value, otherwise they insert a new entry into the map. The only difference is the return value: elisp/proto/map-put follows the convention of puthash and always returns value, while elisp/proto/map-set returns whether a new entry was inserted.

Function: elisp/proto/array-pop array index
Function: elisp/proto/map-pop map key

These functions remove the element with the given index or key and return its value. In the case of an array, elements are shifted left to fill the hole.

The following functions work on ranges in an array. A range is defined by a start index and an end index; the start index is included in the range, but the end index is not. If either index is negative, it’s treated as counting from the end; this facilitates things like addressing the last five elements of an array. If the end index is left out or nil, the length of the array is used instead; this means that passing only a start index addresses the entire remaining subarray starting at that index. These are exactly the same conventions that the functions substring and seq-subseq use. See (elisp)Creating Strings, and see (elisp)Sequence Functions.

Function: elisp/proto/subarray array from [to]

This function returns a shallow copy of the subsequence of array delineated by from and to.

Function: elisp/proto/array-delete array from [to]

This function removes the range delineated by from and to from array. Elements are shifted left to fill in the hole.


7 Building manuals

You can use the elisp_manual rule to generate a Texinfo manual from an Org-mode file. See (texinfo)Top, and see (org)Top.

Rule: elisp_manual (name, src, out, [additional_inputs])
load("@phst_rules_elisp//elisp:elisp_manual.bzl", "elisp_manual")

Generates a GNU Texinfo manual from an Org Mode file. See GNU Texinfo, and see the Org Mode manual. Uses Org’s exporting functionality; see Exporting. You can then use texi2any to generate other document formats from the output file; see texi2any.

The elisp_manual rule supports the following attributes:

name

A unique name for this target. Name; mandatory.

src

Org-mode file to use as manual source; must end in .org. Label; mandatory.

out

Texinfo manual file to write; must end in .texi. Output file; mandatory.

additional_inputs

List of additional files made available during export. List of labels; optional; default: [].


8 Depending on external libraries

rules_elisp provides a module extension to make it easier to depend on external Emacs Lisp libraries that don’t bring their own Bazel support.

Module extension: elisp http_archive
elisp = use_extension("@phst_rules_elisp//elisp/extensions:elisp.bzl", "elisp")

Module extension for Emacs Lisp.

The elisp module extension provides the following tag classes:

Tag class on elisp: http_archive (name, urls, integrity, [strip_prefix], [target_name], [exclude])

Downloads an archive file over HTTP and makes its contents available as an elisp_library. This tag class is very similar to http_archive, except that it always generates a BUILD file containing a single elisp_library rule in the root package for all Emacs Lisp files in the archive. Test files (…-test.el, …-tests.el) and package metadata files (…-pkg.el) are excluded. The elisp_library rule is named library by default, unless overridden by the target_name attribute.

The http_archive tag class supports the following attributes:

name

Name of the repository to generate. Name; mandatory.

urls

List of archive URLs to try. See the corresponding attribute for http_archive. List of strings; mandatory.

integrity

Expected checksum of the archive file in Subresource Integrity format. See the corresponding attribute for http_archive. String; mandatory.

strip_prefix

Directory prefix to strip from the archive contents. See the corresponding attribute for http_archive. String; optional; default: "".

target_name

Name of the elisp_library target to generate. String; optional; default: "library".

exclude

Glob patterns of additional files to exclude from the library. List of strings; optional; default: [].


9 Starlark infrastructure

The emacs_library, emacs_cc_module, and emacs_proto_library return the EmacsLispInfo provider to transport information about Emacs Lisp libraries across target boundaries. See Providers for more information about providers.

Provider: EmacsLispInfo source_files compiled_files load_path data_files transitive_source_files transitive_compiled_files transitive_load_path
load("@phst_rules_elisp//elisp/common:elisp_info.bzl", "EmacsLispInfo")

Provider for Emacs Lisp libraries. The elisp_library, elisp_proto_library, and elisp_cc_module rules produce this provider.

Load path directory entries are structures with the following fields:

  • for_actions is a string specifying the load directory to use for actions, relative to the execution root.
  • for_runfiles is a string specifying the load directory to use at runtime, relative to the runfiles root.

The EmacsLispInfo provider has the following fields:

source_files

A list of File objects containing the Emacs Lisp source files of this library.

compiled_files

A list of File objects containing the byte-compiled Emacs Lisp files and module objects of this library.

load_path

A list containing necessary load path additions for this library. The list elements are structures as described in the provider documentation.

data_files

A list of File objects that this library requires at runtime.

transitive_source_files

A depset of File objects containing the Emacs Lisp source files of this library and all its transitive dependencies.

transitive_compiled_files

A depset of File objects containing the byte-compiled Emacs Lisp files and module objects of this library and all its transitive dependencies.

transitive_load_path

A depset containing necessary load path additions for this library and all its transitive dependencies. The depset uses preorder traversal: entries for libraries closer to the root of the dependency graph come first. The depset elements are structures as described in the provider documentation.

To compile Emacs Lisp source files and runs tests, rules_elisp registers the toolchains of type @phst_rules_elisp//elisp:toolchain_type; see Toolchains. Emacs Lisp toolchains are created using the ‘elisp_toolchain‘ rule.

Rule: elisp_toolchain (name, emacs, [use_default_shell_env], [execution_requirements], [wrap])
load("@phst_rules_elisp//elisp/toolchains:elisp_toolchain.bzl", "elisp_toolchain")

Toolchain rule for Emacs Lisp. This toolchain configures how to run Emacs. The executable passed to the emacs attribute must be a binary that behaves like Emacs. If wrap is False, Bazel calls it as is, passing arguments that a normal Emacs binary would accept. If wrap is True, Bazel calls the binary with a special --manifest option. The value of the option is the filename of a JSON file containing a manifest. The manifest specifies which files should be readable and/​or writable by Emacs. Toolchains can use this to sandbox Emacs, if desired.

If wrap is True, the format of the command line is as follows:

emacs --manifest=MANIFEST -- ARGS…

That is, the original arguments for Emacs are separated by a double hyphen (--) so that argument parsers can distinguish between the --manifest option and Emacs arguments.

The manifest is a JSON object with the following keys:

  • root can be either EXECUTION_ROOT or RUNFILES_ROOT and specifies the root directory for relative file names.
  • loadPath is a list of directory names making up the load path.
  • inputFiles is a list of files that should be readable.
  • outputFiles is a list of files that should be writable.
  • tags is the list of tags for the current rule.

When executing an action, file names are relative to the execution root. Otherwise, file names are relative to the runfiles root. File names in inputFiles or outputFiles can also be absolute; in this case they specify temporary files that are deleted after the action completes, or files passed on the command line interpreted according to the input_args and output_args attributes of the elisp_binary rule.

The elisp_toolchain rule supports the following attributes:

name

A unique name for this target. Name; mandatory.

emacs

An executable file that behaves like the Emacs binary. Depending on whether wrap is True, Bazel invokes this executable with a command line like emacs --manifest=MANIFEST -- ARGS… or emacs ARGS…. The --manifest flag is only present if wrap is True. See the rule documentation for details. Label; mandatory.

use_default_shell_env

Whether actions should inherit the external shell environment. Boolean; optional; default: False.

execution_requirements

Execution requirements for compilation and test actions. Dictionary string → string; optional; default: {}.

wrap

Whether the binary given in the emacs attribute is a wrapper around Emacs proper. If True, Bazel passes a manifest file using the --manifest option. See the rule documentation for details. Boolean; optional; default: False.

Rule: elisp_emacs_binary (name, [mode], srcs, [strip_prefix], [readme], [module_header], [builtin_features], [dump_mode])
load("@phst_rules_elisp//elisp/toolchains:elisp_emacs_binary.bzl", "elisp_emacs_binary")

Builds Emacs from a source repository. The resulting executable can be used to run the compiled Emacs.

The elisp_emacs_binary rule supports the following attributes:

name

A unique name for this target. Name; mandatory.

mode

How to build and install Emacs. Possible values are: - source: Build Emacs from sources using configure and make install. srcs must refer to an unpacked Emacs source archive. - release: Run Emacs directly without building or installing. srcs must refer to an unpacked Emacs release archive containing pre-built binaries for the correct target operating system and architecture. Currently this only works on Windows. String; optional; default: "source".

srcs

Either a single Emacs source archive, or all Emacs source files from an already-unpacked archive. List of labels; mandatory.

strip_prefix

Prefix to strip from the source archive. Ignored if srcs doesn’t refer to an archive. String; optional; default: "".

readme

The README file in the root of the Emacs repository. This is necessary to determine the source root directory if srcs refers to unpacked Emacs sources. If srcs refers to a source archive, readme is ignored. Label; optional; default: None.

module_header

Label for a file target that will receive the emacs-module.h header. If not provided, don’t install the header. Output file; optional; default: None.

builtin_features

Label for a file into which to write the list of builtin features. If not provided, don’t write such a file. This is used by Gazelle. Output file; optional; default: None.


10 Indices


10.2 Symbol index

Jump to:   E   H  
Index EntrySection

E
elisp_binaryUsage
elisp_cc_moduleUsage
elisp_emacs_binaryStarlark infrastructure
elisp_libraryUsage
elisp_manualBuilding manuals
elisp_proto_libraryProtocol buffers
elisp_testUsage
elisp_toolchainStarlark infrastructure
elisp/protoProtocol buffer fields
elisp/proto/any-type-nameWell-known protocol buffer types
elisp/proto/append-arrayProtocol buffer array and map functions
elisp/proto/array-deleteProtocol buffer array and map functions
elisp/proto/array-lengthProtocol buffer array and map functions
elisp/proto/array-mutable-pProtocol buffers
elisp/proto/array-pProtocol buffers
elisp/proto/array-popProtocol buffer array and map functions
elisp/proto/clear-arrayProtocol buffer array and map functions
elisp/proto/clear-mapProtocol buffer array and map functions
elisp/proto/copy-arrayProtocol buffer array and map functions
elisp/proto/copy-mapProtocol buffer array and map functions
elisp/proto/do-arrayProtocol buffer array and map functions
elisp/proto/do-mapProtocol buffer array and map functions
elisp/proto/durationWell-known protocol buffer types
elisp/proto/extend-arrayProtocol buffer array and map functions
elisp/proto/fieldProtocol buffer fields
elisp/proto/has-fieldProtocol buffer fields
elisp/proto/makeProtocol buffers
elisp/proto/make-durationWell-known protocol buffer types
elisp/proto/make-timestampWell-known protocol buffer types
elisp/proto/map-lengthProtocol buffer array and map functions
elisp/proto/map-mutable-pProtocol buffers
elisp/proto/map-pProtocol buffers
elisp/proto/map-popProtocol buffer array and map functions
elisp/proto/map-putProtocol buffer array and map functions
elisp/proto/map-setProtocol buffer array and map functions
elisp/proto/message-mutable-pProtocol buffers
elisp/proto/message-pProtocol buffers
elisp/proto/pack-anyWell-known protocol buffer types
elisp/proto/parseProtocol buffer serialization
elisp/proto/parse-jsonProtocol buffer serialization
elisp/proto/replace-arrayProtocol buffer array and map functions
elisp/proto/replace-mapProtocol buffer array and map functions
elisp/proto/serializeProtocol buffer serialization
elisp/proto/serialize-jsonProtocol buffer serialization
elisp/proto/serialize-textProtocol buffer serialization
elisp/proto/set-durationWell-known protocol buffer types
elisp/proto/set-fieldProtocol buffer fields
elisp/proto/set-timestampWell-known protocol buffer types
elisp/proto/subarrayProtocol buffer array and map functions
elisp/proto/timestampWell-known protocol buffer types
elisp/proto/unpack-anyWell-known protocol buffer types
elisp/proto/update-mapProtocol buffer array and map functions
elisp/runfiles/file-handlerRunfiles
elisp/runfiles/rlocationRunfiles

H
http_archive on elispDepending on external libraries