1739 lines
61 KiB
Text
1739 lines
61 KiB
Text
<!DOCTYPE linuxdoc PUBLIC "-//FreeBSD//DTD linuxdoc//EN">
|
|
<!-- $Id: devel.sgml,v 1.2 1996-10-06 20:17:10 jfieber Exp $ -->
|
|
|
|
<!--
|
|
++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
++ file: /home/james/docs/devel.sgml
|
|
++
|
|
++ Copyright James Raynard, Thursday 30th May 1996
|
|
++
|
|
++ Sgml doc for programming under FreeBSD.
|
|
-->
|
|
|
|
<article>
|
|
|
|
<title>A User's Guide to FreeBSD Programming Tools
|
|
<author>James Raynard, <tt /jraynard@freebsd.org/
|
|
<date>30th May 1996
|
|
|
|
<abstract>
|
|
|
|
This document is an introduction to using some of the programming
|
|
tools supplied with FreeBSD, although much of it will be applicable to
|
|
many other versions of Unix. It does <it /not/ attempt to describe
|
|
coding in any detail. Most of the document assumes little or no
|
|
previous programming knowledge, although it is hoped that most
|
|
programmers will find something of value in it
|
|
|
|
</abstract>
|
|
|
|
<sect><heading>Introduction</heading>
|
|
<p>
|
|
|
|
FreeBSD offers an excellent development environment. Compilers for C,
|
|
C++, and Fortran and an assembler come with the basic system, not to
|
|
mention a Perl interpreter and classic Unix tools such as sed and awk.
|
|
If that isn't enough, there are many more compilers and interpreters
|
|
in the Ports collection. FreeBSD is very compatible with standards
|
|
such as POSIX and ANSI C, as well with its own BSD heritage, so it is
|
|
possible to write applications that will compile and run with little
|
|
or no modification on a wide range of platforms.
|
|
<p>
|
|
However, all this power can be rather overwhelming at first if you've
|
|
never written programs on a Unix platform before. This document aims
|
|
to help you get up and running, without getting too deeply into more
|
|
advanced topics. The intention is that this document should give you
|
|
enough of the basics to be able to make some sense of the
|
|
documentation.
|
|
<p>
|
|
Most of the document requires little or no knowledge of programming,
|
|
although it does assume a basic competence with using Unix and a
|
|
willingness to learn!
|
|
|
|
<sect><heading>Introduction to Programming</heading>
|
|
<p>
|
|
A program is a set of instructions that tell the computer to do
|
|
various things; sometimes the instruction it has to perform depends on
|
|
what happened when it performed a previous instruction. This section
|
|
gives an overview of the two main ways in which you can give these
|
|
instructions, or ``commands'' as they're usually called. One way uses
|
|
an interpreter, the other a compiler. As human languages are too
|
|
difficult for a computer to understand in an unambiguous way, commands
|
|
are usually written in one or other languages specially designed for
|
|
the purpose.
|
|
|
|
<sect1><heading>Interpreters</heading>
|
|
<p>
|
|
With an interpreter, the language comes as an environment, where you
|
|
type in commands at a prompt and the environment executes them for
|
|
you. For more complicated programs, you can type the commands into a
|
|
file and get the interpreter to load the file and execute the commands
|
|
in it. If anything goes wrong, many interpreters will drop you into a
|
|
debugger to help you track down the problem.
|
|
<P>
|
|
The advantage of this is that you can see the results of your commands
|
|
immediately, and mistakes can be corrected readily. The biggest
|
|
disadvantage comes when you want to share your programs with
|
|
someone. They must have the same interpreter (or you must have some
|
|
way of giving it to them) and they need to understand how to use
|
|
it. Also users may not appreciate being thrown into a debugger if they
|
|
press the wrong key! From a performance point of view, interpreters
|
|
can use up a lot of memory, and generally do not generate code as
|
|
efficiently as compilers.
|
|
<p>
|
|
In my opinion, interpreted languages are the best way to start if you
|
|
haven't done any programming before. This kind of environment is
|
|
typically found with languages like Lisp, Smalltalk, Perl and
|
|
Basic. It could also be argued that the Unix shell (sh, csh) is itself
|
|
an interpreter, and many people do in fact write shell `scripts' to
|
|
help with various ``housekeeping'' tasks on their machine. Indeed,
|
|
part of the original Unix philosophy was to provide lots of small
|
|
utility programs that could be linked together in shell scripts to
|
|
perform useful tasks.
|
|
<p>
|
|
<sect1><heading>Interpreters available with FreeBSD</heading>
|
|
<p>
|
|
Here is a list of interpreters that are available as <htmlurl
|
|
url="ftp://ftp.freebsd.org:pub/FreeBSD/packages/" name="FreeBSD
|
|
packages">, with a brief discussion of some of the more popular
|
|
interpreted languages.
|
|
<p>
|
|
To get one of these packages, all you need to do is to click on the
|
|
hotlink for the package, then run
|
|
|
|
<tscreen><verb>
|
|
pkg_add <package name>
|
|
</verb></tscreen>
|
|
|
|
as root. Obviously, you'll need to have a fully-functional FreeBSD
|
|
2.1.0 system for the package to work!
|
|
|
|
<descrip>
|
|
<tag>Basic</tag>
|
|
|
|
Short for Beginner's All-purpose Symbolic Instruction Code. Developed
|
|
in the 1950s for teaching University students to program and provided
|
|
with every self-respecting personal computer in the 1980s, BASIC has
|
|
been the first programming language for many programmers. It's also
|
|
the foundation for Visual Basic.
|
|
|
|
The <htmlurl
|
|
url="ftp://ftp.freebsd.org:pub/FreeBSD/packages/lang/bwbasic-2.10.tgz"
|
|
name="Bywater Basic Interpreter"> and the <htmlurl
|
|
url="ftp://ftp.freebsd.org:pub/FreeBSD/packages/lang/pbasic-2.0.tgz"
|
|
name="Phil Cockroft's Basic Interpreter"> (formerly Rabbit Basic) are
|
|
available as FreeBSD <htmlurl
|
|
url="ftp://ftp.freebsd.org:pub/FreeBSD/packages/" name="FreeBSD
|
|
packages">
|
|
|
|
<tag>Lisp</tag>
|
|
|
|
A language that was developed in the late 1950s as an alternative to
|
|
the ``number-crunching'' languages that were popular at the time.
|
|
Instead of being based on numbers, Lisp is based on `lists'; in fact
|
|
the name is short for "List Processing". Very popular in AI
|
|
(Artificial Intelligence) circles.
|
|
|
|
Lisp is an extremely powerful and sophisticated language, but can be
|
|
rather large and unwieldy.
|
|
|
|
FreeBSD has <htmlurl
|
|
url="ftp://ftp.freebsd.org:pub/FreeBSD/packages/gcl-2.0.tgz" name="GNU
|
|
Common Lisp"> available as a package.
|
|
|
|
<tag>Perl</tag>
|
|
|
|
Very popular with system administrators for writing scripts; also
|
|
often used on World Wide Web servers for writing CGI scripts.
|
|
|
|
Version 4, which is probably still the most widely-used version, comes
|
|
with FreeBSD; the newer
|
|
<htmlurl
|
|
url="ftp://ftp.freebsd.org:pub/FreeBSD/packages/lang/perl-5.001.tgz"
|
|
name="Perl Version 5"> is available as a package.
|
|
|
|
<tag>Scheme</tag>
|
|
|
|
A dialect of Lisp that is rather more compact and cleaner than Common
|
|
Lisp. Popular in Universities as it's simple enough to teach to
|
|
undergraduates as a first language, while it has a high enough level
|
|
of abstraction to be used in research work.
|
|
|
|
FreeBSD has packages of the
|
|
<htmlurl
|
|
url="ftp://ftp.freebsd.org:pub/FreeBSD/packages/lang/elk-3.0.tgz"
|
|
name="Elk Scheme Interpreter">, the
|
|
<htmlurl
|
|
url="ftp://ftp.freebsd.org:pub/FreeBSD/packages/lang/mit-scheme-7.3.tgz"
|
|
name="MIT Scheme Interpreter"> and the
|
|
<htmlurl
|
|
url="ftp://ftp.freebsd.org:pub/FreeBSD/packages/lang/scm-4e1.tgz"
|
|
name="SCM Scheme Interpreter">.
|
|
<!--
|
|
<tag>TCL and Tk</tag>
|
|
|
|
Programming with the X windowing system can best be described as
|
|
rather character-forming. As someone once said, if they designed cars
|
|
the way X was designed, each car would have five steering wheels, all
|
|
following completely different conventions, but you can use the
|
|
radio-cassette player to change gears, which is a really useful
|
|
feature when you think about it. Or perhaps not.
|
|
<p>
|
|
Fortunately, it doesn't have to be like that. A number of people have
|
|
written "toolkits" for X, where all the interaction with X is hidden
|
|
inside toolkit routines and you can just say, in effect, ``pop up a
|
|
window and draw a line from point A to point B''. Many of these are
|
|
`libraries' that have to be called from inside a C program, but one of
|
|
the best known toolkits, John Ousterhout's Tk, provides a
|
|
straightforward way to write GUI programs using a scripted
|
|
language. And by one of those remarkable coincidences, he also happens
|
|
to have written an embeddable language, TCL (Tool Command Language)
|
|
which is very suitable for the purpose, although it is possible to use
|
|
other interpreted languages such as Perl or Scheme to send commands to
|
|
Tk.
|
|
|
|
FreeBSD has a <htmlurl
|
|
url="ftp://ftp.freebsd.org:pub/FreeBSD/packages/lang/tcl-7.4.2.tgz"
|
|
name="Tool Command Language"> package.
|
|
-->
|
|
<tag>Icon</tag>
|
|
|
|
<htmlurl
|
|
url="ftp://ftp.freebsd.org:pub/FreeBSD/packages/lang/icon-9.0.tgz"
|
|
name="The Icon Programming Language">.
|
|
|
|
<tag>Logo</tag>
|
|
|
|
<htmlurl
|
|
url="ftp://ftp.freebsd.org:pub/FreeBSD/packages/lang/ucblogo-3.3.tgz"
|
|
name="Brian Harvey's LOGO Interpreter">.
|
|
|
|
<tag>Python</tag>
|
|
<htmlurl
|
|
url="ftp://ftp.freebsd.org:pub/FreeBSD/packages/lang/python-1.2"
|
|
name="The Python Object-Oriented Programming Language">
|
|
|
|
</descrip>
|
|
|
|
<sect1><heading>Compilers</heading>
|
|
<p>
|
|
Compilers are rather different. First of all, you write your code in a
|
|
file (or files) using an editor. You then run the compiler and see if
|
|
it accepts your program. If it didn't compile, grit your teeth and go
|
|
back to the editor; if it did compile and gave you a program, you can
|
|
run it either at a shell command prompt or in a debugger to see if it
|
|
works properly. (If you run it in the shell, you may get a core dump).
|
|
<p>
|
|
Obviously, this is not quite as direct as using an interpreter.
|
|
However it allows you to do a lot of things which are very difficult
|
|
or even impossible with an interpreter, such as writing code which
|
|
interacts with the operating system - or even writing your own
|
|
operating system! It's also useful if you need to write very efficient
|
|
code, as the compiler can take its time and optimise the code, which
|
|
wouldn't be acceptable in an interpreter. And distributing a program
|
|
written for a compiler is usually more straightforward than one
|
|
written for an interpreter - you can just give them a copy of the
|
|
executable (assuming they have the same operating system as you).
|
|
<p>
|
|
Compiled languages include Pascal, C and C++. C and C++ are rather
|
|
unforgiving languages, and best suited to more experienced
|
|
programmers; Pascal, on the other hand, was designed as an educational
|
|
language, and is quite a good language to start with. Unfortunately,
|
|
FreeBSD doesn't have any Pascal support, except for a Pascal-to-C
|
|
converter in the ports.
|
|
<p>
|
|
As the edit-compile-run-debug cycle is rather tedious when using
|
|
separate programs, many commercial compiler makers have produced
|
|
Integrated Development Environments (IDEs for short). FreeBSD doesn't
|
|
have an IDE as such; however it's possible to use Emacs for this
|
|
purpose. This is discussed under Emacs.
|
|
|
|
<sect><heading>Compiling with cc</heading>
|
|
<p>
|
|
This section deals only with the GNU compiler for C and C++, since
|
|
that comes with the base FreeBSD system. It can be invoked by either
|
|
`cc' or `gcc'. The details of producing a program with an interpreter
|
|
vary considerably between interpreters, and are usually well covered
|
|
in the documentation and on-line help for the interpreter.
|
|
<p>
|
|
Once you've written your masterpiece, the next step is to convert it
|
|
into something that will (hopefully!) run on FreeBSD. This usually
|
|
involves several steps, each of which is done by a separate program.
|
|
|
|
<enum>
|
|
|
|
<item> Pre-process your source code to remove comments and do other
|
|
tricks like expanding `macros' in C.
|
|
|
|
<item> Check the syntax of your code to see if you have obeyed the
|
|
rules of the language. If you haven't, it will complain!
|
|
|
|
<item> Convert the source code into assembler - this is very close to
|
|
machine code, but still understandable by humans. Allegedly. (To be
|
|
strictly accurate, cc converts the source code into its own,
|
|
machine-independent p-code instead of assembler at this stage).
|
|
|
|
<item> Convert the assembler into machine code - yep, we're talking
|
|
bits and bytes, ones and zeros here.
|
|
|
|
<item> Check that you've used things like functions and global
|
|
variables in a consistent way (eg if you've called a non-existent
|
|
function, it'll complain).
|
|
|
|
<item> If you're trying to produce an executable from several source
|
|
code files, work out how to fit them all together.
|
|
|
|
<item> Work out how to produce something that the system's run-time
|
|
loader will be able to load into memory and run.
|
|
|
|
<item> (Finally!) Write the executable on the file system.
|
|
</enum>
|
|
|
|
The word ``compiling'' is often used to refer to just steps 1 to 4 -
|
|
the others are referred to as ``linking''. Sometimes step 1 is
|
|
referred to as ``pre-processing'' and steps 3-4 as ``assembling''.
|
|
<p>
|
|
Fortunately, almost all this detail is hidden from you, as cc is a
|
|
front end that manages calling all these programs with the right
|
|
arguments for you; simply typing
|
|
|
|
<tscreen><verb>
|
|
cc foobar.c
|
|
</verb></tscreen>
|
|
|
|
will cause foobar.c to be compiled by all the steps above. If you have
|
|
more than one file to compile, just do something like
|
|
|
|
<tscreen><verb>
|
|
cc foo.c bar.c
|
|
</verb></tscreen>
|
|
|
|
Note that the syntax checking is just that - checking the syntax. It
|
|
won't check for any logical mistakes you may have made, like putting
|
|
the program into an infinite loop, or using a bubble sort when you
|
|
meant to use a binary sort. {In case you didn't know, a
|
|
binary sort is an efficient way of sorting things into order and a
|
|
bubble sort isn't.}
|
|
<p>
|
|
There are lots and lots of options for cc, which are all in the man
|
|
page. Here are a few of the most important ones, with examples of how
|
|
to use them.
|
|
|
|
<descrip>
|
|
<tag/-o/
|
|
The output name of the file. If you don't use this option, cc will
|
|
produce an executable called `a.out' (the reasons for this are buried
|
|
in the mists of history).
|
|
|
|
Example:-
|
|
<tscreen><verb>
|
|
cc foobar.c executable is a.out
|
|
cc -o foobar foobar.c executable is foobar
|
|
</verb></tscreen>
|
|
|
|
<tag/-c/
|
|
Just compile the file, don't link it. Useful for toy programs where
|
|
you just want to check the syntax, or if you're using a Make file.
|
|
|
|
Example:-
|
|
|
|
<tscreen><verb>
|
|
cc -c foobar.c
|
|
</verb></tscreen>
|
|
|
|
This will produce an ``object file'' (not an executable) called
|
|
`foobar.o'. This can be linked together with other object files
|
|
into an executable.
|
|
|
|
<tag/-g/
|
|
|
|
Create a debug version of the executable. This makes the compiler
|
|
put information into the executable about which line of which
|
|
source file corresponds to which function call. A debugger can use
|
|
this information to show the source code as you step through the
|
|
program, which is <it /very/ useful; the disadvantage is that all
|
|
this extra information makes the program much bigger. Normally,
|
|
you compile with -g while you're developing a program and then
|
|
compile a ``release version'' without -g when you're satisfied it
|
|
works properly.
|
|
|
|
Example:-
|
|
|
|
<tscreen><verb>
|
|
cc -g foobar.c
|
|
</verb></tscreen>
|
|
|
|
This will produce a debug version of the program. (Note, we didn't use
|
|
the -o flag to specify the executable name, so we'll get an executable
|
|
called `a.out'. Producing a debug version called `foobar' is left as an
|
|
exercise for the reader!)
|
|
|
|
<tag/-O/
|
|
Create an optimised version of the executable. The compiler performs
|
|
various clever tricks to try and produce an executable that runs faster
|
|
than normal. You can add a number after the `O' to specify a higher
|
|
level of optimisation, but this often exposes bugs in the compiler's
|
|
optimiser. For instance, the version of cc that comes with the 2.1.0
|
|
release of FreeBSD is known to produce bad code with the `-O2'
|
|
option in some circumstances.
|
|
|
|
Optimisation is usually only turned on when compiling a release version.
|
|
|
|
Example:-
|
|
|
|
<tscreen><verb>
|
|
cc -O -o foobar foobar.c
|
|
</verb></tscreen>
|
|
|
|
This will produce an optimised version of `foobar'.
|
|
<p>
|
|
The following three flags will force cc to check that your code
|
|
complies to the relevant international standard (often referred to
|
|
as the ``ANSI'' standard, though strictly speaking it's an ISO
|
|
standard).
|
|
|
|
<tag/-Wall/
|
|
Enable all the warnings which the authors of cc believe are
|
|
worthwhile. Despite the name, it will not enable all the warnings
|
|
cc is capable of.
|
|
|
|
<tag/-ansi/
|
|
Turn off most (but not all) of the non-standard features provided
|
|
by cc. Despite the name, it does not guarantee strictly that your
|
|
code will comply to the standard.
|
|
|
|
<tag/-pedantic/
|
|
Turn off <it /all/ cc's non-standard features.
|
|
<p>
|
|
Without these flags, cc will allow you to use some of its
|
|
non-standard extensions to the standard. Some of these are very
|
|
useful, but will not work with other compilers - in fact, one of
|
|
the main aims of the standard is to allow people to write code
|
|
that will work with any compiler on any system. (This is known as
|
|
``portable code'').
|
|
<p>
|
|
Generally, you should try to make your code as portable as
|
|
possible, as otherwise you may have to completely re-write the
|
|
program later to get it to work somewhere else - and who knows
|
|
what you may be using in a few years time?
|
|
|
|
Example:-
|
|
<tscreen><verb>
|
|
cc -Wall -ansi -pedantic -o foobar foobar.c
|
|
</verb></tscreen>
|
|
will produce an executable `foobar' after checking foobar.c for standard
|
|
compliance.
|
|
|
|
<tag/-l/
|
|
Specify a library to be used during when linking.
|
|
<p>
|
|
The most common example of this is when compiling a program that
|
|
uses some of the mathematical functions in C. Unlike most other
|
|
platforms, these are in a separate library from the standard C one
|
|
and you have to tell the compiler to add it.
|
|
<p>
|
|
The rule is that if the library is called `libsomething.a', you
|
|
give cc the argument `-lsomething'. For example, the maths library
|
|
is `libm.a', so you give cc the argument `-lm'. A common
|
|
``gotcha'' with the maths library is that it has to be the last
|
|
library on the command line.
|
|
<p>
|
|
Example:-
|
|
<tscreen><verb>
|
|
cc -o foobar foobar.c -lm
|
|
</verb></tscreen>
|
|
will link the maths library functions into `foobar'.
|
|
<p>
|
|
If you're compiling C++ code, you need to add `-lg++' to the
|
|
command line argument, to link the C++ library functions.
|
|
Alternatively, you can run c++ instead of cc, which does this for
|
|
you.
|
|
<p>
|
|
Example:-
|
|
<tscreen><verb>
|
|
cc -o foobar foobar.cc -lg++
|
|
c++ -o foobar foobar.cc
|
|
</verb></tscreen>
|
|
will both produce an executable `foobar' from the C++ source file
|
|
`foobar.cc'. Note that, on Unix systems, C++ source files
|
|
traditionally end in `.C', `.cxx' or `.cc', rather than the
|
|
DOS-style `.cpp' (which was already used for something else). gcc
|
|
used to rely on this to work out what kind of compiler to use on
|
|
the source file; however, this restriction no longer applies, so
|
|
you may now call your C++ files `.cpp' with impunity!
|
|
{c++ can also be invoked as g++ on FreeBSD.}
|
|
</descrip>
|
|
|
|
<sect1><heading>Common cc Queries and Problems</heading>
|
|
<p>
|
|
Q. I'm trying to write a program which uses the sin() function and I get
|
|
an error like this. What does it mean?
|
|
|
|
<tscreen><verb>
|
|
/var/tmp/cc0143941.o: Undefined symbol `_sin' referenced from text segment
|
|
</verb></tscreen>
|
|
|
|
A. When using mathematical functions like sin(), you have to tell cc to link
|
|
in the maths library, like so:-
|
|
<tscreen><verb>
|
|
cc -o foobar foobar.c -lm
|
|
</verb></tscreen>
|
|
Q. All right, I wrote this simple program to practice using -lm. All
|
|
it does is raise 2.1 to the power of 6.
|
|
<code>
|
|
#include <stdio.h>
|
|
|
|
int main() {
|
|
float f;
|
|
|
|
f = pow(2.1, 6);
|
|
printf("2.1 ^ 6 = %f\n", f);
|
|
return 0;
|
|
}
|
|
</code>
|
|
and I compiled it as
|
|
|
|
<tscreen><verb>
|
|
gcc temp.c -lm
|
|
</verb></tscreen>
|
|
|
|
like you said I should, but I get this when I run it:-
|
|
<tscreen><verb>
|
|
$ ./a.out
|
|
2.1 ^ 6 = 1023.000000
|
|
</verb></tscreen>
|
|
|
|
This is <it /not/ the right answer! What the %$&#'s going on?
|
|
<p>
|
|
A. When the compiler sees you call a function, it checks if it's
|
|
already seen a prototype for it. If it hasn't, it assumes the function
|
|
returns an int, which is definitely not what you want here.
|
|
<p>
|
|
Q. So how do I fix this?
|
|
<p>
|
|
A. The prototypes for the mathematical functions are in math.h. If you
|
|
include this file, the compiler will be able to find the prototype and
|
|
it'll stop doing strange things to your calculation!
|
|
|
|
<code>
|
|
#include <math.h>
|
|
#include <stdio.h>
|
|
|
|
int main() {
|
|
...
|
|
</code>
|
|
<p>
|
|
<tscreen><verb>
|
|
$ ./a.out
|
|
2.1 ^ 6 = 85.766121
|
|
</verb></tscreen>
|
|
|
|
Morale: if you're using any of the mathematical functions, always
|
|
include math.h and remember to link in the maths library.
|
|
|
|
Q. I've compiled a file called `foobar.c' and I can't find an executable
|
|
called `foobar'. Where's it gone?
|
|
<p>
|
|
A. cc will call the executable `a.out' unless you tell it differently. Use
|
|
the -o option, eg
|
|
<tscreen><verb>
|
|
cc -o foobar foobar.c
|
|
</verb></tscreen>
|
|
Q. OK, I've got an executable called `foobar', I can see it when I do
|
|
`ls', but when I type in 'foobar' at the command prompt it tells me
|
|
there's no such file. Why can't it find it?
|
|
<p>
|
|
A. Unlike DOS, Unix won't look in the current directory when it's
|
|
trying to find out which executable you want it to run, unless you
|
|
tell it to. Either type `./foobar', which means ``run the file
|
|
called `foobar' in the current directory'', or change your PATH
|
|
environment variable so that it looks something like
|
|
<tscreen><verb>
|
|
bin:/usr/bin:/usr/local/bin:.
|
|
</verb></tscreen>
|
|
(The dot at the end means ``look in the current directory if it's not in
|
|
any of the others'')
|
|
<p>
|
|
Q. I called my executable `test', but nothing happens when I run
|
|
it. What's going on?
|
|
<p>
|
|
A. Most Unix systems have a program called `test' in /usr/bin and the
|
|
shell's picking that one up before it gets to checking the current
|
|
directory. Either type
|
|
|
|
<tscreen><verb>
|
|
./test
|
|
</verb></tscreen>
|
|
|
|
or choose a better name for your program!
|
|
<p>
|
|
Q. I compiled my program and it seemed to run all right at first, then
|
|
there was an error and it said something about ``core
|
|
dumped''. What does that mean?
|
|
<p>
|
|
A. The name ``core dump'' dates back to the very early days of Unix,
|
|
when the machines used core memory for storing data. Basically, if
|
|
the program failed under certain conditions, the system would write
|
|
the contents of core memory to disk in a file called ``core'',
|
|
which the programmer could then pore over to find out what went
|
|
wrong.
|
|
<p>
|
|
Q. Fascinating stuff, but what I am supposed to do now?
|
|
<p>
|
|
A. Use gdb to analyse the core (see Debugging).
|
|
<p>
|
|
Q. When my program dumped core, it said something about a segmentation
|
|
fault. What's that?
|
|
<p>
|
|
A. This basically means that your program tried to perform some sort
|
|
of illegal operation on memory; Unix is designed to protect the
|
|
operating system and other programs from ``rogue'' programs.
|
|
<p>
|
|
Common causes for this are:-
|
|
<itemize>
|
|
<item> Trying to write to a NULL pointer, eg
|
|
<code>
|
|
char *foo = NULL;
|
|
strcpy(foo, "bang!");
|
|
</code>
|
|
<item> Using a pointer that hasn't been initialised, eg
|
|
<code>
|
|
char *foo;
|
|
strcpy(foo, "bang!");
|
|
</code>
|
|
The pointer will have some random value that, with luck,
|
|
will point into an area of memory that isn't available to
|
|
your program and the kernel will kill your program before
|
|
it can do any damage. If you're unlucky, it'll point
|
|
somewhere inside your own program and corrupt one of your
|
|
data structures, causing the program to fail mysteriously.
|
|
<p>
|
|
<item> Trying to access past the end of an array, eg
|
|
<code>
|
|
int bar[20];
|
|
bar[27] = 6;
|
|
</code>
|
|
<item> Trying to store something in read-only memory, eg
|
|
<code>
|
|
char *foo = "My string";
|
|
strcpy(foo, "bang!");
|
|
</code>
|
|
(Unix compilers often put string literals like ``My string'' into
|
|
read-only areas of memory).
|
|
|
|
<item> Doing naughty things with malloc() and free(), eg
|
|
<code>
|
|
char bar[80];
|
|
free(bar);
|
|
</code>
|
|
or
|
|
<code>
|
|
char *foo = malloc(27);
|
|
free(foo);
|
|
free(foo);
|
|
</code>
|
|
</itemize>
|
|
(Note making one of these mistakes will not always lead to an
|
|
error, but they are always bad practice. Some systems and
|
|
compilers are more tolerant than others, which is why programs
|
|
that ran well on one system can crash when you try them on an
|
|
another)
|
|
<p>
|
|
Q. Sometimes when I get a core dump it says ``bus error''. It says in
|
|
my Unix book that this means a hardware problem, but the computer
|
|
still seems to be working. Is this true?
|
|
<p>
|
|
A. No, fortunately not (unless of course you really do have a hardware
|
|
problem...). This is usually another way of saying that you
|
|
accessed memory in a way you shouldn't have.
|
|
<p>
|
|
Q. This dumping core business sounds as though it could be quite
|
|
useful, if I can make it happen when I want to. Can I do this, or
|
|
do I have to wait until there's an error?
|
|
<p>
|
|
A. Yes, just go to another console or xterm, do
|
|
|
|
<tscreen><verb>
|
|
ps
|
|
</verb></tscreen>
|
|
|
|
to find out the process ID of your program, and do
|
|
|
|
<tscreen><verb>
|
|
kill -ABRT <pid>
|
|
</verb></tscreen>
|
|
|
|
This is useful if your program has got stuck in an infinite loop,
|
|
for instance. (If your program traps SIGABRT, there are several
|
|
other signals which have a similar effect).
|
|
|
|
<sect><heading>Make</heading>
|
|
<p>
|
|
<sect1><heading>What is make?</heading>
|
|
<p>
|
|
When you're working on a simple program with only one or two source
|
|
files, typing in
|
|
|
|
<tscreen><verb>
|
|
cc file1.c file2.c
|
|
</verb></tscreen>
|
|
|
|
is not too bad, but it quickly becomes very tedious when there are
|
|
several files - and it can take a while to compile, too.
|
|
<p>
|
|
One way to get around this is to use object files and only recompile
|
|
the source file if the source code has changed. So we could have
|
|
something like:-
|
|
|
|
<tscreen><verb>
|
|
cc file1.o file2.o ... file37.c ...
|
|
</verb></tscreen>
|
|
|
|
if we'd changed file37.c, but not any of the others, since the last
|
|
time we compiled.
|
|
<p>
|
|
This may speed up the compilation quite a bit, but doesn't solve the
|
|
typing problem.
|
|
<p>
|
|
Or we could write a shell script to solve the typing problem, but it
|
|
would have to re-compile everything, making it very inefficient on a
|
|
large project.
|
|
<p>
|
|
What happens if we have hundreds of source files lying about? What if
|
|
we're working in a team with other people who forget to tell us when
|
|
they've changed one of their source files that we use?
|
|
<p>
|
|
Perhaps we could put the two solutions together and write something
|
|
like a shell script that would contain some kind of magic rule saying
|
|
when a source file needs compiling. Now all we need now is a program
|
|
that can understand these rules, as it's a bit too complicated for the
|
|
shell.
|
|
<p>
|
|
This program is called <tt /make/. It reads in a file, called a make
|
|
file, that tells it how different files depend on each other, and
|
|
works out which files need to be re-compiled and which ones don't. For
|
|
example, a rule could say something like ``if fromboz.o is older than
|
|
fromboz.c, that means someone must have changed fromboz.c, so it needs
|
|
to be re-compiled.'' The make file also has rules telling make <it
|
|
/how/ to re-compile the source file, making it a much more powerful
|
|
tool.
|
|
<p>
|
|
Make files are typically kept in the same directory as the source they
|
|
apply to, and can be called `makefile', `Makefile' or `MAKEFILE'. Most
|
|
programmers use the name 'Makefile', as this puts it near the top of a
|
|
directory listing, where it can easily be seen (they don't use the
|
|
`MAKEFILE' form as block capitals are often used for documentation
|
|
files like `README').
|
|
|
|
<sect1><heading>Example of using make</heading>
|
|
<p>
|
|
Here's a very simple make file:-
|
|
<tscreen><verb>
|
|
foo: foo.c
|
|
cc -o foo foo.c
|
|
</verb></tscreen>
|
|
It consists of two lines, a dependency line and a creation line.
|
|
<p>
|
|
The dependency line here consists of the name of the program (known as
|
|
``the target''), followed by a colon, then a gap, then the name of the
|
|
source file. When make reads this line, it looks to see if `foo'
|
|
exists; if it exists, it compares the time 'foo' was last modified to
|
|
the time `foo.c' was last modified. If 'foo' does not exist, or is
|
|
older than `foo.c', it then looks at the creation line to find out
|
|
what to do. In other words, this is the rule for working out when
|
|
foo.c needs to be re-compiled.
|
|
<p>
|
|
The creation line starts with a tab (press the tab key) and then the
|
|
command you would type to create `foo' if you were doing it at a
|
|
command prompt. If `foo' is out of date, or does not exist, `make'
|
|
then executes this command to create it. In other words, this is the
|
|
rule which tells make how to re-compile foo.c.
|
|
<p>
|
|
So, when you type `make', it will make sure that `foo' is up to date
|
|
with respect to your latest changes to `foo.c'. This principle can be
|
|
extended to Makefiles with hundreds of targets - in fact, on FreeBSD,
|
|
it is possible to compile the entire operating system just by typing
|
|
`make world' in the appropriate directory!
|
|
<p>
|
|
Another useful property of make files is that the targets don't have
|
|
to be programs. For instance, we could have a make file that looks
|
|
like this:-
|
|
|
|
<tscreen><verb>
|
|
foo: foo.c
|
|
cc -o foo foo.c
|
|
|
|
install:
|
|
cp foo /home/me
|
|
</verb></tscreen>
|
|
|
|
We can tell make which target we want to make by typing
|
|
|
|
<tscreen><verb>
|
|
make <target>
|
|
</verb></tscreen>
|
|
|
|
make will then only look at that target and ignore any
|
|
others. For example, if we type `make foo' with the make file above,
|
|
make will ignore the 'install' target.
|
|
<p>
|
|
If we just type `make' on its own, make will always look at the first
|
|
target and then stop without looking at any others. So if we typed
|
|
`make' here, it will just go to the `foo' target, re-compile `foo' if
|
|
necessary, and then stop without going on to the `install' target.
|
|
<p>
|
|
Notice that the `install' target doesn't actually depend on anything!
|
|
This means that the command on the following line is always executed
|
|
when we try to make that target by typing `make install'. In this
|
|
case, it will copy `foo' into the user's home directory. This is often
|
|
used by application make files, so that the application can be
|
|
installed in the correct directory when it has been correctly
|
|
compiled.
|
|
<p>
|
|
This is a slightly confusing subject to try and explain. If you don't
|
|
quite understand how make works, the best thing to do is to write a
|
|
simple program like ``hello world'' and a make file like the one above
|
|
and experiment. Then progress to using more than one source file, or
|
|
having the source file include a header file. (The `touch' command is
|
|
very useful here - it changes the date on a file without you having to
|
|
edit it).
|
|
|
|
<sect1><heading>FreeBSD Make Files</heading>
|
|
<p>
|
|
Make files can be rather complicated to write. Fortunately, BSD-based
|
|
systems like FreeBSD come with some very powerful ones as part of the
|
|
system.
|
|
<p>
|
|
One very good example of this is the FreeBSD ports system. Here's the
|
|
essential part of a typical ports Makefile:-
|
|
|
|
<code>
|
|
MASTER_SITES= ftp://freefall.cdrom.com/pub/FreeBSD/LOCAL_PORTS/
|
|
DISTFILES= scheme-microcode+dist-7.3-freebsd.tgz
|
|
|
|
.include <bsd.port.mk>
|
|
</code>
|
|
|
|
Now, if we go to the directory for this port and type make, the
|
|
following happens:-
|
|
|
|
<enum>
|
|
|
|
<item> A check is made to see if the source code for this port is
|
|
already on the system.
|
|
|
|
<item> If it isn't, an FTP connection to the URL in ``MASTER_SITES''
|
|
is set up to download the source.
|
|
|
|
<item> The checksum for the source is calculated and compared it with
|
|
one for a known, good, copy of the source. This is to make sure that
|
|
the source was not corrupted while in transit.
|
|
|
|
<item> Any changes required to make the source work on FreeBSD are
|
|
applied - this is known as ``patching''.
|
|
|
|
<item> Any special configuration needed for the source is done. (Many
|
|
Unix program distributions try to work out which version of Unix they
|
|
are being compiled on and which optional Unix features are present -
|
|
this is where they are given the information in the FreeBSD ports
|
|
scenario).
|
|
|
|
<item> The source code for the program is compiled. In effect, we
|
|
change to the directory where the source was unpacked and do 'make' -
|
|
the program's own make file has the necessary information to build the
|
|
program.
|
|
|
|
<item> We now have a compiled version of the program. If we wish, we
|
|
can test it now; when we feel confident about the program, we can type
|
|
'make install'. This will cause the program and any supporting files
|
|
it needs to be copied into the correct location; an entry is also made
|
|
into a ``package database'', so that the port can easily be
|
|
uninstalled later if we change our mind about it.
|
|
|
|
</enum>
|
|
|
|
Now I think you'll agree that's rather impressive for a four line
|
|
script!
|
|
<p>
|
|
The secret lies in the last line, which tells make to look in the
|
|
system make file called `bsd.port.mk'. It's easy to overlook this
|
|
line, but this is where all the clever stuff comes from - someone has
|
|
written a make file that tells make to do all the things above (plus a
|
|
couple of other things I didn't mention, not to mention handling any
|
|
errors that may occur) and anyone can get access to that just by
|
|
putting a single line in their own make file!
|
|
<p>
|
|
If you want to have a look at these system make files, they're in
|
|
/usr/share/mk, but it's probably best to wait until you've had a bit
|
|
of practice with make files, as they are very complicated (and if you
|
|
do look at them, make sure you have a flask of strong coffee handy!)
|
|
|
|
<sect1><heading>More advanced uses of make</heading>
|
|
<p>
|
|
Make is a very powerful tool, and can do much more than the simple
|
|
example above shows. Unfortunately, there are several different
|
|
versions of make, and they all differ considerably. The best way to
|
|
learn what they can do is probably to read the documentation -
|
|
hopefully this introduction will have given you a base from which you
|
|
can do this.
|
|
<p>
|
|
The version of make that comes with FreeBSD is the Berkeley make;
|
|
there is a tutorial for it in /usr/share/doc/psd/12.make. To view it,
|
|
do
|
|
|
|
<tscreen><verb>
|
|
zmore paper.ascii.gz
|
|
</verb></tscreen>
|
|
|
|
in that directory.
|
|
<p>
|
|
Many applications in the ports use GNU make, which has a very good set
|
|
of `info' pages. If you have installed any of these ports, GNU make
|
|
will automatically have been installed as `gmake'. It's also available
|
|
as a port and package in it's own right.
|
|
<p>
|
|
To view the info pages for GNU make, you will have to edit the `dir'
|
|
file in the /usr/local/info directory to add an entry for it. This
|
|
involves adding a line like
|
|
|
|
<tscreen><verb>
|
|
* Make: (make). The GNU Make utility.
|
|
</verb></tscreen>
|
|
|
|
to the file. Once you have done this, you can type `info' and then
|
|
select make from the menu (or in Emacs, do C-h i).
|
|
|
|
<sect><heading>Debugging</heading>
|
|
<p>
|
|
<sect1><heading>The Debugger</heading>
|
|
<p>
|
|
The debugger that comes with FreeBSD is called `gdb' (GNU debugger). You
|
|
start it up by typing
|
|
|
|
<tscreen><verb>
|
|
gdb <progname>
|
|
</verb></tscreen>
|
|
|
|
although most people prefer to run it inside Emacs. You can do this by
|
|
|
|
<tscreen><verb>
|
|
M-x gdb RET <progname> RET.
|
|
</verb></tscreen>
|
|
|
|
Using a debugger allows you to run the program under more controlled
|
|
circumstances. Typically, you can step through the program a line at a
|
|
time, inspect the value of variables, change them, tell the debugger to run
|
|
up to a certain point and then stop, and so on. You can even attach to a
|
|
program that's already running, or load a core file to investigate why the
|
|
program crashed.
|
|
<p>
|
|
It's even possible to debug the kernel, though that's a little trickier
|
|
than the user applications we'll be discussing in this section.
|
|
<p>
|
|
gdb has quite good on-line help, as well as a set of info pages, so this
|
|
section will concentrate on a few of the basic commands.
|
|
<p>
|
|
Finally, if you find its text-based command-prompt style off-putting,
|
|
there's a graphical front-end for it <htmlurl
|
|
url="ftp://ftp.freebsd.org:pub/FreeBSD/ports/devel/xxgdb.tgz"
|
|
name="xxgdb"> in the ports.
|
|
<p>
|
|
This section is intended to be an introduction to using gdb and does
|
|
not cover specialised topics such as debugging the kernel.
|
|
|
|
<sect1><heading>Running a program in the debugger</heading>
|
|
<p>
|
|
You'll need to have compiled the program with the `-g' option to get the
|
|
most out of using gdb. It will work without, but you'll only see the name
|
|
of the function you're in, instead of the source code. If you see a line
|
|
like
|
|
|
|
<tscreen><verb>
|
|
...(no debugging symbols found)...
|
|
</verb></tscreen>
|
|
|
|
when gdb starts up, you'll know that the program wasn't compiled with
|
|
the `-g' option.
|
|
<p>
|
|
At the gdb prompt, type `break main'. This will tell the debugger to
|
|
skip over the preliminary set-up code in the program and start at the
|
|
beginning of your code. Now type `run' to start the program - it will
|
|
start at the beginning of the set-up code and then get stopped by the
|
|
debugger when it calls main(). (If you've ever wondered where main()
|
|
gets called from, now you know!).
|
|
<p>
|
|
You can now step through the program, a line at a time, by pressing
|
|
`n'. If you get to a function call, you can step into it by pressing
|
|
`s'. Once you're in a function call, you can return from stepping into
|
|
a function call by pressing `f'. You can also use `up' and `down' to
|
|
take a quick look at the caller.
|
|
<p>
|
|
Here's a simple example of how to spot a mistake in a program with
|
|
gdb. This is our program (with a deliberate mistake):-
|
|
|
|
<code>
|
|
#include <stdio.h>
|
|
|
|
int bazz(int anint);
|
|
|
|
main() {
|
|
int i;
|
|
|
|
printf("This is my program\n");
|
|
bazz(i);
|
|
return 0;
|
|
}
|
|
|
|
int bazz(int anint) {
|
|
printf("You gave me %d\n", anint);
|
|
return anint;
|
|
}
|
|
</code>
|
|
|
|
This program sets i to be 5 and passes it to a function bazz() which prints
|
|
out the number we gave it.
|
|
<p>
|
|
When we compile and run the program we get
|
|
|
|
<tscreen><verb>
|
|
cc -g -o temp temp.c
|
|
./temp
|
|
This is my program
|
|
anint = 4231
|
|
</verb></tscreen>
|
|
|
|
That wasn't what we expected! Time to see what's going on!
|
|
|
|
<tscreen><verb>
|
|
Current directory is ~/tmp/
|
|
GDB is free software and you are welcome to distribute copies of it
|
|
under certain conditions; type "show copying" to see the conditions.
|
|
There is absolutely no warranty for GDB; type "show warranty" for details.
|
|
GDB 4.13 (i386-unknown-freebsd),
|
|
Copyright 1994 Free Software Foundation, Inc...
|
|
(gdb) break main # Skip the set-up code
|
|
Breakpoint 1 at 0x160f: file temp.c, line 9. # gdb puts breakpoint at main()
|
|
(gdb) run # Run as far as main()
|
|
Starting program: /home/james/tmp/temp # Program starts running
|
|
|
|
Breakpoint 1, main () at temp.c:9 # gdb stops at main()
|
|
(gdb) n # Go to next line
|
|
This is my program # Program prints out "This .."
|
|
(gdb) s # step into bazz()
|
|
bazz (anint=4231) at temp.c:17 # gdb displays stack frame
|
|
</verb></tscreen>
|
|
|
|
Hang on a minute! How did anint get to be 4231? Didn't we set it to be 5
|
|
in main()? Let's move up to main() and have a look.
|
|
|
|
<tscreen><verb>
|
|
(gdb) up # Move up call stack
|
|
#1 0x1625 in main () at temp.c:11 # gdb displays stack frame
|
|
(gdb) p i # Show us the value of i
|
|
$1 = 4231 # gdb displays 4231
|
|
</verb></tscreen>
|
|
|
|
Oh dear! Looking at the code, we forgot to initialise i. We meant to put
|
|
|
|
<code>
|
|
...
|
|
main() {
|
|
int i;
|
|
|
|
i = 5;
|
|
printf("This is my program\n");
|
|
...
|
|
</code>
|
|
|
|
but we missed the `i=5;' line out. As we didn't initialise i, it had
|
|
whatever number happened to be in that area of memory when the program
|
|
ran, which in this case happened to be 4231.
|
|
<p>
|
|
Note that gdb displays the stack frame every time we go into or out of
|
|
a function, even if we're using `up' and `down' to move around the
|
|
call stack. This shows the name of the function and the values of its
|
|
arguments, which helps us keep track of where we are and what's going
|
|
on. (The stack is a storage area where the program stores information
|
|
about the arguments passed to functions and where to go when it
|
|
returns from a function call).
|
|
|
|
<sect1><heading>Examining a core file</heading>
|
|
<p>
|
|
A core file is basically a file which contains the complete state of
|
|
the process when it crashed. In ``the good old days'', programmers had
|
|
to print out hex listings of core files and sweat over machine code
|
|
manuals, but now life is a bit easier. Incidentally, under FreeBSD and
|
|
other 4.4BSD systems, a core file is called ``progname.core'' instead
|
|
of just core, to make it clearer which program a core file belongs to.
|
|
<p>
|
|
To examine a core file, start up gdb in the usual way. Instead of
|
|
typing `break' or `run', type
|
|
|
|
<tscreen><verb>
|
|
core progname.core
|
|
</verb></tscreen>
|
|
|
|
(if you're not in the same directory as the core file, you'll have to
|
|
do `dir /path/to/core/file' first).
|
|
<p>
|
|
You should see something like this:-
|
|
|
|
<tscreen><verb>
|
|
Current directory is ~/tmp/
|
|
GDB is free software and you are welcome to distribute copies of it
|
|
under certain conditions; type "show copying" to see the conditions.
|
|
There is absolutely no warranty for GDB; type "show warranty" for details.
|
|
GDB 4.13 (i386-unknown-freebsd),
|
|
Copyright 1994 Free Software Foundation, Inc...
|
|
(gdb) core a.out.core
|
|
Core was generated by `a.out'.
|
|
Program terminated with signal 11, Segmentation fault.
|
|
Cannot access memory at address 0x7020796d.
|
|
#0 0x164a in foobar (some_arg=0x5) at temp.c:17
|
|
</verb></tscreen>
|
|
|
|
In this case, the program was called `a.out', so the core file is
|
|
called `a.out.core'. We can see that the program crashed due to trying
|
|
to access an area in memory that was not available to it in a function
|
|
called `bazz'.
|
|
<p>
|
|
Sometimes it's useful to be able to see how a function was called, as
|
|
the problem could have occurred a long way up the call stack in a
|
|
complex program. The `bt' command causes gdb to print out a back-trace
|
|
of the call stack:-
|
|
|
|
<tscreen><verb>
|
|
(gdb) bt
|
|
#0 0x164a in bazz (anint=0x5) at temp.c:17
|
|
#1 0xefbfd888 in end ()
|
|
#2 0x162c in main () at temp.c:11
|
|
</verb></tscreen>
|
|
|
|
The end() function is called when a program crashes; in this case, the
|
|
bazz() function was called from main().
|
|
|
|
<sect1><heading>Attaching to a running program</heading>
|
|
<p>
|
|
One of the neatest features about gdb is that it can attach to a
|
|
program that's already running. (Of course, that assumes you have
|
|
sufficient permissions to do so). A common problem is when you are
|
|
stepping through a program that forks, and you want to trace the
|
|
child, but the debugger will only let you trace the parent.
|
|
<p>
|
|
What you do is start up another gdb, use `ps' to find the process ID
|
|
for the child, and do
|
|
|
|
<tscreen><verb>
|
|
attach <pid>
|
|
</verb></tscreen>
|
|
|
|
in gdb, and then debug as usual.
|
|
<p>
|
|
``That's all very well,'' you're probably thinking, ``but by the time
|
|
I've done that, the child process will be over the hill and far
|
|
away''. Fear not, gentle reader, here's how to do it (courtesy of the
|
|
gdb info pages):-
|
|
|
|
<tscreen><verb>
|
|
...
|
|
if ((pid = fork()) < 0) /* _Always_ check this */
|
|
error();
|
|
else if (pid == 0) { /* child */
|
|
int PauseMode = 1;
|
|
|
|
while (PauseMode)
|
|
sleep(10); /* Wait until someone attaches to us */
|
|
...
|
|
} else { /* parent */
|
|
...
|
|
</verb></tscreen>
|
|
|
|
Now all you have to do is attach to the child, set PauseMode to 0, and
|
|
wait for the sleep() call to return!
|
|
|
|
<sect><heading>Using Emacs as a Development Environment</heading>
|
|
<p>
|
|
<sect1><heading>Emacs</heading>
|
|
<p>
|
|
Unfortunately, Unix systems don't come with the kind of
|
|
everything-you-ever-wanted-and-lots-more-you-didn't-in-one-gigantic-package
|
|
integrated development environments that other systems have (at least,
|
|
not unless you pay out very large sums of money). However, it is
|
|
possible to set up your own environment. It may not be as pretty, and
|
|
it may not be quite as integrated, but you can set it up the way you
|
|
want it. And it's free. And you have the source to it.
|
|
<p>
|
|
The key to it all is Emacs. Now there are some people who loathe it,
|
|
but many who love it. If you're one of the former, I'm afraid this
|
|
section will hold little of interest to you. Also, you'll need a fair
|
|
amount of memory to run it - I'd recommend 8MB in text mode and 16MB
|
|
in X as the bare minimum to get reasonable performance.
|
|
<p>
|
|
Emacs is basically a highly customisable editor - indeed, it has been
|
|
customised to the point where it's more like an operating system than
|
|
an editor! (Many developers and sysadmins do in fact spend practically
|
|
all their time working inside Emacs, leaving it only to log out).
|
|
<p>
|
|
It's impossible even to summarise everything Emacs can do here, but
|
|
here are some of the features of interest to developers:-
|
|
|
|
<itemize>
|
|
<item> Very powerful editor, allowing search-and-replace on both
|
|
strings and regular expressions (patterns), jumping to start/end of
|
|
block expression, etc, etc.
|
|
|
|
<item> Pull-down menus and online help.
|
|
|
|
<item> Language-dependent syntax highlighting and indentation.
|
|
|
|
<item> Completely customisable.
|
|
|
|
<item> You can compile and debug programs within Emacs.
|
|
|
|
<item> On a compilation error, you can jump to the offending line of source
|
|
code.
|
|
|
|
<item> Friendly-ish front-end to the `info' program used for reading GNU
|
|
hypertext documentation (including the documentation on Emacs).
|
|
|
|
<item> Friendly front-end to GDB, allowing you to look at the source code
|
|
as you step through your program.
|
|
|
|
<item> You can read Usenet news and mail while your program is compiling ;-)
|
|
</itemize>
|
|
|
|
And doubtless many more that I've overlooked.
|
|
<p>
|
|
Emacs can be installed on FreeBSD using <htmlurl
|
|
url="ftp://ftp.freebsd.org:pub/FreeBSD/packages/editors/emacs"
|
|
name="the Emacs package">.
|
|
<p>
|
|
Once it's installed, start it up and do C-h t to read an Emacs
|
|
tutorial - that means hold down the control key, press `h', let go of
|
|
the control key, and then press t. (Alternatively, you can you use
|
|
the mouse to select ``Emacs Tutorial'' from the ``Help'' menu).
|
|
<p>
|
|
Although Emacs does have menus, it's well worth learning the key
|
|
bindings, as it's much quicker when you're editing something to press
|
|
a couple of keys than to try and find the mouse and then click on the
|
|
right place. And, when you're talking to seasoned Emacs users, you'll
|
|
find they often casually throw around expressions like
|
|
|
|
<tscreen><verb>
|
|
M-x replace-s RET foo RET bar RET
|
|
</verb></tscreen>
|
|
|
|
so it's useful to know what they mean. And in any case, Emacs has far
|
|
too many useful functions for them to all fit on the menu bars.
|
|
<p>
|
|
Fortunately, it's quite easy to pick up the key-bindings, as they're
|
|
displayed next to the menu item. (My advice is to use the menu item
|
|
for, say, opening a file until you understand how it works and feel
|
|
confident with it, then try doing C-x C-f. When you're happy with
|
|
that, move on to another menu command).
|
|
<p>
|
|
If you can't remember what a particular combination of keys does,
|
|
select ``Describe Key'' from the ``Help'' menu and type it in - Emacs
|
|
will tell you what it does. You can also use the ``Command Apropos''
|
|
menu item to find out all the commands which contain a particular word
|
|
in them, with the key binding next to it.
|
|
<p>
|
|
By the way, the expression above means hold down the Meta key, press
|
|
`x', release the Meta key, type replace-s (short for ``replace-string''
|
|
- another feature of Emacs is that you can abbreviate commands), press
|
|
the return key, type foo (the string you want replaced), press the
|
|
return key, type bar (the string you want to replace ``foo'' with) and
|
|
press return again. Emacs will then do the search-and-replace
|
|
operation you've just requested.
|
|
<p>
|
|
If you're wondering what on earth the Meta key is, it's a special key
|
|
that many Unix workstations have. Unfortunately, PC's don't have one,
|
|
so it's usually the ``alt'' key (or if you're unlucky, the ``escape''
|
|
key).
|
|
<p>
|
|
Oh, and to get out of Emacs, do C-c C-x (that means hold down the
|
|
control key, press `c', press `x' and release the control key). If you
|
|
have any unsaved files open, Emacs will ask you if you want to save
|
|
them. (Ignore the bit in the documentation where it says C-z is the
|
|
usual way to leave Emacs - that leaves Emacs hanging around in the
|
|
background, and is only really useful if you're on a system which
|
|
doesn't have virtual terminals).
|
|
|
|
<sect1><heading>Configuring Emacs</heading>
|
|
<p>
|
|
Emacs does many wonderful things, some of them are built in, some of
|
|
them need to be configured.
|
|
<p>
|
|
Instead of using a proprietary macro language for configuration, Emacs
|
|
uses a version of Lisp specially adapted for editors, known as Emacs
|
|
Lisp. This can be quite useful if you want to go on and learn
|
|
something like Common Lisp, as it's considerably smaller than Common
|
|
Lisp (although still quite big!).
|
|
<p>
|
|
The best way to learn Emacs Lisp is to download the <htmlurl
|
|
url="ftp://prep.ai.mit.edu:pub/gnu/elisp-manual-19-2.4.tar.gz"
|
|
name="Emacs Tutorial">
|
|
<p>
|
|
However, there's no need to actually know any Lisp to get started with
|
|
configuring Emacs, as I've included a sample ``.emacs'' file, which
|
|
should be enough to get you started. Just copy it into your home
|
|
directory and restart Emacs if it's already running; it will read the
|
|
commands from the file and (hopefully) give you a useful basic setup.
|
|
|
|
<sect1><heading>A sample .emacs file</heading>
|
|
<p>
|
|
Unfortunately, there's far too much here to explain it in detail;
|
|
however there are one or two points worth mentioning.
|
|
|
|
<itemize>
|
|
<item> Everything beginning with a `;' is a comment and is ignored by Emacs.
|
|
|
|
<item> In the first line, the -*- Emacs-Lisp -*- is so that we can edit
|
|
the .emacs file itself within Emacs and get all the fancy features for
|
|
editing Emacs Lisp (Emacs usually tries to guess this based on the
|
|
filename, and may not get it right for .emacs).
|
|
|
|
<item> The `tab' key is bound to an indentation function in some modes, so
|
|
when you press the tab key, it will indent the current line of
|
|
code. If you want to put a tab character in whatever you're writing,
|
|
hold the control key down while you're pressing the tab key.
|
|
|
|
<item> This file supports syntax highlighting for C, C++, Perl, Lisp and
|
|
Scheme (by guessing the language from the filename).
|
|
|
|
<item> Emacs already has a pre-defined function called ``next-error''.
|
|
In a compilation output window, this allows you to move from one
|
|
compilation error to the next by doing M-n; we define a complementary
|
|
function, ``previous-error'', that allows you to go to a previous
|
|
error by doing M-p. The nicest feature of all is that C-c C-c will
|
|
open up the source file in which the error occurred and jump to the
|
|
appropriate line.
|
|
|
|
<item> We enable Emacs's ability to act as a server, so that if you're doing
|
|
something outside Emacs and you want to edit a file, you can just
|
|
type in
|
|
<tscreen><verb>
|
|
emacsclient <filename>
|
|
</verb></tscreen>
|
|
|
|
and then you can edit the file in your Emacs! (Many Emacs users set
|
|
their EDITOR environment to `emacsclient' so this happens every time
|
|
they need to edit a file).
|
|
</itemize>
|
|
|
|
<tscreen><verb>
|
|
;; -*-Emacs-Lisp-*-
|
|
|
|
;; This file is designed to be re-evaled; use the variable first-time
|
|
;; to avoid any problems with this.
|
|
(defvar first-time t
|
|
"Flag signifying this is the first time that .emacs has been evaled")
|
|
|
|
;; Meta
|
|
(global-set-key "\M- " 'set-mark-command)
|
|
(global-set-key "\M-\C-h" 'backward-kill-word)
|
|
(global-set-key "\M-\C-r" 'query-replace)
|
|
(global-set-key "\M-r" 'replace-string)
|
|
(global-set-key "\M-g" 'goto-line)
|
|
(global-set-key "\M-h" 'help-command)
|
|
|
|
;; Function keys
|
|
(global-set-key [f1] 'manual-entry)
|
|
(global-set-key [f2] 'info)
|
|
(global-set-key [f3] 'repeat-complex-command)
|
|
(global-set-key [f4] 'advertised-undo)
|
|
(global-set-key [f5] 'eval-current-buffer)
|
|
(global-set-key [f6] 'buffer-menu)
|
|
(global-set-key [f7] 'other-window)
|
|
(global-set-key [f8] 'find-file)
|
|
(global-set-key [f9] 'save-buffer)
|
|
(global-set-key [f10] 'next-error)
|
|
(global-set-key [f11] 'compile)
|
|
(global-set-key [f12] 'grep)
|
|
(global-set-key [C-f1] 'compile)
|
|
(global-set-key [C-f2] 'grep)
|
|
(global-set-key [C-f3] 'next-error)
|
|
(global-set-key [C-f4] 'previous-error)
|
|
(global-set-key [C-f5] 'display-faces)
|
|
(global-set-key [C-f8] 'dired)
|
|
(global-set-key [C-f10] 'kill-compilation)
|
|
|
|
;; Keypad bindings
|
|
(global-set-key [up] "\C-p")
|
|
(global-set-key [down] "\C-n")
|
|
(global-set-key [left] "\C-b")
|
|
(global-set-key [right] "\C-f")
|
|
(global-set-key [home] "\C-a")
|
|
(global-set-key [end] "\C-e")
|
|
(global-set-key [prior] "\M-v")
|
|
(global-set-key [next] "\C-v")
|
|
(global-set-key [C-up] "\M-\C-b")
|
|
(global-set-key [C-down] "\M-\C-f")
|
|
(global-set-key [C-left] "\M-b")
|
|
(global-set-key [C-right] "\M-f")
|
|
(global-set-key [C-home] "\M-<")
|
|
(global-set-key [C-end] "\M->")
|
|
(global-set-key [C-prior] "\M-<")
|
|
(global-set-key [C-next] "\M->")
|
|
|
|
;; Mouse
|
|
(global-set-key [mouse-3] 'imenu)
|
|
|
|
;; Misc
|
|
(global-set-key [C-tab] "\C-q\t") ; Control tab quotes a tab.
|
|
(setq backup-by-copying-when-mismatch t)
|
|
|
|
;; Treat 'y' or <CR> as yes, 'n' as no.
|
|
(fset 'yes-or-no-p 'y-or-n-p)
|
|
(define-key query-replace-map [return] 'act)
|
|
(define-key query-replace-map [?\C-m] 'act)
|
|
|
|
;; Load packages
|
|
(require 'desktop)
|
|
(require 'tar-mode)
|
|
|
|
;; Pretty diff mode
|
|
(autoload 'ediff-buffers "ediff" "Intelligent Emacs interface to diff" t)
|
|
(autoload 'ediff-files "ediff" "Intelligent Emacs interface to diff" t)
|
|
(autoload 'ediff-files-remote "ediff"
|
|
"Intelligent Emacs interface to diff")
|
|
</verb></tscreen>
|
|
<tscreen><verb>
|
|
(if first-time
|
|
(setq auto-mode-alist
|
|
(append '(("\\.cpp$" . c++-mode)
|
|
("\\.hpp$" . c++-mode)
|
|
("\\.lsp$" . lisp-mode)
|
|
("\\.scm$" . scheme-mode)
|
|
("\\.pl$" . perl-mode)
|
|
) auto-mode-alist)))
|
|
|
|
;; Auto font lock mode
|
|
(defvar font-lock-auto-mode-list
|
|
(list 'c-mode 'c++-mode 'c++-c-mode 'emacs-lisp-mode 'lisp-mode 'perl-mode 'scheme-mode)
|
|
"List of modes to always start in font-lock-mode")
|
|
|
|
(defvar font-lock-mode-keyword-alist
|
|
'((c++-c-mode . c-font-lock-keywords)
|
|
(perl-mode . perl-font-lock-keywords))
|
|
"Associations between modes and keywords")
|
|
|
|
(defun font-lock-auto-mode-select ()
|
|
"Automatically select font-lock-mode if the current major mode is
|
|
in font-lock-auto-mode-list"
|
|
(if (memq major-mode font-lock-auto-mode-list)
|
|
(progn
|
|
(font-lock-mode t))
|
|
)
|
|
)
|
|
|
|
(global-set-key [M-f1] 'font-lock-fontify-buffer)
|
|
|
|
;; New dabbrev stuff
|
|
;(require 'new-dabbrev)
|
|
(setq dabbrev-always-check-other-buffers t)
|
|
(setq dabbrev-abbrev-char-regexp "\\sw\\|\\s_")
|
|
(add-hook 'emacs-lisp-mode-hook
|
|
'(lambda ()
|
|
(set (make-local-variable 'dabbrev-case-fold-search) nil)
|
|
(set (make-local-variable 'dabbrev-case-replace) nil)))
|
|
(add-hook 'c-mode-hook
|
|
'(lambda ()
|
|
(set (make-local-variable 'dabbrev-case-fold-search) nil)
|
|
(set (make-local-variable 'dabbrev-case-replace) nil)))
|
|
(add-hook 'text-mode-hook
|
|
'(lambda ()
|
|
(set (make-local-variable 'dabbrev-case-fold-search) t)
|
|
(set (make-local-variable 'dabbrev-case-replace) t)))
|
|
|
|
;; C++ and C mode...
|
|
(defun my-c++-mode-hook ()
|
|
(setq tab-width 4)
|
|
(define-key c++-mode-map "\C-m" 'reindent-then-newline-and-indent)
|
|
(define-key c++-mode-map "\C-ce" 'c-comment-edit)
|
|
(setq c++-auto-hungry-initial-state 'none)
|
|
(setq c++-delete-function 'backward-delete-char)
|
|
(setq c++-tab-always-indent t)
|
|
(setq c-indent-level 4)
|
|
(setq c-continued-statement-offset 4)
|
|
(setq c++-empty-arglist-indent 4))
|
|
|
|
(defun my-c-mode-hook ()
|
|
(setq tab-width 4)
|
|
(define-key c-mode-map "\C-m" 'reindent-then-newline-and-indent)
|
|
(define-key c-mode-map "\C-ce" 'c-comment-edit)
|
|
(setq c-auto-hungry-initial-state 'none)
|
|
(setq c-delete-function 'backward-delete-char)
|
|
(setq c-tab-always-indent t)
|
|
;; BSD-ish indentation style
|
|
(setq c-indent-level 4)
|
|
(setq c-continued-statement-offset 4)
|
|
(setq c-brace-offset -4)
|
|
(setq c-argdecl-indent 0)
|
|
(setq c-label-offset -4))
|
|
|
|
;; Perl mode
|
|
(defun my-perl-mode-hook ()
|
|
(setq tab-width 4)
|
|
(define-key c++-mode-map "\C-m" 'reindent-then-newline-and-indent)
|
|
(setq perl-indent-level 4)
|
|
(setq perl-continued-statement-offset 4))
|
|
|
|
;; Scheme mode...
|
|
(defun my-scheme-mode-hook ()
|
|
(define-key scheme-mode-map "\C-m" 'reindent-then-newline-and-indent))
|
|
|
|
;; Emacs-Lisp mode...
|
|
(defun my-lisp-mode-hook ()
|
|
(define-key lisp-mode-map "\C-m" 'reindent-then-newline-and-indent)
|
|
(define-key lisp-mode-map "\C-i" 'lisp-indent-line)
|
|
(define-key lisp-mode-map "\C-j" 'eval-print-last-sexp))
|
|
|
|
;; Add all of the hooks...
|
|
(add-hook 'c++-mode-hook 'my-c++-mode-hook)
|
|
(add-hook 'c-mode-hook 'my-c-mode-hook)
|
|
(add-hook 'scheme-mode-hook 'my-scheme-mode-hook)
|
|
(add-hook 'emacs-lisp-mode-hook 'my-lisp-mode-hook)
|
|
(add-hook 'lisp-mode-hook 'my-lisp-mode-hook)
|
|
(add-hook 'perl-mode-hook 'my-perl-mode-hook)
|
|
|
|
;; Complement to next-error
|
|
(defun previous-error (n)
|
|
"Visit previous compilation error message and corresponding source code."
|
|
(interactive "p")
|
|
(next-error (- n)))
|
|
</verb></tscreen>
|
|
<tscreen><verb>
|
|
;; Misc...
|
|
(transient-mark-mode 1)
|
|
(setq mark-even-if-inactive t)
|
|
(setq visible-bell nil)
|
|
(setq next-line-add-newlines nil)
|
|
(setq compile-command "make")
|
|
(setq suggest-key-bindings nil)
|
|
(put 'eval-expression 'disabled nil)
|
|
(put 'narrow-to-region 'disabled nil)
|
|
(put 'set-goal-column 'disabled nil)
|
|
|
|
;; Elisp archive searching
|
|
(autoload 'format-lisp-code-directory "lispdir" nil t)
|
|
(autoload 'lisp-dir-apropos "lispdir" nil t)
|
|
(autoload 'lisp-dir-retrieve "lispdir" nil t)
|
|
(autoload 'lisp-dir-verify "lispdir" nil t)
|
|
|
|
;; Font lock mode
|
|
(defun my-make-face (face colour &optional bold)
|
|
"Create a face from a colour and optionally make it bold"
|
|
(make-face face)
|
|
(copy-face 'default face)
|
|
(set-face-foreground face colour)
|
|
(if bold (make-face-bold face))
|
|
)
|
|
|
|
(if (eq window-system 'x)
|
|
(progn
|
|
(my-make-face 'blue "blue")
|
|
(my-make-face 'red "red")
|
|
(my-make-face 'green "dark green")
|
|
(setq font-lock-comment-face 'blue)
|
|
(setq font-lock-string-face 'bold)
|
|
(setq font-lock-type-face 'bold)
|
|
(setq font-lock-keyword-face 'bold)
|
|
(setq font-lock-function-name-face 'red)
|
|
(setq font-lock-doc-string-face 'green)
|
|
(add-hook 'find-file-hooks 'font-lock-auto-mode-select)
|
|
|
|
(setq baud-rate 1000000)
|
|
(global-set-key "\C-cmm" 'menu-bar-mode)
|
|
(global-set-key "\C-cms" 'scroll-bar-mode)
|
|
(global-set-key [backspace] 'backward-delete-char)
|
|
; (global-set-key [delete] 'delete-char)
|
|
(standard-display-european t)
|
|
(load-library "iso-transl")))
|
|
|
|
;; X11 or PC using direct screen writes
|
|
(if window-system
|
|
(progn
|
|
;; (global-set-key [M-f1] 'hilit-repaint-command)
|
|
;; (global-set-key [M-f2] [?\C-u M-f1])
|
|
(setq hilit-mode-enable-list
|
|
'(not text-mode c-mode c++-mode emacs-lisp-mode lisp-mode
|
|
scheme-mode)
|
|
hilit-auto-highlight nil
|
|
hilit-auto-rehighlight 'visible
|
|
hilit-inhibit-hooks nil
|
|
hilit-inhibit-rebinding t)
|
|
(require 'hilit19)
|
|
(require 'paren))
|
|
(setq baud-rate 2400) ; For slow serial connections
|
|
)
|
|
|
|
;; TTY type terminal
|
|
(if (and (not window-system)
|
|
(not (equal system-type 'ms-dos)))
|
|
(progn
|
|
(if first-time
|
|
(progn
|
|
(keyboard-translate ?\C-h ?\C-?)
|
|
(keyboard-translate ?\C-? ?\C-h)))))
|
|
|
|
;; Under UNIX
|
|
(if (not (equal system-type 'ms-dos))
|
|
(progn
|
|
(if first-time
|
|
(server-start))))
|
|
|
|
;; Add any face changes here
|
|
(add-hook 'term-setup-hook 'my-term-setup-hook)
|
|
(defun my-term-setup-hook ()
|
|
(if (eq window-system 'pc)
|
|
(progn
|
|
;; (set-face-background 'default "red")
|
|
)))
|
|
|
|
;; Restore the "desktop" - do this as late as possible
|
|
(if first-time
|
|
(progn
|
|
(desktop-load-default)
|
|
(desktop-read)))
|
|
|
|
;; Indicate that this file has been read at least once
|
|
(setq first-time nil)
|
|
|
|
;; No need to debug anything now
|
|
(setq debug-on-error nil)
|
|
|
|
;; All done
|
|
(message "All done, %s%s" (user-login-name) ".")
|
|
|
|
</verb></tscreen>
|
|
|
|
<sect1><heading>Extending the Range of Languages Emacs Understands</heading>
|
|
<p>
|
|
Now, this is all very well if you only want to program in the
|
|
languages already catered for in the .emacs file (C, C++, Perl, Lisp
|
|
and Scheme), but what happens if a new language called "whizbang"
|
|
comes out, full of exciting features?
|
|
<p>
|
|
The first thing to do is find out if "whizbang" comes with any files
|
|
that tell Emacs about the language. These usually end in ".el", short
|
|
for "Emacs Lisp". For example, if "whizbang" is a FreeBSD port, we can
|
|
locate these files by doing
|
|
|
|
<tscreen><verb>
|
|
find /usr/ports/lang/whizbang -name *.el -print
|
|
</verb></tscreen>
|
|
|
|
and install them by copying them into the Emacs site Lisp directory. On
|
|
FreeBSD 2.1.0-RELEASE, this is /usr/local/share/emacs/site-lisp.
|
|
|
|
So for example, if the output from the find command was
|
|
|
|
<tscreen><verb>
|
|
/usr/ports/lang/whizbang/work/misc/whizbang.el
|
|
</verb></tscreen>
|
|
|
|
we would do
|
|
|
|
<tscreen><verb>
|
|
cp /usr/ports/lang/whizbang/work/misc/whizbang.el /usr/local/share/emacs/site-lisp
|
|
</verb></tscreen>
|
|
|
|
Next, we need to decide what extension whizbang source files
|
|
have. Let's say for the sake of argument that they all end in
|
|
`.wiz'. We need to add an entry to our .emacs file to make sure Emacs
|
|
will be able to use the information in whizbang.el.
|
|
<p>
|
|
Find the auto-mode-alist entry in .emacs and add a line for whizbang,
|
|
such as:-
|
|
|
|
<tscreen><verb>
|
|
...
|
|
("\\.lsp$" . lisp-mode)
|
|
("\\.wiz$" . whizbang-mode)
|
|
("\\.scm$" . scheme-mode)
|
|
...
|
|
</verb></tscreen>
|
|
|
|
This means that Emacs will automatically go into whizbang-mode when
|
|
you edit a file ending in .wiz.
|
|
<p>
|
|
Just below this, you'll find the font-lock-auto-mode-list entry. Add
|
|
whizbang-mode to it like so:-
|
|
|
|
<tscreen><verb>
|
|
;; Auto font lock mode
|
|
(defvar font-lock-auto-mode-list
|
|
(list 'c-mode 'c++-mode 'c++-c-mode 'emacs-lisp-mode 'whizbang-mode 'lisp-mode 'perl-mode 'scheme-mode)
|
|
"List of modes to always start in font-lock-mode")
|
|
</verb></tscreen>
|
|
|
|
This means that Emacs will always enable font-lock-mode (ie syntax
|
|
highlighting) when editing a .wiz file.
|
|
<p>
|
|
And that's all that's needed. If there's anything else you want done
|
|
automatically when you open up a .wiz file, you can add a
|
|
whizbang-mode hook (see my-scheme-mode-hook for a simple example that
|
|
adds auto-indent).
|
|
|
|
<sect><heading>Further Reading</heading>
|
|
<sect1><heading>Bibliography</heading>
|
|
<p>
|
|
<itemize>
|
|
<item>
|
|
Brian Harvey and Matthew Wright
|
|
<em>Simply Scheme</em>
|
|
MIT 1994.
|
|
<newline>ISBN 0-262-08226-8
|
|
</item>
|
|
|
|
<item>
|
|
Randall Schwartz
|
|
<em>Learning Perl</em>
|
|
O'Reilly 1993
|
|
<newline>ISBN 1-56592-042-2
|
|
</item>
|
|
|
|
<item>
|
|
Patrick Henry Winston and Berthold Klaus Paul Horn
|
|
<em>Lisp (3rd Edition)</em>
|
|
Addison-Wesley 1989
|
|
<newline>ISBN 0-201-08319-1
|
|
</item>
|
|
|
|
<item>
|
|
Brian W. Kernighan and Rob Pike
|
|
<em>The Unix Programming Environment</em>
|
|
Prentice-Hall 1984
|
|
<newline>ISBN 0-13-937681-X
|
|
</item>
|
|
|
|
<item>
|
|
Brian W. Kernighan and Dennis M. Ritchie
|
|
<em>The C Programming Language (2nd Edition)</em>
|
|
Prentice-Hall 1988
|
|
<newline>ISBN 0-13-110362-8
|
|
</item>
|
|
|
|
<item>
|
|
Bjarne Stroustrup
|
|
<em>The C++ Programming Language</em>
|
|
Addison-Wesley 1991
|
|
<newline>ISBN 0-201-53992-6
|
|
</item>
|
|
|
|
<item>
|
|
W. Richard Stevens
|
|
<em>Advanced Programming in the Unix Environment</em>
|
|
Addison-Wesley 1992
|
|
<newline>ISBN 0-201-56317-7
|
|
</item>
|
|
|
|
<item>
|
|
W. Richard Stevens
|
|
<em>Unix Network Programming</em>
|
|
Prentice-Hall 1990
|
|
<newline>ISBN 0-13-949876-1
|
|
</item>
|
|
</itemize>
|
|
</article>
|