ChorusOS 5.0 Source Delivery Guide

Chapter 4 Customization

This chapter discusses extending the build process to include new components, new features and new system tunables.

The Embedded Component Markup Language

The Embedded Component Markup Language (ECML) simplifies the building and configuration processes of the ChorusOS operating system. Building and configuring the system require the selection and configuration of BSPs, drivers and applications and as such encompass a wide variety of information. This widely divergent information is handled by multiple languages and configuration tools. ECML was developed to provide a unique interface to the configurable information of the ChorusOS operating system.

ECML is defined using XML syntax, making it benefit from existing XML tools, especially browsers and parsers. ECML is designed to be:

Further information about ECML is contained in Appendix A, ECML Syntax .

Build Management

This section demonstrates through examples how modifications to different layers of the source code must be accounted for when building a ChorusOS system.

imake or mkmk?

A fundamental strength of the ChorusOS operating system is its portability across a range of target family hardware architectures. The trade-off made to achieve broad portability manifests itself as build management complexity. ChorusOS system builds require powerful tools to generate the necessary Makefiles to render the process more straightforward. These tools, imake and mkmk:

ChorusOS operating system builds involve make for end-result build tasks, and involve imake and mkmk for generating and managing Makefiles inside components. The following tables indicate which standard system components are managed using which Makefile generation tool.

Table 4-1 Components Managed with imake

Component 

Description 

BSP

Bootstrap code 

DRV

Drivers 

EXAMPLES

Example applications 

Table 4-2 Components Managed with mkmk

Component 

Description 

NUCLEUS

Microkernel and related code 

OS

POSIX, file system and networking layers of the operating system 

The rule of thumb for choosing between imake and mkmk is simple: use imake if you can; use mkmk if you must. User-level application components can be handled using imake. Hardware driver components can be handled using imake. Subsystem components -- such as microkernel components and components that modify the POSIX, file system and networking layers of the operating system itself -- might require you to use mkmk.

imake Files

An Imakefile is a machine-independent description of the make targets you want to build. In the first step of the build process, the imake tool generates a Makefile from each Imakefile, by selecting the configuration files with dependencies appropriate to your target system. This has the advantage that the Imakefile is a machine-independent description of the targets you want to build and is thus portable.

If files are altered they must be rebuilt. For the imake tool within the ChorusOS operating system, only dependencies between source and binary files are taken into account when altered files are rebuilt.

imake Rules

ChorusOS--specific imake rules are provided in the imake subdirectory of the install-dir/tools directory, as shown below.


host% cd install_dir/chorus-family/tools/imake
host% ls
Imake.rules     Imake.tmpl      Imake32.rules   Package.rules   Project.tmpl
host% 

Table 4-3 presents each imake file.

Table 4-3 The imake files provided with the ChorusOS System

File 

Description 

imake/Imake.rules

imake rules

imake/Imake32.rules

Provides compatibility with r3.2 imake rules

imake/Imake.tmpl

Template Makefile, for imake

imake/Package.rules

Packaging rules, for imake

imake/Project.tmpl

Empty Project.tmpl

Components managed with imake export their public information through packaging rules based on those found in these files. Examples demonstrating the use of ChorusOS--specific imake rules can be found in the ChorusOS 5.0 Application Developer's Guide. Commercially available books offer extensive explanations of how to use imake to manage portable software.

The imake command uses Project.tmpl and Imakefiles you include in each directory of your component source to generate Makefiles. During builds managed with imake, only dependencies between source and binary files are taken into account.

Table 4-4 ChorusOS imake Targets

iMake Target 

Description 

all (default target)

Builds everything 

clean

Removes generated files recursively 

depend

Generates dependencies recursively 

Makefile

Regenerates the Makefile in the current directory. 

Makefiles

Regenerates Makefiles recursively 

Each file in the tgt-make directory deals with make rules for compiling target binary files. Certain files are specific to the gcc compiler, others to the ghs compiler. Only common and gcc/powerpc specific files are described here. All files listed in Table 4-5 are located in the bin_dir/tools/tgt-make directory:

Table 4-5 Target Rules for ChorusOS

File 

Description 

gcc-devsys.mkmake rules used by the imake environment
gcc-ld.ld Linker script used to reduce the section number
gcc-variables.rf make variables, for the mkmk and imake environments
gcc-tgtdevsys.rfmake rules, for mkmk
variables.rf Includes the compiler specific file about variables
tgtdevsys.rf Includes the compiler specific file about rules
shared.rfCalls mkmake
Makefile.mkimageMakefile used during image creation
Makefile.confMakefile used during configurable actor links
genLinkGeneric linker, calls genLink.conf and genLink.noconf
genLink.conf Links configurable actors
genLink.noconf Links non-configurable actors
mkdbginfo Generates offsets and symbol information
powerpc/genOff Create offset files
powerpc/genOff.awkawk file used by genOff
powerpc/act.ld Linker script used for actors using dynamic libraries
powerpc/lib.ld Linker script used to create dynamic libraries

The mkmk Build Process

The mkmk tool is used to generate Makefiles that let you build a particular target system image from source code that supports multiple target hardware architectures. The mkmk rules allow you to manage system configuration entities such as features, parameters and tunables.

The mkmk build process consists of the following steps:

  1. Merging -- creating links to source files from the build directory; the links enable mkmk to locate source code during builds.

  2. Generating Makefiles in the build subdirectory for the component using mkmk.

  3. Building the object component.

  4. Creating the dependency files for subsequent builds.

  5. Building the system image.

Merging

The role of mkmerge is to link the source files and the component's build directory. For further information, see the mkmerge(1CC) man page.

The code for ChorusOS components containing family-specific code is organized in projected trees. Within the projected trees, there are sub-trees for:

Before generation begins, subtrees are merged into a merged tree. There is only one merged tree in each merged component. Initially, it contains symbolic, or hard, links that point to files in the projected trees. The build takes place in the merged tree, so the projected trees remain free of generated files, such as object files and Makefiles. You can delete a merged tree at any time. This will not affect the source code, as it remains clean in the projected trees.

Different merged trees can be built from a given set of subtrees of the projected trees. This allows you to produce several system configurations concurrently.

Building the merged tree is called the merge operation. When performing this operation, you provide a number of first-level options, called generation options. These options correspond to fundamental production choices, such as the choice of a development system or the target family and are typically found in the build profile.

On systems running the Solaris operating environment, mkmerge populates the merge directory with symbolic links. These links point to the source directories required for your build.

merge.rf

Source directories within the projected tree can be populated with special files, named merge.rf (for merge rule files), which provide a number of directives for mkmerge, for example:

During a merge, directories are examined recursively and merge.rf files are analyzed. If no problems are encountered, the real merge begins: directories, links and files are created as specified in the various merge.rf files found.

A merge.rf file is composed of lines that are evaluated one at a time. A status is associated with this file. This status evolves as the file is analyzed. Depending on its value at the end of the merge.rf file, the current directory will be merged or cut.

A merge.rf file can contain commands to describe how the current directory should be merged, where it will go, and when it will be merged. The MKMERGE_IGNORE environment variable can be used to specify a list of file suffixes that should be ignored during the merge process.

For more information about merge.rf, see the mkmerge(1CC) man page.

Build Profile

The build profile used by the configure command is an argument of the mkmerge command. There is one default profile for each board, as shown in"Families, Targets and Profiles" . For non-standard system generation, customize the build profile using the information on the file entries described here.

The build profile contains entries of the following type:

The range of value values depends on the variable. Note that:

Build profile files provide configuration flags used during the merge. The following listing shows an example microkernel build profile file for UltraSPARCTM family targets.


Example 4-1 UltraSPARCTM Target Profile File

[profile]
FLAG=host=solaris
FLAG=target=upSparc
FLAG=devsys=gcc
FLAG=flm=on
FLAG=locks=rt
FLAG=optim=on
FLAG=tree=upSparc

[profile]
devsys=gcc
binfmt=elf

# directories to merge

tree=./../common
tree=./../sparc
tree=./../sparc_v9
tree=./../usparc
 
# kernel locks configuration :
# 2 choices : locks=rt, locks=gp
locks=rt

# available memory management implementations
flm=on
prm=on
vm=off
 
#
# shared_lib support
# choices : sharedlib=on, sharedlib=off
sharedlib=on

# stack fault support :
# 2 choices : stack_fault_support=on, stack_fault_support=off
stack_fault_support=on

# FPU support :
# 2 choices : fpu_support=on, fpu_support=off
fpu_support=on
 
# optimisation type
# choices : optim=on, optim=no
optim=on

# debug on or off (default)
debug=off
 
# profiling on or off (default)
profile=off

The predefined flags include:

Table 4-6 Configuration Flags

Name 

Possible values 

Description 

debug

(off|on)

Indicates whether to compile with debugging information; default is off

devsys

(gcc)

Indicates which host development tool chain is used for compilation; default is gcc

flm

(off|on)

Indicates whether flat memory is in use. 

prm

(off|on)

Indicates whether protected memory is in use 

vm

(off|on)

Indicates whether virtual memory is in use 

locks

(gp|rt)

Specifies which type of locking to use in the core executive; default is gp

merge_dir

(dir)

Specifies the path to the root of the merge tree 

optim

(off|on|size|speed)

Indicates how to optimize compilation; setting this flag to speed might make symbolic debugging impossible; default is on, a compromise between size and speed optimizations

profile

(off|on)

Indicates whether to compile with performance profiling capabilities; default is off

shared_lib

(off|on)

Shared library support. Default is on.

softload

(off|on)

Library fp emulation. Default is on.

tree

(dir1,dir2,...)

Specifies projected tree directories to merge 

mkmk Files

The mkmk tool uses portable description files, independently of both the host and target systems. High-level mkmk rules are included in .bf, .df and .mf portable description files for a component, and are then processed to create Makefiles and .dp dependency files for the builds.

The mkmk command uses three types of build description files, suffixed by .df, .bf, and .mf, to produce Makefiles and generate all .dp dependencies. With mkmk, you create a .mf file for each host. In this way the mkmk tool ensures portability during cross compilation and so ensures the portability of hosts and targets.

.bf Files

The .bf suffix denotes build file.

The .bf files are a subset of Imakefiles. They contain link directives , and you can have several .bf files per directory. The mkmk tool concatenates the .bf files inside the Makefile product. The .bf file is preprocessed by the macro processor m4(1).

Table 4-7 lists the macros used in a .bf file. The Actor, ConfigurableActor, Library and BigObject macros use getExport, either directly or indirectly, to get the list of object files. The getExport command computes the list of object files to use when creating a link.

Table 4-7 Macros used in .bf Files

Macro 

Description 

Build actor using libs

Build actor using libs

Build lib

Build a relocatable object file 

Copy file into dir

Copy file into dir

Build actor using libs

Build actor using libs

Build lib

Build a relocatable object file 

Copy file into dir

Copy file into dir

Build a pre-built actor and its finalized makefile using libs and local_libs.

.df Files

The .df suffix denotes definitions file.

The .df files are used as shell scripts that are launched when the Makefile is created to adjust variables before they are written into the Makefile. The .df files define the following variables:

The .df files have similar properties to the Project.tmpl files of the imake tool. They affect the building of the Makefiles for all the subdirectories. With mkmk, you can have several .df files in each directory of the source tree. This contrasts with the imake tool, which has only one Project.tmpl file per component.

The inheritance mechanism of the mkmk tool is different from that of the imake tool. With mkmk, every Makefile is dependent on the Makefile present in the parent directory. However, with imake, every Makefile is dependent on the Project.tmpl file present in the top-level directory of the component and on the few variables inherited from the parent directory. The variables and macros are defined in the production tools. Table 4-8 lists those you must not modify and Table 4-9 lists those you can modify.

Table 4-8 Variables for the .df Files that must not Change

Variable 

Description 

DTL(DEVTOOLS_DIR)/host/bin/
GROOT ../../ (the relative path to the root component)
BDIR build_dir
BNAME Name of current directory
HOST Type of host
FAMILY Type of target
COMPILER  Type of compiler

MPATH

Pathname of current directory relative to the component root 

BFILESList of .bf files found in your work directory
MFILESList of .lf and .mf files found in your work directory
DFILESList of .df files in your work directory

Table 4-9 Variables in the .df Files hat can Change

Variable 

Description 

DEFINES List of macro definitions to use in every compilation rule
INCLUDES List of directories to search for header files
VARIABLESThe list of user defined variables to export in Makefiles produced in subdirectories
SUB_DIRS The list of directories to use when compiling; these are usually the subdirectories of your build directory
EXTRA_DIRS A list of directories to use, in addition to SUB_DIRS, when creating libraries or linking actors (usually empty)
MODULES The name of the module to which the object in your build directory (and subdirectories) belong; this is only useful in configurable actors

FARROP

Application profiling 

FEXCEPTION  (ON/OFF): Compile with exception support
FPU  (ON/OFF): Compile with FPU support
FOPTIM  (ON/OFF): Compile with optimization
FPROF  (ON/OFF): Support for profiling
FREMOTEDEB  (ON/OFF): Compile with debug options, to enable source level debugging
FVERBOSE (ON/OFF): Verbose compilations
FWARN(STRICT/ON/OFF): Enable production of warnings during compilation; with STRICT, warnings are treated as errors. The NUCLEUS component uses STRICT

FASSERT

(ON/OFF): Enable or disable assertions 

FGCOV

(ON/OFF): Enable or disable code coverage testing with gcov

FPIC

(ON/OFF): Enable or disable compilation for inclusion in shared libraries 

FVEC

(ON/OFF): Enable or disable generation/build options to use or not use a unit vector 

.mf Files

The .mf suffix denotes make file.

The .mf files contain lists of source files. The .mf files are used during make sources when the binary file to be built uses many subdirectories, each subdirectory containing a variable number of files to be compiled.

Another form of .mf files are .lf files. The variables and macros used in the .mf and .lf files are listed in Table 4-10.

Table 4-10 Variables and Macros used in .mf and .lf Files

Variable 

Description 

C++SRCS  C++ source files
C_SRCS  C source files
AS_SRCS  Assembly code source files
M4_SRCS  M4 source files (assembly code source files preprocessed with m4).
OF_SRCS C++ source files used to produce offset files

The Makefiles Created by the mkmk Tool

During generation, mkmk goes down the build tree and creates a Makefile for each build directory. The Makefiles are used to build the binary files and each of these Makefiles is autonomous. This means that you can set make running from any directory and all files located in the subdirectories attached to that directory are built automatically. The Makefile content depends on the mkmk production files.

In each directory, where mkmk produces a Makefile, mkmk:

The list of files to be compiled varies depending on the merge operation. Writing a Makefile that will work on several configurations can be complicated. The solution offered by mkmk is to:

The .mf files do not have an equivalent within the imake tool.

The mkmk tool will regenerate the Makefile produced if the .df, .bf or .mf files used to build it change.

Managing Dependencies

Once a file has been modified, for example with an editor, or by a previous compilation, the files that depend on the altered file must be rebuilt. Most development tools only deal with the dependencies between source and binary files. The mkmk system goes further, taking into account any changes which occur in the source files during the build process.

The relationship between the different components is managed through the components' Makefile.bin and Makefile.src files and through the build paths found in the Paths file in your ChorusOS build directory. For example, applications can access both the microkernel API and the OS API through the variables set in the Paths file:

Make Targets for mkmk

This section presents the complete list of make targets you can use with the mkmk tool.

Table 4-11 Description of Make Targets used with mkmk

Make Target 

Description 

all  Default make target, builds everything
Makefile Rebuild the Makefile in current directory
makemk Rebuild the Makefiles (recursively)
merge  Remerge the current component
makesrc  Build offset files (recursively)
sources  Build offset files in the current directory
makeprod  Build object files and libraries (recursively)
prod Build object files and libraries in the current directory
makelink Link libraries and actors (recursively)
link  Link libraries and actors in the current directory
depend Generate dependencies (recursively)
cleanRemove files produced (recursively), with the exception of Makefiles and dependency files
clobber Remove files produced (recursively)

Compiling a binary with cdstool

There also exists an alternative to imake, cdstool, which you can use to compile simple binaries. The cdstool utility is a wrapper for the C compiler delivered with the ChorusOS operating system.

#include <stdio.h>
main()
{
		printf("Hello world\n");
}
host% build_dir/bin/cdstool cc example.c -o example

$

Examining a Built Component

This section uses the example of the built OS component to present the component build directories and files.

Example: The OS Component Build Directory

Table 4-12 and Table 4-13 show the content of build_dir/build-OS after running make:

Table 4-12 Directories in the OS Component Build Directory

Directory 

Description 

includeHeader files exported by the OS component
libLibraries used by the OS component
obj Object files needed to link the OS component
srcSource files of the OS component
confConfiguration files of the OS component (used by mkmerge)

Table 4-13 Files Generated in the OS Component Build Directory

File 

Description 

DONE Created by Makefile.src when compilation is complete
profile  Created by the merge process, it contains merge options
merge.log Created by the merge process, it contains all mkmerge output
export.lst The list of files to export; mkmake uses this file to determine which files it should copy and where to copy them
Makefile The top level Makefile, produced by mkmk

Example: The OS Component Build Files

For the OS component, the OS source files are merged into the component's build directory, build_dir/build-OS. In this directory, exports.1st is produced by the mkmerge command. This directory relies on the profile file to ensure that the NUCLEUS component is merged before the OS component.

To look in greater detail at the OS build directory, list the contents of build_dir/build-OS/src/sys. This directory contains the following:

Table 4-14 Files Generated in /build-OS/src/sys

File 

Description 

MakefileThe Makefile of the directory, produced by mkmk
C_OS The C_OS actor
all.dpDependency file, produced by make depend and getExport
sys_agglo.mkInternal Makefile, used when linking the configurable actor, to copy files from the src directory to the obj directory

sys.bf

The build file 

sys.df

The definition file 

sys_rule.xml

XML rules for the OS component

sys_action.xml

XML action rules for the OS component

The contents the sys.bf and sys.df files, the Makefile and the common.mf and all.dp files are given below:

sys.df

The sys.df file, defines the INCLUDES and DEFINES variables.


Example 4-2 A sys.df File

INCLUDES="                              \
 -I${OS_DIR}/src/sys                    \
 -I${OS_DIR}/src/sys/chorus/sys         \
 -I${OS_DIR}/src/sys/sys                \
 -I${OS_DIR}/src/sys/machine            \
 -I${NUCLEUS_DIR}/include               \
 -I${NUCLEUS_DIR}/include/chorus        \
 -I${OS_DIR}/include/chorus             \
 -I${OS_DIR}/include"

DEFINES="$DEFINES -DKERNEL -D_KERNEL -D__FreeBSD__ -DINET -DNO_CACHE"
DEFINES="$DEFINES -DMSDOSFS -DNFS"

FWARN=STRICT

sys.bf

In this example, S_LIBS contains the list of libraries used to link the OS component. The ConfigurableActor rule is also used to link the OS component to build the C_OS actor.


Example 4-3 A sys.bf File

S_LIBS = $(OS_DIR)/lib/sys/libufs.a \
         $(OS_DIR)/lib/sys/libdisk.a \
         $(OS_DIR)/lib/sys/libgen.a \
         $(OS_DIR)/lib/sys/libmem.a \
         $(OS_DIR)/lib/sys/libunresolved.a \
         $(OS_DIR)/lib/sys/libloader.s.a \
         $(NUCLEUS_DIR)/lib/zlib/zlib.a \
         $(OS_DIR)/lib/sys/libio.s.a \
         $(NUCLEUS_DIR)/lib/stdc/libstdc++.a \
         $(NUCLEUS_DIR)/lib/embedded/libebd.s.a \
         $(NUCLEUS_DIR)/lib/cpu/cpu.s.a \
         $(NUCLEUS_DIR)/lib/ddi/net.s.a \
         $(NUCLEUS_DIR)/lib/ddm/ddm.s.a \
         $(NUCLEUS_DIR)/lib/sysevent/sysevent.a \
         $(NUCLEUS_DIR)/lib/visu/visu.s.a \
         $(NUCLEUS_DIR)/lib/gauges/gauges.s.a \
         $(NUCLEUS_DIR)/lib/classix/libsys.s.a \
         $(DRV_DIR)/lib/drv_tools/drv_tools.s.a

ConfigurableActor(C_OS, $(S_LIBS))

Makefile

The Makefile generated by mkmk contains two parts. The first part has a list of the definitions of variables as defined in Table 4-8, Table 4-9, Table 4-7 and Table 4-10. The second part contains preprocessed copies of the .bf, .lf, and .mf files found in the work directory. In this example there is only a .bf file present in the work directory.


Example 4-4 A Makefile Generated by mkmk

BDIR = build_dir
FAMILY = usparc
COMPILER = gcc

include $(BDIR)/Paths
include $(DEVTOOLS_DIR)/tgt-make/host.conf
include $(DEVTOOLS_DIR)/tgt-make/variables.rf

BNAME = sys
MPATH = src/sys
DEFINES = -DKERNEL -D_KERNEL -D__FreeBSD__ -DINET -DNO_CACHE -DMSDOSFS -DNFS
INCLUDES = -I/build_dir/build-OS/src/sys -Ibuild_dir
/build-OS/src/sys/chorus/sys
-I/build_dir/build-OS/src/sys/sys
-I/build_dir/build-OS/src/sys/machine
-I/build_dir/build-NUCLEUS/include
-I/build_dir/build-NUCLEUS/include/chorus
-I/build_dir/build-OS/include/chorus
-I/build_dir/build-OS/include
FEXCEPTION = OFF
FFPU = ON
FOPTIM = OFF
FPROF = OFF
FREMOTEDEB = ON
FVERBOSE = OFF
FASSERT = ON
FWARN = STRICT
FGCOV = OFF
FPIC = OFF
FLARGEGOT = OFF
FVEC = OFF
VARIABLES = OS_DIR NUCLEUS_DIR DRV_DIR OS_USER_LIBS OS_SUP_LIBS
SUB_DIRS = cam chorus crypto dev isofs kern libkern machine miscfs 
msdosfs net netinet
netinet6 netkey netns nfs nfs_noserver solaris sys ufs vm
EXTRA_DIRS = 
BFILES = sys.bf
MFILES = 
DFILES = debug.df sys.df
MODULES = 
OS_DIR = build_dir/build-OS
NUCLEUS_DIR = build_dir/build-NUCLEUS
DRV_DIR = build_dir/build-DRV
OS_USER_LIBS = build_dir/build-OS/lib/libc.a build_dir/build-OS/lib/sys/
libsystrap.u.a
/net/abdias/export/build/orivat/chorus/dev-r50/sparc/dev-int2709/
build-OS/lib/libc.a
OS_SUP_LIBS = build_dir/build-OS/lib/libc.a build_dir/build-OS/lib/sys/
libsyscall.a
/build_dir/build-OS/lib/libc.a

include $(BDIR)/Paths
include $(DEVTOOLS_DIR)/tgt-make/shared.rf

# produced from sys.bf -- begin

S_LIBS = $(OS_DIR)/lib/sys/libufs.a \
         $(OS_DIR)/lib/sys/libdisk.a \
         $(OS_DIR)/lib/sys/libgen.a \
         $(OS_DIR)/lib/sys/libmem.a \
         $(OS_DIR)/lib/sys/libunresolved.a \
         $(OS_DIR)/lib/sys/libloader.s.a \
         $(NUCLEUS_DIR)/lib/zlib/zlib.a \
         $(OS_DIR)/lib/sys/libio.s.a \
         $(NUCLEUS_DIR)/lib/stdc/libstdc++.a \
         $(NUCLEUS_DIR)/lib/embedded/libebd.s.a \
         $(NUCLEUS_DIR)/lib/cpu/cpu.s.a \
         $(NUCLEUS_DIR)/lib/ddi/net.s.a \
         $(NUCLEUS_DIR)/lib/ddm/ddm.s.a \
         $(NUCLEUS_DIR)/lib/sysevent/sysevent.a \
         $(NUCLEUS_DIR)/lib/visu/visu.s.a \
         $(NUCLEUS_DIR)/lib/gauges/gauges.s.a \
         $(NUCLEUS_DIR)/lib/classix/libsys.s.a \
         $(DRV_DIR)/lib/drv_tools/drv_tools.s.a

BINARY += C_OS

C_OS: $(S_LIBS)
        $(MKLINK) -r -c -e _start -o C_OS -B $(S_LIBS)

# produced from sys.bf -- end

include all.dp
include $(DEVTOOLS_DIR)/tgt-make/tgtdevsys.rf
DTL=${DEVTOOLS_DIR}/host/bin/

common.mf

The common.mf file is found in the build_dir/build-OS/src/sys/chorus/lib/gen directory.


Example 4-5 A common.mf File

....
C__SRCS = \
        insremque.c ovbcopy.c memstat.c util.c sysInitFuncs.c 

The .mf files contain the definition of variables and nothing else. These variables are listed in Table 4-10.

all.dp

The Makefile listed above for the OS component, located at build_dir/build-OS/src/sys, includes a dependency file, all.dp. This dependency file is located in the same directory as the Makefile. In the OS component, the all.dp file contains the list of files upon which the linked binary files, such as actors or libraries, are dependent. The -export lines at the top of the file are used by getExport during the link phase. In this example, as the directory contains no object file, these lines are empty.


Example 4-6 An all.dp File

host% head all.dp
#       automatically generated file
# -export ALL :      
# -export SUP :                                        
# -export USR :                                        
# built from a complex makefile

C_OS: cam/scsi/all.dp
C_OS: cam/scsi/scsi_da.o
C_OS: cam/scsi/scsi_all.o
....
C_OS: all.dp

Creating a ChorusOS Component

This section shows you how to create your own component for your ChorusOS system. You can create this type of component with mkmk, imake or a tool of your choice.

A component must provide a set of Makefiles so that you can configure it using the configure tool. These Makefiles are as follows:

When you receive the source delivery of the ChorusOS operating system, the Makefile.src and Makefile.bin files are provided for each component. This has the advantage that, prior to configuration, all the components have characteristics in common. Consequently, the components are compatible, even when they have been built using different tools.

You can choose a selection of components generated with the mkmk and imake tools to create your system image.

You can also create your own components by creating the Makefile.bin, Makefile.src, and src.df files yourself as shown in this chapter.

Building a Component With imake

This section describes how to build a ChorusOS component with imake and the basic operations needed to manage your component. The information is provided in the form of a tutorial, leading you through an example which shows you how to perform each step.

The procedures below show you how to build a very simple ChorusOS component called TEST, containing an application that displays a short message.

Build a TEST Component
  1. Create a TEST directory in your /tmp directory to contain your new component.

    host% cd /tmp/TEST
    host% mkdir TEST
    
  2. Add the files listed below to the TEST directory

    • Makefile.bin

    • Makefile.src

    • Project.tmpl

    • Imakefile

    • src.df

    Examples of these files are given below.


Example 4-7 Creating a TEST Component: Makefile.bin

The Makefile.bin file can contain the following information:

COMPONENT += TEST
ROOT      += $(TEST_DIR)/root

TEST.all::

The first line in the output, which declares the component's name, is mandatory.

As the COMPONENT variable is the list of all components to be configured, use '+=', and not '='.

The ROOT variable contains a list of directories to be copied to the target root file system.



Example 4-8 Creating a TEST Component: Makefile.src

The Makefile.src file, can contain the following information:

all:: TEST.all 

TEST.all:: NUCLEUS.all OS.all DRV.all
TEST.all:: $(TEST_DIR)/DONE

$(TEST_DIR)/DONE: $(TEST_DIR)/Makefile
        sh $(DEVTOOLS_DIR)/resync TEST -f $(TEST) -s $(TEST_DIR)
        cd $(TEST_DIR); $(make)
        touch $(TEST_DIR)/DONE

$(TEST_DIR)/Makefile: $(TEST)/Imakefile
        sh $(DEVTOOLS_DIR)/ChorusOSMkMf $(BUILD_DIR) -s $(TEST) 
        -b $(TEST_DIR) -d
$(TEST_DIR)
        cd $(TEST_DIR); $(make) Makefiles

TEST_DIST = $(BUILD_DIR)/dist-TEST
TEST.dist: TEST.all
        rm -rf $(TEST_DIST)
        cd $(TEST_DIR); $(make) DIST_DIR=$(TEST_DIST)

This file is more complex than the Makefile.bin file as it describes how to build the component. The first lines of output give the list of components that must be built before the TEST component.

As your application requires operating system services, you must build the NUCLEUS and OS components before building the TEST component.



Example 4-9 Creating a TEST Component: Project.tmpl

The Project.tmpl file can contain the following information:

#include "Package.rules"

SRC_DIR         = SourceDir
BUILD_DIR       = BuildDir
DIST_DIR        = DistDir

VPATH           = $(SRC_DIR)$(REL_DIR)

WARN            = $(WARN_ON)

TEST_DIST_BIN   = $(DIST_DIR)/bin/test


Example 4-10 Creating a TEST Component: Imakefile

The Imakefile indicates that you will have subdirectories (in this case /src).

#define IHaveSubdirs

SUBDIRS = \
        src

DistFile(Makefile.bin,$(DIST_DIR))


Example 4-11 Creating a TEST Component: src.df

The src.df contains the following information:

. ../Paths
VARIABLES="OS_DIR NUCLEUS_DIR"
BDIR=${BUILD_DIR}
SUB_DIRS=src

This file sets the parameters required for the make command to work.


Creating a Simple Hello Application

You now need to create an application for the TEST component to perform.

  1. Create a subdirectory, src, within your /tmp/TEST directory.

    host% cd /tmp/TEST
    host% mkdir src
    
  2. Create the following two files:

    bonjour.c

    This source file will say "Hello World":

    #include <stdio.h>
    int main()
    {
          /* Print the message */
      printf("Hello World\n");
      return 0;
    }

    Imakefile

    This file provides rules to build the application:

    CSRCS=  bonjour.c 
    
    OBJS= $(CSRCS:.c=.o)
    
    DEBUG=$(DEBUG_ON)
    
    UserActorTarget(bonjour_u,bonjour.o,)
    SupActorTarget(bonjour_s, bonjour.o,)
    
    DistActor(bonjour_u, $(DIST_DIR)/root/test/src)
    DistActor(bonjour_s, $(DIST_DIR)/root/test/src)
    The Imakefile file declares:
    • The source files to be compiled.

    • The libraries to be used.

    • The fact that you want to build the bonjour actor.

    • The fact that you want to copy the bonjour actor into the root/bin directory, once it is built.

  3. Build your component in your work directory using the make command

    host% make
    
  4. Add the bonjour binary file to the target file system

    host% make root
    
Adding the Component to the System Configuration

Once you have created the component, with its application, you must include it in the system configuration.

  1. Run make reconfigure

    Use the make reconfigure command in the directory in build_dir in which you have previously run configure to build your system image. Run make to compile your component:

    host% make reconfigure='-s /tmp/TEST'
    
  2. Compile the component

    Type make to compile your TEST component.

    host% rm -rf build_dir/build-TEST
    host% make
    

Adding Features and Tunables

This section demonstrates through examples how to add new features and tunables to the ChorusOS operating system.

Adding a Tunable
  1. Define the Tunable

    To add a tunable (my_tunable) to the OS component, write an integer named my_tunable in an OS source file, as follows:

    extern int my_tunable;
    This integer is configured using the external name iom.my.tunable. The default value for my_tunable is 0.

  2. Add the Tunable to the XML Source Configuration File

    To add the tunable to the XML source configuration file for the OS component, go to the directory containing the OS configuration files:

    host% cd source_dir/os
    
  3. Modify sys_rule.xml and sys_action.xml

    To add the iom.my.tunable, you must modify two files, sys_rule.xml and sys_action.xml.

    • The sys_rule.xml file contains the description of the configurable entities as features and tunables, and their associated dependency.

    • The sys_action.xml file contains the internal implementation rules for management of features and tunables and provides the interface with the mkmk environment.

    Include the definition of the tunable in XML in the sys_rule.xml file.

    <tunable name=iom.my.tunable>
         <description> My Tunable </description>
         <int>
         <const>0</const>
         </tunable>

    This definition includes the external name, a description field that will be accessible through the ews configuration tool, and a default value. All tunable values are integers; the default value is 0 in this example.

  4. Include the standard rule used for the management of the OS tunables in sys_action.xml:

     <setting name="sys.tunables">
    <condition><ifdef name="iom.my.tunable"></condition>
    <value index="size">
    <vstring>my_tunable iom.my.tunable ${iom.my.tunable}</vstring>
    </value>
    </setting>

    Note -

    iom.my.tunable is the external name of the tunable and my_tunable is the corresponding integer declaration in the source code.


  5. Update the configuration in the build directory and build the new system image.

    As you modified XML configuration files in the source directory, you must propagate these changes back to the work directory. Remove the corresponding XML files and run make xml.

    host% cd build_dir
    host% rm conf/mkconfig/sys_rule.xml conf/mkconfig/sys_action.xml
    host% make xml
    
  6. Set your tunable and check that it is now visible in the configuration

    host% configurator -set iom.my.tunable=0x12345
    host% configurator -list tunables | grep my
    host%  iom.my.tunable:'0x12345'
    
  7. Build the new system image and check that the tunable is in the C_OS actor:

    host% make build
    host% powerpc-elf-nm image/RAM/chorus/bin/C_OS | grep my_
    host% a00b44f0 D my_tunable a00b44f0:       00 01 23 45     .long 0x12345
    
Adding a Feature

Features are implemented by source code modules. The example below demonstrates how to use modules to add a feature, called TEST, to your ChorusOS operating system. In this feature, we shall include a test file, mytest.c.

  1. Create a test directory

    host% cd source_dir/os/sys
    host% mkdir test
    
  2. Create the a modules.df file in this directory

    MODULES=bsd__test
  3. Create mytest.c and common.mf files

    mytest.c:
    #include <stdio.h>
    
    
    int hello()
    {
      printf("hello world\n");
      return 0;
    }
    common.mf:
    C__SRCS = \
            mytest.c
  4. Add the TEST feature to the sys_action.xml and sys_rule.xml files

    Add the following to sys_action.xml:

    sys_action.xml:
    <!--
    bsd__test=on/off
    -->
      <setting name="iom.modules"/>
    
        <description/>bsd__test/<description>
        <condition>
    
          <var name="TEST">
        /<condition>
        <value index="size">
    
          <const>bsd__test/<const>
        /<value>
      /<setting>

    Add the following to the sys_rule.xml file:

    sys_rule.xml:
      <feature name="TEST">
    
          <description> TEST /<description>
          <false>
        /<feature>
  5. Build the TEST feature

    Since the XML configuration files have been modified, you must propagate the changes. The existing sys_action.xml, and sys_rule.xml files must be updated.

    host% cd build_dir
    host% rm conf/mkconfig/sys_rule.xml conf/mkconfig/sys_action.xml
    host% make xml
    
  6. Check that the TEST feature is present

    host% build-DEVTOOLS/host/bin/configurator -list features | grep TEST
    TEST:bool='false'
    
  7. Assert the TEST feature

    host% build-DEVTOOLS/host/bin/configurator -set TEST=true
    
  8. Building the test directory

    Before building a new archive with the TEST feature asserted, merge the source code corresponding to TEST within the working environment:

    host% cd build_dir/build-OS/src
    host% ../../build-DEVTOOLS/host/bin/mkmerge -U
    host% cd build_dir
    host% make mkmk
    

    To perform the merge, you must first run mkmerge in build-OS/ to perform a merge update, then run make mkmk in build_dir.

  9. Compile the system to produce an new archive with the TEST feature

    host% make
    host% make chorus
    

Adding a New XML File

XML files used during ChorusOS system generation are copied to the conf directory, so that they can be modified using the configurator command or the ews graphical tool. A component that adds new XML files must have rules to execute these files in its Makefile.bin file. For instance, the Makefile.bin of the OS component contains:

OS_XML = os.xml sys_rule.xml sys_action.xml cinit.xml cinit_action.xml 
hrCtrl.xm
l hrCtrl_action.xml
OS_SYSADM = sysadm.ini


xml:: DEVTOOLS.all $(OS_DIR)/exports.lst
    @sh $(DEVTOOLS_DIR)/cpxml $(BUILD_DIR)/conf/mkconfig $(OS_DIR)/conf/
    mkconfig $(OS_XML)
    @sh $(DEVTOOLS_DIR)/cpxml $(BUILD_DIR)/conf $(OS_DIR)/conf $(OS_SYSADM)
    @sh $(DEVTOOLS_DIR)/cpxml $(OS_DIR) $(OS) Makefile.bin

In this example, the XML files have to be copied from the OS merged tree, so the XML target depends on $(OS_DIR)/exports.lst (which is produced by mkmerge during the OS merge). The cpxml command acts as a wrapper around cp.