442 lines
13 KiB
HTML
442 lines
13 KiB
HTML
|
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
|
||
|
<HTML
|
||
|
><HEAD
|
||
|
><TITLE
|
||
|
>Good development practice</TITLE
|
||
|
><META
|
||
|
NAME="GENERATOR"
|
||
|
CONTENT="Modular DocBook HTML Stylesheet Version 1.7"><LINK
|
||
|
REL="HOME"
|
||
|
TITLE="Software Release Practice HOWTO"
|
||
|
HREF="index.html"><LINK
|
||
|
REL="PREVIOUS"
|
||
|
TITLE="Good licensing and copyright practice: the practice"
|
||
|
HREF="licensepractice.html"><LINK
|
||
|
REL="NEXT"
|
||
|
TITLE="Good distribution-making practice"
|
||
|
HREF="distpractice.html"></HEAD
|
||
|
><BODY
|
||
|
CLASS="sect1"
|
||
|
BGCOLOR="#FFFFFF"
|
||
|
TEXT="#000000"
|
||
|
LINK="#0000FF"
|
||
|
VLINK="#840084"
|
||
|
ALINK="#0000FF"
|
||
|
><DIV
|
||
|
CLASS="NAVHEADER"
|
||
|
><TABLE
|
||
|
SUMMARY="Header navigation table"
|
||
|
WIDTH="100%"
|
||
|
BORDER="0"
|
||
|
CELLPADDING="0"
|
||
|
CELLSPACING="0"
|
||
|
><TR
|
||
|
><TH
|
||
|
COLSPAN="3"
|
||
|
ALIGN="center"
|
||
|
>Software Release Practice HOWTO</TH
|
||
|
></TR
|
||
|
><TR
|
||
|
><TD
|
||
|
WIDTH="10%"
|
||
|
ALIGN="left"
|
||
|
VALIGN="bottom"
|
||
|
><A
|
||
|
HREF="licensepractice.html"
|
||
|
ACCESSKEY="P"
|
||
|
>Prev</A
|
||
|
></TD
|
||
|
><TD
|
||
|
WIDTH="80%"
|
||
|
ALIGN="center"
|
||
|
VALIGN="bottom"
|
||
|
></TD
|
||
|
><TD
|
||
|
WIDTH="10%"
|
||
|
ALIGN="right"
|
||
|
VALIGN="bottom"
|
||
|
><A
|
||
|
HREF="distpractice.html"
|
||
|
ACCESSKEY="N"
|
||
|
>Next</A
|
||
|
></TD
|
||
|
></TR
|
||
|
></TABLE
|
||
|
><HR
|
||
|
ALIGN="LEFT"
|
||
|
WIDTH="100%"></DIV
|
||
|
><DIV
|
||
|
CLASS="sect1"
|
||
|
><H1
|
||
|
CLASS="sect1"
|
||
|
><A
|
||
|
NAME="develpractice"
|
||
|
></A
|
||
|
>6. Good development practice</H1
|
||
|
><P
|
||
|
>Most of these are concerned with ensuring portability across all
|
||
|
POSIX and POSIX-like systems. Being widely portable is not just a worthy
|
||
|
form of professionalism and hackerly politeness, it's valuable insurance
|
||
|
against future changes in Linux.</P
|
||
|
><P
|
||
|
>Finally, other people <EM
|
||
|
>will</EM
|
||
|
> try to build your
|
||
|
code on non-Linux systems; portability reduces the amount of support
|
||
|
email you receive.</P
|
||
|
><DIV
|
||
|
CLASS="sect2"
|
||
|
><H2
|
||
|
CLASS="sect2"
|
||
|
><A
|
||
|
NAME="language"
|
||
|
></A
|
||
|
>6.1. Choose the most portable language you can</H2
|
||
|
><P
|
||
|
>Choose a development language which minimizes the differences of
|
||
|
the underlying environments in which it will run. C/C++ programs are
|
||
|
likely to be more portable than Fortran. Java is preferable to C/C++,
|
||
|
and a high-level scripting language such as Perl, Python or Ruby is the
|
||
|
best choice of all (since scripting languages have only one
|
||
|
cross-platform implementation).</P
|
||
|
><P
|
||
|
>Scripting languages that qualify include Python, Perl, Tcl, Emacs
|
||
|
Lisp, and PHP. Historic Bourne shell (/bin/sh) does
|
||
|
<EM
|
||
|
>not</EM
|
||
|
> qualify; there are too many different
|
||
|
implementations with subtle idiosyncrasies, and the shell environment
|
||
|
is subject to disruption by user customizations such as shell
|
||
|
aliases.</P
|
||
|
><P
|
||
|
>If you choose a compiled language such as C/C++, do not use
|
||
|
compiler extensions (such as allocating variable-length arrays on the
|
||
|
stack, or indirecting through void pointers). Regularly build using as
|
||
|
many different compilers and test machines as you can.</P
|
||
|
></DIV
|
||
|
><DIV
|
||
|
CLASS="sect2"
|
||
|
><H2
|
||
|
CLASS="sect2"
|
||
|
><A
|
||
|
NAME="proprietary"
|
||
|
></A
|
||
|
>6.2. Don't rely on proprietary code</H2
|
||
|
><P
|
||
|
>Don't rely on proprietary languages, libraries, or other code.
|
||
|
In the open-source community this is considered rude. Open-source
|
||
|
developers don't trust code for which they can't review the source.</P
|
||
|
></DIV
|
||
|
><DIV
|
||
|
CLASS="sect2"
|
||
|
><H2
|
||
|
CLASS="sect2"
|
||
|
><A
|
||
|
NAME="build_systems"
|
||
|
></A
|
||
|
>6.3. Build systems</H2
|
||
|
><P
|
||
|
>A significant advantage of open source distributions is they allow
|
||
|
each source package to adapt at compile-time to the environment it finds.
|
||
|
One of the choices you need to make is of a "build system", the toolkit you
|
||
|
(and other people) will rely on to transform your source into
|
||
|
executables.</P
|
||
|
><P
|
||
|
>One thing your build script cannot do is ask the user for system
|
||
|
information at compile-time. The user installing the package will not
|
||
|
necessarily know the answers to your questions, so this approach is doomed
|
||
|
from the start. Your software, calling the build system tools, must be able
|
||
|
to determine for itself any information that it may need at compile- or
|
||
|
install-time.</P
|
||
|
><P
|
||
|
>Community notions of best practice in build systems are now (rearly
|
||
|
2010) in a starte of some flux.</P
|
||
|
><DIV
|
||
|
CLASS="sect3"
|
||
|
><H3
|
||
|
CLASS="sect3"
|
||
|
><A
|
||
|
NAME="autoconf"
|
||
|
></A
|
||
|
>6.3.1. GNU autotools: fading but still standard</H3
|
||
|
><P
|
||
|
>Previous versions of this HOWTO urged using GNU autotools to handle
|
||
|
portability issues, do system-configuration probes, and tailor your
|
||
|
makefiles. This is still the standard and most popular approach, but it is
|
||
|
becoming increasingly problematic because GNU autotools is showing its age.
|
||
|
Autotools was always a pile of crocks upon hacks upon kluges, implemented
|
||
|
in a messy mixture of languages and with some serious design flaws. The
|
||
|
resulting mess was tolerable for many years, but as projects become
|
||
|
more complex it is increasingly failing.</P
|
||
|
><P
|
||
|
>Still, people building from C sources expect to be able to type
|
||
|
"configure; make; make install" and get a clean build. Supposing you choose
|
||
|
a non-autotools system, you will probably want to emulate this behavior
|
||
|
(which should be easy).</P
|
||
|
><P
|
||
|
>There is a good tutorial on autotools <A
|
||
|
HREF="http://seul.org/docs/autotut/"
|
||
|
TARGET="_top"
|
||
|
>here</A
|
||
|
>.</P
|
||
|
></DIV
|
||
|
><DIV
|
||
|
CLASS="sect3"
|
||
|
><H3
|
||
|
CLASS="sect3"
|
||
|
><A
|
||
|
NAME="scons"
|
||
|
></A
|
||
|
>6.3.2. SCons: leading a crowded field</H3
|
||
|
><P
|
||
|
>The race to replace autotools does not yet have a winner, but it has
|
||
|
a front runner: <A
|
||
|
HREF="http://www.scons.org/"
|
||
|
TARGET="_top"
|
||
|
>SCons</A
|
||
|
>. SCons
|
||
|
abolishes makefiles; it combines the "configure" and "make" parts of the
|
||
|
autotools build sequence into one step. It offers cross-platfoem builds
|
||
|
with a single recipe on Unix/Linux, Maoc OS X, and Windows. It is
|
||
|
written in Python, is extensible in Python, and is to some extent riding
|
||
|
the increasing popularity of that language.</P
|
||
|
></DIV
|
||
|
><DIV
|
||
|
CLASS="sect3"
|
||
|
><H3
|
||
|
CLASS="sect3"
|
||
|
><A
|
||
|
NAME="cmake_and_others"
|
||
|
></A
|
||
|
>6.3.3. CMake and others</H3
|
||
|
><P
|
||
|
>SCons is still a minority choice, and has stiff competition from
|
||
|
several others, of which CMake and WAF are probably the most
|
||
|
prominant. Fairly even-handed cross-comparisons, considering the source,
|
||
|
can be <A
|
||
|
HREF="http://www.scons.org/wiki/SconsVsOtherBuildTools"
|
||
|
TARGET="_top"
|
||
|
>found
|
||
|
on the SCons wiki</A
|
||
|
>.</P
|
||
|
></DIV
|
||
|
></DIV
|
||
|
><DIV
|
||
|
CLASS="sect2"
|
||
|
><H2
|
||
|
CLASS="sect2"
|
||
|
><A
|
||
|
NAME="testcode"
|
||
|
></A
|
||
|
>6.4. Test your code before release</H2
|
||
|
><P
|
||
|
>A good test suite allows the team to buy inexpensive hardware for
|
||
|
testing and then easily run regression tests before releases. Create a
|
||
|
strong, usable test framework so that you can incrementally add tests
|
||
|
to your software without having to train developers up in the
|
||
|
intricacies of the test suite.</P
|
||
|
><P
|
||
|
>Distributing the test suite allows the community of users to test
|
||
|
their ports before contributing them back to the group.</P
|
||
|
><P
|
||
|
>Encourage your developers to use a wide variety of platforms as
|
||
|
their desktop and test machines so that code is continuously being
|
||
|
tested for portability flaws as part of normal development.</P
|
||
|
></DIV
|
||
|
><DIV
|
||
|
CLASS="sect2"
|
||
|
><H2
|
||
|
CLASS="sect2"
|
||
|
><A
|
||
|
NAME="sanitycode"
|
||
|
></A
|
||
|
>6.5. Sanity-check your code before release</H2
|
||
|
><P
|
||
|
>If you're writing C/C++ using GCC, test-compile with -Wall and
|
||
|
clean up all warning messages before each release. Compile your code
|
||
|
with every compiler you can find — different compilers often find
|
||
|
different problems. Specifically, compile your software on true 64-bit
|
||
|
machine. Underlying data types can change on 64-bit machines, and you
|
||
|
will often find new problems there. Find a UNIX vendor's system and run
|
||
|
the lint utility over your software.</P
|
||
|
><P
|
||
|
>Run tools that for memory leaks and other run-time errors;
|
||
|
Electric Fence
|
||
|
and
|
||
|
<A
|
||
|
HREF="http://developer.kde.org/~sewardj"
|
||
|
TARGET="_top"
|
||
|
>Valgrind</A
|
||
|
>
|
||
|
are two good ones available in open source.</P
|
||
|
><P
|
||
|
>For Python projects, the
|
||
|
<A
|
||
|
HREF="http://sourceforge.net/projects/pychecker"
|
||
|
TARGET="_top"
|
||
|
>PyChecker</A
|
||
|
>
|
||
|
program can be a useful check. It's not out of beta yet, but nevertheless
|
||
|
often catches nontrivial errors.</P
|
||
|
><P
|
||
|
>If you're writing Perl, check your code with perl -c (and maybe
|
||
|
-T, if applicable). Use perl -w and 'use strict' religiously. (See the
|
||
|
Perl documentation for further discussion.)</P
|
||
|
></DIV
|
||
|
><DIV
|
||
|
CLASS="sect2"
|
||
|
><H2
|
||
|
CLASS="sect2"
|
||
|
><A
|
||
|
NAME="sanitydocs"
|
||
|
></A
|
||
|
>6.6. Sanity-check your documentation and READMEs before release</H2
|
||
|
><P
|
||
|
>Spell-check your documentation, README files and error messages
|
||
|
in your software. Sloppy code, code that produces warning messages when
|
||
|
compiled, and spelling errors in README files or error messages, leads
|
||
|
users to believe the engineering behind it is also haphazard and
|
||
|
sloppy.</P
|
||
|
></DIV
|
||
|
><DIV
|
||
|
CLASS="sect2"
|
||
|
><H2
|
||
|
CLASS="sect2"
|
||
|
><A
|
||
|
NAME="cport"
|
||
|
></A
|
||
|
>6.7. Recommended C/C++ portability practices</H2
|
||
|
><P
|
||
|
>If you are writing C, feel free to use the full ANSI features.
|
||
|
Specifically, do use function prototypes, which will help you spot
|
||
|
cross-module inconsistencies. The old-style K&R compilers are
|
||
|
history.</P
|
||
|
><P
|
||
|
>Do not assume compiler-specific features such as the GCC "-pipe"
|
||
|
option or nested functions are available. These will come around and
|
||
|
bite you the second somebody ports to a non-Linux, non-GCC system.</P
|
||
|
><P
|
||
|
>Code required for portability should be isolated to a single area
|
||
|
and a single set of source files (for example, an "os" subdirectory).
|
||
|
Compiler, library and operating system interfaces with portability
|
||
|
issues should be abstracted to files in this directory. This includes
|
||
|
variables such as "errno", library interfaces such as "malloc", and
|
||
|
operating system interfaces such as "mmap".</P
|
||
|
><P
|
||
|
>Portability layers make it easier to do new software ports. It is
|
||
|
often the case that no member of the development team knows the porting
|
||
|
platform (for example, there are literally hundreds of different
|
||
|
embedded operating systems, and nobody knows any significant fraction
|
||
|
of them). By creating a separate portability layer it is possible for
|
||
|
someone who knows the port platform to port your software without having
|
||
|
to understand it.</P
|
||
|
><P
|
||
|
>Portability layers simplify applications. Software rarely needs
|
||
|
the full functionality of more complex system calls such as mmap or
|
||
|
stat, and programmers commonly configure such complex interfaces
|
||
|
incorrectly. A portability layer with abstracted interfaces
|
||
|
("__file_exists" instead of a call to stat) allows you to export only
|
||
|
the limited, necessary functionality from the system, simplifying the
|
||
|
code in your application.</P
|
||
|
><P
|
||
|
>Always write your portability layer to select based on a feature,
|
||
|
never based on a platform. Trying to create a separate portability layer
|
||
|
for each supported platform results in a multiple update problem
|
||
|
maintenance nightmare. A "platform" is always selected on at least two
|
||
|
axes: the compiler and the library/operating system release. In some
|
||
|
cases there are three axes, as when Linux vendors select a C library
|
||
|
independently of the operating system release. With M vendors, N
|
||
|
compilers and O operating system releases, the number of "platforms"
|
||
|
quickly scales out of reach of any but the largest development teams.
|
||
|
By using language and systems standards such as ANSI and POSIX 1003.1,
|
||
|
the set of features is relatively constrained.</P
|
||
|
><P
|
||
|
>Portability choices can be made along either lines of code or
|
||
|
compiled files. It doesn't make a difference if you select alternate
|
||
|
lines of code on a platform, or one of a few different files. A rule of
|
||
|
thumb is to move portability code for different platforms into separate
|
||
|
files when the implementations diverged significantly (shared memory
|
||
|
mapping on UNIX vs. Windows), and leave portability code in a single
|
||
|
file when the differences are minimal (using gettimeofday,
|
||
|
clock_gettime, ftime or time to find out the current
|
||
|
time-of-day).</P
|
||
|
><P
|
||
|
>Avoid using complex types such as "off_t" and "size_t". They vary
|
||
|
in size from system to system, especially on 64-bit systems. Limit your
|
||
|
usage of "off_t" to the portability layer, and your usage of "size_t"
|
||
|
to mean only the length of a string in memory, and nothing else.</P
|
||
|
><P
|
||
|
>Never step on the namespace of any other part of the system,
|
||
|
(including file names, error return values and function names). Where
|
||
|
the namespace is shared, document the portion of the namespace that you
|
||
|
use.</P
|
||
|
><P
|
||
|
>Choose a coding standard. The debate over the choice of standard
|
||
|
can go on forever — regardless, it is too difficult and expensive to
|
||
|
maintain software built using multiple coding standards, and so some
|
||
|
coding standard must be chosen. Enforce your coding standard ruthlessly,
|
||
|
as consistency and cleanliness of the code are of the highest priority;
|
||
|
the details of the coding standard itself are a distant second.</P
|
||
|
></DIV
|
||
|
></DIV
|
||
|
><DIV
|
||
|
CLASS="NAVFOOTER"
|
||
|
><HR
|
||
|
ALIGN="LEFT"
|
||
|
WIDTH="100%"><TABLE
|
||
|
SUMMARY="Footer navigation table"
|
||
|
WIDTH="100%"
|
||
|
BORDER="0"
|
||
|
CELLPADDING="0"
|
||
|
CELLSPACING="0"
|
||
|
><TR
|
||
|
><TD
|
||
|
WIDTH="33%"
|
||
|
ALIGN="left"
|
||
|
VALIGN="top"
|
||
|
><A
|
||
|
HREF="licensepractice.html"
|
||
|
ACCESSKEY="P"
|
||
|
>Prev</A
|
||
|
></TD
|
||
|
><TD
|
||
|
WIDTH="34%"
|
||
|
ALIGN="center"
|
||
|
VALIGN="top"
|
||
|
><A
|
||
|
HREF="index.html"
|
||
|
ACCESSKEY="H"
|
||
|
>Home</A
|
||
|
></TD
|
||
|
><TD
|
||
|
WIDTH="33%"
|
||
|
ALIGN="right"
|
||
|
VALIGN="top"
|
||
|
><A
|
||
|
HREF="distpractice.html"
|
||
|
ACCESSKEY="N"
|
||
|
>Next</A
|
||
|
></TD
|
||
|
></TR
|
||
|
><TR
|
||
|
><TD
|
||
|
WIDTH="33%"
|
||
|
ALIGN="left"
|
||
|
VALIGN="top"
|
||
|
>Good licensing and copyright practice: the practice</TD
|
||
|
><TD
|
||
|
WIDTH="34%"
|
||
|
ALIGN="center"
|
||
|
VALIGN="top"
|
||
|
> </TD
|
||
|
><TD
|
||
|
WIDTH="33%"
|
||
|
ALIGN="right"
|
||
|
VALIGN="top"
|
||
|
>Good distribution-making practice</TD
|
||
|
></TR
|
||
|
></TABLE
|
||
|
></DIV
|
||
|
></BODY
|
||
|
></HTML
|
||
|
>
|