Workbook for BaBar Offline Users - Compile, Link and Run
Note: To follow this WorkBook page, you will need to have
completed the Workbook section on Editing to create the PExample
files needed. It is worth working through both of these sections
carefully as they provide an excellent introduction to BaBar analysis
code.
Also, before running, remember to do (from the release directory,
ana30):
srtpath <enter> <enter>
cond18boot
Writing code in a unix environment involves the use of several
tools. The two main tools are the compiler and
linker. To see the results of the minor changes you have made
will involve first compiling your new code, linking it, and then
running the new executable.
A very important part of compiling and linking is patience - you
must check the output from each stage to make sure there are no
errors or other messages that hint at problems and often have to go
back several times, clean up, recompile, relink, make sure you're on
the correct machine, start again....
An executable is built from the code defined in multiple files. When
changes are made in one or more of these files the code in the
modified files and all dependent files will need to be
re-compiled and re-linked. Compile and link commands often involve
many options, such as directory search paths for included files, names
for compiled files, warning messages, debugging information and so
forth. Compile and link commands quickly become quite lengthy, and in
large software projects the dependencies amongst files is usually
rather involved. A utility called gmake, is used to
manage the complicated and tedious nature of this process.
GNUmakefiles
The gmake utility uses a programmer written file, called
the GNUmakefile to define a set of instructions for how
to compile and assemble the code segments into the executable. The
file also defines many variables such as search paths, which compiler
to use, etc. The instructions specify the dependencies of the code
segments so that the gmake utility can recognize only
those components that need to be reprocessed. A well written makefile
can reduce unnecessary compilation and save much time.
The gmake facility looks in the current directory for a file named
GNUmakefile, makefile, or
Makefile (in that order). The first one of these files
found is used to define the dependency/build rules for the given
target.
Targets, Dependencies, and Build Rules
The general structure of an instruction in the GNUmakefile consists of
a target, a dependency, and a rule. The
target is in the name for that particular instruction. You execute the
rules associated with a particular target by issuing the command:
> gmake <target_name>
This is referred to as "making" the target. Associated with
each target is a set of dependent files. When any of the
dependent files have been modified or if the target file
does not exist, the target will be rebuilt (or built)
in accordance with the rule. For example, a line in a
GNUmakefile might be:
foo.o : foo.cc foo.hh bar.hh
g++ -c foo.cc
The target is foo.o, the dependent files are foo.cc, foo.hh, and bar.hh,
and the rule is "g++ -c foo.cc". If any of foo.cc, foo.hh or bar.hh have
been modified, or if the foo.o does not yet exist, issuing
gmake foo.o will result in the recompilation of foo.cc in
accordance with the rule.
The default target is the first target
listed in the GNUmakefile. It is the rule that will be executed when gmake
is invoked without an argument.
Sometimes targets are used to perform tasks not related to compiling
and linking code. If you define a target for which there is no file of
the same name, and the rule commands do not create the target file,
then a file of the target name will not exist in the
directory. Because the target does not have a corresponding file it is
always considered out of date; the rules will be executed every time
the target is made. These targets are referred to as phony
targets. Phony targets do not usually have dependent files.
A GNUmakefile is part of any release, including the test release you
created. GNUmakefiles are also included in any package that you check
out. The GNUmakefile of the release is the master makefile. This is
why you issue gmake commands from the release
directory. Commands issued from a subdirectory of a release will only
have access to targets defined in the subdirectory's GNUmakefile (assuming
there is one). The master makefile defines the target all that
you made in the Quicktour analysis.
For general use of BaBar software, you will use gmake commands
often, but you will probably not need to write or modify a GNUmakefile.
Even users writing new analysis modules rarely need to make significant
modifications to a GNUmakefile.
Related documents:
-
HOWTO-GNUmakefile - specific information about the BaBar
GNUmakefile from the SoftRelTools package
- GNU
make manual - describes gmake and all of its subtleties in
detail.
- If you are interested you can browse the
GNUmakefile that came with your test release.
gmake relies on time stamps to determine what needs to be
redone. The Makefile (or GNUmakefile) for a given package knows about
the dependences between all the files. If a given file is being
compiled with a gmake command, any files that it depends upon and that
are newer than it will also be compiled. Therefore, if file
X is newer than file Y, but Y
depends on X, recompiling Y will
force a recompilation of X, and any other files that
might have been edited since Y was last touched.
As such, to force a file to be recompiled, you may need to
manually "touch" one of the relevant files. An example of
such a command is:
touch BetaMiniUser/AppUserBuildBase.cc
which will force AppUserBuildBase.cc to be recompiled. In this
case, this will cause almost the entire package to recompile as
almost all the other files in the package depend on AppUserBuildBase.cc.
In BaBar software each package includes a link_PACKAGE.mk file in
addition to the GNUmakefile. The link file is used by the
GNUmakefile. The use of this file is mainly for overriding previous
definitions of linking rules defined by the test release's
GNUmakefile. This overriding mostly serves to append the new package
directory to the linking list. More information on this can be found
in the HOWTO package in
HOWTO-dependency.
The all target
In the Quicktour, you used the
command "gmake all" to compile and link your code. The all target
is a "smart" target that makes all of the targets you need (and some that
you may not need) in the correct order. The targets made by gmake all are:
- installdirs - Creates the required architecture-specific
directories (for example, lib/$BFARCH and bin/$BFARCH).
- database.import - A database command. Creates a local copy of a
database and its bootfile. (But it will not work unless you have made your
.bbobjy file.)
- schema - A database command. Sets up class definitions for a
database.
- include - Makes any needed include files.
- lib - Compiles the code.
- bin - Links the code.
- javalinks - Support for java.
- python - Support for python.
Some of these targets are needed for a sucessful compile and link.
"gmake include" takes care of dependencies. "gmake lib" compiles the
code, and "gmake bin" links it. And the first command, "gmake installdirs",
creates the $BFARCH directories needed to store the files created by the
include, lib and bin targets.
On the other hand, as mentioned in the
Quicktour,
many of these targets are not needed for your simple BetaMiniUser job.
For example, the database commands are needed only if you are planning
to set up your own federated database, which is unlikely unless you are
an advanced user running simulation software. Also, the javalinks and
python targets are not really needed here. They are included in gmake all
to ensure that the targets are made in the right order for users who
do need them.
The installdirs target
Different machine architectures have different compiled formats. To
keep object files of different architecture formats separate the
lib and bin directories have a subdirectory for each architecture
that you compile code on.
The command that makes these subdirectories is gmake installdirs.
A new test release comes with lib, bin, tmp and test directories, but they
are all empty. The command gmake installdirs creates a subdirectory called
$BFARCH in each one of these subdirectories. Here $BFARCH is the
architecture that you chose when you entered the srtpath command; for
example, Linux24SL3_i386_gcc323.
The include target
The include target creates any include files needed.
The lib target
The command to compile your code is gmake lib.
When you compile your C++ code a preprocessor is run first. As
discussed in editing code, the
preprocessor does such things as prepend header files and execute
macro definitions. In addition, the dependencies among the files are
recorded in files with the same root as the source file and a '.d'
suffix. In BaBar software these files are stored in the
tmp directory of your release.
After precompilation regular compilation takes place. This converts
the file into a re-locatable, architecture-dependent version of the
source code. The result of this step is called an object. The object
files also have the same root name as the source file with a '.o'
suffix. Object files are also stored in the tmp directory
of your test release.
These object files are swept into archive libraries. Libraries are
stored in the lib directory of your release and have a '.a' suffix.
Like the lib and bin directories, the tmp directory has a subdirectory
for each architecture that you compile code on.
The bin Target
This command makes all of the bin targets in all of the packages in your
test release. The new executables are located in your bin/$BFARCH directory.
Once object modules have been created they need to be linked together
to build the executable. The command to link your code is gmake bin.
This command makes all of the bin targets in all of the packages in your
test release. The new executables are located in your bin/$BFARCH directory.
If you list this directory, you will see a '*' after the names of most of
the files, indicating that they are executables.
For the BetaMiniUser package the executable is named BetaMiniApp.
This is the only one that you actually need.
Starting clean: the clean target
In a moment you will use the gmake all command to recompile and relink
your code to incorporate your new PExample. But first, you will enter
the gmake clean command.
When issued from your test release directory,
gmake clean will delete the files in the
directories: bin, lib, tmp, test, and results for all
architectures. This removes all object files, libraries, and the
executable from your release so that you may restart the compilation
and building process of the executable from a "clean" state.
If do a "gmake clean", then you will have to reenter all
of your gmake commands before your code will work again. In this
case, this means that you will have to reenter your gmake all command,
as you will see below.
(On the other hand, gmake clean usually does not undo your gmake
workdir.setup command, unless you accidentally issue gmake clean
from workdir. If so, just go to your test release directory and
reenter "gmake workdir.setup", and that should fix it.)
Another related useful target is cleanarch. The command gmake cleanarch
command removes only library, binary and temporary files saved under
the current architecture (i.e. the architecture set when you most
recently issued an srtpath command in the current session).
But it leaves the libraries and/or binaries for built with other architectures
intact.
Example: Compile and link your new code
Now it is time to recompile and relink the code to incorporate
the new PExample module and modification to AppUserBuildBase.cc into the
executable. From your test release issue
ana30> gmake clean
ana30> rm all.log
ana30> bsub -q bldrecoq -o all.log gmake all ROPT=-noOptimize-Debug
Note: you should use the bldrecoq queue only for building libraries
and executables, not for running analysis jobs.
You can see the output in all.log. Check
your own output to make sure there are no error messages which must be
fixed. When you look at your log file, note that the arrows "->" indicate
which gmake command it is working on. So if your job crashes, you know which
gmake command was running when it failed.
You may have noticed that the above command is a little
different from the one you used in the Quicktour. In the
Quicktour you typed:
ana30> bsub -q bldrecoq -o all.log gmake all
without the "ROPT=-noOptimize-Debug". The default settings for the compiler
and linker for this release are to retain symbols for debugging but
also to optimize the code for fastest execution. In the next part of the
Workbook, you will be using the debugger for your own code. This is most
easily done if our code is not optimized, so that all variables
are available in the debug session. The rest of the code in the release
(ie, the packages that you did not check out)
has already been compiled optimized, but presumably you will not be
debugging the production code.
It is important to issue this command from the test release directory
because that's where the GNUmakefile that defines the lib target
resides. Check the output to verify that your code has compiled
before going to the next step (linking).
You may not have a successful compilation the first time. There are
many common error messages that you will inevitably need to become
familiar with.
Typical compile errors:
- Errors with incorrect use of gmake.
- Failure to find header file during precompilation,
- Errors caused by lack of forward declaration/include statement in header/implementation file.
- Reading between the lines: the line that the compiler says contains the
error is often not the line where the actual mistake is.
- Declarations of variables: multiple and lack of.
- Loops within loops within loops. How to check those close
brackets - e.g. smart editors like emacs.
- Cascading errors: often, later errors are caused by earlier ones.
Don't try to 'correct' everything before recompiling.
Typical linking problems:
The linker message "No rule to make target libPACKAGE.a"
Failure due to undefined/unresolved symbols
Got enough disk space for your executable?!
Often an error is due to a typo, or missing closed brace
etc. Any errors will need to be interpreted, fixed in the source
file, and then re-compiled. This is an iterative process until
the compilation is successful.
A Shortcut: Compiling or linking only one package
So far, you have always used the command "gmake all" to compile
and link your code. But if all you want to do is make the
BetaMiniApp executable, then you need only some of the gmake commands
invoked by "gmake all":
gmake lib
gmake BetaMiniUser.bin
Or you could put them together to make a single command:
bsub -q bldrecoq -o mylog.log gmake lib BetaMiniUser.bin
You will notice that the link command, gmake BetaMiniUser.bin,
is a bit different from the gmake bin command that you used before.
In general, commands of the form "gmake package.target" perform
the task "gmake target" on the files in "package" only.
The command "gmake BetaMiniUser.bin" to links only the code in
BetaMiniUser. This is useful if you have a lot of packages
checked out, because
instead of making BetaMiniApp plus executables you don't need from
the other packages, you make only BetaMiniApp.
Let's look at another example. Assume that you have checked out:
BetaMiniUser
KanEvent
RecoDataK
and have made substantial changes to files in BetaMiniUser and a few in
at least one of the other two packages. Assume also, that there are
two binaries (i.e. executable files) that can possibly be built in the
BetaMiniUser package, FirstApp and SecondApp, and that it takes a long time
to compile the binaries. In the case that you care only about the
SecondApp executable, a common series of commands would be:
gmake clean //remove pre-editing libraries and other temporary files
gmake lib //rebuild the libraries for all the packages
gmake BetaMiniUser.SecondApp //build only the SecondApp executable
The gmake clean command removes the library and binary files and other
auxilliary and machine-generated files that existed before the package was
edited to avoid possible conflicts. The gmake lib command need remakes all
the needed library files. Then gmake BetaMiniUser.SecondApp builds
the SecondApp executable.
Using only the gmake commands that you need can save you
some compile time, and avoids the creation of lots of unnecessary
files. A word of caution, however: if you are going to skip parts of
gmake all, make sure that you know what you are doing. If your
job keeps crashing, try gmake all instead.
The gmake command comes with a number of useful options.
The command "gmake -n TARGET" doesn't actually run commands, it
just prints them. For example, if you enter the command
"gmake -n lib" from your ana30 directory, then you will get the
following output:
GNU Make version 3.79.1,
Build OPTIONS = Linux24SL3_i386_gcc323-Debug-native-Objy-Optimize-Fastbuild-
Ldlink2-SkipSlaclog-Static-Lstatic
Linux yakut02 2.4.21-37.0.1.ELsmp #1 SMP Thu Jan 19 17:17:30 CST 2006 i686
athlon i386 GNU/Linux [uname -a]
echo "-> lib";
for package in xx BetaMiniUser KanModules database workdir; do if [ "$package"
!= "xx" -a "$package" != "BASE" ]; then gmake $package.lib NOPKG=yes; fi; done
If you can understand it, this message gives you an idea of
what the gmake lib command would do if you entered
it without the "-n" switch. However, if you check in your
lib directory:
ana30> ls -l lib/$BFARCH
you will not find any new lib files; only old lib files
(if you have compiled before) or none at all.
Another useful gmake command is "gmake -k TARGET". This
command tells gmake to keep going even when some targets
can't be made.
To see a full list of options and a description of each one,
enter "gmake --help" at the command line.
The PExample module code is compiled because it is located in the
BetaMiniUser directory. It is linked into the executable because the
AppUserBuildBase.cc file loads it into the framework. The final step is to
include your newly-created module in your analysis application.
As discussed in the Beta section,
the BetaMiniApp executable needs to be run from the workdir directory.
Depending on the input data source, a tcl script is passed to the
executable as an argument. The job is passed from tcl file to tcl
file (via the "sourceFoundFile" command) until it is finished.
In the Quicktour, the snippet.tcl script was passed to BetaMiniApp
as an argument. The snippet file performed some initiial setup,
and then passed the job to MyMiniAnalysis.tcl, which did some more setup
and added some modules to the framework's path ("Everything").
Then MyMiniAnalysis.tcl passed the job to btaMini.tcl,
the main tcl file used to access the Mini database.
Now that you have created a new module class and
compiled and linked the code, you will need to include
the PExample module in your analysis path.
In the Quicktour analysis the file snippet.tcl is
passed to the analysis executable. This file sources (or rather,
"sourceFoundFile"s) a secondary tcl file called MyMiniAnalysis.tcl.
It is in MyMiniAnalysis.tcl that your user-specific analysis path
is defined. This is the file that should be modified to append
PExample to the path instead of NTrkExample. This is a very simple
edit, and because it is a tcl file and not C++ code, it is independent
of compiling and linking your code.
A working example of a MyMiniAnalysis.tcl script that places the PExample
module in the execution path is in the WorkBook's NewExamples/PExample
directory.
The command
ana30/workdir> BetaMiniApp snippet.tcl
will run the executable BetaMiniApp.
Now you will need to input collection(s) to KanEventInput,
and start the job, as in the Quicktour:
> mod talk KanEventInput
KanEventInput> input add /store/SP/R18/001237/200309/18.6.0b/SP_001237_013238
KanEventInput> exit
> ev beg -nev 40
> exit
When your job is done, go into ROOT and load the .root file as before.
You should now see a directory for your new module:
TFile** myHistogram.root Created for you by RooTupleManager
TFile* myHistogram.root Created for you by RooTupleManager
KEY: TH1F h1d1;1 MC reco abs mtm difference
KEY: TH1F h1d2;1 Reco track momentum
KEY: TH1F h1d3;1 Tracks per Event
KEY: TH1F h1d4;1 Momentum
KEY: TH1F h1d5;1 TagInspector Status
In addition to the histogram for tracks/event there is now a momentum
histogram. Go ahead and plot it with the commands:
root[] h1d4->Draw():
It should look like this:
You might wonder whether or not the axes are ideal. In our example
code the histogram axes are hard-coded. To change them would involve
editing the code, recompiling, relinking, re-running, and
re-analyzing. Basically you would need to do everything over.
That is very time-consuming. Fortunately there is code available to
make some parameters more dynamic and flexible than this. Instead of
redoing everything we will discuss how to modify the PExample class
to make certain parameters (of the histogram for example) changeable
during the analysis process in the
Framework Continued chapter.
Runtime gotchas:
Just because your code compiled and linked doesn't mean that
everything will work as planned. For example, memory misuse
errors may allow your code to compile and link sucessfully,
but will cause problems at runtime.
Segmentation violations - accessing a null pointer?
Bus Errors - has the size of an object changed?
Something strange to do with memory allocation(especially on Sun)
- remake from cold.
Further investigation/understanding of the problem - see the
chapter on Debugging Code
Non-existent binaries
Missing binaries can catch you out in two ways:
- if your gmake bin command fails due to some
compile-time error, the binary won't be made
- if you put your release in your scratch area (as in the Quicktour),
and you haven't used your binary for some time (approximately a
week), it will be deleted, as the scratch disk cleans out unused files
There are two ways in which a missing binary will manifest itself:
- The binary will simply not be found when you try to execute it
- A binary in the BaBar compiled code (in workdir/PARENT) will run,
and none of your changes will be in it
In the second case, what happens is that the system searches for an
executable in your bin/$BFARCH/ directory, and when it doesn't find
one, it looks in the original analysis-30 release, finds the
central, pre-compiled binary, and uses that one instead.
This problem can be very difficult to spot - the code
appears to run just fine, but none of your changes are in the output
files!
In either case, the way to check things is to look at output from
the compile and link stages and, particularly if it is just the case
that you haven't tried to run your binary for some time, check the
directories:
ls -l ana30/lib/$BFARCH/
ls -l ana30/bin/$BFARCH/
(There is also a link, "bin", in your workdir to ana30/bin.)
If this directory does not contain the binary you wanted to run, then
the binary hasn't been built, or has got old and been deleted.
Mainly just to make the user aware of the fact that compiler and
runtime behaviour is platform-dependent. Important example:
incremental linking on Sun. Also, note that the same code that
compiles or links on one platform may not do so on another.
General Related Documents:
Author:
Tracey Marsh
Contributors: James Weatherall,
Joseph Perl,
Leon Rochester,
Jenny Williams,
Last modification: 3 March 2006
Last significant update: 14 September 2005
|