The nitrile.yml reference

This page documents the nitrile.yml file. For a large example, see the Nitrile package file.


In this key a list of actions can be specified. Actions are simple scripts that can be run with nitrile do. The following example defines an action run:

    script: [...]


A list of strings, which will be joined by newlines and executed as a shell script (/bin/sh, on Unix systems) or a PowerShell script (on Windows systems). This script is run in a single process (which is useful if you use variables or change directory).

The script can take arguments using $@ (Shell) or $args (PowerShell). For usage details, see the documentation on nitrile do.


In this key a list of build goals can be specified. The content of this key should be a mapping from goal names to build specifications. The following example defines the build goals tools and library:

    script: [...]

    depends: [tools]
    required_dependencies: [json]
    script: [...]

nitrile build builds the build goals, taking depends into account.


A list of build goals that should be built before building this goal.


A list of names of optional dependencies that are required for this specific build job.


Requires format_version >= 0.4.11.


This is the actual specification of the build. It consists of a list of build commands.

Currently, the following types of build commands are available:

The list of build commands is converted to a shell script (/bin/sh, on Unix systems) or a PowerShell script (on Windows systems). This script is run in a single process (which is useful if you use variables or change directory).

System commands

A system command is a simple shell command:

      - make -C src

On Unix systems, this command is run with /bin/sh. On Windows, this command is run with PowerShell.


With the clm build type, the clm make tool can be used to build an application. This requires base-clm (or base) in the dependencies.

For example:

    version: ^1.0.0
    scope: Build
      - clm:
          main: app
          target: bin/app

For the possible options in the clm mapping, see clm_options. Some additional keys are accepted only here:

  • main: the main module of the application to build (without file extension).
  • target: the file path for the executable. Defaults to the value of main.


This runs the test-runner tool (which is assumed to be installed in dependencies or otherwise available). This is mainly useful in tests:script, not in build:script.

For example:

      - test-runner:
          junit_xml: case-1.xml
          tests: [./]

The options are:

  • output_format: JSON to output JSON test events instead of human-readable messages.
  • junit_xml: the file path to a file to write a JUnit-style report to. This file can then be parsed by GitLab to give test reports on commits and merge requests.
  • tests: these are the actual tests. A test can be simply the name of an executable. If arguments need to be given, use a mapping, e.g.: {executable: ./, options: [--my-option]}.


This sets global options for:

They can be overridden there.

General options:

  • src: a list of file paths included for just this build goal (see src for the global option).
  • compiler: the name of a different binary than cocl (from base-compiler) to use as a compiler (e.g. cocl-itasks from base-compiler-itasks). This binary should be provided by some package in the exe directory. On Windows, .exe is appended to the filename if it does not already end with .exe.
  • compiler_options: a list of command line arguments to be passed to the compiler.

Compilation options:

  • undecidable_instances: true to allow undecidable instances. This lifts some restrictions (e.g. the coverage condition1) that ensure instance resolution terminates and setting this to true may therefore result in non-termination of the compiler.


    Requires format_version >= 0.4.10.

  • check_indices: true to generate code to check for out-of-bounds array indexing.

  • partial_functions: Ignore to ignore partial functions; Warning to generate warnings; Error to generate errors.
  • profiling: NoProfiling (default), StackTracing, TimeProfiling, or CallgraphProfiling. See here for a description of the different profiling options.
  • generate_descriptors: true to generate all descriptors.
  • export_local_labels: true to export local labels.
  • bytecode: true to enable bytecode generation for the ABC interpreter; null to disable bytecode generation (the default); prelinked to enable bytecode generation as well as prelinking for the WebAssembly interpreter. By default, optimized ABC code is used when bytecode generation is turned on. To use unoptimized ABC code, give a mapping: bytecode: {optimize_abc: false, prelink: true}.
  • list_types: None (default), Inferred, LackingStrictness, or All to either list no function types, list the inferred function types, list the types of functions for which not all strictness information has been exported, or list all function types.
  • warnings: false to disable compiler warnings.
  • fusion: NoFusion to disable fusion (the default); PlainFusion to enable fusion on normal functions only; GenericFusion to enable fusion on generic functions; AllFusion to enable fusion on both normal and generic functions. Generic fusion may require you to increase the compiler heap size using compiler_options: [-h, 512m] (for instance).

Linker options:

  • strip: false to disable stripping of the final executable.
  • link: a list of object files that should be linked with the application.
  • post_link: a file name for a post link step, or null to disable the post link step (the default). This should be an executable in a exe directory of one of the dependencies. On Windows, .exe is appended to the filename if it does not already end with .exe. As its arguments it gets the object files that are being linked (except special files like _startup.o) and -o followed by the output file path.

Application options:

  • heap: a memory size for the maximum heap size of the application. This can be an integer (number of bytes), or the suffixes k and m can be used for kilobytes and megabytes.
  • stack: a memory size for the maximum stack size of the application. This takes the same format as the heap.
  • print_constructors: false to disable printing of constructors of the result by the application.
  • print_result: false to disable printing of the result by the application.
  • print_time: false to disable printing execution and garbage collection time after termination of the application.
  • wait_for_key_press: true to wait for a key press before exiting the program (Windows only).
  • garbage_collector: can be CopyingCollector or MarkingCollector. See this page for a description of the two garbage collectors.


An email address where the maintainer can be reached. This field is required to publish a package.


The dependencies of the project. This should be specified as a mapping from package names to version constraints, for example:

  base: ^2.0
  containers: ^1.0

There is also a more verbose format in which other options related to dependencies can be set, such as optionality and scope:

    version: ^1.0
    scope: Build
    optional: true

When several dependencies have the same options, a shorthand is possible. In the following example, the last two dependencies have scope: Test:

  base: ^2.0

  {scope: Test}:
    gast: ^0.4
    test-runner: ^2.0


The shorthand syntax requires format_version >= 0.4.13.


Dependencies can be marked as optional when they are not necessary for the package to work. This allows a package to specify a constraint on another package without requiring a user to install that package.

A possible use case is a package that defines types and functions to deal with some application domain. It may be useful to define common instances for serialization or testing in the library. However, if an end user does not use the same serialization or testing methods, it should not be required to install the corresponding packages. In this case the library can define the instances in separate modules (e.g., Data.MyDomain.Gast), and specify the related dependencies (e.g., gast) as optional.

In this case, if a project depends on this domain library but not on gast, gast will not be installed:

name: my-domain-library
    version: ^0.2
    optional: true


name: my-application
  my-domain-library: ^1.0

However, if a project depends on the domain library and gast, the constraint will be used:

name: my-application
  my-domain-library: ^1.0
    version: ^0.2
    scope: Test

The benefit is that if the depending project tries to use an incompatible version of the optional dependency, nitrile fetch will fail:

name: my-application
  my-domain-library: ^1.0
    version: ^0.3
    scope: Test


Dependencies that are only needed for building or testing the package can be given scope: Build or scope: Test:

    version: ^1.0.0
    scope: Build
    version: ^3.0
    scope: Test

By default, the scope is Build for packages with the type Application and Use for libraries and miscellaneous packages.

The difference between Build and Use is that dependencies with the Use scope propagate, i.e. are required by all packages using this package.


This key gives the version constraint for a dependency. If there are no other keys, only the version constraint needs to be given:

  base: ^1.0 # shorthand for {version: ^1.0}
    version: ^3.0
    scope: Test

A version constraint has the following syntax, based on that of npm:

<Constraint>     ::= <ConstraintPart> '||' <Constraint>      -- disjunction
                   | <ConstraintPart>

<ConstraintPart> ::= <ConstraintPart> ' ' <ConstraintPart>   -- conjunction
                   | <Version> '-' <Version>                 -- inclusive range
                   | <Limiter> <Version>

<Limiter>        ::= '^'                                     -- keep first non-zero
                   | '~'                                     -- keep minor version
                   | '>' | '>=' | '<' | '<=' | '='

<Version>        ::= <Integer> '.' <Integer> '.' <Integer>
                   | <Integer> '.' <Integer>
                   | <Integer>


A short description of the project. This field is required to publish a package.

It is advised that the description starts with a capital and ends with a period.


The version of the nitrile.yml format used. This allows projects to continue using an old version of the nitrile.yml format with a newer version of Nitrile. When Nitrile encounters a nitrile.yml in an older format, it will attempt to migrate the configuration automatically (without writing the new configuration to nitrile.yml).

The format_version increases with the version of Nitrile itself. Therefore, a format_version of x.y is guaranteed to work with Nitrile x.*, but not with z.*. (As long as Nitrile is in the 0.x range, backwards incompatible changes may be introduced in the minor version).

format_version defaults to 0.4.4, the version in which the field was introduced. It is not possible to specify a format version below this version, as no migrations for these older versions are defined.

For an overview of the changes in each version, see the changelog.


The SPDX identifier of the license under which the package is distributed. This field is required to publish a package.


The name of the project maintainer. This field is required to publish a package.


The name of the application or library. This field is required to package or publish a package.

The name may contain only lowercase letters, digits, and hyphens (-). It must start with a letter and may not end with a hyphen.


This key allows for additional options for the nitrile package command.


For packages that include library modules, this key may contain a list of module name patterns that should be considered ‘core’ modules. This is used by Cloogle, as described here.

This key should contain a list of patterns. Patterns are matched using simple string equality, but a wildcard (*) can be used to match any substring. For example: Lib.Internal.*.


Note that Internal* will match Internal and Internal.X, but also InternalX. On the other hand, Internal.* will not match InternalX but also not match Internal. To match Internal and Internal.* to the exclusion of Internal*, use two patterns: Internal and Internal.*.


A list of files to exclude from the package. The pattern format is inspired by that of .gitignore:

  • / is used as a directory separator. Directory separators may occur at the beginning, middle, or end of a pattern.
  • If there is a separator at a non-final position, the pattern is interpreted as relative to the root directory. Otherwise the pattern may match any leaf in the directory tree.
  • If there is a separator at a final position the pattern only matches directories.
  • Asterisk (*) matches any number of characters except /; question mark (?) matches any one character except /. Character ranges (e.g. [a-z]) are not supported.
  • **/ at the start, /** at the end, or /**/ in the middle of a pattern can be used to match any number of directories.


A list of files that should be included in the package. For example:


Files can be just a file path, in which case the source and destination path are the same. When they are not the same, a mapping with src and dst fields can be given:

    - src: doc/documentation.pdf
      dst: documentation.pdf


By default, only *.icl and *.dcl are included in libraries when running nitrile package. With this key a list of filename patterns can be specified that should also be included. This is useful if the package should include some ABC or object files. For example:

    - systemProcessSupport.o

The patterns have the same syntax as in package:exclude.


This key allows you to specify settings that are only used under certain circumstances. The value should be a mapping from rule conditions to settings. For example:

  - src/lib
      - src/lib-posix

      - src/lib-windows

In this example, we have a directory src/lib for platform-independent code, and two additional directories src/lib-posix and src/lib-windows, which are used only on POSIX and Windows systems, respectively.

For a real-world example, see Nitrile’s own package file.

Rule conditions

There are a number of basic conditions. These can be conjuncted using and. For example, posix and 64bit matches only 64-bit POSIX platforms.

There is currently no support for disjunctions (i.e., or) or parentheses.

The basic conditions are:

  • For architectures: arm and intel
  • For bitwidths: 32bit and 64bit
  • For platforms: linux, mac, and windows

There are some shorthands:

  • arm64 for arm and 64bit (there is no arm32)
  • x64 for intel and 64bit
  • x86 for intel and 32bit
  • posix for linux or mac

Rule settings

The following settings are allowed in rules:


Defines extra actions. See actions for details.


Defines extra build steps. See build for details.


Defines extra dependencies. See dependencies for details.


Defines extra package options. See package for details.


Defines extra source directories. See src for details.


Defines extra tests. See tests for details.


A list of source directories, for example:

  - src

Source directories are available in the include path of build tools like clm.


This key gives the path of the source directory. If there are no other keys, only the path needs to be given:

  - src # shorthand for {path: src}
  - path: test
    scope: Test


Source directories that are only needed for building or testing the package can be given scope: Build or scope: Test:

  - path: src
    scope: Build
  - path: test
    scope: Test

By default, the scope is Build for applications and Use for libraries and miscellaneous packages (see type). Directories with scope: Use are included when running nitrile package on a library package.


A mapping of test cases. Each entry has a name (the key) and a number of options (the value). For example:

  - path: test
    scope: Test
  test case 1:
    depends: [library]
      - clm:
          main: test_case_1
      - ./test/test_case_1
    expected_result: test/test_case_1.expected_result

Globally, there are three kinds of tests:

  • Those using script: the script should be an array of commands, similar to the script in build sections. The test passes if all steps return exit code 0. It may be useful to use test-runner commands in the script to use the test-runner tool.

  • Those using expected_result. There should also be a script. The test passes if the output last command in the script matches the contents of the file mentioned in expected_result.

  • Those using compilation. This simply checks that each module in src can be compiled.

  • Those using properties. This uses the property-tester tool to collect Gast properties from definition modules and generate test modules for them, which are then run using test-runner.


A compilation test simply checks that each module in the src directories can be compiled.

      clm_options: { ... }
      #only_modules: [ ... ]
      #except_modules: [ ... ]

When no options are needed, an empty record can be given:

    compilation: {}


Compilation tests are intended as a basic check that code exported to library users compiles. For this reason, compilation tests only cover modules in directories with scope: Use and can only use dependencies with scope: Use.

If there is a need to test compilation of modules from other directories, they can be added to the src option in clm_options.


Allows to specify clm options for this test only. The record takes the same form as the global clm_options setting.


A list of module names that should not be tested. This option is incompatible with only_modules.


Requires format_version >= 0.4.13.


A list of module names that should be tested. Other modules will not be tested. This option is incompatible with except_modules.


Requires format_version >= 0.4.13.


A list of build goals that should be built before running the test. This takes the same form as build:depends.


This field can contain a file path. When present, the test only passes if the output of the last script command matches the content of this file.

For a real-world example, see Gast.


On Windows, the output of the script will be forcefully encoded in UTF-8 before checking the result (instead of UTF-16, which is used by default in PowerShell). Also, \r\n will be replaced by \n in both the program output and the expected_result file. On other systems, the output of the program is used as-is.


This allows you to use property-tester to collect Gast properties from definition modules and generate test modules, which are then run by test-runner. property-tester and test-runner are assumed to be in your dependencies.

property-tester will search for properties in definition modules in src.

The execution of property tests may be parallelized over multiple processes by providing the parallel test runner option.

The following options are accepted:

  • clm_options: allows setting compilation options for the property modules. The same options as in clm_options are accepted.
  • junit_xml: see build:script:test-runner for details.
  • output_format: see build:script:test-runner for details.
  • test_options: a list of options for running the tests. These are defined in Gast’s Testoption type, and can be found when running one of the tests with --help. For example, Tests 10000 will run 10,000 tests.


The tests are generated in ./nitrile-tests, so that you can inspect the generated modules and/or use the generated executables as well.


A list of names of optional dependencies that are required for this specific test. This takes the same form as build:required_dependencies.


Requires format_version >= 0.4.11.


This field contains a list of commands that are run by the test runner. The exit code of the commands should be 0 for the test to pass.

The same commands are supported as in build:script.


Required. This must be one of Application, Library, or Miscellaneous.

The type influences the way nitrile package works, as well as the default dependency scope and source directory scope.

Other than that, it is just there to indicate to users what kind of project they are dealing with.


The URL to the repository of the project.

To publish a package, this field is required and must be a URL, e.g. This is because the registry only integrates with


A SemVer 2.0.0-compatible version. (Currently, additional labels for pre-releases are not supported.) This field is required to package or publish a package.

To start, 0.1.0 is a good value. For more details on versioning, see the packaging and publishing checklist.


This key allows for additional options for the nitrile watch command.


A list of strings, which are interpreted as PCRE regular expressions. nitrile watch will ignore changes on any file of which the whole name matches any of these patterns.

iTasks developers may want to use exclude: ['-www/'].

  1. See e.g. Definition 7 in Sulzmann, Martin, et al. “Understanding functional dependencies via constraint handling rules.” Journal of Functional Programming 17.1 (2007): 83-129.