LCFG Header Development Tips
There are a number of common activities that people do in relation to the LCFG header sources. This topic contains short HOWTOs explaining how best to do various common things:
Header and Package List Naming Conventions
For sake of consistency and in some cases technical reasons a number of naming conventions have been established for header and package list files.
Header File Naming
In general headers should have descriptive names that use full words with underscores used to separate words when required. Exceptions to this rule are the
office-*.h
and
studentlab-*.h
header files that have already been referenced in machine profiles using dashes as the word separators.
Package List Naming
Package list files should follow the following naming scheme:
<level name>_<os name>_<list name>.{rpms,pkgs}
For example:
dice_fc3_env.rpms
.
The
<level name>
prefix is required to differentiate between package lists at different levels given that the package lists can only be referenced by file basename and not by a more descriptive path when using the
@
operator.
<list name>
should be a descriptive name, using underscores to separate words, that suggests why the packages are grouped together.
Adding a New Component
TODO: Write this.
How to Write <options>.h Headers
TODO: Write this.
How to Decide if Something Should Live in "live/"
Generally speaking, a header file should go into
live/
only if it contains resources that are likely to need to be changed at very short notice to preserve the overall stability of DICE. With the introduction of
ReleaseManagement all the headers in the
lcfg/
,
ed/
and
dice/
levels will be subject to a staging and scrutiny period (
testing
) prior to being pushed out into production. Consequently, changes to these levels could have a lead time of a few days depending on how many machines the changes effect. For some resources this may not be practical, hence the reason for the
live/
hierarchy.
When a header does exist in
live/
it is preferable that only the
volatile resources be set within it. As much material as possible should be factored back into the standard
lcfg/
,
ed/
and
dice/
levels. In some cases it may be possible to rearrange things such that none of the resources need to live in
live/
at all (e.g. using dns aliases).
--
CarwynEdwards: Yes I'm making this up as I go along.
Dealing With Operating System Specific Resources
TODO: Finish this.
Operating system dependent resources are selected using the following CPP definitions:
-
#define OS_LINUX
-
#define LINUX_FC3
-
#define LINUX_RH9
-
#define OS_SOLARIS
-
#define SOLARIS_8
-
#define SOLARIS_9
--
CarwynEdwards: Maybe and example pattern?
Multiple Inclusion and How To Deal With It
In a nutshell the issue is this:
For an environment where you have full control of the header hierarchy it is possible to come up with rules and procedures to keep things sane, however it is less clear what to do when you consider external sites. A typical use case is an external site that needs to add a local component that is not in the upstream
lcfg/
or
ed/
levels. If that component, or even just a componenet with the same name, is later added to
lcfg/
or
ed/
then you need to be careful.
One could argue that the scenario depicted in the diagram should not happen, but consider the case when an lcfg/ level component is not part of the
lcfg/defaults.h
base platform. What if there are also defaults modifications to be done at a higher level? We end up with this:
ed/defaults.h
includes
ed/defaults/thing.h
which includes
lcfg/defaults/thing.h
(if this isn't the case then how else do you do this?)
If component "thing" is then added to the
lcfg/defaults.h
then the multiple inclusions depicted in the diagram are created. You could then remove the inclusion path from
ed/defaults/thing.h
to
lcfg/defaults/thing.h
? Whatever the solution third parties using the lcfg level need to know what the impact on them will be.
Is multiple inclusion all that bad though when dealing with LCFG resources? If multiple inclusion is allowed then the following discussions apply:
For performance reasons it initially seems prudent to use the following pattern in the
defaults/*.h
files if multiple inclusion is allowed:
#ifndef <something>
#define <something>
/* stuff */
#endif
If this was to be done I think
needs to be of the form:
#define SEEN_<level>_<component>
.. as the resource sets are distinct at each level.
However! To ensure the correct behaviour in relation to CCP conditionals it may be better to not guard against mutliple inclusion. For example:
If lcfg/defaults/thing.h
contains:
#ifndef GUARD
#define GUARD
#ifdef BLAH
/* do stuff */
#endif
#endif
and BLAH
is not set at the lcfg/
level, "stuff" will not happen.
If then ed/defaults/thing.h
includes lcfg/defaults/thing.h
and ed/defaults.h
includes ed/defaults/thing.h
we have then set up a multiple inclusion (not necessarily a bad thing).
If BLAH
is then set in ed/defaults.h
"stuff" will still not happen as the multiple inclusion guard is blocking the reprocessing. Without the guard things will work as expected, at least in this case.
Another important rule that I think needs to be applied to defaults/*.h
files is that they should not define any CPP variables that are used in other defaults/*.h
files (preferably none at all). Otherwise this can happen:
-
lcfg/defaults/thing.h
- defines MYVAR
-
lcfg/defaults.h
- includes lcfg/thing.h
-
ed/defaults/another.h
- references MYVAR
-
ed/defaults/thing.h
- redefines MYVAR
ed/another.h
inclusion comes before ed/thing.h
inclusion in ed/defaults.h
and hence misses the redefinition.
This problem doesn't exist with LCFG references (<%%>) as they are resolved later.
Performance is another potential issue but it would probably be best to test this rather than assume it's a problem.
-- CarwynEdwards: Isn't this a namespace issue? If components were bound to levels in terms of scope then downstream component clashes wouldn't happen. With a level binding, downsteam components would only inherit upstream component resources if the relationship was explicitly defined. This is the same problem that programming languages solved with local naming prefixes, modules or packages is it not? Summary: Maybe resources need to be bound to levels too.
lcfg.mycomponent.myresource = foo
ed.mycomponent isa lcfg.mycomponent
ed.mycomponent.myresource = bar
With the actual component then being passed all resources that satisfy isa lcfg.mycomponent
?
-- CarwynEdwards - 22 Jun 2005