The un*x to OS/2-EMX Porting FAQ

Preface

First I'm going to answer some questions that nobody ever asked ...

What Is It?

This is a collection of tips & tricks for porting software from un*x (here the term "un*x" means UNIX and UNIX-like systems") to IBM's OS/2. If you need a more thorough introduction into the business of porting, you should read the draft for the UNIX/POSIX to emx-OS/2 Porting Guide written by Arnd Hanses: it's also available in a local PDF version.

In general porting requires a broad range of knowledge, so this document also includes general information about coding techniques, un*x & X11 programming, and much more. I assume that the reader is already familiar with OS/2 and has some experience with un*x (usage at least, perhaps even system programming), C programming and EMX/gcc.
Otherwise you can't do anything worthwhile here... Sorry!

How To Use This FAQ?

There is a PDF version of this document available . This is the only "official" version since it features a Table of Contents and is complete within a single file. You can even create printouts and extract a plain text version. (try pdftops and pdftotext, which are part of the xpdf distribution.) Remember that the FIND function of your browser/viewer is your friend! Some parts have been put in external documents with "local linkage", i.e. "compiled" ("official") versions already include those.

Due to the substantial amount of external links within this FAQ access to the Internet is nearly mandatory.

How To Report Bugs?

In case you are going to correct an error, contribute another entry or just fix spelling or grammar, please check first the primary location of this FAQ at
http://homepages.tu-darmstadt.de/~st002279/os2/porting.html
for the latest revision. You may send me an email with corrections, enhancements and criticism!

Copyright, License, Legal Stuff

Contributions to this document came from various people and resources on the net. However to avoid that a single one is neglected in a reference or credits list, all are omitted! Two exceptions are being made for two individuals without their efforts I would not use OS/2 anymore and therefore not work on this FAQ: Eberhard Mattes (author of the EMX package including the docs which I frequently cite) and Holger Veit (who ported XFree86 to OS/2). Many hints given here came from these two people and the numerous members of their projects' mailing lists.
This document is being made available as copyrighted freeware (copyright holder being me, Alexander Mai). This means you may get this document and re-distribute it for free or put excerpts in another work just as you want. But if you re-distribute a substantial part of this FAQ you have to mention my copyright notice in a credits section!

Note that usage of the tips & procedures described here is totally on your own risk, there is no warranty that they do what you might expect without any unwanted side effects!

News

General News

Since I do not get much feedback concerning this document it is not only growing slowly, but also still contains lot of typos and other errors.
Beginning in early 2002 I started to overhaul the whole document, including many errors in the language and removal of some useless phrases. At the same time I'm trying to push the PDF document towards publishing quality.

Work is ongoing to get many of the hints and workarounds mentioned here into a powerful extension library for EMX (AKA "libext"). Take a look and see what's already done! Especially try to look up whether symbols missing in this FAQ are already included there.

Latest Changes

Last Update (I may list some of the previous changes as well):

The Golden Rules

There are some famous Golden Rules out there. The first one is quite simple:
Check out what's already available!

This is also known as:
Do not re-invent the wheel!

Many programmers waste time doing things over and over again, and especially many OS/2 users seem to enjoy this (just look at all those coding the very same kind of utilities over and over again, like file managers, thousands of wget clones, etc).
After you have searched on OS/2 software sites altavista (or similar search engines) and ask on the EMX or XFree86OS/2 mailinglists.
Enhance portability when porting!

Do not produce code which in turn does no longer build on the platform where it comes from. Minimum requirement is to use the
#ifdef __EMX__
...
#endif
clause (I'm talking about C/C++ only here). You should however even try to go a step further and use generic catches like:
#ifndef HAVE_NON_STANDARD_FEATURE_FOO
...
#endif

Tools

To actually port something you need to have EMX (see OS/2 software sites) and all important related development packages installed properly (in their latest version). To deal with X11 applications you need the XFree86OS/2 package including the development stuff (all older commercial alternatives like IBM's PMX or Hummingbirds Exceed are abandoned/outdated and therefore neglected here. Project Everblue, an X11 to PM mapper for local apps, is still in very early stage of development and of no use so far). At least for the X server itself you have more choices in addition to XFree86OS/2:

Also check out libext. Except the libc enhancements it also ships a set of utilities.

gcc 2.8.1, the default C compiler from the current EMX 0.9d distribution, is quite old. However meanwhile there are alternatives. I suggest to install pgcc which you may download from OS/2 software sites or it's homesite. The Pentium optimized GCC offers OS/2 users access to a gcc of the 2.9x series, as opposed to EMX which is at gcc level 2.8.1. PGCC/2 even offers new features: improved code generation for recent processors, a new version of GAS(=GNU assembler) with MMX support, less C++ -related bugs, enhanced C++ features/language set, new, but broken g77=Fortran 77 compiler,
Recently there also came up a port (beta status) of gcc 3.x. Probably won't bring much for plain C programming, but certainly has enhanced support for C++.

There are various tutorials on getting EMX and XFree86OS/2 to work, please refer to the according link section.

Standard Tools

Except the basic requirements as outlined above you will need additional tools if you want to build packages bigger than the famous "Hello_World.c" example. The following list is probably too long, but except a waste of disk space I see no reason not to install some utilities in advance ;-)
Those tools have to be first in %PATH% before any other incompatible versions!
All should be available from OS/2 software sites. Don't forget to put sh.exe into the /bin subdirectory on your working drive to keep many scripts/Makefiles running without changes (this holds for other standard tools as well, like rm, cp, ...).
Other useful tools include:

Scripting Languages

un*x offers a variety of script languages like perl and Tcl/Tk. Some are used for rather simple tasks if the more basic tools (like sed, awk, etc.) are no longer sufficient or the suitable command lines become too awful. The OS/2 command shell cmd.exe can not execute such things directly, so you either have to explicitly call the interpreter (like foo bar.foo) or rename it to foo.cmd and add a suitable first line containing extproc foo like e.g. for perl scripts:
extproc perl -S
Perl scripts of this kind have to be in your %PATH%!

The following table contains several language interpreters which have already been ported to OS/2. The offered links may not necessarily point to the latest version, but you will find out yourself.
Script languages and their OS/2 ports
Language OS/2 port
awk (e.g. GNU awk="gawk") OS/2 software sites
m4 OS/2 software sites
perl ftp.math.ohio-state.edu or numerous versions from OS/2 software sites
python www.python.org and another page
(un*x) shell script various ports; see sites.html
Tcl www.vaeshiep.demon.nl
Tk www.vaeshiep.demon.nl

Archiver Formats

Here is a list of some common archiver formats and the according tools to extract them (see OS/2 software sites).
On un*x it's common to use cumulative suffixes, so hello.tar.gz refers to a file hello.tar which is an archive file produced by tar which has finally been packed by gzip.
Archiver formats
Extension Related Tool
.bz2 bzip2
.cpio cpio
.deb Package for Debian linux
.gz (GNU) gzip [gzip -d, gunzip]
.rpm RPM; OS/2 port of this tool
.shar sh (shell archives) [sh foo.shar]
.tar tar
.uue uudecode/uudeview
.Z decompress/gunzip
.z pack/unpack
.zip Info-(un)zip

Helpful Stuff

Here I bring some tools to your attention which you don't really need perhaps, but which are really nice to have around!

Common APIs

Beyond the problems of getting configuration and Makefiles to run properly on OS/2 the most striking problem is obviously to get the missing un*x API calls done on OS/2. In general there are two solutions:
The first one sounds like the preferable approach, but on a single-user, non-un*x systems it doesn't make much sense to deal in detail with concepts which doesn't exist at all on the target platform!

Useful & Dirty Workarounds

These are not necessarily "canonical" and clean approaches, but often they will fulfill their purpose very well. This section includes functions, macros and constants. The functions/macro replacements might be "enhanced" by adding the correct number of arguments. Obviously defining a macro/function to either 0 or the appropriate return code upon error relies on the concept that the source was written properly and to some extent handles failures of these APIs properly.
Attention: using these redefinitions will make debugging more complicated since you have to remember all of them! At least I don't have a source code debugger which offers additional support here.

#define chdir              _chdir2           /* see below */
#define chown(x,y,z)       (0)
#define endgrent()                           /* is type void */
#define FNDELAY            O_NONBLOCK
#define getcwd             _getcwd2          /* see below */
#define getdtablesize ()   (1024)
#define getgrent()         ((group*)NULL)
#define link(x, y)         (-1)              /* no hard links, below */
#define lstat(n, b)        stat(n, b)        /* see stat(), links */
#define major(dev)         (0)               /* see below */
#define makedev(dev,minr)  (0)               /* see below */
#define minor(dev)         (0)               /* see below */
#define mkfifo(p,m)        (0)               /* see below for mkfifo() */
#define mknod(p,m,d)       (0)               /* see below */
#define mlock              (-1)              /* see below */
#define munlock            (-1)              /* see below */
#define munlockall         (-1)              /* see below */
#define readlink(x,y,z)    (0)               /* or (-1) and use errno? */
#define setgrent()                           /* is of type void */
#define setpgrp()          (0)               /* ? */
#define sigset(x,y)        signal(x,y)       /* well, almost ... */
#define strcasecmp         stricmp           /* see libExt */
#define strncasecmp        strnicmp          /* see libExt */
#define symlink(x,y)       (-1)              /* see below */
#define sync()                               /* check out fsync(), etc. */
#define S_ISLNK(x)         (0)               /* see below */
#define S_IFLNK            (0)               /* see below */
#define S_ISBLK(x)         (0)               /* see below */
#define S_IFBLK            (0)               /* see below */
#define S_ISVTX            (0)               /* see below */
#define usleep(t)   _sleep2(((t)+500)/1000)  /* see below */

APIs that need Special Care

This section features some comments on available APIs which have to be handled with special care and some thoughts on not yet implemented ones.
ecvt(), fcvt(), gcvt()
Convert a floating-point number into a string. Not available as far as I know. Try replacing it by *printf() or even attempt to write your own version. Shouldn't be too hard ...
errno
errno is nothing un*x-specific, but an integral part of ANSI/ISO C's error handling. The catch here is that some programmers erroneously #define errno to something like int or even abuse it as a name for an identifier.
Related to errno is an important thumb-rule: always compile and link your EMX apps as multi-threaded applications (gcc flag -Zmt). This will avoid much trouble.
exec*()
See fork() and the section about process handling.
Replace exec*() with spawn*() and exit() if the parent process waits for the termination of the new process (by calling wait() or by waiting for SIGCHLD). This is required to keep the process ID of the child process. In a forked process, however, you don't have to do this because emx.dll does it for you.
fchmod()
Part of libext.
fcntl()
F_SETLK is not supported.
Write your own fcntl() or add code which makes use of an existing flock*() implementation. Or watch libext.
flock()
Check out the native API DosSetFileLocks(). Also see libext.
fork()
See exec*() and the section about process handling.
Replace fork() and exec*() with spawn*(). Under OS/2, fork() is inefficient. You may not care if it's rarely being called, but read the docs for any specific information about the fork() implementation.
Don't forget that fork() doesn't work in link386 (-Zomf) created executables!
Read the section about XTHREADS if you are going to use fork() or threads within an X11 application.
getenv()
See section about environment variables.
getrlimit()
This is not a POSIX.1 function, but should be part of libExt
Also see ulimit(3), sysconf(3), emxdev: chapter "7 Customizing".
mlock(), munlock(), munlockall()
The DevHlp*() interfaces (API for device drivers) provide such calls, to mark memory pages as non-swappable. However this is no trivial replacement which could be implemented by inserting a few lines of code.
poll()
A call similar to select(). Check out libExt for an emulation using this relationship.
popen()
Ensure to use the "b" in the mode flag when necessary!
Also see system().
random()
The EMX docs claim that random() is superior to rand(), so try to use this instead. It's hidden in libbsd.
realpath()
libext has an implementation which can be used as a stand-alone version after editing a few lines.
rename()
EMX' rename() doesn't replace existing targets.
It also fails on open files.
Also see remove().
remove()
remove() fails on open files.
On un*x you can (re)move open files. On OS/2 you can not and therefore this call might fail (this is a simplified picture; it can also fail on un*x - but won't do that often). A major component here is the file system, and since modern operating systems can deal with many of them, it is not precise to make statements based only on the OS being used.
select()
select() is a common source of portability problems. These may involve: the necessary header files, argument types or some "EMXisms", like the following: select() will report that stdin is "ready", i.e. will return immediately. If you want to trigger on any new input, i.e. keystrokes, you have to change the terminal settings (see tcsetattr()). A small code snippet should give you the idea:
#include <sys/types.h>
#include <stdio.h>
#include <termio.h>
#include <termios.h>
#include <sys/time.h>
#include <sys/select.h>

int nfds, retval;
fd_set rfds;
struct timeval tv;
struct termios tio;

/* initialize rfds to 0: */
FD_ZERO(&rfds);
/* Watch stdin to see when it has input: */
FD_SET(fileno(stdin), &rfds);
/* only one file descriptor to monitor: */
nfds=1;
/* Now change EMX' default settings: */
tcgetattr(fileno(stdin), &tio);
tio.c_lflag &= ~IDEFAULT;
tcsetattr(fileno(stdin), TCSANOW, &tio);
/* Wait up to five seconds: */
tv.tv_sec = 5; tv.tv_usec = 0;
retval = select(nfds, &rfds, NULL, NULL, &tv);
if (retval > 0) {
   printf("Data is available now.\n");   
   /* FD_ISSET(0, &rfds) is 'true' here now */
}
sigaction()
Check the code which signal model is used and choose the appropriate linker flags (see signal()). Especially check if you need to link with -Zbsd-signals while XFree86OS/2 (imake; perhaps the docs mention it as well) still tends to use -Zsysv-signals .
The EMX docs describe what happens if sigaction() and signal() are used together.
signal()
By default EMX' signal processing is different from any existing standard (as of SVID or BSD): SIG_ACK should be used instead of the signal handler address to re-enable a signal by calling signal() when the signal handler has been called. This behavior can be changed with the -Zbsd-signals and -Zsysv-signals linker options of EMX gcc. If you use POSIX.1 functions for signal handling, SIG_ACK is not required.
Comment out or replace code which is based on non-implemented signals. The EMX (IBM toolkit) docs list all available signals and give further information. But, of course, you need to know what you're going to miss then ...

By collecting signal types from various operating systems I got a rather long list - see below. The references {OS/2-IBM, EMX, Both, none} may be incomplete or even wrong. Please check the according docs, or even the headers!

Collection of signal types
SIGNAL name Description Reference Comments
SIGABRT Process abort signal B e.g. by abort()
SIGALRM Alarm clock E  
SIGBREAK CTRL-BREAK by user B OS/2 only
SIGBUS Bus error E  
SIGCHLD (SIGCLD) Child process stopped/terminated E  
SIGCONT Continue if stopped -  
SIGDANGER Danger signal -  
SIGEMT ? E  
SIGFPE Floating point exception B  
SIGHUP Hangup E  
SIGILL Illegal instruction B  
SIGINFO Information request -  
SIGINT Interrupt from terminal B  
SIGIO IO now possible - (4.2 BSD)
SIGIOT IOT trap -  
SIGRANT Monitor mode granted -  
SIGKILL Kill process E cannot be be caught or ignored
SIGLOST Resource lost -  
SIGLWP ? -  
SIGMSG Monitor mode data available -  
SIGNOFP Floating point co-processor not available -  
SIGPHONE ? -  
SIGPIPE Broken pipe E write to pipe without reading process
SIGPOLL I/O possible -  
SIGPROF Profiling timer expired -  
SIGPWR Power failure -  
SIGQUIT Quit from terminal E  
SIGRETRACT Need to relinquish monitor mode -  
SIGSEGV Segmentation fault B  
SIGSOUND Sound completed -  
SIGSTKFLTT Stack fault on coprocessor - (linux)
SIGSTOP Stop process -  
SIGSYS Illegal system call E  
SIGTERM Termination B  
SIGTRAP Breakpoint/tracepoint trap E (see hard-coded breakpoint)
SIGTSTP Stop typed at tty -  
SIGTTIN tty input for background process -  
SIGTTOU tty output for background process -  
SIGUNUSED Unused signal - a very important one ;-)
SIGURG Urgent I/O condition -  
SIGUSR1 User defined signal #1 B  
SIGUSR2 User defined signal #2 B  
SIGUSR3 User defined signal #3 I EMX seems to miss this!?
SIGVTALRM Virtual timer expired -  
SIGWINCH Window resize E see termsize lib
SIGWIND ? -  
SIGXCPU CPU time limit exceeded -  
SIGXFSZ File size limit exceeded -  

stat(), fstat(), lstat()
A call to query about an entry in your filesytem. This may be non-portable when it checks for non-existing properties on the new platform, like special file types or even low-level entries within the file system internals (inodes, etc.).
lstat() may be mapped to stat(), but for compatibility with future enhancements it should have it's own wrapper (see libext).
system()
If you are lazy and keep the un*x-like forward slashes in paths arguments for system() calls may be passed to cmd.exe which might not be able to handle them!
system() and popen() do not expand wildcards unless COMSPEC/EMXSHELL points to a shell which expands wildcards (of course on un*x those calls wouldn't do either - but the shell being called). Read the EMX docs to learn which shell is called by these routines! One may run across code like system("foo&"); which would try to launch a job in the background with an un*x shell but this won't work with cmd.exe. See "sh vs. cmd.exe"!
tcsetattr()
Any kind of subtle problems with VIO programs may stem from the fact the EMX by default uses a non-standard mode for terminal IO. The first call to tcsetattr() switches to Posix mode. This related to the
unlink()
An obsolete call. Use remove() instead.
usleep()
The workaround given above (using _sleep2()) doesn't feature a microsecond resolution; but contrary to its name many implementations on un*x won't do either. More info on timers on OS/2 is available on EDM/2. Also see info about g/setitimer().
Another quite "portable" approach uses select() as shown in the example code below. You must not specify descriptors to monitor, but only a timeout. Check out the docs which resolution actually is provided here and about properties of this call in general (e.g. the effect of signals being raised).
#include <sys/types.h>
#include <sys/time.h>
#include <sys/select.h>

struct timeval tv;
long secs, microsecs;


/* set the interval: seconds and microseconds */
tv.tv_sec  = secs;
tv.tv_usec = microsecs;

/* tell select() to monitor no file descriptors */
select(0, (fd_set *)NULL, (fd_set *)NULL, (fd_set *)NULL, &tv);

Ported APIs

This is a collection of known ports of APIs which are more complex than a simple wrapper like:
#define foo bar
I try to list only "general purpose" stuff that can used in any kind of application. Interfaces for rather special purposes may be collected elsewhere. Some of those and many others are meanwhile part of libExt.

un*x Process Stuff

Process handling is a bit different on un*x. However often you won't notice that, since the most frequently used APIs are dealing with starting a process via system(), exec*(), etc. which are available on OS/2 EMX (also see fork()).

The term thread has no unique meaning in the un*x world as opposed to OS/2. Those un*x systems which had already offered something similar to the OS/2 threads concept often developed their own standard for this (see threads-FAQ for more details). Finally pthreads (POSIX threads) settled down as a standard. A wrapper library from this API set to native OS/2 threads exists (see OS/2 software sites), but may still be work in progress.

Starting Processes

For purposes similar to those of multi-threading often child processes started via fork() are being used.

When fork()/ exec*() is used to start a subprocess often communication between the parent and child process is done. The most simple way is to redirect std* (=stdin/stdout/stderr) using pipes (created by pipe()). If you migrate the code from fork()/ exec*() to spawn*() you have to change this code slightly as well: in the former case pipes are created, then the child process switches it's std* to the according ends of the previously created pipes before calling exec*(). The parent just closes the unused ends of the pipes and keeps those required to communicate with the child. When using spawn*() you don't have explicit access to the child, but it inherits the pipes/handles given from it's parent. So you have to redirect std* of the whole process to the pipes, start the child and fixup std* again:

  1. create backups of the std* handles (-> dup())
  2. redirect the std* handles (-> dup2())
  3. start the child (-> spawn*())
  4. restore std* (-> dup2()) and close() unused file handles

An example (no warranty, but it seems to work) with those two alternatives is now given: it will execute the command given as the first argument. First the version using fork()/ exec*():
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main(int argc, char *argv[]) {

  char data[1024];
  int fd[2], result;

  if (pipe(fd)) exit(1);                 /* error creating pipe */
  fflush(stdout);                        /* flush stream before redirection */
  if ((result=fork())) {                 /* parent process */
    if(result==-1) exit(2);              /* error fork()ing */
    else {
      close(fd[1]);                      /* close writing end */
      setvbuf(stdout, NULL, _IONBF, 0);  /* disable buffering */
      while ( read(fd[0], data, 1) ) {
         putchar((char)data[0]);
      }
      close(fd[0]);
      } /* parent */
  }
  else { /* child */
    close(fd[0]);                        /* close reading end */
    dup2(fd[1],1);                       /* connect writing end to stdout */
    close(fd[1]);
    execv(argv[1], argv+1);
    exit(3);                             /* exec*() returns on error only */
    }
  exit(0);
}
or with spawn*():
#include <stdlib.h>
#include <stdio.h>
#include <process.h>
#include <fcntl.h>
#include <io.h>

int main(int argc, char *argv[]){
  char data[1024];
  int fd[2], ftmp;

  if (pipe(fd)) exit(1);             /* error creating pipe */
  fflush(stdout);                    /* flush stream before redirection */
  ftmp=dup(1);                       /* save the stdout handle */
  dup2(fd[1],1);                     /* assign write end of pipe to stdout */
  close(fd[1]);                      /* close pipe handle*/
  setvbuf(stdout, NULL, _IONBF, 0);  /* disable buffering */
  /* prevent unused pipe handles from being inherited by childs */
  fcntl(ftmp, F_SETFD, FD_CLOEXEC);
  fcntl(fd[0], F_SETFD, FD_CLOEXEC);
  spawnv(P_NOWAIT, argv[1], argv+1); /* start child process */

  /* restore the original stdout file handle and close pipe */
  dup2(ftmp,1);
  close(ftmp);
  /* demonstrate that things work as expected: read and print out something */
  read(fd[0], data, sizeof(data));
  printf("%s\n", data);
  close(fd[0]);
  exit(0);
  }

Watch out for open files (socket, ...), better: file handles, being passed to subprocesses: e.g. handles to an open file which are being passed to a spawned child process may prevent the parent from removing that file later on. See fcloseall() and fcntl() (-> FD_CLOEXEC flag).

Process Properties

Nothing sophisticated from the un*x point of view is taught here, just briefly mention some interesting features from an OS/2 users point of view ...

un*x Filesystem Stuff

Common "native" un*x filesystems are quite different from those usually found on OS/2 (FAT, HPFS, HPFS386, JFS). Be aware that some really surprising things may show up: interfaces to memory, processes and hardware devices for example!

Let's have a look at some of the interesting properties:

Miscellaneous Issues

This is a collection of various helpful suggestions which don't fit yet in the other sections.

Various Hints

sh vs. cmd.exe

While many want to abandon the "good old", but brain-dead cmd.exe there are many reasons to keep it, mainly for compatibility to existing solutions. So one may have to migrate a couple of shell commands and even complete simple scripts.

In & Out

This is a section about general Input/Output related topics. Since that issues are rather complex I can't even nearly fill/discuss all subsections ...

Device Driver Interfaces

Under un*x device drivers frequently feature interfaces which show up in the file system. This is at first glance something new to OS/2 users, but actually they already know similar interfaces (\PIPE\). Since this mechanism to access arbitrary devices has no trivial mapping to OS/2 capabilities, not all related interfaces can be ported: the code needs a major rewrite.

Printing

Printing on un*x is quite different to OS/2: no sophisticated system interfaces exist (read: may exist but are rarely used and not necessarily portable) so all applications have to do this on their own. Existing no-cost solutions (since only those are - if at all - of interest to OS/2 users in this context) include: Common denominator is that a Postscript-capable printer is supposed to be attached to the system. Also a set of standard utilities to submit/manipulate jobs for this device is required.
If you're lucky enough to have a Postscript printer on your OS/2 system you may use the lpr and lpd tools (shipped with Warp 4) to access the Postscript printer queues from the commandline.
More on this topic can be found in the separate document printing.html which however covers "only" printing from non-PM applications.

Sound

Portable audio doesn't seem to be available across operating system borders. For many un*x flavors there's the Open Sound System (OSS), which brings digital audio (also MIDI) with an "open" interface.
There's a /dev/audio emulation available from OS/2 software sites (devaudio*.zip). Given this version one might imagine to have the current implementation enhanced by additional features.

Miscellaneous I/O

With respect to general hardware access it's hard to find a portable standard at all here. Here's a short list of docs/projects which deal with portable I/O:

EMX & OS/2 Specifics

Here I address peculiarities and problems that the EMX runtime and OS/2 system present to the programmer. Most are taken from "emxlib.doc: 5.1 Porting Unix applications" and from emxdev.doc: 5 Hints for porting Unix programs to emx", but I'm also adding entries here myself.

From EMX docs

Though the following entries are more or less excerpts from the EMX docs I've started to modify them and therefore do no longer claim that it's actually the same what you can read in the EMX distributions!

From other sources

Configuration Stuff

Various build mechanisms are used in the un*x world: simple/complex/nested Makefiles, crazy batch files, autoconf, Imakefiles, ...
Anyway you should get all available un*x tools which are already ported, many of them being from GNU. More details can be found at the description of autoconf and in the tools section.

Makefiles

In my opinion Makefiles are the best build mechanism. Up to obscure internal rules of the Make utils it is a clean and obvious approach and also it's very easy to learn.

Batch Files

The term "batch file" here refers to scripts written for an un*x-like shell (see below). Those shells scan the first line of an executable batch file for the interpreter being required (similar to EXTPROC which cmd.exe recognizes) while you can also write some commands for the current shell without that header:
#! /bin/sh

Some comments on shell scripts:

auto* tools

GNU autoconf is a tool (set) which produces configuration and Makefiles to build software in different environments. Given the software is properly adapted and autoconf has support for that platform it will then automatically detect the available tools and programming environment (libraries, headers, etc.).

autoconf

Source distributions of packages usually include a created "config.h" header which specifies the locally available features via preprocessor clauses like
/* Define if you have the "useless.h" header */
#undef HAVE_USELESS_H

/* Define if your libc has the strange() function */
#define HAVE_STRANGE 1

For more details on this read the short introduction into the auto* business written by Ian Lance Taylor.
Some OS/2-specific comments are helpful. An important requirement is probably experience with that stuff on a real un*x-platform, otherwise you'll struggle way too often.

automake

automake is a companion to autoconf and OS/2 ports are available at the same places usually. A project might start from an even simpler set of input files which will then be processed by automake and autoconf to end up with a configure script which will finally create all Makefiles and configuration files. automake itself creates a Makefile.in out of a Makefile.am. In general all files configure should process have to carry the .in postfix.

libtool

GNU libtool is being used to build libraries. Usually only for shared libs, since producing static ones should be quite simple (and standard).

Imakefile

imake and related tools like xmkmf ship with X11 distributions. It is used for X11 software only. Run xmkmf (mxmkmf exists for LessTif systems; the OS/2 port lacks this so far) to create a Makefile from an input Imakefile.

X11 Specifics

In general you don't need to make changes specific related to the XFree86OS/2 implementation of the X11 standard. It is very close to the level which is supplied for un*x platforms. In turn XFree86 is based on the official releases from the OpenGroup and therefore conforming to the standards. Similar to the M*tif case, here the official implementation is the standard ...
In fact most problems arising are already covered in the XFree86OS/2 FAQ and on the related mailinglist.

How to get a single key pressed in an xterm?
This is a real FAQ for un*x programming.
By default many terminals are in a mode which blocks until RETURN is pressed. The major task to be done is therefore setting the terminal in the correct mode. Fortunately there is a standard interface for this defined within POSIX.1.
You should read about tcsetattr() and check out the sample code which I provide for the select() call or have a look at some other sample code.
How to work around the non-working SIGWINCH?
Have a look at this termsize library
Is X11 multi-threaded?
XFree86OS/2 does not support the X11 threading concept called XTHREADS. This is not a critical limitation since any valid software has to check (and can easily do) whether this feature is enabled or not. Here's a suitable autoconf macro:
AC_TRY_RUN(
[
#include <X11/Intrinsic.h>
int main() {
Boolean brc;
brc=XtToolkitThreadInitialize();
if (True==brc)
  exit(0);
else
  exit(1);
}
],
have_xthreads=yes,
have_xthreads=no,
have_xthreads=dunno)

It is important to perform all X11 calls from a single thread. Otherwise you may get errors like:
Xlib: unexpected async reply .
This may require quite some efforts if you have an application which uses multiple threads to emulate some missing timer APIs like g/setitimer().

How to debug an X11 application?
See debugging.html for some general comments. Remember that an X11 application isn't running straight through some main() routine (except for the beginning or end perhaps), but most of the time it stays in a loop which waits for events like keyboard or mouse actions. Then it calls the appropriate routines ("callbacks") which have been installed to react upon them.
How to resolve X errors?
If the app foo uses the XIntrinsics (usually linked against Xt.dll) run foo -sync inside a debugger and set a breakpoint on exit(). Also check out the according section in debugging.html.
What if an (X11) app fails to link due to unresolved symbols?
If the linking process fails, this probably means you didn't specify some library, or the required libraries aren't available on your system (this is nothing X11 specific). Also you could have missed to specify an object file. Error messages indicating this problem contain long lists of undefined symbols, most of which have a name with an identical prefix, such as Xm. The leading underscore which gets added to all symbols (at least using EMX/gcc) is omitted here for brevity.

In the following I list some prefixes and the related linker command to select the required library. A concise description is given as well as an entry which tells you from where to get the library. The entries are sorted by the name of the library, not by the exported symbols.
X11 related libraries
Prefix Library Description Origin
fltk -lfltk GUI Toolkit (C++) fltk (OS/2 port)
fl_ -lforms GUI Toolkit (C) xforms (OS/2 ports)
gtk_, GTK_ -lgtk GUI Toolkit (C) ?
Ice -lICE Inter-Client Exchange XFree86 OS/2
gl_ -lMesaGL OpenGL clone (3d API) MesaGL (OS/2 ports)
Mrm -lMrm Motif Resource Manager Motif
PEX -lPEX PHIGS Extension for X (3d APIset) XFree86 OS/2
qt_, ... -lqt GUI Toolkit (C++) ?
shm -lshm Provides Shared Memory various sources
Smc, Sms -lSM Session Management XFree86 OS/2
Uil -lUil User Interface Library Motif
X -lX11 Standard X11 core routines XFree86 OS/2
Xau -lXau X authority database routines XFree86 OS/2
Xaw -lXaw Athena widgets XFree86 OS/2 (?) (also check OS/2 ports)
Xbae -lXbae Matrix Widget Set Xbae (LessTif)
Xdmcp -lXdmcp X Display Manager Control Protocol XFree86 OS/2
DPMS -lXdpms X Display Power Management (DPMS) Extension XFree86 OS/2
Xdbe, Xext, XShape -lXext X Extensions XFree86 OS/2
Xie -lXie X Input Extensions XFree86 OS/2
Xlt -lXlt Widget Set (Motif Extensions) Xlt (LessTif)
Xm -lXm Motif (GUI toolkit) Motif
Xmu, XEditRes -lXmu Miscellaneous X utility functions XFree86 OS/2
Xp -lXp X Print Server XFree86 OS/2
Xpm, xpm -lXpm Bitmap/Pixmap Routines XFree86 OS/2, ports
XScreenSaver -lXss ScreenSaver Support XFree86 OS/2
Xt -lXt X Toolkit Intrinsics XFree86 OS/2
Tcl_ -lxtcl Tk (GUI for Tcl) ports
Tk_ -lxtk Tcl to X11 interface ports
XTest, XRecord -lXtst Test Extensions XFree86 OS/2

You may locate symbols which aren't listed here by running emxexp on the libraries in %X11ROOT%/XFree86/lib. Obviously the library name tends to be the same cryptic letter combination as the prefix you are looking for. Libraries marked as C++ -bindings have mangled names, i.e. a complex mixture between the plain name of the function/variable/method and its signature (if it's a routine). Use nm -C foo.o to see the demangled names.

The order in which you have to link these libs is partially fixed:

-lUil -lMrm -lXm -lXt -lXmu -lXp -lXext -lXpm -lSM -lICE -lX11

Requirement is that a library which depends on another one is specified before that other one. Of course not all of these libraries are always necessary, but in some cases even more libraries may be required. The socket library (-lsocket) is another candidate here. It provides e.g. gethostname() or connect().
How to link an X11 application statically?
If you want to debug an X11 application and need to deal with X Errors (see debugging.html and debugging_os2.html) you may consider to link the X11 libraries statically as well (though you don't gain much here).
To do so you have to get the static libraries package from the official distribution. Then replace all link requests -lfoo by -lfoo_s. Switching one library from dynamic to static linkage might force you to do the same with others as well! However you may try to link only those statically which are required to satisfy the linker (see example below). In addition new libraries might now be required, e.g. -lsocket (see "What if an (X11) app fails to link due to unresolved symbols?"). A sample commandline would be:
gcc -Zmtd -Zbsd-signals -o bar.exe bar.o -lXt_s -lX11_s -lsocket
Be warned though: statically linked X11 apps might cause problems once you update your X/2 system. My instructions here could also be incomplete: I got some strange errors which I could not explain so far ...
And don't forget that applications for XFree86OS/2 demand to be linked via -Zmtd.
How to create a "dualmode" application?
When building a dualmode application (command line and X11 app in a single executable) you may wish to link to the X11 libraries statically. This way you can distribute a binary to people which don't have XFree86OS/2 installed.
Actually I should better say "stand-alone, dualmode" application, therefore see also "How to link an X11 application statically?" Many X11 apps feature a commandline interface as well, e.g. to issue a help message upon -help. This is (almost) never found within OS/2 PM applications since this didn't fit into IBM's shortminded concept of separating PM and VIO apps unfortunately. This can be done by "morphing" the application. You may try out the sample code provided by Darren Abbott.
How to distinguish between VIO, PM, X11 session?!
Sometimes one need to check programmatically whether a process is running in a VIO, PM or X11 session. The latter is not recognized by native OS/2 or EMX APIs, so we need to look for some hacks...

If some parent process was started from within the X11 session the environment variable WINDOWID is set to some integer value. A more thorough check seems to be difficult; even if one would climb up the process hierarchy it's not obvious what to check for: e.g. a search for "xterm" wouldn't catch alternatives like "rxvt". One would have to check whether the current process (or one of its parents) belongs to a window on the current display?!

The even more fundamental check whether X11 itself is available (and running) can be based on that code snippet:

#include <X11/Xlib.h>
Display *disp=XOpenDisplay(NULL);
which should assign a non-NULL value to disp.
If you want to make that binary running without X11 to be installed add those two steps before:
  1. check for %X11ROOT%
  2. try to dynamically load libX11:
    dlopen( %X11ROOT%/XFree86/lib/X11.dll ) /* pseudeo code only! */
    and perform that check.
However in general it's better to link the whole application statically against the X11 libs then.
Which GUI toolkits/widget sets are available?
Dozens of them exist in the un*x world and many of them have been ported already (check out sites.html). However there are none of the commercial ones available, i.e. those which don't offer sources for free. Mostly used in the X11 world is the industry standard Motif® (developed & owned by the OpenGroup; core part of it is libXm). Meanwhile you may use the OpenMotif release on a few platforms, but not on OS/2 (you may however obtain a source license for big money and try to compile for XFree86 OS/2). Instead you may download LessTif from www.lesstif.org: it is a free (LGPL'ed) available clone of Motif. It is source compatible, so you can just rebuild sources written for Motif®.

External Resources

This is mainly a link section. Except references to documents which I've written I refer to OS/2-related information sources.

Related Documents

Some related documents which I have written and still work on. Most of them were initially just excerpts from this porting FAQ. Then I got the idea that they might be useful for other purposes as well ...

Online Resources

There are many big, useless link lists out there. I try to collect real helpful ones, i.e. canonical resources as well as sites which have real unique offers.


Send Feedback to
Alexander Mai <st002279@hrzpub.tu-darmstadt.de> or <amai@lesstif.org>

Last modified on 20020218