Using glastpack for Code Development

Preliminaries
Creating a development area
Getting ready to use an area
Using an area
glastpack and gdb
Obscure but useful gdb commands
Tools for shareables

Preliminaries

Need to be able to find glastpack. If you're using a SLAC public Linux machine it's at /afs/slac.stanford.edu/g/glast/ground/scripts/glastpack.pl so, e.g., run the group cshrc which

Otherwise, you'll need to pick up your own copy of glastpack.pl and put it in a directory included in your PATH. One way or another you'll have to also get CVS, CMT and external libraries properly set up.

Creating a development area

Make the playpen
bash$ cd /somewhere/writable
bash$ glastpack.pl create myDir
What this does for you is to make a file called CMTPATH in this directory. This way you can switch from one working area to another, using the glastpack.pl login and glastpack.pl logout commands to point to the correct one of these files at any given time.
Start using it
bash$ cd myDir; glastpack.pl login
(In more detail, glastpack.pl makes a soft link in your home directory, .cmtrc, to the correct CMTPATH file.)
Modify CMTPATH if necessary (otherwise only thing in CMTPATH will be the new playpen).
bash$ glastpack.pl add /path/to/somewhere
bash$ glastpack.pl remove /path/unwanted
Check out a package and everything it depends on
bash$ glastpack.pl rco topPackage version
For development one may specify HEAD for the version. As always, the latest matching tagged version of subsidiary packages will be checked. If any of these packages are also to be developed, you'll want the HEAD. You can get it by issuing the right type of cvs update, one that says to forget about sticky tags:
bash$ cd devPack/version
bash$ cvs update -A
Stop using an area
bash$ glastpack.pl logout

Caution

The logout command breaks the connection between .cmtrc in your home directory and the CMTPATH for the area. By default CMT uses .cmtrc in your home directory, if there is one, for the CMTPATH definition. If you don't issue a logout, future CMT commands will continue to use the area's CMTPATH, even if you logged off the computer and then logged back in.

Getting ready to use a previously-created area

Typically you only need to go through the above steps once for each tree of packages you want to work with. (One exception is the cvs update command to replace a tagged version of a package with the HEAD, something you might want to do at any time.) If you have already gone through the above steps in some previous login (i.e., computer login), all you need to do to pick up in a new session is issue the glastpack login again:

bash$ cd /somewhere/writable/myDir; glastpack.pl login

Using the area

Typical things to do will be to build a package (and packages it depends on if binaries are out of date) or run a test program

Building
bash$ glastpack.pl build aPackage dirTagVersion
Here dirTagVersion is the string appearing as part of the path to the package. For tagged packages this string will just be the tag. A package in development (HEAD version) still will have some tag-like string as part of its path; this is what you use. For example,
bash$ glastpack.pl build detModel v2r12
Running a program
bash$ glastpack.pl run packageName app
bash$ glastpack.pl run detModel test.exe

glastpack and gdb

Normally glastpack defines necessary environment variables only when you issue a command such as glastpack.pl build.. or glastpack.pl run... and only within the context of that command. As of August, 2002, there is no glastpack command to start up the debugger; at best such a thing would be awkward to use. Instead, one can start up the debugger as usual as long as necessary environment variables, including LD_LIBRARY_PATH, are defined. Just go to the cmt directory of the top package (e.g., Gleam) and, preferably from a bash shell, issue the setup command:

  bash$ source setup.sh

Now your process has all the requisite definitions. Child processes will inherit them, as long as you don't reset anything (LD_LIBRARY_PATH is the most likely and most harmful to reset) in your .cshrc or .bashrc. This is crucial since gdb started from your terminal session (or gdb started from emacs started from your terminal session) is a child process. I haven't tried it, but it should also be possible to start up ddd this way.

Obscure but useful gdb commands

A few gdb commands which I've never had occasion to use before can come in very handy when debugging a large complicated application with dynamically-loaded libraries like Gleam.

control-C control-C
This sequence issues SIGINT. Since our applications don't handle SIGINT, the default action is for the debugger handle it by stopping execution and bringing up the (gdb) prompt. You can then examine variables, set breakpoints, etc. This can be useful if you want to break in to set a breakpoint while the application is waiting for interactive input (e.g., request for next event) or if application execution seems to be going wild.
info sharedlibrary
shows you which shared libraries have been loaded. You can't set a breakpoint in a shared library until it's been loaded. (But gdb does keep track if you rerun the program. It will complain when you first restart the program that breakpoints in dynamically-loaded shareables can't be enabled, but will automatically reactivate them when the shareable is again loaded.)
directory path-specification
This command adds a new directory to the list which will be searched for source code. By default this list includes only the current directory and the path of the source when it was compiled. Usually this is good enough, but not if object files or the source they were compiled from has moved.

(We have long since moved past Gaudi9, but the following still provides a model for what to do if gdb can't find the source.)

The pre-compiled version of Gaudi9 available to public Linux machines at SLAC had this category. In order to help gdb find the source for GaudiKernel of Gaudi9, for example, you can issue the following (as of August, 2002, for GaudiSys_v9r0p6).

(gdb) directory /afs/slac/g/glast/ground/releases/GaudiSys_v9r0p6/GaudiKernel/v11r0p2/src/Lib

For some unknown reason in this context gdb would not translate an environment variable; I could only make this work by typing out the full absolute path.

To see what the current search path is, use the command show directories.

The commands necessary to get to the source for Gaudi9 GaudiKernel and GaudiSvc packages can be found in ~jrb/util/gaudi9src.gdb. To run these commands from inside gdb (on SLAC Linux), type

(gdb) source ~jrb/util/gaudi9src.gdb

print var-name.method(..)
If name is a std::string gdb won't let you just print it. Here is what happens:
(gdb) print name
$1 {static npos = Cannot access memory at address 0x0
However you can examine non-static fields or call non-static methods:
(gdb) print name.c_str()
$2 = 0x83b4fc8 "EventCnvSvc"

Tools for shareables

When you ask Gaudi to load a component library (via the appropriate job option line), down in the bowels of the code (in System.cpp) it calls ::dlopen. This was failing for a first version of libCalibSvc.so, which ::dlopen indicates by returning null. ::dlerror() returns a text string describing the last error, but the Gaudi code doesn't call it immediately; it tries some other things first. However, within the debugger I was able to call it immediately after the failed ::dlopen:

(gdb) call ::dlerror() $43 = 0x8349850 "/a/surrey10/g.glast_users/glground/jrb/Calib/CalibSvc/v0r0/Linux-i686/libCalibSvc.so: undefined symbol: __ti16ICalibMetaCnvSvc"

This indicated there was something wrong with the way the library had been built so that symbols for the ICalibMetaCnvSvc were not all getting resolved properly. That was confirmed by using the unix command nm with appropriate options (see output from the command info nm to learn about them)

bash-2.05$ nm -g libCalibSvc.so | grep ICalib
00034dc0 W __12ICalibXmlSvci
00033e38 W __16ICalibMetaCnvSvci
00034d60 W __tf12ICalibXmlSvc
         U __tf16ICalibMetaCnvSvc
000440b4 B __ti12ICalibXmlSvc
         U __ti16ICalibMetaCnvSvc
0003a0dc V __vt_12ICalibXmlSvc
0003a0e8 V __vt_12ICalibXmlSvc.10IInterface
00039600 D __vt_14CalibXmlCnvSvc.12ICalibXmlSvc
00039460 D __vt_16CalibMySQLCnvSvc.16ICalibMetaCnvSvc
         U __vt_16ICalibMetaCnvSvc
         U __vt_16ICalibMetaCnvSvc.10IInterface


bash-2.05$ nm -g -C libCalibSvc.so | grep ICalib
00034dc0 W ICalibXmlSvc::ICalibXmlSvc(int)
00033e38 W ICalibMetaCnvSvc::ICalibMetaCnvSvc(int)
00034d60 W ICalibXmlSvc type_info function
         U ICalibMetaCnvSvc type_info function
000440b4 B ICalibXmlSvc type_info node
         U ICalibMetaCnvSvc type_info node
0003a0dc V ICalibXmlSvc virtual table
0003a0e8 V ICalibXmlSvc::IInterface virtual table
00039600 D CalibXmlCnvSvc::ICalibXmlSvc virtual table
00039460 D CalibMySQLCnvSvc::ICalibMetaCnvSvc virtual table
         U ICalibMetaCnvSvc virtual table
         U ICalibMetaCnvSvc::IInterface virtual table

Note that there are undefined symbols for ICalibMetaCnvSvc but not for the analogous ICalibXmlSvc. After perusing all relevant files (more than once) I discovered I had forgotten to declare one of the functions in ICalibMetaCnvSvc as pure virtual. After fixing this and rebuilding, nm gave the following:

bash-2.05$ nm -g -C libCalibSvc.so | grep ICalib
00034ef0 W ICalibXmlSvc::ICalibXmlSvc(int)
00033f70 W ICalibMetaCnvSvc::ICalibMetaCnvSvc(int)
00034e90 W ICalibXmlSvc type_info function
00033f10 W ICalibMetaCnvSvc type_info function
00044264 B ICalibXmlSvc type_info node
000441e0 B ICalibMetaCnvSvc type_info node
0003a248 V ICalibXmlSvc virtual table
0003a254 V ICalibXmlSvc::IInterface virtual table
00039740 D CalibXmlCnvSvc::ICalibXmlSvc virtual table
000395a0 D CalibMySQLCnvSvc::ICalibMetaCnvSvc virtual table
0003a1d4 V ICalibMetaCnvSvc virtual table
0003a1ec V ICalibMetaCnvSvc::IInterface virtual table

However, when I tried to run the newly-built test program, the ::dlopen still failed, this time complaining

(gdb) call ::dlerror() $5 = 0x8347a00 "/a/surrey10/g.glast_users/glground/jrb/Calib/CalibSvc/v0r0/Linux-i686/libCalibSvc.so: undefined symbol: updateObj__10XmlBaseCnvP14IOpaqueAddressRP10DataObject"

Back to the drawing board!

See also a guide to debugging on Linux.


Created: 14 June 2002  J. Bogart
Last modified: