To use QEF's full power to produce an optimized build that promotes a really effective software process will require knowledge beyond the scope of this chapter and the material thus far presented. Hence this chapter will concentrate on the application of relatively straight forward QEF tools and procedures to similar projects that require little, if any, restructuring or modification of the source. Issues to be considered when dealing with a large or complicated project are presented in Chapter 12: QEF and Large Projects. What is described in this chapter is not the simplest application of QEF in that we are considering a multi-directory project that may need to be built by multiple people, possibly on different platforms. The simplest application is a single directory as illustrated in the first tutorial in Chapter 4.1: Tutorial 1. The only required file is the qeffile. All the other infrastructure files are optional. The settings that would normally be done in root.vrs and the other files are either not required or can be done in the qeffile. However, a single directory project is just an application of the approach described in Section 4 and Section 5 below and will not be discussed any further. Creating the QEF files required to use qef to do the project's construction is basically a matter of the following:
|
The typical QEF project will contain the following files:
% dirsetup newproj -- create qeffile -- create read.me ...In addition to the files named above, four additional files will be created. These are read.me files in the current, QefAdm/treedirs, and QefAdm/confvrs directories, and QefAdm/treedirs/example.lst. Their purpose should be obvious, given their names. They can be removed if necessary or desirable. The modification of the tree.vrs and confdefl.vrs files is discussed in Section 7.2 and the qeffile is discussed in Section 7.3. Other than the root.vrs file, the other files do not need to be modified. |
||||||||||||||||||||||||
Setting Necessary root.vrs Variables |
The root.vrs file in the root of the baseline or master tree, unlike a root.vrs file in an object tree, is actually a source file. It provides important base information. The following variables probably need to be set.
Assuming that the current settings of the Project, Revision, and VCSys variables have to be set to "myproj", "4.5", and "rcs" respectively, one would use the command: % rootvrs +Project myproj -r4.5 -vrcs # output to root.vrs addpath RootPath # none cset RootAlias @NotSet cset Project myproj cset Revision 4.5 cset TreeType baseline cset BuildHost @NotSet cset BuildSys @NotSet cset QremoteEnv @NotSet # defaults to qremote cset _DestDir_ @NotSet cset ConfigName @NotSet cset ConfVrs @NotSet # defaults to conf.vrs cset SysVrs @NotSet # defaults to linux2.vrs cset TreedirsList @NotSet # defaults to treedirs.lst cset QefAdm QefAdm cset VCSys rcs cset VCRoot @NotSet # defaults to @LastRoot cset VCBranch @NotSet cset OldRoot @NotSet cset EditBranches @NotSet # defaults to 0 qdupd: Added: 31 myproj 4.5 baseline you host - /home/myproj/srcIf you don't remember what a "cset Variable @NotSet" statement does, see the Chapter 4 note on the subject. |
Modifying the tree.vrs and QefAdm/confvrs/confdefl.vrs files are not quite so simple. | |
Fixing tree.vrs |
The tree.vrs file that was created should be examined, as it does contain comments and example settings. Initially the tree.vrs file does not need to be changed as it will work as is, but eventually the @ProdDir value should be set to an appropriate directory. @ProdDir will usually be set to the name of the production version of the product to be used for header files, libraries, and tools, but it should be set in the tree.vrs file to a reasonable default so that various search tools such as libs and incls have useful search paths even when not in an object tree (i.e., even when @_DestDir_ is not set). Given that the @ProdDir setting will depend on the release and system, its setting is sometimes done in a project specific configuration file (see <psysvrs>.vrs(x-qvrs)) or explicitly set by users in their conf.vrs file. Ultimately, as the QEF files evolve, there might be settings that are used by numerous directories that would be best done in the top level tree.vrs file, but at this time it is best to add then to the individual directory's qeffile. |
Fixing confdefl.vrs |
The QefAdm/confvrs/confdefl.vrs file serves as both the default user configuration file
and the annotated prototype for the users' conf.vrs files
in the root of their object trees.
As such the QefAdm/confvrs/confdefl.vrs file should contain the default settings for the
variables that would normally be subject to user tastes or preferences,
or are required to specify the necessary controls of the configuration
that cannot be determined automagically.
The dirsetup command will have created a QefAdm/confvrs/confdefl.vrs file somewhat
like the following:
% cat QefAdm/confvrs/confdefl.vrs options # e.g., DEBUGGING, NO_MAN, PURIFY # STAND_ALONE if not to use ProdDir directories # Run ``x-qvrs opt-vars'' for standard list cset ProdDir @NotSet # the project's product directory cset _F_cc @NotSet # flag to all cc executions cset _F_cc_c @NotSet # flags to cc -c executions cset _F_cc_o @NotSet # flags to cc -o executions cset _F_instal -qIs # instal(1) flags cset _T_cc @NotSet # name of ccAgain, the above will work for the time being, but as options and/or required user settings evolve they should be added in the file. |
For most reasonably structured projects, the root directory's
processing will be to invoke builds in some of its sub-directories.
In fact QEF does tend to work best with project structures
in which directories are either collections of sub-directories
to be processed or collections of source files with associated actions.
It can handle directories that are a mixture of sub-directories,
other directories,
and source to be processed, but at this time we'll keep it simple.
Assuming that the root directory's processing is to control the execution of sub-directories' processing, the qeffile that was created was a qefdirs specification. % cat qeffile set _DefaultArgs_ All # Normal default in root directory set SaveQefTrack 1 # Save the qef track if build fails Begin qefdirs P = Post apply post processing passes All = Install Man Post # add directories and operations after this line + # last level should consist of file system integrity package # (if available) and the relinfo directory # QefAdm/fsic P QefAdm/relinfo PThe necessary modifications will be to add the names of the directories to be processed and the constructions that are supported. This may require the addition of new action keys, such as the "P = Post" in the above. By default the qefdirs provides I (for Install), L (for Local), M (for Man), R (for no Remove), and N (for Lint). The new directories should be inserted in the qeffile before the entries for fsic (currently commented out) and relinfo. For example, to add a directory called cmd that has Local, Install, and Man constructions, one would add the line: cmd ILMto the file where indicated.
cmd ILmIf the Man pass within the cmd is actually just to invoke processing in a subdirectory man one could add: cmd IL cmd/man minstead, thereby saving eliminating the unnecessary processing of cmd during the Man pass. If there is another directory example that depends on tools built within cmd one could add a dependency as in: example IL cmdFinally, if there is processing to be done in the current directory, one adds the directory . as in: . ILMIn this case, the current directory's construction script is put into the file qeffile2, instead of qeffile, as the latter is already being used for the multi-directory control. |
Creating the controls for an individual directory is primarily
the creation of a qeffile that controls the following:
The lines of the qeffile up to and including the Begin line are qvrs lines. They begin with a qvrs keyword, followed by arguments that might incorporate variables and functions. The first three sections of Appendix F: The QEF Specialist's Reference Card cover Qvrs Keywords, Qvrs Variables, and Qvrs Functions respectively. |
|||||||||||||||||||||
The preamble |
The optional preamble section is used to set options that need
to be set before the higher directory tree.vrs file or the
system configuration files are processed.
In most cases this means specifying the DEBUGGING
of PROFILING options.
If specified, the preamble section
must constitute the first significant lines of the qeffile.
The preamble section consists of a "preamble" line, the settings,
and a terminating "endpreamble" line, as in:
preamble options DEBUGGING # indentation is optional endpreamble
|
||||||||||||||||||||
Suffixes |
The @Suffixes variable is used to specify the suffixes of
source files to be found by sls in the source path.
Usually this list is saved in the srclist._ file.
If @Suffixes is not specified, the default setting (c, y, l, and sh) is used. However, if additional or different suffixes are required, one sets the @Suffixes, as in: set Suffixes 1 qh cppIf one wanted the standard suffixes or the `idl' suffixes one uses the flags s or i, as in: set Suffixes -std -i 1 qhThe @Suffixes variable can also specify the files produced by processing a file of a particular suffix. For example, "c/s" or "/(*).c/&.s" both specify that X.c may produce X.s. A more complicated example is "/(*).y/&.c;y.tab.c" which specifies that a f.y file may produce f.c and y.tab.c. Note that usually there is no @Suffixes setting or it is simply "-s" plus a list of simple suffixes. In preparing a qeffile, one determines the list of primary files to be processed and/or installed and set the @Suffixes variable to the suffixes that would generate that list. If does not need to be complete, as individual files can be named within the construction script, or files can be ignored or removed from the list within the construction script. |
||||||||||||||||||||
SrcPath | The @SrcPath is initially set to the @Branch sub-directories of the @RootPath. @Branch is the current directory's displacement from the root. @SrcPath rarely needs to be modified. The exception is when other directories need to be spliced into the source path, as will be illustrated in a later example. | ||||||||||||||||||||
InclPath |
@InclPath specifies the directories to be searched for C
#include files.
Usually @InclPath is initialized in the top directory's tree.vrs
and local modifications are made in the qeffile file to add additional
directories.
Most frequently this will be to add the @SrcPath directories
(i.e., corresponds to the current directory) as in:
addpath InclPath @SrcPathNote that the addpath keyword will usually insert its arguments at the beginning of the current list. If adding something like the X11 directories, one wants those directories to be added after the project's directories. Furthermore the name of the X11 include directory should have been configured in the host's sysnm.vrs file. To add the X11 include directory to @InclPath add the line: addpath InclPath -s @InclDirs[X11]The s specifies that the directories that follow should be inserted into the @InclPath list in the system header files portion of the list. |
||||||||||||||||||||
LibPath |
@LibPath specifies the directories to be searched for libraries.
It will be initialized in the system's sysnm.vrs file
to the list of standard library directories.
As is the case with @InclPath, addpath is used to insert or
append new directories to the current list, as in:
addpath LibPath -s @LibDirs[X11] |
||||||||||||||||||||
Libraries |
In addition to the @LibPath library search path, there is a
variety of settings that control the libraries linked with a program.
set LIBS[echo.c] -lsocket # libraries linked with echo.c # better to put it in echo.c itself -- see below set LibMap[-lxxx] -lxxx -ltermcap # additional -lxxx mappings # such mappings usually done in sysnm.vrs file set LibStatic[-lxxx] pat* # use static version for -lxxx # for programs that match pat*Use libs X for a list of library search controls, and examples and short descriptions for each control. Use qvrs l for library search controls for the current directory. Use libs echo.c for list of libraries that will be linked with echo.c after library mapping and searches. |
||||||||||||||||||||
Other Flags |
There are a variety of other flags, options, and controls that
might be required.
The most common class of flags will be Cc flags, install modes,
and tool names, as in:
set _F_cc_c[echo.c] -DMACRO_DEF if @(sys hpux*) && ! @(option DEBUGGING) # if system is hpux* and DEBUGGING is not set # then make compilation of qsglib.c safe set _Optimize_index_[qsglib.c] Safe fi if @(sys unix5.4-mx300i) # on mx300 install qmsg setgid, group tty set _F_instal[qmsg] -g tty -M 2755 fi cset _T_tclsh @PrereqRoot[tcl]/bin/tclsh
Similarly, @InclPath or @LibPath settings shared by the directories of a project should be done within such a tree.vrs file. |
||||||||||||||||||||
The Begin line |
The Begin line can take a number of forms as described
by Begin(x-qvrs), qvrs(1), and many other documents.
Basically it defines the input script and the processor,
or the command that generates the script.
The most common forms (greater than 98% of qeffiles) are:
Begin # defaults to qsg M Begin qefdirs Begin qsg other flagsThe first form is used for most directories with constructions. Given the qsg M form, qef will automatically invoke sls to build the source database. The qefdirs form was discussed in Section 7.3. The third form is used when the source database is not required or additional flags are required. If the qsg invocation is to have either the M or S flags, they must be the first flag to be recognized by qef as forcing sls to be run.
|
We have already introduced qefdirs type scripts in
Section 7.3 above.
That covers about 10 to 20% of qeffiles.
Nearly all other qeffiles are qsg scripts.
qsg is introduced in Chapter 9 and fully documented in qsg(1) and the x_db database x-qsg. Appendix F: The QEF Specialist's Reference Card lists qsg keywords, functions, list operators, and standard scripts. qsg is a programming language specifically designed to generate input to other programs.
keyword arguments script flags argumentsFor example, in # If on windows, link sls to sls.exe if @(sys winnt* win9[58]*) mklink -d _DestDir_/bin sls sls.exe else @# drop rc.sh and msdev.sh remove argv rc.sh msdev.sh @# not needed if not windows fithe if, else, remove, and fi are qsg keywords. The "@#" is used to begin a comment in the middle of a statement. The `#' is treated literally anywhere other than at the beginning of a line. The mklink statement is a script from the standard qsg script library. The documentation for mklink can be retrieved using: % x-qsg mklink mklink : create qef script to create links Synopsis: mklink [-slcC] [-d dir] [-T construct] [-] file link_names ... -c suppress default inclusion of target in Target group -C applies condln -c flag - aborts if file writable ...Similarly the documentation for any keyword, such as remove can be retrieved using: % x-qsg keywordThere are five special keywords to simplify output, as in: >this line, other than leading `>' output to stdout <\1>arguments output with long lines split at white space@ with second and subsequent lines preceded by a@ backslash, a newline, and one tab. The backslash is@ optional and the 1 can be replaced by 0 through 8. << lines following "<<" up to ">>" output ><message This is a command inside HERE-IS output. Any embedded expressions, such as @<b bold> are interpreted. >>however, their use within qeffiles files is discouraged. Before going into the programming of a qeffile's qsg script any further, a brief discussion of the `@' magic is required. See Appendix E: Special @ Sequences in QSG in the reference card for a list of the special `@' interpretations. Immediately above it you will also see a list of the special @ sequences in qvrs.
The item @(x-qsg) will give an extended description of the syntax and input conventions employed with qsg scripts: % x-qsg @ qsg-input : qsg input conventions and the @ escape qsg scripts should consist of printable ASCII characters, tabs, spaces and newlines. Any occurrence of a control character or DEL (octal 177) raises a fatal error. ... Another powerful feature of the qsg language is the use of the operators that can be used to modify a value of a variable or function call. For a complete description see qsg-listopts(x-qsg). For a list of the operators see Qsg Listops in the specialist's reference card. Although qsg is a fairly complete, albeit unconventional, programming language, most of its programming facilities are provided to implement the scripts. Within qeffiles the qsg scripts are usually limited to simple variable manipulation, if and set statements and calls to standard scripts.
The description of any of the above scripts can be obtained using: % x-qsg scriptBrief introductions to the listed scripts follow. |
||||||||||||||||||||||||||||||||||||||||
program |
This script is used for multiple module programs, as in:
program -v prog.c parser.y lexer.lThis command outputs a qef script to create and install the program prog. An alternative name may be specified using a n flag. The libraries for the program are specified in prog.c, @LIBS[prog.c], or the module named by the M flag. Directives are output to create each intermediate file (e.g., parser.c, lexer.c, prog.o). If the option @GOT_PURIFY is true, directives needed to produce the purify, quantify, purecov, and purelink versions of the program are also produced with targets: prog_{p,q,v,l} respectively -- see pureeh(x-qsg). program provides flags to suppress installation (L), suppress construction unless explicitly named (c), to specify the aggregate group to which the object is bound (T -- defaults to Install), and to name the destination directory (d -- default _DestDir_/_BinDir_). The processing of each individual module is selected by the suffix which will usually be done by the script mkobj_X, where X is the suffix. Furthermore suffixes can be mapped to specific handlers -- see qsg-sfxmaps(x-qsg). The v flag illustrated in the example command is one of the useful options. If specified, a version file is created and linked with the modules to embed a link time version string into the resulting binary. program also provides significant support for window specific features such as creating dlls, handling precompiled header files, and registering the constructed file. This script is the most commonly used. In fact the statistics given above are misleading in that the 56 commands script invocations invoke program about 400 times (albeit in loops) to produce the directives to produce the programs of the Q-Tree. |
|||||||||||||||||||||||||||||||||||||||
commands |
The commands script is used to handle a list of single module programs,
man pages, shell scripts, and other files.
Most often it is included in a qeffile as the last command to
process all those files in the argument list not already processed,
as in:
commands @argvNote that if an argument has already been processed by a previous script, such as program, it will not be re-processed. commands does not actually do any of the processing. For each argument source it invokes the appropriate qsg script, as determined by suffix, and that script will typically generate the qef directives to build and install the appropriate files. The selection of which script is done using the suffix as described in commands(x-qsg). Briefly for a suffix X, if script mkobj_X exists, then program is used to process the file. If cmds_X exists, it is invoked. Note that suffixes can be mapped to handlers via settings of the qsg global variable QsgCmdProc[Sfx] which is usually set by the individual qsg library's initialization script. |
|||||||||||||||||||||||||||||||||||||||
generic |
This qsg script is used to output qef directives and recipes
to build and optionally install a file with a specified recipe.
This script is commonly used when the file's processing is non-standard.
Flags are provided to specify prerequisites, touch files,
attributes, various other controls, the destination directory
(if any), the target and the recipe, as in:
generic -P prereq -S source_prereq -d _DestDir_/bin @ target_name <recipe ...> Individual commands in the recipe should be separated by semi-colons. finstall (see below) is invoked to install the file if the d flag is specified. |
|||||||||||||||||||||||||||||||||||||||
mklink |
This script creates qef script to make links from first
argument file to other argument files, using condln.
For instance, the example script at the beginning of this section
contained:
mklink sls sls.exewhich will output directives to link sls to a name that can be recognized by MicroSoft's Visual Studio. The d argument (default _DestDir_/_BinDir_) is used as the directory for either the target or link file when a file does not contain a slash. |
|||||||||||||||||||||||||||||||||||||||
library |
Building libraries for which the source is spread across
multiple directories will be covered in a later section.
Most libraries for which the entire source is within a single
directory can be built with a command similar to the following:
library -v -n exmpl c.c y.y l.l x.x ...which creates and installs a library called "libexmpl.a" (or "exmpl.lib" on DOS or windows). Like program, the argument modules are processed using mkobj_X, where X is the module's suffix or the script to which it is mapped by the qsg global variable QsgCmdProc[suffix]. The v flag specifies that a version module is to be created, compiled, and added to the library. Note that any modules added to a library will be marked such that if passed as arguments to commands or program, they are ignored. This means that one can build a library and programs as in: # Must map -lexmpl explicitly as it won't exist # when search for libraries done. set Library[-lexmpl] lib.@LibSuffix set LIBS[*] -lexmpl Begin library -L mod1.c mod2.c mod3.c @# -L suppresses installation commands @argv @# no need to remove mod[123].c as @# will be ignored since processed by library |
|||||||||||||||||||||||||||||||||||||||
finstall |
finstall is used to specify the installation of a single file.
Multiple files can be installed using instfls or install.
The latter script just calls finstall in a loop.
The following are a series of example finstall invocations:
finstall F @# install `sls F` as _DestDir_/_LibDir_/F finstall -l F @# same but uses local F finstall -d dir F @# install `sls F` as dir/F finstall -s -d dir F.dat @# strip suffix so install as dir/F finstall -n X -d dir F @# install `sls F` as dir/X finstall F -P -M555 @# add instal flags -P and -M555
|
|||||||||||||||||||||||||||||||||||||||
instfls | instfls creates a script and the instfls input file to do installations. instfls uses instal to do the actual installations, but only if the source file differs from the target file. It is most often used to install header files so that gratuitous changes will not be made. The flags for instfls are almost the same as those for finstall except for the addition of a M mode flag. | |||||||||||||||||||||||||||||||||||||||
manlink |
This script is used to link a previously installed man section
to a new name in the same directory. So
manlink bp.1 howto.1 qfunc.1outputs a script to link bp.1 to howto.1 and qfunc.1 in the appropriate man directory. |
|||||||||||||||||||||||||||||||||||||||
cmds_man | cmds_man handles manual sections, installing its argument files in the appropriate man or docs directory. This is the script invoked by commands to process *.[1-9] files. | |||||||||||||||||||||||||||||||||||||||
putdeps |
This script is used to output dependencies that cannot be deduced
by incls or the qsg scripts.
For example:
putdeps -AV T1 T2 ... : D1 D2 ... # outputs dependencies T1 T2 ...:V: D1 D2 ...This is obviously a fairly simple conversion, yet it is recommended that putdeps be used instead of raw output so that future changes to the back-end or retargeting to an alternative back-end will not require changing the qeffiles. |
|||||||||||||||||||||||||||||||||||||||
Checking the Construction Scripts |
Once the qeffile and qvrs files are prepared there are a number of
steps that can be used to validate settings:
% qef -Ptargets # output list of Targets % qef -Pscript # output generated script % qef -Pppscript # output post-processed script % qvrs # output all qvrs settings % qvrs -W var # show where var set % qef -n # show scripts for default targets % libs -a echo.c # show libraries for echo % qef -n echo # shows what would be done |
There are two recommended modifications to C and C++ source files:
|
|||||
Fixing the #include "file"s |
The C ANSI standard does not define the behaviour of
#include "file"thus its interpretation varies from system to system, whereas the <file> form does not. That fact alone should be sufficient reason to avoid the "form", however, the real dangers of the "form" are the inability to map an #include file out of context and the potential of two different files using two different versions of an included file.
If f.c and h.h are copied to a user's working directory for modification, when f.c is compiled it will use the working directory version of h.h. However, g.c use the h.h in the original directory. The incls parsers do support the "file" form, but the potential ambiguities may lead to problems due to version skew or user confusion. Finding all the includes, provided programmers have not embedded comments in between the `#', the "include", and the "file", is simply a matter of: % rep -rF '^\-#\-include\-"' srclistwhere srclist contains a list of the files to be checked. The output should be saved, and edited to replace the "file" forms by appropriate <file> forms. To apply the changes run the following with the changes file as the standard input: % rpl -vr
A more complete and comprehensive discussion of this subject may be retrieved using: % x-qmisc \#includes |
||||
Adding LIBS comment |
Adding the LIBS line to the main source module is optional,
but it is convenient and reduces the number of lines that need
to be added to the qeffile.
The LIBS line should be a comment within the first 1024
characters of the file.
A colon (`:') must immediately follow LIBS.
The list of libraries should be a space separated list of
lsym symbols naming the libraries required by the program.
/* LIBS: */ /* another comment * LIBS: -lsocket -lX11 */ /* Back slashes can be used to split up long lists * LIBS: -lsocket \ * -lX11 */ |
The dirsetup dir-set qegappl contains a simple
example application, complete with its qeffiles and qvrs files.
To extract the files use:
% dirsetup -d eg qegappl - create eg/read.me - create eg/appl/appl.h ...The created tree contains directories appl, cmd, lib, and man, containing a header, a command file, a library, and man page respectively. It also contains the qeffiles to build and install all the components and read.me files to explain everything. The qvrs files are all annotated to explain the various commands and settings. This simple system should be examined as a prototype for bigger sub-projects. The dirsetup dir-set qeglibeg contains the qeffiles, qvrs files, and the source for three libraries, each built using a different directory architecture. To extract these prototypes, use: % dirsetup -d libeg qeglibegThe three architectures are:
|
|||||||
Summary | |||||||
At this time you should be able to create simple qeffiles and the necessary qvrs files and project infrastructure. The balance of this guide is intended for the advanced user and project administrator and at this time can probably wait until you have accumulated some experience using QEF and its 214 tools. |
c063.qh - 9.4 - 03/10/22 |