29.3. Adding Platform Types and Platforms

When abuild starts up, it reads its internal information about supported platforms and platform types. It then reads additional information from plugins, which it combines with its built-in information. This section contains information about the specific formats of the directives used to add platform types and platforms to abuild.

Platform type information is read from a plain text file that contains platform type declarations. Information about platforms is obtained by running a program, usually written in Perl. The reason for putting platform type information in a file and platform information in a program is that the list of platform types should be static for a given build tree, while the list of available platforms is a function of what the build host can provide. Abuild automatically skips build items that belong to a valid platform type that happens to have no platforms in it, but if it encounters a build item with invalid platform types, it considers that an error.

29.3.1. Adding Platform Types

Of the target types that abuild supports, the only one for which additional platform types and platforms may be specified is the object-code target type. Platform types are declared in a file called platform-types. Abuild looks for this file first in its own private directory and then at the root of each declared plugin. The platform-types file contains a single platform type declaration on each line. Comment lines starting with the # character and blank lines are ignored. Each line may have the following syntax:

platform-type new-platform-type [-parent parent-platform-type]

Platform type names may contain only alphanumeric characters, underscores, and dashes.

You may optionally specify another previously-declared object-code platform type as the new platform type's parent. If a platform type is declared without a parent platform type, it has indep as its implicit parent. (Note that indep may not be declared explicitly as a parent; only other object-code platform types may be declared are parents.) Declaring a parent platform type means that any platform in the new platform type may link against any platform in the parent platform type. It is up to the creator of the platform types to ensure that this is actually the case.

One example use of parent platform types would be to implement a base platform type for a particular environment and then to create derived platform types that refine some aspect of the base platform type. For example, this could be used to overlay additional include directories or libraries on top of support for an embedded operating system to support selective hardware. It would also be possible to create platform types that refine the native platform type for specific circumstances. Most uses of parent platform types could be achieved in some other way, such as through use of conditionals in Abuild.interface or Abuild.mk files or through use of pass-through build items with multiple dependencies, but when used properly, parent platform types can reduce the number of times common code has to be recompiled for different platform types.

The ability to specify parent platform types was introduced in abuild 1.1.4 and is closely related to platform type compatibility as discussed in Section 24.2, “Dependencies and Platform Compatibility”. It's possible that a future version of abuild may further generalize the ability to create compatibility relationships among platform types.

29.3.2. Adding Platforms

Since platforms are, by their nature, dynamic, abuild runs a program that outputs platform declarations rather than reading them from a file. This makes it possible for the existence of a platform to be conditional upon the existence of a specific tool, the value of an environment variable, or other factors. To get the list of platforms, abuild runs a program called list_platforms. Abuild invokes list_platforms with the following arguments:

list_platforms [ --windows ] --native-data os cpu toolset

The --windows option is only present when abuild is running on a Windows system. The three options to --native-data provide information about the default native platform. Most compiler plugins will not need to use this information since there is special way to add a native platform, as discussed below.

To discover new platforms, abuild first runs the list_platforms program in its own private directory, and then it runs any list_platforms programs it finds at the root directories of any plugins. On a Windows system, abuild explicitly invokes the list_platforms program as perl list_platforms options. For this reason, to support portability to a Windows system, list_platforms programs must be written in perl. If necessary, a future version of abuild may provide a mechanism to make writing list_platforms programs in other languages. Note that abuild passes the --windows flag to list_platforms when running on Windows. This not only saves the list_platforms program from detecting Windows on its own but is actually necessary since list_platforms couldn't tell on its own whether it is being run to support a native Windows build of abuild or whether it is being run to support a Cygwin build of abuild. [56]

Each line of output of list_platforms declares either a new platform or a new native compiler, which implies a new platform. A given platform may be declared exactly one time across abuild's internally defined platforms and plugins. When a platform type contains multiple platforms, unless overridden, abuild always chooses to build on the last platform declared that belongs to a given platform type. Since plugins are evaluated in the order in which they are declared, that means that platforms declared in later plugins can override earlier ones as well as abuild's internal platform list with respect to determining which platforms will be built by default. [57] When specifying a new platform or local compiler, the list_platforms program may include the option -lowpri to indicate that this is a low priority platform or native compiler. This will cause the new platform to be added with lower priority than previously declared compilers including the built-in ones. Such compilers will only be chosen if explicitly selected. The user can further refine the choice of which platforms are built, including selecting low priority compilers and platforms, by using platform selectors (see Section 24.1, “Platform Selection”).

Each line of output of list_platforms must take one of the following forms:

platform [-lowpri] new-platform -type platform-type
native-compiler [-lowpri] compiler[.option]

By convention, each native compiler should support a platform with no options, a platform with the debug option, and a platform with the release option. The default should be to select the platform with no options, which means the list_platforms program should output platforms with no options last. The platform with no options should provide both debugging and optimization flags. The debug platform should omit all optimization flags, and the release platform should omit all debugging flags. For normal, everyday development, it generally makes sense to have both debugging and optimization turned on. The reason to have debugging turned on is that it makes it possible to do light debugging in a debugger even with optimized code. The reason to have optimization turned on is so that any problems introduced by the optimizer and additional static analysis that the compiler may do when optimizing will be enabled during normal development. Since optimized code is harder to debug in a symbolic debugger, the debug version of a platform omits all optimization. Since it is often desirable to ship code without debugging information in it, the release version of a platform omits all debug information.

These options only define the default behavior. It is still possible to override debugging and optimization information on a per-file basis or globally for a build item in Abuild.mk (see Section 18.2.1, “C and C++: ccxx Rules”). Note that on some platforms (such as Windows with Visual C++), mixing debugging and non-debugging code may not be reliable. On most UNIX platforms, it works fine to mix debugging and non-debugging code.

When declaring a platform, all platform types that contain the platform must have already been declared.

Note that object code platform names take the form os.cpu.toolset.compiler[.option]. When declaring a platform with the native-compiler directive, abuild automatically constructs a platform name by using the native values for os, cpu, and toolset. This saves every list_platforms program from having to determine this information.

[56] Note that Cygwin is not Windows. Cygwin is really more like a UNIX environment. Although abuild uses Cygwin to provide make and other UNIX-like tools, the Windows abuild executable is a native Windows application. If you were to compile a Cygwin version of abuild, it would not consider itself to be running in Windows and would not invoke list_platforms with the --windows option. That said, there are a few pieces of code in the periphery of abuild that assume that, if we're in a Cygwin environment, it is to support Windows. These are all commented as such. Those parts of the code would need to change if someone were to attempt to package abuild for Cygwin.

[57] Note, however, that the --list-platforms option shows highest priority platforms first, which effectively means that it shows the user platforms in the opposite of their declaration order.