2.0 Program Organization
A source program generally consists of one or more source, object, and
library files. As a project gets larger and the number of files increases, it
becomes difficult to keep track of the files in a project. This is especially
true if a number of different projects share a common set of source modules.
This section will address these concerns.
2.1 Library Functions
A library, by its very nature, suggests stability. Ignoring the possibility
of software defects, one would rarely expect the number or function of routines
in a library to vary from project to project. A good example is the "UCR
Standard Library for 80x86 Assembly Language Programmers." One would expect
"printf" to behave identically in two different programs that use the Standard
Library. Contrast this against two programs, each of which implement their own
version of printf. One could not reasonably assume both programs have identical
implementations[8]. This leads to the following
rule:
- Rule:
- Library functions are those routines intended for common reuse in many
different assembly language programs. All assembly language (callable)
libraries on a system should exist as ".lib" files and should appear in the
"/lib" or "/asmlib" subdirectory.
- Guideline:
- "/asmlib" is probably a better choice if you're using multiple languages
since those other languages may need to put files in a "/lib" directory.
- Exception:
- It's probably reasonable to leave the UCR Standard Library's "stdlib.lib"
file in the "/stdlib/lib" directory since most people expect it there.
The rule above ensures that the library files are all in one location so they
are easy to find, modify, and review. By putting all your library modules into a
single directory, you avoid configuration management problems such as having
outdated versions of a library linking with one program and up-to-date versions
linking with other programs.
2.2 Common Object Modules
This document defines a library as a collection of object modules that have
wide application in many different programs. The UCR Standard Library is a
typical example of a library. Some object modules are not so general purpose,
but still find application in two or more different programs. Two major
configuration management problems exist in this situation: (1) making sure the
".obj" file is up-to-date when linking it with a program; (2) Knowing which
modules use the module so one can verify that changes to the module won't break
existing code.
The following rules takes care of case one:
- Rule:
- If two different program share an object module, then the associated
source, object, and makefiles for that module should appear in a subdirectory
that is specific to that module (i.e., no other files in the subdirectory).
The subdirectory name should be the same as the module name. If possible, you
should create a set of link/alias/shortcuts to this subdirectory and place
these links in the main directory of each of the projects that utilize the
module. If links are not possible, you should place the module's subdirectory
in the "/common" subdirectory.
- Enforced Rule:
- Every subdirectory containing one or more modules should have a make file
that will automatically generate the appropriate, up-to-date, ".obj" files. An
individual, a batch file, or another make file should be able to automatically
generate new object modules (if necessary) by simply executing the make
program.
- Guideline:
- Use Microsoft's nmake program. At the very least, use nmake acceptable
syntax in your makefiles.
The other problem, noting which projects use a given module is much more
difficult. The obvious solution, commenting the source code associated with the
module to tell the reader which programs use the module, is impractical.
Maintaining these comments is too error-prone and the comments will quickly get
out of phase and be worse than useless -- they would be incorrect. A better
solution is to create a dummy file using the module's name with a ".elw"
(elsewhere) suffix and placing this file in the main subdirectory of each
program that links the module. Now, using one of the venerable "whereis"
programs, you can easily locate all projects that use the module.
- Guideline:
- If a project uses a module that is not local to the project's
subdirectory, create a dummy file (using "TOUCH" or a comparable program) that
uses the module's main name with a ".elw" suffix. This will allow someone to
easily search for all the projects that use a common object module by using a
"whereis" program.
2.3 Local Modules
Local modules are those that a single program/project uses. Typically, the
source and object code for each module appears in the same directory as the
other files associated with the project. This is a reasonable arrangement until
the number of files increases to the point that it is difficult to find a file
in a directory listing. At that point, most programmers begin reorganizing their
directory by creating subdirectories to hold many of these source modules.
However, the placement, name, and contents of these new subdirectories can have
a big impact on the overall readability of the program. This section will
address these issues.
The first issue to consider is the contents of these new subdirectories.
Since programmers rummaging through this project in the future will need to
easily locate source files in a project, it is important that you organize these
new subdirectories so that it is easy to find the source files you are moving
into them. The best organization is to put each source module (or a small group
of strongly related modules) into its own subdirectory. The subdirectory should
bear the name of the source module minus its suffix (or the main module if there
is more than one present in the subdirectory). If you place two or more source
files in the same directory, ensure this set of source files forms a cohesive
set (meaning the source files contain code that solve a single problem). A
discussion of cohesiveness appears later in this document.
- Rule:
- If a project directory contains too many files, try to move some of the
modules to subdirectories within the project directory; give the subdirectory
the same name as the source file without the suffix. This will nearly reduce
the number of files in half. If this reduction is insufficient, try
categorizing the source modules (e.g., FileIO, Graphics, Rendering, and Sound)
and move these modules to a subdirectory bearing the name of the category.
- Enforced Rule:
- Each new subdirectory you create should have its own make file that will
automatically assemble all source modules within that subdirectory, as
appropriate.
- Enforced Rule:
- Any new subdirectories you create for these source modules should appear
within the directory containing the project. The only excepts are those
modules that are, or you anticipate, sharing with other projects. See "Common Object Modules" on page 13 for more details.
Stand-alone assembly language programs generally contain a "main" procedure -
the first program unit that executes when the operating system loads the program
into memory. For any programmer new to a project, this procedure is the anchor
where one first begins reading the code and the point where the reader will
continually refer. Therefore, the reader should be able to easily locate this
source file. The following rule helps ensure this is the case:
- Rule:
- The source module containing the main program should have the same name as
the executable (obviously the suffix will be different). For example, if the
"Simulate 886" program's executable name is "Sim886.exe" then you should find
the main program in the "Sim886.asm" source file.
Finding the souce file that contains the main program is one thing. Finding
the main program itself can be almost as hard. Assembly language lets you give
the main program any name you want. However, to make the main procedure easy to
find (both in the source code and at the O/S level), you should actually name
this program "main". See "Module Organization" on page
15 for more details about the placement of the main program.
- Rule:
- The name of the main procedure in an assembly language program should be
"main".
2.4 Program Make Files
Every project, even if it contains only a single source module, should have
an associated make file. If someone want to assemble your program, they should
have to worry about what program (e.g., MASM) to use, what command line options
to use, what library modules to use, etc. They should be able to type "nmake"[9] and wind up with an executable program. Even if
assembling the program consists of nothing more than typing the name of the
assembler and the source file, you should still have a make file. Someone else
may not realize that's all that is necessary.
- Enforced Rule:
- The main project directory should contain a make file that will
automatically generate an executable (or other expected object module) in
response to a simple make/nmake command.
- Rule:
- If your project uses object modules that are not in the same subdirectory
as the main program's module, you should test the ".obj" files for those
modules and execute the corresponding make files in their directories if the
object code is out of date. You can assume that library files are up to date.
- Guideline:
- Avoid using fancy "make" features. Most programmers only learn the basics
about make and will not be able to understand what your make file is doing if
you fully exploit the make language. Especially avoid the use of default rules
since this can create havoc if someone arbitrarily adds or removes files from
the directory containing the make file.
|