[1]

Towards an UNIX/POSIX to emx-OS/2 Porting Guide

Use the Imakefile! \\ or: \\ Some mean tricks to get the stuff compiled!

Use the Imakefile!
or:
Some mean tricks to get the stuff compiled!

Copyright © for the compilation:
Arnd.H.Hanses@rz.ruhr-uni-bochum.de

"Good programmers know what to write.
Great ones know what to rewrite (and reuse)."
(ERIC S. RAYMOND, IN: "THE CATHEDRAL AND THE BAZAAR")


Alfieri: > E la fama? <
Gozzi: > E la fame? <
(COMMEDIA DELL'ARTE)

Informal introduction into aspects of porting from UNIX/POSIX to OS/2 that are closely related to the emx development tools. Teaching ANSI C is not intended, some familiarity with programming in C or C++ is assumed; pointers to tutorials for rank beginners are included.

(Authorship is usually indicated. Please mail me any errors and suggested additions. I am looking forward to adding new chapters written by interested readers. If the author's name is omitted and not evident, I am citing usually an excerpt from the emx documentation. Those hundreds of trademarks are those of their respective owners.)

Contents

I   The Tutorial
1  Instead of an Introduction
    1.1  Why Are the Emx Development Tools Important for Writing Modern Portable Code ?
        1.1.1  What's emx?
        1.1.2  What's That Hype About ``Code Reuse''?
    1.2  Where to Start?
2  Survive With Emx Tools (cc, make, gdb, emacs)
    2.1  Let's contrast Emx With FreeBSD.
        2.1.1  Compiling With cc
        2.1.2  Common cc Queries and Problems
        2.1.3  Make
            2.1.3.1  What's make?
            2.1.3.2  Example of using make
            2.1.3.3  More advanced uses of make
    2.2  Debugging
        2.2.1  The Debugger
        2.2.2  Running a program in the debugger
        2.2.3  Examining a core file
        2.2.4  Attaching to a running program
    2.3  Configuring Emacs
        2.3.1  A sample .emacs file
        2.3.2  Example A sample .emacs file
        2.3.3  Extending the Range of Languages Emacs Understands
    2.4  Further Reading
II   Special Problems
3  Frequently Used Concepts
    3.1  What's ' \@mathcal X'?
    3.2  The 'official' port of XFree86
        3.2.1  General Information
        3.2.2  The XFree86/OS2 Infrastructure
        3.2.3  Tip: Everblue
    3.3  And Posix, etc.?
4  A Silly Demo and Some Comments
    4.1  Read the Emx Documentation
    4.2  Source with Comments
    4.3  Module Definition File - Executable
5  XFree86: Hardware Gets Involved
    5.1  Devices, \@mathcal X Servers, Clients
        5.1.1  '/dev/fastio$', '/dev/console$', '/dev/ptyP0$', etc.
        5.1.2  Concepts Related to Hardware (vio) Access and Kernel Level API 's
    5.2  Inter Process (Session) Communication
    5.3  Emx and device driver programming (hardware devices)
6  Building Libraries
    6.1  Explaining Some Library Concepts
        6.1.1  Dynamic Link Libraries (DLL's) Versus Static Libraries
            6.1.1.1  Static Libraries (*.a or *.lib)
            6.1.1.2  Shared Objects (*.so)
        6.1.2  Shared and Dynamic Libraries (TOG Spec1170)
    6.2  Exporting symbols from a DLL (OS/2 OMF)
    6.3  'dynamic library' and 'shared object' (*.so) versus DLL
    6.4  Demo
    6.5  How to Link Your DLL
    6.6  Library Debugging
    6.7  Building a C++ DLL
    6.8  Some Special Tricks for libraries
        6.8.1  Instead of using preprocessor macros, you can use import libraries
        6.8.2  Debugging huge DLL's
        6.8.3  Length limitation for symbol names in OMF-Format
        6.8.4  Specify the name without the extension
        6.8.5  C++-DLL's
        6.8.6  Multiply defined symbols error with C++-DLL's
        6.8.7  Sys 0008
Imakefile or configure, that's the question!
    7.1  A short overview: Autoconf vs. Imakefile
(by Hung-Chi Chu <hcchu@r350.ee.ntu.edu.tw>)

    7.2  Preliminary steps
        7.2.1  RTF docs
        7.2.2  Some additions to /XFree86/lib/X11/config/os2.cf and os2.rules
    7.3  Common initial problems
        7.3.1  'xmkmf -a' crashes because of 'sh' and 'Rexx' conflicts
        7.3.2  'make' crashes because of 'sh' and 'Rexx' conflicts
    7.4  Imakefile examples
        7.4.1  creating a static library (archive):
NormalLibraryTarget(rw, $(OBJS))

        7.4.2  creating an executable: ComplexProgramTarget(xart)
    7.5  Some maybe useful defines
8  XFree86/2 and Multi-threading
9  Numerical Math
    9.1  Types, Limits, Conversion.
    9.2  IEEE Maths.
    9.3  Useful Math Extensions
10  What Shall I Better Change in the Sources?
    10.1  Globbing
    10.2  DOS `\"text `\" mode, binary reading, etc.
    10.3  Process management and fork()
        10.3.1  What is the difference between fork() and spawnvp()?
            10.3.1.1  fork() and emx
            10.3.1.2  making it work
        10.3.2  replacing fork() and execvp(), etc.
        10.3.3  fork()/exec() and dual way pipe communication
        10.3.4  Example (C++-Code from modified LYX 1.0.4 sources):
    10.4  Multithreading instead of fork()/vfork()
    10.5  Unix file system issues
    10.6  Sockets
    10.7  Environment (getenv())
    10.8  Miscellanea
III   Appendices
11  Some Notes on Portability and Coding Style

0.12
"I have found a cool X utility which I want to port. How should I proceed?
Normally, with X utilities, you get an Imakefile. Simply proceed as if you were under Unix. Run xmkmf -a to compile. Read the programming section on special issues."

("The XFree86/OS2 FAQ")

Preface
(What should be the aim of an emx-tutorial?)

Since I am not a professional programmer, I am advocating user friendly tools and user friendly documentation. I do not think such helpful things should aim at becoming large or comprehensive, but simple and down-to-earth. It should just enable the first simple steps and help to reduce the beginners problems, thus providing the necessary basis and some pointers so that you learn how to get access to the huge piles of helpful information on the Net and elsewhere. Well, it is time now to make the first step towards a (still epigonous and rudimentary) porting tutorial, compiling in the form of short articles some of the helpful information that's scattered in small bits and pieces everywhere (while trying to identify and name the author). Everybody may contribute such a small article for inclusion.

It is best used together with Alexander Mai's Unix to OS/2 Porting FAQ1. If his concise notes are too short for your purposes, some explanation may be found here.

The first chapter 'Instead of an Introduction' is, what a novice should read. Those who want to use imake should read the respective chapter, etc.

Bochum, in November 1999, Arnd Hanses

Ok, just let me begin, resuming and continuing an ongoing dialog in the net, thus introducing how to efficiently use the lists contributions and their archives (better insights always welcome):


Part 1
The Tutorial


Chapter 1
Instead of an Introduction

1.1  Why Are the Emx Development Tools Important for Writing Modern Portable Code ?

The number of new compilers for OS/2, which provide all (now standardized or still experimental) features of bleeding edge STL versions is very limited. 'Workframe' solutions fail, when a huge codebase with hundreds of megabytes of source is involved and a reasonable make process (i.e. based on Unix' 20 years of scientific and industrial experience with complex projects for heterogenous platforms and distributed networking, using quality software engineering strategies for code reliability) is required for any serious development. A prominent example is XFree86/OS2, where all make utilities and development tools except the GNU make utility and the GNU compiler gcc failed. Both are based on the emx libraries:

1.1.1  What's emx?

[excerpt from emx 0.9d INTRODUCTION 21-Dec-1998]

``Introduction

Welcome to emx 0.9d, an environment for creating 32-bit programs for OS/2 and DOS. You can use the GNU C compiler to compile programs for emx. The main design goal of emx is to simplify porting Unix software to OS/2 and DOS. Moreover, you can create `native' OS/2 programs, including Presentation Manager applications.

The emx package includes:

Additionally, the following GNU programs are available compiled and with patches and sources: You can get the complete unpatched GNU sources by anonymous ftp from prep.ai.mit.edu and other archives such as ftp.leo.org.

Additionally, the following libraries are provided:

After unpacking the emx runtime and development system packages, you'll find further information in the following files: After unpacking the GNU and BSD packages, you'll find further information in the following files: [...] emx is available for anonymous ftp on An emx-related mailing list has been created. The address for people to request to be added to or removed from the list is:

majordomo@iaehv.nl

To subscribe, send a message containing

subscribe emx

to majordomo@iaehv.nl. [...]

This may be the right moment now to carefully read emx/doc/INSTALL file, and to test if you can successfully compile, run and debug the programs mentioned there.

Highly optimized and bleeding edge C++-code can be compiled with the most recent experimental GNU Pentium Compiler Group's pgcc, which also contains tools updates, interesting for assembler (MMX) programmers.

1.1.2  What's That Hype About ``Code Reuse''?

Although not completely POSIX compliant, emx for OS/2 is nearly as close as can be for the pre-POSIX operating system OS/2. This makes it an ideal platform for CODE REUSE and OPEN PORTABILITY.

" X - a portable network transparent window system", as the authors call it, enables the reuse of Unix software for OS/2 and in general gives you the chance to write extremely portable gui code, running on a PC as well as on a super-computer by simply recompiling it, provided you have a POSIX-like programming interface.

"Why is writing portable code (and therefore emx) so important?"
"As for non-existing API, I would recommend to stick to well-known things like POSIX, BSD networking, X11 and avoid system-specific calls like DosWrite() etc. completely. If you're doing really multiplatform project. Really 'standard' calls are the same everywhere and rarely require re-implementation. There's some oddity here and there (I heard Ultrix(?) does not have strdup()?) but you can add it in transparent way, namely linking on Ultrix with your own implementation of strdup()."

(Dr. Sergey Ayukov, Sternberg Astronomical Institute Moscow, Russia http://www.ayukov.com, http://crydee.sai.msu.ru/index-asv.html)

Well, the tutorials motto is:

"Good programmers know what to write. Great ones know what to rewrite (and reuse)."
Paramount for reuse in the future is reusability through open standards (and - even more important - good comments ;-). Here the open Posix/BSD/MIT API 's distinguish XFree/emx/gcc/pgcc from other compilers and make it the 'future compatible' development platform. For this reason it is outstanding and may well be recommended.

Nevertheless we should try to explain what those ' X files' are about (an informal glossary of uncommon terms and related hints) and provide some external references.

1.2  Where to Start?

"Heelpp, I'm stuck! Where to begin?"

(anonymous)

A good tutorial to ANSI C (cf. e.g. "An Introduction to C Programming", by Carsten Whimster

http://www.edm2.com/0408/introc1.html
is certainly not bad, but even for the beginner's purposes often insufficient. You will stumble over unknown concepts and interfaces, such as traditional ' K&R -style' 'BSD Unix' sources/sockets, the general preference to use exclusively the uncommon POSIX extensions, notwithstanding widespread adherence to the GNU language and C Library ("glibc") extensions. This tends to 'pollute' nearly every app coming from the UNIX world of operating systems. What you certainly would expect are Xlib (MIT X Standard) and Xt, Xaw, Xext, etc. library and toolkit extensions, as well as gui toolkits with rapidly changing popularity, namely 'qt', 'KDE', 'gnome', 'xforms', 'Motif/CDE' or 'lesstif', etc. We will pronounce now and here the well-meant advice:

"Use standard ANSI C (or C++) whereever possible!"
Only, in this moment this will probably help you less than nothing. Moreover, the only viable solution often requires low-level functions. Remember that ' EMX/GCC' as well as 'x11make' of XFree86/OS2 (or 'gmake') is generally a superset of the Unix standard 'cc', 'cxx' and 'make'. So, if you like to read a basic tutorial for beginners with a strictly didactical approach, I recommend as a good starting point:

"ANSI C for Programmers on UNIX Systems",
by T. P. Love, CUED Cambridge University Engineering Department)
<tpl@eng.cam.ac.uk>,
ftp://svr-ftp.eng.cam.ac.uk/pub/misc/love_C.ps.Z"
'Sunsite' mirrors distribute it in the 'tutorial' directory (they are the Unix World's first place to dig for source code, help and information).

In the following, to fill some gaps, I'll give a very short summary of porting-related concepts and specialties. For general information please refer to the online documentation that comes with recent Linux and FreeBSD distributions. It is also necessary that you have access to a good Unix/Linux tutorial, explaining those numerous concepts unfamiliar for OS/2, which cannot be covered here. For standards, try e.g.:

http://standards.ieee.org/announcements/opengroup.html 
Before you start writing much maths-related code, check to see that it hasn't all been done before. Many maths routines, including routines that offer arbitrary precision are available by ftp from netlib.att.com.

This tutorial will concentrate on emx-specific questions that recently were discussed on the respective lists. Further sources of information are indexed by Timur Tabi:

http://www.edm2.com/links/index.html
Some info for a better initial understanding of XFree86/OS2 can be found at:

http://hayai.freeshell.org/os2_xfree86.html

Chapter 2
Survive With Emx Tools (cc, make, gdb, emacs)

0.30section
"Those who do not understand Unix are condemned to reinvent it, poorly."

(Henry Spencer)

2.1  Let's contrast Emx With FreeBSD.

The following are some excerpts from a terse introduction into how to behave in a FreeBSD Unix development environment (``A User's Guide to FreeBSD Programming Tools``)

http://www.de.freebsd.org/tutorials.
This excerpt - with few extra comments - is meant to contrast emx and FreeBSD based Posix development (historic BSD Unix, besides SYSV, is the most prominent root of what later was distilled to the Posix interface), i.e. to demonstrate what is behind the well-known advice, emx gurus will give you:

``Simply proceed as if you were under Unix!''
I'm sure, you'll soon discover how little a programmer who is writing portable ('posixified') applications has to re-learn or re-do.

2.1.1  Compiling With cc

``This section deals only with the GNU compiler for C and C++, since that comes with the base FreeBSD [and the emx] system. It can be invoked by either cc [write a cc.cmd file] or gcc. ... Once you've written your masterpiece, the next step is to convert it into something that will (hopefully!) run on FreeBSD [as well as on OS/2 after compiling your portable Posix source with emx gcc]. This usually involves several steps, each of which is done by a separate program:

  1. Pre-process your source code to remove comments and do other tricks like expanding macros in C.

    1. Check the syntax of your code to see if you have obeyed the rules of the language. If you have not, it will complain! [Cf. the different warning options: Use at least -Wall.]
    2. Convert the source code into assembly language - this is very close to machine code, but still understandable by humans. Allegedly.
    3. Convert the assembly language into machine code - yep, we are talking bits and bytes, ones and zeros here.
    4. Check that you have used things like functions and global variables in a consistent way. For example, if you have called a non-existent function, it will complain. [Something like 'Unresolved reference foo in bar': Try to find out where you can steal the library, which contains this function or variable. Or maybe you forgot to specify -foolib on the command line?]
    5. If you are trying to produce an executable from several source code files, work out how to fit them all together. [This is the fixup of unresolved symbols, it is done by the linker ld or link386 (if you specified -Zomf), respectively.]
    6. Work out how to produce something that the system's run-time loader will be able to load into memory and run. [emxbind or link386]
    7. Finally, write the executable on the file system.
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. 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

% cc foobar.c
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

% cc foo.c bar.c
Note that the syntax checking is just that - checking the syntax. It will not 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.

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.

-o filename 
The output name of the file [containing a trailing .exe or -Zexe switch]. If you do not use this option, cc will produce an executable called a.out.

% cc -c foobar.c
Just compile the file, do not link it. Useful for toy programs where you just want to check the syntax, or if you are using a Makefile. This will produce an object file (not an executable) called foobar.o. This can be linked together with other object files into an executable.

% cc -g foobar.c 
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 very useful; the disadvantage is that all this extra information makes the program much bigger.

% cc -O -o foobar foobar.c

Create an optimised version of the executable. The compiler performs various clevertricks 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 bugsin the compiler's optimiser. ... Optimisation is usually only turned on when compiling a release version. ...

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 is an ISO standard.

-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.

-ansi 
Turn off most, but not all, of the non-ANSI C features provided by cc. Despite the name, it does not guarantee strictly that your code will comply to the standard.

-pedantic 
Turn off all cc's non-ANSI C features.

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. 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?

% cc -Wall -ansi -pedantic -o foobar.exe foobar.c
This will produce an executable foobar after checking foobar.c for standard compliance.

% cc -o foobar foobar.c -lm
Specify a function library to be used during when linking.

The most common example of this is when compiling a program that uses some of the mathematical functions in C. Unlike most other platforms [emx included], these are in a separate library from the standard C one and you have to tell the compiler to add it.

The rule is that if the library is called libsomething.a, you give cc the argument -lsomething. For example, the math library is libm.a, so you give cc the argument -lm. A common "gotcha" with the math library is that it has to be the last library on the command line. [Emx does not cut off the leading 'lib' part of library names and m.a or m.lib is just a dummy library which can be used for your own common extension modules.]

If you are compiling C++ code, you need to add -lg++, or -lstdc++ ... to the command line argument to link the C++ library functions. ...

Each of these 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 MS-DOS&trade; 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!

2.1.2  Common cc Queries and Problems

Q: I am trying to write a program which uses the sin() function and I get an error like this. What does it mean?

/var/tmp/cc0143941.o: Undefined symbol `_sin' referenced from text segment
A: When using mathematical functions like sin(), you have to [you need not, since emx does it for you] tell cc to link in the math library. [Nevertheless the error occurs if you are missing something else.]

Q: All right, I wrote this simple program to practice using -lm. All it does is raise 2.1 to the power of 6.

#include <stdio.h>

     

int main() 

{

float f = pow(2.1, 6);

   printf("2.1 ^ 6 = %f", f);

 return 0;

}

and I compiled it as:

% cc temp.c -lm
like you said I should, but I get this when I run it:

% ./a.out

2.1 ^ 6 = 1023.000000

This is not the right answer! What is going on?

A: When the compiler sees you call a function, it checks if it has already seen a prototype for it. If it has not, it assumes the function returns an int, which is definitely not what you want here.

Q: So how do I fix this?

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 will stop doing strange things to your calculation!

    #include <math.h>

    #include <stdio.h>

     

    int main() {

    ...

After recompiling it as you did before, run it:

% ./a.out

2.1 ^ 6 = 85.766121

If you are using any of the mathematical functions, always include math.h and remember to link in the math library. [This problem can occur with any missing header. Let the compiler warn you: Always use the -Wall flag!]

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?

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.

Q: Fascinating stuff, but what I am supposed to do now?

A: Use gdb to analyse the core (see Section 5).

Q: When my program dumped core, it said something about a segmentation fault. What's that?

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.

Common causes for this are [Read this carefully, well meant advice]:

Trying to write to a NULL pointer, eg

char *foo = NULL;

strcpy(foo, "bang!");

Using a pointer that hasn't been initialised, eg

 char *foo;

 strcpy(foo, "bang!");

Trying to access past the end of an array, eg

int bar[20];

bar[27] = 6;

Trying to store something in read-only memory, e.g.

char *foo = "My string";

strcpy(foo, "bang!");

Unix compilers often put string literals like "My string" into read-only areas of memory. [Declare constants always explicitly as such:

const char *foo = "My string"; /* constant! */
Now the compiler will warn you. Remember: Let the compiler warn you: Always use the -Wall flag!]

Doing naughty things with malloc() and free(), eg

char bar[80];

free(bar);

or

char *foo = malloc(27);

free(foo);

free(foo);

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.

2.1.3  Make

2.1.3.1  What's make?

It reads in a file, called a makefile, 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 makefile also has rules telling make how to re-compile the source file, making it a much more powerful tool.

Makefiles 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.

2.1.3.2  Example of using make

Here's a very simple make file:

    foo: foo.c

        cc -o foo foo.c

It consists of two lines, a dependency line and a creation line. The dependency line here consists of the name of the program (known as the TARGET), followed by a colon, then whitespace, 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.

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.

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! Another useful property of makefiles is that the targets don't have to be programs. For instance, we could have a make file that looks like this:

    foo: foo.c

        cc -o foo.exe foo.c

     

    install:

        cp foo /home/me

We can tell make which target we want to make by typing:

    % make target
make will then only look at that target and ignore any others. For example, if we type make foo with the makefile above, make will ignore the install target.

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.

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 makefiles, so that the application can be installed in the correct directory when it has been correctly compiled.

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. ...

2.1.3.3  More advanced uses of make

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.

The version of make that comes with FreeBSD is the Berkeley make ... 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 its own right.

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

 * Make: (make).                 The GNU Make utility.
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).

2.2  Debugging

2.2.1  The Debugger

The debugger that comes with FreeBSD [and emx] is called gdb (GNU debugger). You start it up by typing

    % gdb progname
although most people prefer to run it inside Emacs. You can do this by:

    M-x gdb RET progname RET
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. ... 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. Finally, if you find its text-based command-prompt style off-putting, there's a graphical

front-end for it xxgdb in the ports collection. [Emx calls it pmgdb.} ...

2.2.2  Running a program in the debugger

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:

    ... (no debugging symbols found) ...
when gdb starts up, you'll know that the program wasn't compiled with the -g option.

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!).

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.

Here's a simple example of how to spot a mistake in a program with gdb. This is our program (with a deliberate mistake):

    #include <stdio.h>

     

    int bazz(int anint);

     

    main() {

        int i;

     

        printf("This is my programn");

        bazz(i);

        return 0;

    }

     

    int bazz(int anint) {

        printf("You gave me %dn", anint);

        return anint;

    }

This program sets i to be 5 and passes it to a function bazz() which prints out the number we gave it.

When we compile and run the program we get

    % cc -g -o temp temp.c

    % ./temp

    This is my program

    anint = 4231

That wasn't what we expected! Time to see what's going on!

% gdb temp

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. breakpoint at main()

(gdb) run                           Run as far as main()

Starting program: 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

(gdb) s                                  step into bazz()

bazz (anint=4231) at temp.c:17   gdb displays stack frame

(gdb)

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.

(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

Oh dear! Looking at the code, we forgot to initialise i. We meant to put

    ...

    main() {

        int i;

     

        i = 5;

        printf("This is my programn");

    ...

but we left 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.

Note: 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).

2.2.3  Examining a core file

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. [emx calls it just core.]

To examine a core file, start up gdb in the usual way. Instead of typing break or run, type

    (gdb) core progname.core [emx: gdb progname core]
If you're not in the same directory as the core file, you'll have to do dir /path/to/core/file first.

You should see something like this:

    % gdb a.out

    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 bazz (anint=0x5) at temp.c:17

    (gdb)

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.

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:

    (gdb) bt

    #0  0x164a in bazz (anint=0x5) at temp.c:17

    #1  0xefbfd888 in end()

    #2  0x162c in main() at temp.c:11

    (gdb)

The end() function is called when a program crashes; in this case, the bazz() function was called from main().

2.2.4  Attaching to a running program

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.

What you do is start up another gdb, use ps to find the process ID for the child, and do

(gdb) attach pid
in gdb, and then debug as usual.

"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):

...

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 */

        ...

Now all you have to do is attach to the child, set PauseMode to 0, and wait for the sleep() call to return!

Using Emacs as a Development Environment

Emacs

[...] 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. [I recommend also to test elvis, a vi clone.] It's impossible even to summarise everything Emacs can do here, but here are some of the features of interest to developers:

Emacs can be installed on FreeBSD [and on emx] using the Emacs port.

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).

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 "M-x replace-s RET foo RET bar RET" 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.

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.

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.

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. 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).

Oh, and to get out of Emacs, do C-x C-c (that means hold down the control key, press x, press c 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).

2.3  Configuring Emacs

Emacs does many wonderful things; some of them are built in, some of them need to be configured.

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!).

The best way to learn Emacs Lisp is to download the Emacs Tutorial. 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.

2.3.1  A sample .emacs file

Unfortunately, there's far too much here to explain it in detail; however there are one or two points worth mentioning.

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.

This file supports syntax highlighting for C, C++, Perl, Lisp and Scheme, by guessing the language from the filename.

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.

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

% emacsclient filename
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.

2.3.2  Example A sample .emacs file

    ;; -*-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-qt")   ; 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")

     

    (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)))

     

    ;; 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) ".")

2.3.3  Extending the Range of Languages Emacs Understands

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?

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

% find /usr/ports/lang/whizbang -name "*.el" -print
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. [Depends on the emx port of your emacs.]

So for example, if the output from the find command was

/usr/ports/lang/whizbang/work/misc/whizbang.el
we would do

# cp /usr/ports/lang/whizbang/work/misc/whizbang.el /usr/local/share/emacs/site-lisp
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.

Find the auto-mode-alist entry in .emacs and add a line for whizbang, such as:

    ...

    (".lsp$" . lisp-mode)

    (".wiz$" . whizbang-mode)

    (".scm$" . scheme-mode)

    ...

This means that Emacs will automatically go into whizbang-mode when you edit a file

ending in .wiz.

Just below this, you'll find the font-lock-auto-mode-list entry. Add whizbang-mode to it like so:

    ;; 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")

This means that Emacs will always enable font-lock-mode (ie syntax highlighting) when editing a .wiz file.

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).

2.4  Further Reading


Part 2
Special Problems


Chapter 3
Frequently Used Concepts

0.40section
"Too much X around, I'm confused!"

(A novice to X )

3.1  What's ' X\protect '?

The Manual Page

Running 'man X' on Unix - and on your system if the necessary backends are installed ('man' or 'xman' is generally a good idea for terse descriptions of terms, apps and interfaces) - spits out something (cryptical) like:

NAME 

X - a portable, network-transparent window system 

SYNOPSIS 

The  X  Window System is a network transparent window system which 

runs on a wide range of computing and graphics machines. It should 

be relatively straightforward to build the  X  Consortium software 

distribution on most ANSI C and POSIX compliant systems. Commercial 

implementations are also available for a wide range of platforms.

The  X  Consortium requests that the following names be used when 

referring to this software:

XX  Window System;  X  Version 11;  X  Window System, Version 11; 

X 11

X  Window System is a trademark of  X  Consortium, Inc. 

DESCRIPTION 

X  Window System servers run on computers with bitmap displays. The 

server distributes user input to and accepts output requests from 

various client programs through a variety of different interprocess 

communication channels. Although the most common case is for the 

client programs to be running on the same machine as the server, 

clients can be run transparently from other machines (including 

machines with different architectures and operating systems) as well.

X  supports overlapping hierarchical subwindows and text and graphics 

operations, on both monochrome and color dis plays. For a full 

explanation of the functions that are available, see the Xlib - 

C Language  X  Interface manual, the  X  Window System Protocol 

specification, the  X  Toolkit Intrinsics - C Language Interface 

manual, and various toolkit documents.

The number of programs that use  X  is quite large. Programs provided 

in the core  X  Consortium distribution include: a terminal emulator, 

xterm; a window manager, twm; [...] access control programs, xauth, 

xhost, and iceauth; user preference setting programs, xrdb, xcmsdb, 

xset, xsetroot, xstdcmap, and xmodmap; [...]; utilities for listing 

information about [...] displays, xdpyinfo, xlsatoms, and xprop; 

[...]; a display server and related utilities, Xserver [...]; a 

utility to terminate clients, xkill; [...] 

Many other utilities, window managers, games, toolkits, etc. are 

included as user-contributed software in the  X  Consortium distribution, 

or are available using anonymous ftp on the Internet. See your site 

administrator for details.

Nice tip, isn't it: On a single user system like an OS/2 workstation the 'site administrator' is: You!

3.2  The 'official' port of XFree86

The newest OS/2-port is introduced in "The XFree86/OS2 FAQ" (by Holger Veit, Sebastien Marineau):

http://www-set.gmd.de/~veit/os2/x11os2faq.html 

3.2.1  General Information

*1.1 What is X11, X11R6.3, XFree86, XFree86/OS2?

X11, more precisely called "The X Window System" is a complete window system that usually runs as the de-facto standard in Unix environments. X11R6.3 is the name of the current release (precisely, the most recent one is X11R6.4, but this is not part of the 3.X server line. XFree86 is a port of the X Window System to x86-based systems. XFree86/OS2 is a particular port of XFree86 for OS/2 based systems.

1.2 Where can I find more information?

Books about X11 exist in any well-sorted CS bookstore.

Some URLs:

http://www.x11.org/ (this has a rather large bibliography) 

http://www.xfree86.org/

http://set.gmd.de/~veit/os2/xf86os2.html (XFree86/OS2) 

Newsgroups:
comp.windows.x.* (X11 specific things) 

comp.os.os2.programmer.* (OS/2 specific things) 

Mailing list (for XFree86/OS2): see Q 1.7 [...]

*1.7 Is there a mailing list for XFree86/OS2?

Yes, read

http://set.gmd.de/~veit/os2/xf86mail.html 
for details. [...] There is also a digest version available, read the above URL. [...]

1.16 Are there some X11 books?

Sure, ask in your book store. A user's guide is for instance:

Niall Mansfield, The X Window System - A User's Guide, Addison Wesley, or The Definite Guides to the X Windows System, Volume Three, X Window System User's Guide, O'Reilly&Associates

The latter one is part of an eight (nine,ten?) volume documentation set for the X11 programmer. From my biased point of view of a programmer, this is the most comprehensive must-have for the serious programmer (however, it does not belong to the cheaper booksets, unfortunately)."

3.2.2  The XFree86/OS2 Infrastructure

3.2.3  Tip: Everblue

3.3  And Posix, etc.?

Run e.g. on Linux

man 2 intro 

NAME 

intro - Introduction to system calls 

DESCRIPTION 

This chapter describes system calls.

Calling Directly In most cases, it is unnecessary to invoke a system 

call directly, but there are times when the Standard C library does 

not implement a nice function call for you.

Synopsis #include <unistd.h> [...]  

CONFORMING TO 

Certain codes are used to indicate Unix variants and standards to 

which calls in the section conform. These are:

SVr4 

System V Release 4 Unix, as described in the "Programmer's Reference 

Manual: Operating System API (Intel processors)" (Prentice-Hall 1992, 

ISBN 0-13-951294-2)

SVID 

System V Interface Definition, as described in "The System V Interface 

Definition, Fourth Edition", available at ftp://ftp.fpk.novell.com/pub/unix- standards/svid in Postscript files.

POSIX.1 

IEEE 1003.1-1990 part 1, aka ISO/IEC 9945-1:1990s, aka "IEEE Portable 

Operating System Interface for Computing Environments", as elucidated 

in Donald Lewine's "POSIX Programmer's Guide" (O'Reilly & Associates, 

Inc., 1991, ISBN 0-937175-73-0.

POSIX.1b 

IEEE Std 1003.1b-1993 (POSIX.1b standard) describing real-time 

facilities for portable operating systems, aka ISO/IEC 9945-1:1996, as 

elucidated in "Programming for the real world - POSIX.4" by Bill O. 

Gallmeister (O'Reilly & Associates, Inc. ISBN 1-56592-074-0). 

[Note: No specific emx support!]

4.3BSD/4.4BSD 

The 4.3 and 4.4 distributions of Berkeley Unix. 4.4BSD was 

upward-compatible from 4.3.

V7 Version 7, the ancestral Unix from Bell Labs. 

FILES 

/usr/include/linux/_unistd.h"

Note: You are not in Linux! Nor will you use GNU glibc. IMHO GNU glibc is a sad example of investing too much work in interfaces that invite programmers to write unportable code and that unneccessarily eat up ressources. But in fact they never really claimed to be Posix, only to (often arbitrarily) aim at some compatibility, while implementing things 'better'; very similar is their goal to make a 'better' platform than BSD Unix, while retaining some compatibility. EMX has:

emx/include/unistd.h  
emx/include/io.h 
Cf. Chapter 1.3 of the EMX LIB C REFERENCE for an overview of 'unistd.h' and 'io.h' library interfaces. Cf. also Chapter 10:

System calls are documented in /emx/doc/system.doc.

All system calls are declared in <emx/syscalls.h>. Interface routines are in the emx.a and emx.lib libraries. System call emulation routines are in the sys.lib libraries. Please do not use system calls from application programs - always use C library functions. If you need a system call, put a function into the library which issues the system call. [...] The goal is to have Unix-like system calls.

The term ' POSIX' denotes in the following all (development) platforms "aiming at IEEE 1003.1/2 compatability" and is not restricted to those relatively few commercial platforms that passed the official tests and paid the license fee. Please note that there is e.g. an old Linux/POSIX distribution with an 'official' POSIX label. This means: We will neglect all old broken pre-Posix Unix-like systems and encourage to completely forget about them.

Moreover if we go into details we should explain XPG, X/OPEN, Spec1170, etc. Please consult Unix tutorials here.

And to How Get Posix, etc. Defined?

Specify the desired environment (cf. emx GNU gcc manual 2.12/2.8):

"The preprocessor CPP defines the symbols __32BIT__ and 

__EMX__. If the -Zmt, -Zmts, or -Zmtd option is given on the 

GCC command line, the symbol __MT__ is defined." 

"The following assertions are predefined in the emx port of 

gcc: 

#system(unix), 

#system(emx), 

#cpu(i386) and 

#machine(i386)."

Some important gcc switches are:

`-ansi'
switch to the GNU C compiler defines __STRICT_ANSI__. This is recommended, those definitions in the headers which contradict ANSI will not be included; most of the extensions are usually not necessary. Tip: Use

#define inline __inline__ 
to become standard conformant and to avoid error messages.
`-pedantic'
switch complains loudly about non_ANSI code,
`-posix'
defines _POSIX_SOURCE.

If more than one of these are defined, they accumulate. For example:

__STRICT_ANSI__, _POSIX_SOURCE and _POSIX_C_SOURCE 
together give you ISO C, 1003.1, and 1003.2, but nothing else:

__STRICT_ANSI__ ISO Standard C. 

_POSIX_SOURCE IEEE Std 1003.1. 

_POSIX_C_SOURCE 

If ==1, like _POSIX_SOURCE; 

if >=2 add IEEE Std 1003.2; 

if >=199309L, add IEEE Std 1003.1b-1993 

[Note: No specific emx support! Also cf. 

/XFREE86/INCLUDE/X11/Xos.h from XFree86/OS2]

'-v -Q'
gives you important debug info, including builtin symbols and assertions, as well as a complete list of enabled optimization switches. The latter is crucial for pgcc's experimental optimizing. I've experienced internal compiler problems ('virtual memory exhausted') or unexpected program behaviour with pgcc v. 1.1.3 (gcc v. 2.92.66) and the following optimizations (if in any doubt, use the switches below). I also recommend to disable the experimental C++ feature 'rtti' and 'exceptions':

-fno-gcse -fno-schedule-insns2 -fno-reg-reg-copy-opt -fno-omit-frame-pointer -fno-exceptions -fno-rtti

Chapter 4
A Silly Demo and Some Comments

Now time has come to compile some simple demo code. Here I will not add another one to the pile of introduction to ANSI C, several excellent tutorials exist. All I can express here is a kind of compliment to Eberhard Mattes for his emx development tools and libraries: There is not much to say about compiling standard C (and C++; provided you use a recent compiler version) with emx. Just start.

4.1  Read the Emx Documentation

This is just the right moment to re-read the README and INSTALL file of emx. Then compile the sample code provided by Eberhard Mattes and have a close look at the first chapters of the Emx Application Developers Guide, which introduce its philosophy. Doing both carefully might save you trouble later:

``There are three methods for creating executable files:

(E1) using ld and emxbind

(E2) using emxomf, emxomfld and LINK386, the program will use the emx.dll dynamic link library for performing system calls

(E3) using emxomf, emxomfld and LINK386, the program will be linked with a system call library (creating a stand-alone application or DLL)

The assembler [GNU as] creates a Unix-style a.out object file (.o file). When using method (E1), .o files created by the assembler are linked by a Unix-style linker [GNU ld] with Unix-style libraries (.a files) to create a Unix-style a.out file. Then, emxbind is used to turn this file into an .exe file that can be executed under both OS/2 and DOS. Using method (E1) enables core dumps and fork(). Moreover, programs created with method (E1) can be debugged using GDB, the GNU debugger. Programs created using method (E1) use emx (emx.dll under OS/2, emx.exe under DOS) for system calls.

When using method (E2), the .o files created by the assembler are converted to Object Module Format files (.obj files). These files are linked with the OS/2 linker LINK386. The libraries are .lib files. emxomfld is a front end to LINK386 which converts the ld command line to a LINK386 command line. Programs created with method (E2) cannot create core dumps, cannot call fork() and cannot be debugged with GDB. Method (E2) works only under OS/2 and creates programs that work only under OS/2. You can use IBM's IPMD and SD386 debuggers to debug programs created with methods (E2) and (E3). Files created with method (E2) are usually smaller. The emx.dll dynamic link library is used for system calls. The -Zomf option of GCC selects method (E2).

When using method (E3), the program won't call the emx.dll dynamic link library. A system call library (emx emulator) is linked to the program. The system call library maps system calls to OS/2 API calls. Only a subset of the emx system calls is available with method (E3). For instance, the general terminal interface is not available. Functions which are not available or are limited with method (E3) are marked [*] in the library reference. Use a module definition file and the STACKSIZE statement to set the stack size. Alternatively, you can use the -Zstack option of GCC.''

The default stack size is 0x8000 bytes. 512 kbytes of local stack are sufficient for small tools, but too small for complex programs; pre-allocate 32 Mbytes local stack to be on the safer side. Note that all of the command line arguments and environment pointers are copied to the stack on startup!!! Small local stacksizes are the most prominent reason for seemingly arbitrary erroneous program behaviour. (Your program code is correct: The error will disappear when you perform the usual testing in a debugger ;-).

4.2  Source with Comments

Now a trivial example to illustrate some Posix compliant emx interfaces. Refer to the Emx C Library Reference for the details about open(), read(), write(), etc.

(For an example how to use the more efficient ANSI streams counterparts fopen(), fread(), fwrite(), etc., and how to change file attributes like date and time, please cf. below: cpfile.c in the Chapter ``Some Notes on Portability and Coding Style''. It is an example for a widely portable symlink() replacement ).

Please read the comments in the source; in fact the source has only been written to illustrate the comments and to introduce the compiler commandline frontend 'gcc.exe'.

-----snip: cut here-------

/* demonstrate_EMX_and_XFree86_os2_io.c: gcc -Zbin-files

 

Just try to compile this primitive example with any 

commercial OS/2 compiler

   */

 

#define TRUE 1

#define _POSIX_C_SOURCE 2

 

#include <unistd.h> /* Posix io and constants; contains  

                        #define _POSIX_SOURCE, 

                        #define _POSIX_VERSION          199009L 

                    */

#include <stdio.h>      /* ANSI conformant io, Posix extensions:

                         * fdopen(), fileno() 

                         */

#include <stdlib.h>     /* ANSI C: getenv(); Posix: environ */

#include <sys/types.h>  /* Posix: for open() you need 

                           sys/types.h, */ 

#include <sys/stat.h>   /* sys/stat.h and fcntl.h */

#include <fcntl.h>      /* man pages/Lib Ref. of the command say 

                 which include files need to be mentioned, for

                 portability follow ANSI and Posix,  X apps should 

                 conform to the similar MIT  X Open standard */

#include <string.h>

 

 

/* MIT  X Open/Posix and ANSI type globals */

 

ssize_t bytes_read;