This section explains how one can modify a single package or a hierarchy of packages nested inside one package. The approach described here is practical if the package in question builds shared libraries or executables, or if all the packages of interest are contained in one single tree. A package or a hiearchy of packages that produce only archive libraries should not be built this way unless the purpose is only to test the packages; one should build at least one application that uses the libraries. For a hierarchy of packages, the entire tree need not be checked out; one can check out only portions of it. An explanation of how this can be done can be found in Section 11.3, ``Extracting Partial Hierarchies From CVS''.
It is also assumed that the package has a configure script as recommended in Section 10.5, ``Writing The Configuration Script''. If that is not the case, or some other requirement stated above does not hold, the procedure explained in Section 8.2, ``Using A Working Release'' describes a slightly more general approach that lifts these restrictions.
First you need to determine which release and hence which package versions you want to work with. The subdirectories of $SRT_DIST are the available release candidates. You may also choose a symbolic link such as current or production in that directory if it points to a real release.
You then need to decide which version of the package you wish to modify. If you intend to commit your changes back to the repository, and hence become one of the package developers, you will most likely want to take the head version from the mainline. On the other hand, if that is not your purpose, you will most likely want to take some of the previously tagged versions. Unless you have a very strong reason not to, you should probably start from the same version that was used in the base release. In this case, you can just use the tag for the base release, such as offline-00-00-04.
If you wish to get a version other than the head or an official release, you need to know the name of the tag. You can learn this by contacting the package author, or you can get the list of available tags by using the CVS commands. For example, you can go to the package directory in the base release and issue the following command:
$ cvs status -v PACKAGE |
![]() | If you choose a version other than the one used in the base release, you take a risk. For instance, if you take the head version, there may be changes that cause binary incompatibilities even if the code compiles without errors and warnings. These may manifest as fatal errors the minute you run an application, but more commonly appear as seemingly valid but in reality incorrect results or as random crashes. Sometimes the differences can be very subtle and exceedingly difficult to debug. |
Once you have decided which package and version to go with, go to some working directory of yours and issue the following command:
$ cvs checkout -d package -r tag path-to-package |
Here, package is the name of the package without the directories that lead to it, tag is the version you chose, and path-to-package is the full path to the package inside the CVS repository. For instance, if the full package path was offline/Simulation/TruthEvent and you wanted the version offline-00-00-04, you would issue the following command:
$ cvs checkout -d TruthEvent -r offline-00-00-04 offline/Simulation/TruthEvent |
You need to tell the release tools about your base release choice. Do so by going to the directory created by the CVS checkout command in the previous step and by using the base tool. For instance, if we continue the example from the previous step, you would type the following commands:
$ cd TruthEvent $ srt base 0.0.4 |
The next step is to configure the package. Not surprisingly, this is done by running a script called configure. The purpose of this step is to adapt the package to the compilation environment, such as which packages you have checked out and which ones will be looked up in the base release. It may also determine operating system and compiler characteristics. The script will execute without asking any questions and will print out diagnostics about what it is doing and what guesses it makes. Continuing our example again, you would type:
$ ./configure |
If the configure script fails you should correct the error causes before proceeding. One possible error is that you forgot to set your environment properly, in which case you should follow the instructions in Chapter 7, ``Getting Started''. If configure prints out warnings, you should make sure you understand the cause for the warnings and deem them fine before proceeding.
![]() | Here we assume the simplest possible way of building the package. If you are interested in building the package on multiple targets simultanously, please refer to Section 8.3, ``Three Ways of Building Packages''. |
![]() | If the package has no configure script you have been following the wrong instructions. Please refer to Section 8.2, ``Using A Working Release'' for instructions that work for packages that do not have configure scripts themselves. |
If the configuration script finishes successfully, you are ready to build the package. You can do so by simply running make (but note Section 7.2, ``Using The Right Make Program''):
$ make |
If you did not encounter any errors, the products of the package should now have been built. If the build did fail, you might want to contact the package author or the software librarian to understand the reasons, or if you are willing to dive into the details, figure it out yourself and inform the package developers about your discoveries. If nothing at all happened, make sure the package did not disable itself automatically.
If you want to reduce the amount of output produced by the make command, refer to Section 13.1, ``Reducing Make Output''.
If the package you are working with produces a program you wish to run, it should now exist. For instance, if the package produces an application called program in the current directory, you would type the following:
$ ./program |
When shared libraries are involved, things get a little bit more complicated. This is because the release tools build the applications such that they will run correctly when the libraries and the executables have been installed. The side-effect of this is that usually they will not run correctly from the build directory. For example, if the package builds a shared library in the directory lib and an application program in the directory app, you could issue the following commands (but keep Section 7.4, ``Running Software'' in mind as well; in particular, the directories from the base release should come after the directories named here, otherwise the system will prefer shared libraries from the base release):
$ export LD_LIBRARY_PATH=./lib:$LD_LIBRARY_PATH $ app/program |
If the package builds only shared libraries that you intend to use with an application, you would issue commands such as these:
$ export LD_LIBRARY_PATH=./lib:$LD_LIBRARY_PATH $ $SRT_DIST/0.0.4/installed/$SRT_TARGET/bin/program |
![]() | Beware that if you change the binary interface of a shared library, the application may fail to execute properly. The fact the application runs does not mean that it will run correctly. If your change was drastic enough, you will be lucky and get an error message from the dynamic linker. If the change was more subtle, the application may crash randomly, or worse yet, produce incorrect but seemingly valid results. |
![]() | If the package only builds archive libraries, you must also build an application that uses the library. Just building the archive library will not take you anywhere. |
Once you have compiled the package successfully you can start modifying the package. You can edit the files, add more files, remove files, and so forth. After you are happy with your changes, rerun the make command again. It will automatically rebuild the parts that are affected by your changes. For instance, if you modify one source file, just that source file will be recompiled, followed by rebuilding the targets that depend on that object file.
Most packages should come with little self-test routines built into the makefiles. You should consult your project's development policies to understand exactly what each package is required to provide. The release tools directly support one particular form of performing self-tests: the check makefile target. If the package you are modifying implements such tests, you can execute them with the following command:
$ make check |
In addition to the package's internal tests, you can excercise it with various testing tools. These include validating the package against the project's coding-style rules, collecting various kinds of metrics, ensuring the validity of run-time memory accesses, and analysing for coverage or performance bottlenecks. Many such features are supported either through the option sets (see the next subsection and Section F.2, ``Option Sets'') or the --with-tool option to the configure scripts (see Appendix G, ``Details on Tools'').
For example, to profile an application called program in the package, you would issue commands such as these on a unix-like system:
$ make USE_OPTION_SETS=profile $ ./program $ gprof program |
To compile and test the application with Insure++, you would issue commands such as these:
$ ./configure --with-tool=insure++ $ make $ ./program |
As already hinted at in the previous section, you can adjust the build-time compiler options via a mechanism called option sets. These are prepackaged, commonly useful sets of compiler options, such as debug or optimise (the available sets are given in Section F.2, ``Option Sets''). If you do not specify anything yourself and the package does not make an overriding choice, you will get the debug set.
You can change the option sets either with the --with-option-sets option to the configure script, or by setting the USE_OPTION_SETS variable on the make command line, or by using both. Using the configure option makes the choice persistent so you do not need to remember to supply it every time for make. On the other hand, setting the variable on the make command line gives you more freedom, but then you need to remember to supply it every time you run make. You can use the combination of the two to get the benefits of both. For example, if you want to compile the package with optimisation, except that you want to debug routines in file.o, you could issue commands along these lines:[1]
$ ./configure --with-option-sets=optimise $ make $ rm file.o $ make USE_OPTION_SETS=debug $ ddd ./program |
As another example, suppose you want to combine several option sets at the time: you wish to compile the package for both profiling and debugging. You would issue commands such as these:
$ ./configure --with-option-sets="debug profile" $ make |
At times you may want to get rid of some files produced by make, for example if you want to recompile the package with different option sets. Or, you may simply want to conserve some disk space if you know you are not going to work with the package for a while. The release tools provide makefile targets for several degrees of cleanliness, listed below in the order of increasing number of files nuked.
Like clean, but will refrain from deleting a number of files that people normally don't want to regenerate or recompile. That is, most intermediate files will be deleted. Examples of files that will be left behind are the sources and headers generated from Objectivity schemas. Examples of files that will be deleted are the object files and built executables.
Will delete all files that are normally created by building the package. It will not delete files that record the results of running configure. It also will not delete files that are normally produced only once.
Will delete all the files that are created by configuring or building the package. Typically this returns the package to the state it was in when it was checked out from CVS. For packages that are also used outside the release tools, this target may refrain from deleting files that can be generated by the makefile but the generation requires special tools and hence the files are usually distributed with the package.
Will delete almost everything that be can be reconstructed with this makefile. This includes everything deleted by distclean and more, including files that may require special tools to regenerate and are therefore stored in CVS. The reason for ``almost everything'' is that this target will not delete the configure script, or anything that the script requires to run, even if they can be remade using rules in the makefile.
Executing this target may result in putting the package into a state where you cannot build it any more (at least not without a cvs update). Hence, building this target will cause a warning to be printed out before anything is deleted.
| [1] | This example is somewhat artifical because many compilers let you optimise and debug at the same time. Just use the option sets debug and optimise at the same time. |
| [1] | Literally, it will build the first target in the makefile, which by convention is all. The release tools define all to build the all typical targets in the package, such as executables and libraries. |
| [1] | ``Partial'' because it may not be necessary to duplicate all the directories, just some of them. Note that only directories are usually duplicated, files almost never. |
| [2] | If your mkdir does not support the -p option, use $SRT_HOME/bin/mkinstalldirs or give mkdir two separate arguments, .srt/$SRT_ARCH and .srt/$SRT_TARGET. |
| [1] | There is a bug in current AFS implementing in that sometimes certain cvs commands, including release, fail to remove empty directories. See Section B.1, ``Interactions Between AFS And CVS'' for details. |