PowerAda Automating the Build Process
Once you have defined the
adalib.imports files for your project, the next step is to compile everything. If these files are defined correctly, automatically building and updating a project interactively is very straightforward using the operations in the powerada Build Menu, and individual developers will generally use this interface. However, one or more shell scripts which build everything in the project (a full build) or just certain changes (a delta build) are generally necessary and recommended. The following steps must usually be performed:
- Determine the kind of build.
- Create a project.
- Extract files from CM.
- Hide deleted files.
- Compile/translate non-Ada files.
- Load all Ada files.
- Bind main programs.
- Compile remaining files.
- Identify the project.
- Baseline the project.
- Update the POWERADA_BASELINES file.
Each of these is described more fully below. The script
illustrates these steps as much as possible in a site-independent way.
Determine the kind of build.
The design of PowerAda projects suggests a two-level build process:
- Full Build
- A project with no parent baseline which contains all the software and files that developers will need access to. For small projects – say under 1000 files – this is probably all that is necessary. Developers will designate a full build project as the parent baseline when creating their working projects.
- Delta Build
- A project with a Full Build (or another delta build) as its parent baseline. This contains only selected files that have changed since the parent baseline was created. The selection of the files is determined entirely by the organization of your development effort and CM system, and may include all changed files, all files changed by a certain group for whom the Delta Build is created, or all files associated with specific changes that are to be tested.
Both types of build may be handled by a single script which takes the name of the parent baseline project as a parameter; if this parameter is missing, it is assumed to be a full build.
Create a project.
It is assumed everything will be built in a single project – if not, the entire procedure applies to the separate projects being built. If it is a Full Build, then the new project will not have a parent baseline:
In a Delta Build you should specify the previously-built baseline project that is to be the parent:
aprojinit delta.980201 -B full.980131
Extract files from CM.
When a project is initially created it is empty. All files that are of interest to users should then be copied into the project from the location where they are maintained on disk. The files should already be organized to support the PowerAda compilation process as described above in "Setting Up the PowerAda Project".
Hide deleted files.
This is a tricky issue unique to the layered-project concept. Here is the problem: suppose a baseline project is created with a file whose project-relative name is
which contains the unit tire_manager. In the delta build we find that the developer has deleted this unit from this directory and moved it to a different directory associated with a different sublibrary:
How do we ensure that the compilation process considers the file at the new path that is provided in the working project, but ignores the file at its original path and the corresponding units in the original sublibrary?
There is a special tool to handle this: aprojhide. Its operations are not available from the powerada GUI because it's not usually necessary for developers to consider. However, the build script must deal with this.
In this case, it must be expected that the developer has correctly updated the
adalib.files for both sublibraries so the file is named only in one place. Thus we can determine the files that need to be "hidden" by comparing the
adalib.files in the baseline project with the one in the delta. aprojhide is then invoked for those that are missing from the delta project.
With clever use of aprojfind one can get the two
adalib.files that are needed, use the AIX
comm command to determine those that are missing, and run aprojhide on this output. A script to do this is provided in
Compile/translate non-Ada files.
Generally there will be some C or other files that can not be directly compiled with the PowerAda tools. The build script must deal with these explicitly. Often this is done with Makefiles and require all referenced source to exist in the same directory. This can be simulated with a script that soft-links everything from the baseline project into a local project. Such a script is provided with PowerAda and is called
aprojflatten. The object files created by these operations should be named in the
adalib.imports file with a linker directive as described in Incorporating Non-Ada Source Code above.
Load all Ada files.
If all the adalib.imports files are defined, this is a single line:
aprojbuild -Fv -pr -- $OPTIONS
-F allows aprojbuild to continue if errors occur
-v shows progress message
-p operates on the entire project
-r loads the files but does not compile them
-- precedes options to be passed to the compiler
If compilation options such as -O (optimize) are needed, they should be recorded in an environment variable as shown above for easy maintenance.
If only certain files need to be compiled with special options, they can be explicitly re-loaded afterward, for example:
aprojbuild -I -Fvl -- $SPECIAL_OPTIONS < special_files.list
Bind main programs.
In a full build this is fairly simple: visit each sublibrary that contains a main subprogram unit and do:
aprojbuild -vF -b main_unit -o exe_name -- $BIND_OPTIONS
This will determine all the units that need to be compiled, compile them, then bind the executable.
When doing a delta build, you may want to bind directly against the existing executable:
aprojbuild -vF -x exe_name -- $BIND_OPTIONS
In this case, no new executable file will be created if no changes occurred.
It is often the case that an Ada program contains non-Ada subprograms. If there are source code changes between the full build and delta build, then we would like the build process to identify these changes and perform an incremental bind against the executable in the full build. If these changes are purely in Ada source, then (providing the project structure described in this chapter is adhered to) the aprojbuild tool will pick up these changes in an incremental bind of the executable. However, a full bind of all the original object and archive files is necessary in order to pick up changes in non-Ada source code. In order to recognize when this is necessary, the build process requires a minor modification.
First, you must explicitly identify any foreign object code that is to be included (see Linking with Foreign Object Code in Chapter 10 for an explanation of how to identify non-Ada object code).
In addition, when doing the full build, you will need to add "-q listobjs" to the list of bind options wherever you bind a main program that includes non-Ada subprograms. This will create a file named <exe_name>.objs that will contain the fully-qualified names of all object files included in the bind operation.
In the delta build, the build process will read the object files list from the <exe_name>.objs file in the full build, and determine whether any foreign object code is newer than the executable in the full build. If newer foreign object code is found, then a full bind will be performed, rather than a link against the previous executable image. If you require assistance in adding this functionality to your build process, contact OC Systems.
Compile remaining files.
The above will only compile those files that are needed to build the executable. However, there are often files that are still in development that are not yet part of a main program that should still be compiled. These can be picked up afterward with a general project-wide update:
aprojbuild -vF -p
Identify the project.
At some point in the build process, after the project has been created but before it is baselined, a file called .
adaproj_info may be inserted in the root directory of the project. The information in this file appears in the output of the Project Info query (aprojinfo) and in the dialogs shown when choosing a baseline (see "Update the POWERADA_BASELINES file" below).
Baseline the project.
After the build has completed, the project must be baselined in order for other users to create working projects against it:
Depending on the size of the project this can be a time-consuming process as cache files are created and protections changed. If errors occurred during the build process which must be fixed up, you will have to "unbaseline" the project with
aprojbaseline -u $PROJECT
before making the changes, then run aprojbaseline again. You may find that it is preferable to wait until the build is verified as being successful before doing this last step.
If you want to be able to update the
.adaproj_info file after baselining, your script should do
chmod +w $PROJECT/.adaproj_info
after baselining is complete, or specify
-w on the aprojbaseline command to prevent it from making everything read-only.
Update the POWERADA_BASELINES file.
When a build is complete and a baseline project is available for developers to reference, the path of the project root and a more mnemonic alias can be recorded in a POWERADA_BASELINES file. This is simply a text file with lines of the form:
The location of this file is identified by the environment variable
POWERADA_BASELINES. This file is maintained "by hand", and is not updated by aprojbaseline. However, the contents of the file are shown in the Find Baseline dialog, and the alias provided there may be specified as the -B argument to aprojinit.