L4Re Support

The L4Re build system is based on Makefiles, and the mk directory within the idl4re software distribution contains a collection of make-compatible files that integrate the idl tool and interface files with the L4Re build system so that the tool is invoked automatically when necessary.

  1. Basic Makefile Structure
  2. Interface-Related Settings
  3. Filename Transformations
  4. Interface Definitions
    1. Compound Interfaces

To write or adapt a package Makefile, some additional definitions and statements are needed to introduce the additional processing steps that take interface descriptions and generate source code from them when needed.

processingInterface:file.idlGenerated sources:file_server.cfile_client.c...idlOutput programExisting sources

This document describes the form a package Makefile should take and introduces the required elements to integrate interface code generation into the package build process.

Basic Makefile Structure

The general form of a suitable Makefile employing interface generation follows that broadly used within L4Re, with a top-level package employing the following definitions:

PKGDIR ?= .
L4DIR  ?= $(PKGDIR)/../..

Appropriate target and build mode definitions may be specified. For example, for a program:

TARGET = myserver
MODE   = shared

For a library:

TARGET = libserver.a libserver.so

Various locations and the inclusion of some rules are useful to define at this point:

IDL_DIR         = $(L4DIR)/pkg/libsystypes/idl
IDL_MK_DIR      = $(L4DIR)/idl4re/mk
IDL_BUILD_DIR   = .
IDL_EXPORT_DIR  = .

include $(IDL_MK_DIR)/idl.mk

(These are described below.)

Usage of interface descriptions should be defined. For example, for some interfaces employed by client programs in the C language:

CLIENT_INTERFACES_C = file mapped_file

For interfaces used by C++ server programs:

SERVER_INTERFACES_CC = dataspace dataspace_factory

These interface definitions are then complemented with definitions that expand to the source files involved. For example:

CLIENT_INTERFACES_SRC_C = $(call interfaces_to_client_c,$(CLIENT_INTERFACES_C))

Or:

SERVER_INTERFACES_SRC_CC = $(call interfaces_to_server_cc,$(SERVER_INTERFACES_CC))

After these definitions, it is convenient to provide the plain source files that are present in the package. For example:

PLAIN_SRC_C = routines.c main.c

With this, it is possible to provide the normal source file definitions which will be a combination of the plain source files with the ones providing support for interfaces.

For example, for a client program employing generated C language files:

SRC_C = $(PLAIN_SRC_C) $(CLIENT_INTERFACES_SRC_C)

To make sure that any required headers are generated before attempts are made to compile the source files, a special rule is required at the end of the file. This is mentioned below.

Library-related and header-related definitions are typically needed. For example:

REQUIRES_LIBS   = libipc libsystypes
PRIVATE_INCDIR  = $(IDL_BUILD_DIR) $(IDL_EXPORT_DIR)

As usual, the Makefile ends with the appropriate role-specific rule inclusion. For example, for programs:

include $(L4DIR)/mk/prog.mk

For interface-driven file generation, an accompanying statement is also required:

include $(IDL_MK_DIR)/interface_rules.mk

This must appear after the role-specific inclusion statement.

Finally, to coordinate the generation of header files with compilation, a rule must be added after the L4Re build system include statements. This must make the plain source files dependent on generated files. For example:

$(PLAIN_SRC_C): $(CLIENT_INTERFACES_SRC_C)

Or, for C++ server code, using the above naming conventions:

$(PLAIN_SRC_CC): $(SERVER_INTERFACES_SRC_CC)

The following sections describe the different elements of this basic arrangement in more detail.

In a Makefile used to build a L4Re component, the following settings can be used to configure the generation of code from interfaces.

Variable Purpose
IDL_DIR Finding .idl files to be processed
IDL_MK_DIR Finding the idl4re/mk directory and rule files
IDL_BUILD_DIR The location of generated code for this component
IDL_EXPORT_DIR Exporting interface headers

The roles of the variables can be summarised in a diagram:

variablesIDL_DIRfile.idl...idlIDL_BUILD_DIRfile_client.c...IDL_EXPORT_DIRfile_interface.h...IDL_MK_DIRidl.mk...

Typically, the following kinds of values will be used:

Variable Value
IDL_DIR A directory containing interfaces
IDL_MK_DIR $(L4DIR)/idl4re/mk
IDL_BUILD_DIR .
IDL_EXPORT_DIR (See below for discussion.)

In the case of IDL_EXPORT_DIR, the variable needs to indicate the location of interface header files that can be referenced by code needing to use the component interfaces. Where such code resides in the same package, the current directory (.) can be used. Where such code resides in other packages, a location is required to export the generated files to those packages.

To avoid mixing up any exported generated interface headers with original non-generated headers, a value of the following form can be used:

$(OBJ_BASE)/include/contrib/$(CONTRIB_INCDIR)

Here, a header called file_interface.h would be exported and included using just this simple name. However, in some cases, there may be other packages exporting headers of the same name, and this may result in confusion.

The solution to this is to organise headers (of any kind) in collections. Here, the header could be placed inside a directory called fsserver and be included as fsserver/file_interface.h. This would be achieved by using a location of the following form:

$(OBJ_BASE)/include/contrib/$(CONTRIB_INCDIR)/fsserver

Filename Transformations

Immediately after the settings, it is typically useful to define some filename transformations:

include $(IDL_MK_DIR)/idl.mk

These make it easier to define the various interfaces used by a component and to derive the filenames involved using transformation functions such as the following:

$(call interfaces_to_client_cc,$(CLIENT_INTERFACES_CC))

Remember that a conventional package Makefile will be concerned with source files and their compilation. Since interface files will be used to generate files that do not initially exist, knowledge about the names of these generated source files needs to be applied to tell the build system which files it will ultimately need to compile.

transformationsfile.idlfile_client.cinterfaces_to_client_cfile_server.cinterfaces_to_server_c

Various rules are applied in the build system to make sure that source files are then handled appropriately.

Interface Definitions

After the settings and the inclusion of the idl.mk file, it is appropriate to define certain variables describing the use of individual interfaces:

Variable Interface Usage
CLIENT_INTERFACES_C C language client code
CLIENT_INTERFACES_CC C++ language client code
SERVER_INTERFACES_C C language server code
SERVER_INTERFACES_CC C++ language server code

These variables reference .idl files containing interface descriptions. For example:

SERVER_INTERFACES_CC = dataspace mapped_file

This indicates that server code in C++ will need to be generated from dataspace.idl and mapped_file.idl, and rules are generated to ensure that make becomes aware of this need.

The variables are then employed in filename transformations, described in more detail elsewhere in this document.

Compound Interfaces

The idl tool also supports compound interfaces which combine individual interface descriptions so that server components can expose multiple interfaces. Here, a naming convention is employed:

Variable Details
interface_NAME Indicates the program name of a compound object
interface_INTERFACES A list of individual interface descriptions

The interface portion of each variable is replaced by a compound interface name as in the following example:

mapped_file_object_NAME       = MappedFileObject
mapped_file_object_INTERFACES = dataspace file mapped_file sync

Thus, the compound interface description mapped_file_object employs the stated individual interfaces and program name:

exampleMappedFileObject(from mapped_file_object)Dataspace(from dataspace)File(from file)MappedFile(from mapped_file)Sync(from sync)

Defining a compound interface would be equivalent to defining an interface as follows, if idl were to support this syntax:

interface MappedFileObject inherits Dataspace, File, MappedFile, Sync
{
};

(Currently, this syntax is not supported due to limitations with the tool.)

Just as with individual interface descriptions, rules are generated to ensure that code supporting compound interfaces is generated from the interface description files.

Special variables act as manifests of all compound interface descriptions used in a particular way:

Variable Interface Usage
COMP_INTERFACES_C C language server code
COMP_INTERFACES_CC C++ language server code

For example:

COMP_INTERFACES_CC = filesystem_object mapped_file_object

Here, two compound interfaces are listed for generation as C++ components. Thus, appropriate _NAME and _INTERFACES variables must be defined to permit the necessary rule generation so that make can generate and build all appropriate files.