Use Flags

Use Flags are a way to affect the compilation of a Recipe based on the Programs installed on a system and the user’s preferences, without having to edit the Recipe explicitly. Different configure options may be passed to the program being compiled, and additional hook functions may be run by Compile, depending on which flags are activated. Flags may be activated by the presence of installed dependencies, or explicitly by the user.

Also see Available use flags.

Use Flags Names

Flags are lower-case alphanumeric plus underscore, and should be named after what they do - the other program, tool, hardware, or functionality they enable, with any other characters stripped out if necessary.

Example names would be python, ipw2200, gtk.

Enabling Use Flags

Flags are enabled in three ways. The first is through the global default flag set, in /Programs/Scripts/Current/Data/SystemUseFlags.conf. At the moment, this set is empty, but it will probably end up populated based on what is used for packages and the ISO. The second is the local flags, set in /System/Settings/UseFlags.conf. Finally, the USE environment variable is read for flag specifications. It is intended that this be used for single Compile runs, such as for testing recipes, and not to set flags for your system (use UseFlags.conf for that). Later flag specifications overwrite earlier ones, both in the order listed above and within the files.

A flag specification has the format (-|+)<flag>[ program1[ program2 ...]]. + enables the flag, - disables it, and providing a space-separated list of programs after the flag makes that specification apply only to those programs. Only one flag specification should be included on each line, and everything after a # is ignored as a comment. An example file for clarity:

+foo # Enable foo globally. This text is ignored.
-bar
+bar FooBar

This enables the foo flag globally and disables bar, but then enables the bar flag for only the program FooBar. If the last two lines were the other way around, bar would be globally disabled again. A special specification is -*. This disables all flags, and is probably most useful in the environment variable.

The environment variable takes a space-separated list of flag specifications (rather than newline), so it accepts a special syntax for the specifications, with @ instead of a space when listing programs to go with a flag. It takes the ugly syntax because it’s likely to be by far the least common way of using it. The same set of flags from above could be applied with:

USE="+foo -bar +bar@FooBar"

Use Flags in Recipes

Flags should be listed in the Dependencies or BuildDependencies file in the same manner as the existing cross/!cross flag:

FooBar >= 1.2 [foo,bar]

Flags are separated by commas, and treated as a disjunction - the dependency will be enabled if and only if at least one of the listed flags is enabled. If the cross/!cross flag is specified, it must be the first flag listed (technical limitation; may be lifted in time).

If a flag has no associated dependency, first consider whether it is necessary at all, or whether support should just be enabled by default. If the flag is necessary, it should be listed at the end of the Dependencies file as an entry without a corresponding dependency:

FooBar >= 1.2 [foo,bar]
[baz,quux]

Dependency-free flags may be necessary when associated with hardware, or when there is some lengthy compilation, large filesize, or mutual incompatibility associated with them.

Within a Recipe file, the with_<flag> variable may be set for the common case of adding a configure option:

with_gtk="--with-gtk=$gtk__path"

Or to add multiple configure options:

with_gtk=(
    "--with-gtk=$gtk_path"
    "--with-foo=$foo_path"
    "--with-bar=$bar_path"
)

This will add the value of the variables to the most common configuration array for the recipe type. For configure, this is configure_options; Other options are: python, python_options; makefile, build_variables; scons, scons_variables; cmake, cmake_options; cabal, cabal_options. In the case where more complicated changes are needed to enable support, there is a function using_<flag>() available:

using_gtk() {
   configure_options=( "${configure_options[@]}" "--with-gtk=$gtk__path" )
}

This example does the same thing as the with_gtk one above, but the function can alter other variables as well. It should not alter code, execute scripts, move files, or apply patches; that is what the flag hook functions are for. Each of the existing hook functions (pre_link, pre_patch, pre_build, pre_install, post_install) has a corresponding using_<flag>_<hook>() function:

using_gtk_pre_build() {
   rm -rf *
}

These are run through Run_Hook and so are sudoed the same as the bare hooks (for the moment). This may cause problems if you create files or directories from the hook, so keep it in mind (it applies to all hook functions, but it should be noted especially too). If necessary, you can unsudo yourself with exec sudo -u "$SUDO_USER" -H env SUDO_OK=1 $0 "${@}". That won’t affect anything other than the currently-executing hook, so it should be safe.

In most cases, dependencies are autodetected by configure correctly and no change to the Recipe file will be necessary. In that case, the with_<flag> variables should not be used only to convey redundant information, and the flag should just be listed appropriately in Dependencies. Note that this means that unlike Gentoo’s, our flags are not exclusive: their support may be compiled in even if the flag is disabled, if the dependency is installed and autodetected correctly. Compilations using ChrootCompile will not experience this effect, as the dependency will be left out of the chroot environment.

This means that in the ideal world of well-behaved software, the Recipe file itself should need no modification at all. Complex or less well-behaved software will inevitably end up with longer and more complicated recipes, but in most cases they should be concise and simple.

In all cases, only the variables and functions for flags that are both enabled and listed in the (Build)?Dependencies file will be applied, and others have no effect even if the flag is enabled. This avoids looping through many inapplicable flags several times during the Compile process.

The flags enabled for a given compilation are saved into Resources/UseFlags in the installed program directory. This enables tools such as Freshen to display which flags have changed state since the last installation of a given program, or find programs that could benefit from recompilation.

Use Flags in Tools Development

Flags are accessed from the shell through the UseFlags script, which takes either a program name or a recipe directory as its first argument. The latter method is preferred where possible, because it will read the Dependencies file and limit the flags to only those listed there; giving just a name will include all flags that would be enabled for that program (including global flags that it doesn’t use at all). With only one argument, it will output the list of flags to standard output, one per line, suitable for iterating in a script or saving to a file. If called with no arguments, it will do the same for only global flags.

Given a second argument of a flag to test, the script returns true if the flag is enabled, and false otherwise. If the -v option is specified, it will also output a message giving the state of the flag.

From Python, the module is named UseFlags and may be imported as usual. The most important method is UseFlags, which takes an (optional) program parameter, which can also be either a recipe directory or a program name. It returns a frozenset of the enabled flags. The return value is cached, so the method may be called repeatedly with the same arguments without much penalty. Another useful public method is potentialFlags, which takes only a recipe directory and returns a frozenset of all the flags that could possibly be enabled for that recipe. Freshen uses that to provide output on which flags could be enabled, modeled after emerge, only without the ugliness. The other methods should be treated as private.

See the mailing list thread.