# JEDI Package Generator

## Summary

Introduction
About the package generator
Package XML source files format
XML Configuration file format
Template Files format
Include File parsing
Detailed generation process
Conditions parsing
Command line reference
Notes to developers

## Introduction

In an effort to make the generation of component packages for the JVCL easier, a package generator has been created. Even if it is extensively used by the JVCL team, it has been designed to be as generic as possible and as such may seem a bit complex at first. You will find in this file the documentation you need to understand how to take advantage of this tool.

The package generator comes in two different version: Graphical User Interface (pgEdit.exe) and Command Line (pg.exe). They both work from the same set of XML configuration files, pgEdit having the advantage to allow you to safely edit the source XML files. Here is the flow diagram:

Each file has its own role:

Package XML Source Files | Each package XML source file indicates which files are to be included in the package, which other packages this package depends on and various compilation options such as PFLAGS (Pascal Flags) for C++ Builder. All inclusions and dependencies can be conditionally altered by a compilation directive. A runtime package should have a '-R' suffix, while a design time package should have a '-D' suffix. Hence, JvCore-R.xml is a runtime package source file while JvCore-D.xml is a design time package source file.
XML Configuration File | This file contains the declaration of models that the package generator will use to generate the files. Each model declares targets (one version of Delphi, C++ Builder or Kylix), the format of the filenames to output, the location of package files and optionally an include file.
Template Files | These files are skeletons for the final output files. They contain special markers that will get replaced by values taken from the XML configuration file and the Package Source XML files to generate the final output files.
Include File | It is possible to specify conditions for inclusion of packages and source files in packages. The conditions are read from the include file given to the package generator. Because the syntax of these conditions can be quite complex, the packages must be regenerated whenever the given include file has changed so that packages are synchronised with it. If you don't regenerate the packages, you may have errors when compiling the packages.
Existing Output Files | If the files to be generated already exist, they will be used to determine if any change was done to them since the last time they were generated. If unchanged, the output files will be left untouched.

## About the package generator

The package generator is released by the JEDI VCL group under the Mozilla Public License 1.1 and was originally written by Olivier Sannier. It has since benefitted from the contributions of various people in order to make it as generic as possible. Should you have any questions regarding this program, please feel free to contact the original author or the JVCL team.

## Package XML Source Files Format

Here is a basic XML source file (Extracted from JvCore-R.xml):

`<?xml version="1.0" encoding="iso-8859-1"?> <Package Name="JvCore" Design="0"> <Description>JVCL Core Runtime Package</Description> <CLXDescription>JVCLX Core Runtime Package</Description> <GUID>{CCA5391F-35F6-43D1-AB48-187085D1EF5B}</GUID> <C5PFlags>-LUCJcl50</C5PFlags> <C6PFlags>-LUCJcl</C6PFlags> <C5Libs/> <C6Libs/> <Requires> <Package Name="ThemeManager6" Targets="D6,D6p,C6,C6p" Condition="JVCLThemesEnabled"/> <Package Name="CJCL" Targets="C6,C6p" Condition=""/> <Package Name="vclx" Targets="D6,D6p,D7,D7p,C6,C6p,K2,K3" Condition=""/> </Requires> <Contains> <File Name="..\..\common\JvConsts.pas" Targets="all" Formname="" Condition=""/> <File Name="..\..\run\JvColorProvider.pas" Targets="all" Formname="" Condition=""/> <File Name="..\..\run\JvComponent.pas" Targets="all" Formname="" Condition=""/> <File Name="..\..\run\JvJVCLAboutForm.pas" Targets="all" Formname="JvJVCLAboutForm" Condition=""/> </Contains> </Package>`

When reading the files, the package generator doesn't check for the existence of the nodes and properties in the XML file. It assumes they exist and if they don't you will most likely end up with an Access Violation exception. This is why we recommend that you use pgEdit.exe to edit the files, which will ensure that the format of the xml files is correct. Here is a description of each node and its usage:

Node | Parent Node | Description
Package | none (root node) | This is the root node. Its only properties are Name and Design. Name is obviously the name of the package while Design is 1 when the package is a designtime package, 0 when it is a run time package. The root node doesn't have to be called package, but it MUST have those two properties.
Description | Package | This is the description of the package as it will be displayed in the IDE.
ClxDescription | Package | This is the description of the package as it will be displayed in the IDE, when the package is generated for a CLX target.
GUID | Package | Delphi 2005 requires a GUID to be present in bdsproj files. This is the value that will be used as replacement for the %GUID% marker, allowing you to put such a GUID in a file if required. This is read as a string value, no verification is made to ensure that the value actually is a valid GUID.
C5PFlags | Package | The package files for C++ Builder 5 contain a special node to allow for passing extra arguments to the pascal compiler. This node indicates the value to use for the PFLAGS node in C++ Builder 5 packages. In the example above, we added -LUCJcl50 to indicate to link the file CJcl50.dcp into the package. Options are separated by spaces and if followed by a string in parenthesis, the string is considered to be a condition. If the condition doesn't exist when the file is generated, the option is removed. For instance, if you type -LUCJcl50(USEJVCL) then if USEJVCL is not defined in the include file, -LUCJcl50 will be removed from the final PFLAGS value. This final value will be the replacement for %C5PFLAGS% in template files.
C6PFlags | Package | This node has the same meaning as C5PFlags but for C++ Builder 6, hence being the replacement for %C6PFLAGS%
C10PFlags | Package | This node has the same meaning as C6PFlags but for C++ Builder 10, hence being the replacement for %C10PFLAGS%. If the node is absent, the value of C6PFlags is used.
C5Libs | Package | In some rare occasions, it may be necessary to indicate some extra libraries to the C++ linker. This happened for instance with the Network related packages in the JVCL as they required wininet.lib. The value here should be a space separated list of library files and will be the replacement for %C5LIBS%
C6Libs | Package | This node has the same meaning as C5Libs but will be the replacement for %C6LIBS%
C10Libs | Package | This node has the same meaning as C6Libs but will be the replacement for %C10LIBS%. If the node is absent, the value of C6Libs is used.
ImageBase | Package | A string that will be the replacement for %IMAGE_BASE%. It's recommended use is to set the base of the image in a compiler directive. This node is not compulsory, an empty string being used by default.
VersionMajorNumber | Package | A string that will be the replacement for %VERSION_MAJOR_NUMBER%. It's recommended use is to store the major version number. This node is not compulsory, an empty string being used as a default.
VersionMinorNumber | Package | A string that will be the replacement for %VERSION_MINOR_NUMBER%. It's recommended use is to store the minor version number. This node is not compulsory, an empty string being used as a default.
ReleaseNumber | Package | A string that will be the replacement for %RELEASE_NUMBER%. It's recommended use is to store the release number. This node is not compulsory, an empty string being used as a default.
BuildNumber | Package | A string that will be the replacement for %BUILD_NUMBER%. It's recommended use is to store the build number. This node is not compulsory, an empty string being used as a default.
Requires | Package | This node is only the parent of all the 'package' nodes, indicating the packages required by the current package.
Contains | Package | This node is only the parent of all the 'file' nodes, indicating the files contained in the current package.
Package | Requires | Each package node in a Require node indicates a package that the current package requires in order to be compiled. It must have the following three attributes:
Name | The name of the package that is being required. No extension should be given here. If the name starts with the prefix for the current model, it will be modified according to the format in the model. For instance, if Name is 'JvCore-R', prefix is 'Jv', format is '%p%e%v%t' and the current target is C++ Builder 6, the name will be replaced by JvCoreC6R. Please see the detailed description of the generation process for further information.
Targets | The targets for which the package is required.
Condition | The condition under which the package is required. If empty, no condition is necessary to require the package in the current one. Please see the 'Conditions parsing' section for details about the available operators.
File | Contains | Each File node in a Contains node indicates a file to include in the package. It must have the following four attributes:
Name | The name of the file to include. The extension must be included.
Targets | The targets for which the file is to be included.
Formname | The name of the form (dfm) associated with the pas file, if any. It is not the type name, but the name of the form that must be indicated here. For instance, if the form is of type TForm1 then the value must be Form1. Moreover, if the dfm file describes a Frame or a Data Module, the name must be followed by a colon, a space and TFrame or TDataModule (as in 'myFrame: TFrame').
Condition | The condition under which the file is to be included. If empty, no condition is necessary to include the file. Please see the 'Conditions parsing' section for details about the available operators.

## XML Configuration File Format

Here is a basic XML Configuration file, derived from the full pgEdit.xml distributed with the JVCL:

`<?xml version="1.0" encoding="iso-8859-1"?> <Configuration> <pgEdit> <odlAddFiles_InitialDir>..\..\run</odlAddFiles_InitialDir> <cmbModel_ItemIndex>0</cmbModel_ItemIndex> </pgEdit> <models> <model name="JVCL" prefix="Jv" ClxPrefix="JvQ" format="%p%n%e%v%t" packages="..\..\packages" incfile="..\..\common\jvcl.inc"> <targets> <target name="d7" pname="d7p" pdir="d7per" defines="COMPILER7_UP"/> </targets> <aliases> <alias name="Delphi" value="d7,d7p"/> </aliases> <ClxReplacements> <replacement original="\run\Jv" replacement="\qrun\JvQ"/>` `</ClxReplacements>` `</model> </models> </Configuration>`

Contrary to the package XML source files, the validity of this file is checked when read and an explanatory message will be displayed if the file is corrupted. However, only the basic structure is checked and you may end up with an Acces Violation exception anyway. To get a meaningful file, you need to indicate the correct values according to the following table:

Node | Parent Node | Description
Configuration | node (root node) | This is the root node of the XML file. It doesn't have to have any attributes and may be named differently, but doing so would mean that pgEdit.exe needs to be changed to cope with the modification. pg.exe doesn't care.
pgEdit | Configuration | This node contains all the subnodes required by pgEdit to save its state when closed down. The state includes the values of various component fields, the size of the form, its position etc.
models | Configuration | This node holds the model nodes, those nodes being the actual configuration described in this file.
model | models | Each model node defines a generation model that can be used by the package generator. The first five attributes are compulsory and serve the following purpose:
name | The name of the model.
prefix | The prefix indicates the first characters of package names that are to be modified when encountered in a required package node for a package to generate. Please see the detailled description of the generation process for further information.
format | The format of the string that will replace 'template' in a template filename. It will also replace a package name that matches the prefix while being processed in the 'Requires section' state. Please see the detailed description of the generation process for further information. Some special markers will get replaced:
%e | A single character indicating the environment. See below for more details.
%n | The package name without suffix. In the example above, it would be "Core".
%p | A fixed prefix. In the example above it would be "Jv".
%t | The type of package. Simply the character after the dash. "R" for run-time packages, "D" for design time packages.
%v | The target version. See below for more details
packages | The location of the packages. This is considered as a root, meaning that the Package XML source files will be searched in the xml subdirectory. The directories used to output the files for each target will have to exist in this pseudo root directory.
incfile | The name of the include file to parse. This only has an impact for C++ Builder targets.
NoLibSuffixFormat | Delphi and C++ Builder prior to version 6 do not support the LibSuffix concept. If you want to emulate it with your packages, you may want to use this attribute. If it is defined, its value will be used for all versions prior to 6. The same replacement rules applies to it. If it is not defined, it defaults to the value of the format attribute.
NoLibSuffixPrefix | As with format and NoLibSuffixFormat, If this attribute is defined it will be used with versions prior to 6. If it is not defined, the value of Prefix is used.
ClxFormat | In some instances, it may be interesting to have a different format string for the names of packages that are used when creating CLX applications. Define this attribute to use a different format when a CLX target is being used. Please see below for the definition of a CLX target. If this attribute is not defined, the value of Format will be used
ClxPrefix | As with Format and ClxFormat, you may want to have a different prefix for CLX targets (For instance, the JVCL uses 'JvQ' instead of 'Jv'). Define this attribute if you want to use that feature, its value being the one of Prefix if it is not defined.
targets | model | This node holds the target nodes, one node for each target your suite can support.
aliases | model | This node holds the alias nodes, one node for each target alias you want to provide. In the example above, using "Delphi" in a target node in a package XML source file is equivalent to using "d7,d7p". The aliases are not resolved recursively and are not case sensitive. You don't have to define the 'all' alias, as it will be derived from the list of targets.
ClxReplacements | model | This node, if it exists, holds the replacement nodes, one node per filename replacement. These replacements will only occur on the filename of the contained files for a package, and only when the target being generated is marked as CLX.
target | targets | Each target node must have at least the name attribute. All other attributes are optionnal:
name | The name of the target. Required.
dir | The directory where to generate the packages. Defaults to 'name'. It must exists in the packages directory before starting the generation of packages. If not, errors will occur and the error messages may not be self-explanatory.
pname | The name of the associated Personal target. A personal target is the target that will be used to force the generation of a different package for a version of the target that do not support some common features (database generally). Leave empty or do not define if there are no reason to use this feature. For instance, Delphi Personal Editions doesn't support databases. With the example above you could use the d7 target alone when specifying a file that is to be included for Delphi 7 and not Delphi 7 Personal Edition. Use 'd7,d7p' when including a file that is supported by all versions of Delphi 7.
pdir | The directory for the associated personal target. Defaults to pname
env | A character to identify the development environment. Defaults to the first character of 'name'. Expected values are "D" for Delphi, "C" for C++ Builder and "K" for Kylix. Any other value will most likely lead to errors while generating the packages.
ver | A character to identify the version of the environment. Defaults to the substring of digits starting from the second character of 'name'. That is, if the target is d7 or d7clx, then the default value will be 7. If you don't want this to happen, explicitly specify a value for this property.
defines | A comma separated string to indicate which Conditional Compilation symbols are defined as the result of using this target so that your include file can enclose some $DEFINE in $IFDEF that relate to the compiler being used. For instance, in the JVCL we have the JVCLThemesEnabled compilation directive. It can be turned on manually, but if the target compiler is version 7 or later, it is always turned on as the theme support is included in Delphi 7. Hence in the include file, we have this: ``
`{$IFDEF COMPILER7_UP} {$DEFINE JVCLThemesEnabled} {$ENDIF}`
`` Now, when a file is included with the JVCLThemesEnabled condition, it will only be included if the COMPILER7_UP condition is also available. But this is only the case when compiling because it is derived from the version number of the compiler. However, you can specifically indicate that a given target will define a condition using this attribute, hence mimicking what happens during compilation. Please refer to the Include File parsing section for more information on the handling of the include file.
PathSep | Indicates which character is to be used as a path separator for the target. If not specified, this value defaults to "\". You are most likely to setup this value for Linux targets, where it should be set to "/"
IsCLX | If set to 1 (True), this indicates that the target is a CLX target and the ClxPrefix and ClxFormat values will be used when generating the packages. See above for more details.
alias | aliases | Each alias node must have those two attributes:
name | The name of the alias.
value | A comma separated list of targets this alias will expand to. No recursion is done when resolving the aliases. If you defined any Personal targets, do not forget to include them in the value for your alias.
replacement | ClxReplacements | Each replacement node must have those two attributes:
original | The orignal string to be replaced.
replacement | The value to use as a replacement of the original string

## Template Files Format

The template files are either binary or text files. To determine if a file is binary, the first 50 bytes are read from it and if more than 10 percent of them are not ASCII readable characters, the file is considered to be binary. An ASCII readable character is one from the [#9, #10, #13, #32..#127] set (Delphi Notation). The results of this analysis are cached to ensure that this doesn't impact on the speed of generation.
If a template file is binary, then no special treatment is applied to it, it is simply copied over to the output file.
If a template file is text, then it is read line by line according to this state diagram:
In each state, special markers can be found on the line being read. Markers are case sensitive and unless indicated otherwise, can be found anywhere on the line and can appear more than once.

State | Marker | Description
Standard Line | <%%% START REQUIRES %%%> | Must be alone on the line. Goes to the 'Requires Section' state.
<%%% START FILES %%%> | Must be alone on the line. Goes to the 'Files Section' state.
<%%% START FORMS %%%> | Must be alone on the line. Goes to the 'Forms Section' state.
<%%% START LIBS %%%> | Must be alone on the line. Goes to the 'Libs Section' state.
%NAME% | Replaced by the name of the output file.
%XMLNAME% | Replaced by the name of the package XML source file.
%GUID% | Replaced by the value from the GUID node in the package XML source file.
%DESCRIPTION% | Replaced by the description of the package. If the target for which the generation occurs is marked as being CLX, the CLX description is used here.
%C5PFLAGS% | Replaced by the value from the c5pflags node in the package XML source file, after it has been processed for conditions.
%C6PFLAGS% | Replaced by the value from the c6pflags node in the package XML source file, after it has been processed for conditions.
%IMAGE_BASE% | Replaced by the value from the ImageBase node in the package XML source file.
%VERSION_MAJOR_NUMBER% | Replaced by the value from the VersionMajorNumber node in the package XML source file.
%VERSION_MINOR_NUMBER% | Replaced by the value from the VersionMinorNumber node in the package XML source file.
%RELEASE_NUMBER% | Replaced by the value from the ReleaseNumber node in the package XML source file.
%BUILD_NUMBER% | Replaced by the value from the BuildNumber node in the package XML source file.
%TYPE% | Replaced by 'DESIGN' or 'RUN' depending on the type of the package.
%type% | Replaced by 'd' or 'r' according to the type of the package.
%DATETIME% | Replaced by the current date and time adjusted to UTC, formatted according to the string 'dd-mm-yyyy hh:nn:ss' and followed by ' UTC'. You should only use this marker once in the entire template for the difference detection mechanism to work correctly. Please see the detailed description of the generation process for more details.
Requires section | %NAME% | The name of the package being required, taken from the package node in the package XML source file. As explained before, the name may be modified according to the format for the current model and the current target.
<%%% END REQUIRES %%%> | Must be alone on the line. Returns to the 'Standard Line' state.
Files section Forms section | %FILENAME% | The name of the source file as taken from the 'file' node in the package XML source file. If the target for which the generation occurs is marked as CLX, then the CLX replacements will occur on this value, as well as on all the others applicable in this state.
%UNITNAME% | The name of the source file without any path information and without the extension.
%Unitname% | Same as %UNITNAME% but the replacement is all in lower case except for the first letter which is converted to upper case.
%FORMNAME% | The name of the form, if any. Taken from the formname attribute of the 'file' node in the package XML source file.
%FORMTYPE% | The type of the form, if any.
%FORMNAMEANDTYPE% | The name and the type of the form put together. If no type was specified in the formname attribute, then this is equivalent to %FORMNAME%.
%FORMPATHNAME% | The name of the dfm file containing the definition of the form. No extension is added, it is simply the filename with the extension removed.
Files section | <%%% END FILES %%%> | Must be alone on the line. Returns to the 'Standard Line' state.
Forms section | <%%% END FORMS %%%> | Must be alone on the line. Returns to the 'Standard Line' state.
Libs section | %FILENAME% | The filename of the library file.
%UNITNAME% | The filename of the library file, without any path information or extension.
<%%% END LIBS %%%> | Must be alone on the line. Returns to the 'Standard Line' state.

Lines that result in a transition are not included in the output file. Any line read in the 'Standard Line' state is written in the output file after marker replacement has been done. Lines read in the 'Section' states will be repeated according to this table:

Repeating section | Description
Requires | The lines read while in this state will be replaced for every package required by the one being generated. That is, for every 'package' node found in the package XML source file. The markers will be replaced before output is written.
Libs | The lines read while in this state will be replaced for every library to be included in the package being generated. That is, for every name in the space delimited value of the 'C5Libs' or 'C6Libs' node in the package XML source file. The node used depends on the target for which the generation takes place. If the target environment is not C and/or its version is not 5 or 6, the generator will most likely trigger an Access Violation exception.
Files | The lines read while in this state will be replaced for every file to be included in the package being generated. That is, for every 'file' node found in the package XML source file. The markers will be replaced before output is written.
Forms | This section follows the same repeat conditions as the Files section, except that a 'file' node will only be used if its 'formname' attribute is not empty.

## Include File parsing

Delphi package files are source files and as such accept conditional compilation directives. These are used in the JVCL to include files depending on settings in the jvcl.inc file. These includes use of DxGettext, use of the GIF file format, use of the ThemeManager and many others.

C++ Builder package files, however, are XML files and do not support conditional compilation directives. The only way to reproduce the behaviour supported by Delphi is to regenerate the packages every time the include file is modified. This is because the package generator analyses the include file (if told to do so by the model) and outputs a conditioned line if the condition is defined in the include file.

Before the generation process takes place, the include file is parsed to determine which conditions are defined. A list of 'defines' is created from the file, and each 'define' has a list of 'ifdefs' associated with it. This list indicates which other conditions must or must not be defined for this one to be defined. Let's consider this simple file:

`{$DEFINE DIRECT_DEFINE} {$IFDEF TEST} {$DEFINE INSIDE_TEST} {$ELSE} {$DEFINE INSIDE_NOT_TEST} {$ENDIF} {$IFNDEF SOME_STUFF} {$DEFINE OTHER} {$ENDIF}`

After the file has been processed, the following will be true:

- DIRECT_DEFINE is defined
- INSIDE_TEST is defined if TEST is defined
- INSIDE_NOT_TEST is defined if TEST is not defined
- OTHER is defined if SOME_STUFF is not defined

When a node in the package XML source file indicates a condition, the list of 'defines' is read to determine if the node must be considered or not. If the target doesn't indicate any additional 'define' then only DIRECT_DEFINE and INSIDE_NOT_TEST are defined. But if the target indicates that TEST is defined, then only DIRECT_DEFINE and INSIDE_TEST are defined. The same goes for SOME_STUFF: If the target defines it then OTHER will be defined. When a 'define' depends on other 'defines' the list is read recursively but only up to the line where the define was found. This ensure a behaviour similar to what the compiler does. A define provided by a target is considered to exist even before the first line of the file.
There is no limit to the number of tests that can be done before the definition of a symbol (except for available memory) .

## Detailed Generation process

This detailed description will not be narrative, but rather algorithmic. You should not have to know any particular programming language to understand it, simple logic should be enough.
Read the xml configuration file
Load the model to use
Load the include file indicated by the model, if any.
For all asked targets do
For all 'template.*' files in the target's subdirectory of the packages root directory ('..\..\packages' in the example above)1. do
For all '*.xml' files in the 'xml' subdirectory of the packages root directory2. do
Determine the output filename by applying the format read in the model and using the extension of the template file3..
If the template is binary4. and is different5. from the exisiting output file then
Copy the binary file to the output file
else
Create an output file in memory
For every line in the template file do
If the line starts a 'Requires' section then
Read lines until the end marker is found
For all required packages do
Do the required replacements in the read lines
If there is no condition or the condition(s) evaluate to True then
Copy the modified lines read in the memory output file
else if the line starts a 'Files' section then
Read lines until the end marker is found
For all required packages do
Do the required replacements in the read lines
If there is no condition or the condition(s) evaluate to True then
Copy the modified lines read in the memory output file
else if the line starts a 'Forms' section then
Read lines until the end marker is found
For all required packages do
Do the required replacements in the read lines
If there is no condition or the condition(s) evaluate to True then
Copy the modified lines read in the memory output file
else if the line starts a 'Libs' section then
Read lines until the end marker is found
For all required packages do
Do the required replacements in the read lines
Copy the modified lines read in the memory output file
else
Do the appropriate replacements in the line
Copy the modified line in the memory output file
If the memory output file is different6. from the existing output file then
Write the memory output file into the output file on disk7.
If a difference was detected between the current target and the associated perso target8. then
If the perso directory contains a template named the same as the current template then
Use that template
Generate the output file for the perso target9.
Notes:
1. If the current target directory name is 'c6' then this means '..\..\packages\c6\template.*'
2. Using the example above, this would be '..\..\packages\xml\*.xml'
3. If 'template.bpk' was used with the example configuration file, a target called 'c6' and the file JvCore-R.xml, this would expand to JvCoreC6R.bpk
4. A file is said to be binary if more than 10% of its 50 first bytes are not in this ensemble (Delphi notation): [#9, #13, #10, #32..#127]. The results of that test are cached to increase the speed of the generation process.
5. The difference is determined by performing a byte per byte comparison.
6. The difference is determined by doing a line by line comparison. The last %DATETIME% marker in the file will be ignored, thus allowing a file that is only different by the date time tag to be treated as unmodified.
7. If no file was found to be included in the generated package for the current target, no file will be written. Please note that if the package only requires other packages but doesn't contain any file, it won't be output as a package is only meaningful if it contains files.
8. This is determined while processing 'package' and 'file' nodes. If a file or package is used by a target and not by its associated personal target (or vice-versa), then the two 'flavors' of the package being generated are different.
9. The output file will be placed in the directory set for the personal target. This is done by repeating all steps from the line where note 4 is. As the target name is a personal target, it has no associated personal target and the test for a difference between 'flavours' is unnecessary.

## Conditions parsing

A simple parser is used to read the conditions applied to the various items of the package XML source files. Here are its specifications:
Syntax:

<b-exp> | ::= <b-term> ( [ "|" | "||" | "^" ] <b-term> )*
<b-term> | ::= <b-notfactor> ( [ "&" | "&&" ] <b-notfactor> )*
<b-notfactor> | ::= <b-factor> | "!" <b-factor>
<b-factor> | ::= "(" <b-exp> ")" | <ident>

Symbols:

! | not
&, && | and
|, || | or
^ | xor

Examples:

`!A && (B || C) || (D && E) && F || G || H QREPORT4 & JvclUseQuickReport`

## Command line reference

pg.exe is the command line version of the package generator. It has been designed to be used from batch files and the JVLC installer. Here are the options it accepts:

-h | Displays a help message, reminder of the available options, then exits.
-m=MODEL | Indicates the model to use. The model must exist in the configuration file. Defaults to 'JVCL'.
-x=CONFIGFILE | Indicates the location of the xml configuration file. Defaults to 'pg.xml'. If 'pg.xml' does not exists, defaults to 'pgEdit.xml'. This has been done to allow for the usage of one xml file shared by both pg.exe and pgedit.exe.
-t=TARGETS | Indicates the targets to build as a list of comma separated target names. You should not indicate any personal targets here. Defaults to 'all'.
-p=PATH | Indicates the root path for the packages. Defaults to the value defined in the model to use.
-r=PREFIX | Indicates the prefix for the packages. Defaults to the value defined in the model to use.
-f=FORMAT | Indicates the format of the name of packages. Defaults to the value defined in the model to use.
-i=INCLUDEFILE | Indicates the name of the include file to parse. Defaults to the value defined in the model to use.

## Notes to developers

Even if the package generator is considered to be fairly complete at the time of writing, it may need some further refinements. If you want to suggest an improvement and provide the code for it, please be sure to have read this documentation entirely and to keep in mind that the package generator must be generic so that it can be used by other groups. If you want to fix a bug that occurs with the JVCL, please think about a generic way to fix it, rather than hard-coding strings.

In any case, please feel free to contact the JVCL team.