| 1 |
INTRODUCTION |
|---|
| 2 |
------------------------------------- |
|---|
| 3 |
libCrash is a library of handy functions and classes for day to day use. |
|---|
| 4 |
|
|---|
| 5 |
But it's a bit more than that. It also has the facility to extract the source |
|---|
| 6 |
of specific classes and functions into your own source tree. While this may |
|---|
| 7 |
sound a bit odd, I find it exceptionally useful for the kind of functions that |
|---|
| 8 |
libCrash contains. |
|---|
| 9 |
|
|---|
| 10 |
libCrash consists of three seperate portions. |
|---|
| 11 |
|
|---|
| 12 |
The first is the source code, which is installed in a system wide directory. |
|---|
| 13 |
The module map is generated from this source code after it is installed. |
|---|
| 14 |
|
|---|
| 15 |
crash-module is the second part, it is the means by which the modules can be |
|---|
| 16 |
queried and extracted. In addition to using crash-module to extract modules |
|---|
| 17 |
from libCrash, maps can be generated from arbitrary code. To do this, you can |
|---|
| 18 |
either insert //<module ...> tags into the source code manually or use the |
|---|
| 19 |
--auto parameter of crash-module to automatically generate a map from the |
|---|
| 20 |
source code. eg. |
|---|
| 21 |
|
|---|
| 22 |
crash-module --source *.cc *.h --auto --module=module.map |
|---|
| 23 |
|
|---|
| 24 |
The third and final part is crash-config. This lets you use libCrash as a |
|---|
| 25 |
standard, linkable, library. It has similar functionality to gtk-config or |
|---|
| 26 |
other scripts of that nature. For example, to link a test program to libCrash: |
|---|
| 27 |
|
|---|
| 28 |
gcc test.c `crash-config --cflags --libs` -o test |
|---|
| 29 |
|
|---|
| 30 |
WHY? |
|---|
| 31 |
------------------------------------- |
|---|
| 32 |
I write a lot of programs. I write small utilities to help me in day to day |
|---|
| 33 |
use of the system and to help me in programming, as well as projects that |
|---|
| 34 |
aren't quite so small. libCrash is my way of making the task a bit easier. |
|---|
| 35 |
|
|---|
| 36 |
The notion of a normal library is that it encapsulates functions that are |
|---|
| 37 |
used by other programs, so that they don't have to duplicate the |
|---|
| 38 |
functionality. This is a Good Thing. |
|---|
| 39 |
|
|---|
| 40 |
However, there is also the case where a program only needs to use a very small |
|---|
| 41 |
subset of the required functionality of a library. Requiring that the user of |
|---|
| 42 |
a program have this library on their system just to run your little utility |
|---|
| 43 |
might be asking a bit much, which could lead to the person not using your |
|---|
| 44 |
program. How many times have you gone to freshmeat and seen a program that |
|---|
| 45 |
took your fancy only to find, upon further investigation, that it requires you |
|---|
| 46 |
to install 8 other libraries? |
|---|
| 47 |
|
|---|
| 48 |
For an example of this, I'm going to use a program that I've developed myself. |
|---|
| 49 |
This program is called 'todo' and allows programmers to tag directories with |
|---|
| 50 |
a heirarchical list of outstanding tasks. Now this is not a complex program, |
|---|
| 51 |
however, I wanted to use XML to store the database of tasks and the program |
|---|
| 52 |
itself performed a large amount of string manipulation. Now for the first |
|---|
| 53 |
option I could have used something like libxml from the Gnome project, for |
|---|
| 54 |
the second I would have had to use various different libraries. By Using |
|---|
| 55 |
libCrash this is a non-issue. It has a basic XML parser built in as well as a |
|---|
| 56 |
large number of useful string manipulation functions. So all I had to do was |
|---|
| 57 |
this: |
|---|
| 58 |
|
|---|
| 59 |
crash-module --extract --module XML String --trim |
|---|
| 60 |
|
|---|
| 61 |
This generated eight source files. Eh? Well, this is because the XML module |
|---|
| 62 |
relies on another module called Lexer (which, as the name suggests, is a |
|---|
| 63 |
lexical analyser). Lexer, in turn, relies on the module Regex (which is a |
|---|
| 64 |
C++ wrapper around the regexp library). So that gives us the eight source |
|---|
| 65 |
files: |
|---|
| 66 |
|
|---|
| 67 |
XML.cc XML.h |
|---|
| 68 |
Lexer.cc Lexer.h |
|---|
| 69 |
Regex.cc Regex.h |
|---|
| 70 |
String.cc String.h |
|---|
| 71 |
|
|---|
| 72 |
|
|---|
| 73 |
HOW? |
|---|
| 74 |
------------------------------------- |
|---|
| 75 |
libCrash uses tags inside comments to define where modules are and what they |
|---|
| 76 |
require. |
|---|
| 77 |
|
|---|
| 78 |
When parsing an input file, the logic is as follows: |
|---|
| 79 |
|
|---|
| 80 |
For each source file, extract and store all lines of the form #include <....>. |
|---|
| 81 |
Any headers included with this form are automatically included in source code |
|---|
| 82 |
generated from modules. Headers of the form #include "..." are ignored. This |
|---|
| 83 |
is because they are assumed to be other modules which will be automatically |
|---|
| 84 |
included by a 'requires' attribute. |
|---|
| 85 |
|
|---|
| 86 |
If a line of the form //<module ...> is encountered, the source between it and |
|---|
| 87 |
the corresponding //</module> line is added to the list of source segments in |
|---|
| 88 |
that module. This allows multiple segments (possibly from seperate source |
|---|
| 89 |
files) to be merged to make one module. |
|---|
| 90 |
|
|---|
| 91 |
Any modules listed in the 'requires=...' attribute for a module are added as |
|---|
| 92 |
#include lines when generating output. So if you had requires=Lexer, that |
|---|
| 93 |
would end up being #include "Lexer.h". |
|---|
| 94 |
|
|---|
| 95 |
Modules have to have a 'name=...' attribute to determine what name to give the |
|---|
| 96 |
generated output source files. |
|---|
| 97 |
|
|---|
| 98 |
Another attribute, but one that is optional, is the 'description=...' one. It |
|---|
| 99 |
lets you give a human readable description of the modules functionality. This |
|---|
| 100 |
can be displayed by passing the --verbose option to crash-module. |
|---|
| 101 |
|
|---|
| 102 |
The optional attribute 'include=...' is used to force inclusion of headers |
|---|
| 103 |
that are only used for one module, but not others in the same source file. |
|---|
| 104 |
This is handy if you have one input source file with a whole lot of functions |
|---|
| 105 |
but wish to seperate the individual functions into seperate modules. |
|---|
| 106 |
|
|---|
| 107 |
The last attribute is the 'optional' attribute, which lets certain 'required' |
|---|
| 108 |
modules be excluded if their use is optional. The XML module is one that uses |
|---|
| 109 |
this functionality. It can optionally use the Signal module to allow callbacks |
|---|
| 110 |
to user programs. However, if this functionality is not required, crash-module |
|---|
| 111 |
can be passed the parameter --exclude when extracting modules. This is |
|---|
| 112 |
handled in the module source code by using #ifdef's. Each module defines a |
|---|
| 113 |
macro of the form CRASH_<module>. So in the case of the XML module it would |
|---|
| 114 |
have '#ifdef CRASH_SIGNAL' around any code that uses Signal functionality. |
|---|
| 115 |
|
|---|
| 116 |
Taking the above example further, the following example shows a snippet of |
|---|
| 117 |
the XML module. |
|---|
| 118 |
|
|---|
| 119 |
XML.h |
|---|
| 120 |
----- |
|---|
| 121 |
#ifndef CRASH_XML |
|---|
| 122 |
#define CRASH_XML |
|---|
| 123 |
|
|---|
| 124 |
#include "Lexer.h" |
|---|
| 125 |
|
|---|
| 126 |
//<module name=XML requires=Lexer optional=Signal description='XML parser'> |
|---|
| 127 |
class XML { |
|---|
| 128 |
... |
|---|
| 129 |
#ifdef CRASH_SIGNAL |
|---|
| 130 |
Signal1<string const &> onElementEnd; |
|---|
| 131 |
#endif |
|---|
| 132 |
... |
|---|
| 133 |
}; |
|---|
| 134 |
//<module> |
|---|
| 135 |
|
|---|
| 136 |
#endif |
|---|
| 137 |
|
|---|
| 138 |
XML.cc |
|---|
| 139 |
------ |
|---|
| 140 |
#include "XML.h" |
|---|
| 141 |
|
|---|
| 142 |
//<module name=XML> |
|---|
| 143 |
XML::XML() { |
|---|
| 144 |
} |
|---|
| 145 |
|
|---|
| 146 |
XML::~XML() { |
|---|
| 147 |
} |
|---|
| 148 |
|
|---|
| 149 |
... |
|---|
| 150 |
.. |
|---|
| 151 |
. |
|---|
| 152 |
//</module> |
|---|