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

From EDM2
Jump to: navigation, search

by Alexander Mai

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 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 fix spelling or grammar, you are welcome to edit this wiki pages.

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 in this document came from these two people and the numerous members of their projects' mailing lists.

Alexander Mai give permission to republish this articles under the Creative Commons Attribution-Share Alike 3.0 license to be included on this wiki.

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 growing slowly, and also still contains lot of typos and errors. Currently (Q4/2003) the document is quite "stable", I'm busy fixing errors and broken links.

Work is/was 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):

  • Caught some grammar/spelling errors
  • Updates to the standards document
  • Update many external links
  • Update some of my links and my email address (For checking links I'm using ALC Alexander's Link Checker)

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 programmers for OS/2 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). Before you start coding search on [sites.html OS/2 software sites] google (or similar search engines) and asked on the EMX, XFree86OS/2 and related 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 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. In addition to providing libc enhancements it also ships with 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 also 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 and a new, but broken g77 (=GNU Fortran 77 compiler.

Recently there also came up a port (beta status) of gcc 3.x (a more recent version is available from Innotek. 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 [[#nameclash|incompatible versions]!

All should be available from OS/2 software sites.

  • GNU file utils (cp, install, [#ln ln], ls, mkdir, mv, rm)
  • GNU shell utils (expr, pwd, sleep, tee, [#test_exe test])
  • GNU text utils (cat, head, join, sort, tail, uniq)
  • find
  • bash, ash (or other standard-like shell)
  • GNU bison (yacc replacement)
  • flex (lex replacement)
  • grep (egrep, fgrep, etc.)
  • [#gzip gzip ("GNU zip")]
  • (GNU) Make
  • patch
  • sed
  • tar
  • uname (unfortunately many versions exist; get one that is compatible with your [#autoconf autoconf] version)
  • uudecode/uuencode

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:

  • diff (to create patches, so called "diffs", for textfiles only)
  • groff, man (to read [#un*x un*x] man pages)
  • indent (to format source code)

Scripting Languages

[#un*x 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") [sites.html OS/2 software sites]
m4 [sites.html OS/2 software sites]
perl ftp.math.ohio-state.edu or numerous versions from [sites.html 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 [sites.html OS/2 software sites]).

On [#un*x 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 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 present some tools which you don't really need, but which are nice to have around!

  • There are numerous utilities available which translate files from [#un*x un*x] to DOS [#text_formats text format] (and Macintosh if required) and vice versa: dos2unix/unix2dos, recode, tr, trans, ...
  • TVFS: Toronto Virtual File System.

Available from OS/2 software sites. It installs a virtual drive and allows to create links on it. So you can access all your partitions on that single virtual drive and don't need to use drive letters!

  • OS2TRACE (OS/2 API tracer)

A tool which can trace down most OS/2 API calls. Not very helpful when starting work on a port ...

  • Get chk4dlls somewhere. It lists all DLLs required by an executable/DLL and is an equivalent to the ldd utility available on many [#un*x un*x] systems.

Note that it doesn't list libraries which are explicitly dynamically loaded during runtime using DosLoadModule(), dlopen(), etc.

  • Get some tools to process the various documentation formats. Converters are available for

Those converters may be combined in a tool chain, so that a conversion of some lengthy man page to a simple-structured INF document is actually possible.

  • Get CVS (Concurrent Versions System): A tool used for many open source projects on the net.

You do not need to actively participate in the development to benefit from CVS: You can then easily get upgrades without downloading the whole package. The given link may carry outdated executables; check out OS/2 software sites.

  • Get ctags.

It scans the sources and produces a reference list of all symbols together with their precise location. Together with a suitable editor (like NEdit, Emacs, XEmacs, vi and it's clones, ...) this makes a powerful combination: e.g. you select a function's name and a single keystroke will bring you to its definition!

The probably best, because most powerful implementation is Exuberant ctags.

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 un*x] API calls done on OS/2. In general there are two solutions:

  • map them to native interfaces
  • forget about them

The first one sounds like the preferable approach, but on a single-user, non-un*x system it doesn't make much sense to deal in detail with concepts which don't exist on the target platform!

Useful & Dirty Workarounds

These are not necessarily "canonical" and clean approaches, but often they 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 </nowiki>[#_chdir2 below] */
 #define chown(x,y,z)       (0)
 #define endgrent()                           /* is type void */
 #define FNDELAY            O_NONBLOCK
 #define getcwd             _getcwd2          /* see [#_getcwd2 below] */
 #define getdtablesize ()   (1024)
 #define getgrent()         ((group*)NULL)
 #define link(x, y)         (-1)              /* no hard links, [#links below] */
 #define lstat(n, b)        stat(n, b)        /* see [#stat stat()], [#links links] */
 #define major(dev)         (0)               /* see [#devicedriverinterfaces below] */
 #define makedev(dev,minr)  (0)               /* see [#devicedriverinterfaces below] */
 #define minor(dev)         (0)               /* see [#devicedriverinterfaces below] */
 #define mkfifo(p,m)        (0)               /* see below for [#mkfifo mkfifo()] */
 #define mknod(p,m,d)       (0)               /* see [#devicedriverinterfaces below] */
 #define mlock              (-1)              /* see [#mlock below] */
 #define munlock            (-1)              /* see [#mlock below] */
 #define munlockall         (-1)              /* see [#mlock below] */
 #define readlink(x,y,z)    (0)               /* or (-1) and use [#errno errno]? */
 #define setgrent()                           /* is of type void */
 #define setpgrp()          (0)               /* ? */
 #define sigset(x,y)        signal(x,y)       /* well, almost ... */
 #define strcasecmp         stricmp           /* see [#libext libExt] */
 #define strncasecmp        strnicmp          /* see [#libext libExt] */
 #define symlink(x,y)       (-1)              /* see [#links below] */
 #define sync()                               /* check out fsync(), etc. */
 #define S_ISLNK(x)         (0)               /* see [#stat below] */
 #define S_IFLNK            (0)               /* see [#stat below] */
 #define S_ISBLK(x)         (0)               /* see [#stat below] */
 #define S_IFBLK            (0)               /* see [#stat below] */
 #define S_ISVTX            (0)               /* see [#stat below] */
 #define usleep(t)   _sleep2(((t)+500)/1000)  /* see [#usleep 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 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 fork()] and the section about [#process process] handling.
Replace exec*() with [#spawn spawn*()] and exit() if the parent process waits for the termination of the new process (by calling wait() or by waiting for [#sigchld 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 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 libext].
flock()
Check out the native API DosSetFileLocks(). Also see [#libext libext].
fork()
See [#exec exec*()] and the section about [#process process] handling.
Replace fork() and [#exec exec*()] with [#spawn 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 XTHREADS] if you are going to use fork() or threads within an X11 application.
getenv()
See section about [#envvars environment variables].
getrlimit()
This is not a [Standards.html#posix POSIX.1] function, but should be part of [#libext 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 select()]. Check out [#libext libExt] for an emulation using this relationship.
popen()
Ensure to use the "b" in the mode flag when necessary!
Also see [#system 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 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()
remove() fails on open files.
On [#un*x 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 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 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 signal()]). Especially check if you need to link with -Zbsd-signals while [#x2 XFree86OS/2] ([#imake imake]; perhaps the docs mention it as well) still tends to use -Zsysv-signals .
The EMX docs describe what happens if sigaction() and [#signal signal()] are used together.
signal()
By default EMX' signal processing is different from any existing standard (as of [Standards.html#sysvid SVID] or [Standards.html#bsd 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 [Standards.html#posix 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

[#process_stop Continue if stopped]

-
SIGDANGER Danger signal -
SIGEMT Emulator trap (results from certain unimplemented instructions) 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 -
SIGGRANT Monitor mode granted -
SIGKILL Kill process E cannot be be caught or ignored
SIGLOST Resource lost -
SIGLWP Used by thread library. -
SIGMSG Monitor mode data available -
SIGNOFP Floating point co-processor not available -
SIGPHONE Line status changed -
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

[#process_stop Stop process]

-
SIGSYS Illegal system call E
SIGTERM Termination B
SIGTRAP Breakpoint/tracepoint trap E

(see [debugging_os2.html#hardcoded_bp 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 termsize lib]

SIGWIND Window change -
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 libext]).
system()
If you are lazy and keep the [#un*x 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 popen()] do not expand wildcards unless COMSPEC/EMXSHELL points to a shell which expands wildcards (of course on [#un*x 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 un*x] shell but this won't work with cmd.exe. See [#shvscmd "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.
unlink()
An obsolete call. Use [#remove 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 un*x] won't do either. More info on timers on OS/2 is available on EDM/2. Also see info about [#itimer g/setitimer()].
Another quite portable approach uses [#select 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 libExt].

  • dlopen()/dlfcn() (access to dynamic link libraries)

Part of [#libext libExt].

  • drand48(), srand48() (random numbers)

Part of [#libext libExt]. You can try to write a simple wrapper around rand() or even better [#random random()]. Just be aware of the slightly different interface.

  • gettext() (National Language Support library from GNU)

(on [sites.html OS/2 software sites] and from H.C. Chu)

  • mmap(), munmap(), etc. (mapping files into memory)
    A work in progress implementation is part of [#libext libExt] and a closed-source one on [sites.html OS/2 software sites].
    There's an article explaining how to write your own implementation.
  • mkfifo(3) (a named-pipe mechanism using the file system)
    An implementation comes with the math package Octave (on [sites.html OS/2 software sites]).
  • pthreads (POSIX threads) (on [sites.html OS/2 software sites] and on ftp.everblue.org)
  • (GNU) readline (provides simple editing features in an input line on terminals)
    Implementations are on [sites.html OS/2 software sites], but are not usable in xterms.
  • regex ([regex.html regular expressions]) (on [sites.html OS/2 software sites]; also part of [#libext libext])
    A Regular Expression is a text string that describes some set of strings. You can use it to search (and afterwards edit/process) for certain patterns. See regex.html for a small summary.
    Be aware that beyond some [regex.html common features] there are portability problems waiting if you use it heavily.
  • rpc (Remote Procedure Call) interfaces are supplied with [#libext libExt].
    H. Veit has done a port for EMX.
  • scandir() (read directory entries)
    Part of [#libext libExt].
  • setitimer()/getitimer() (timer functions)
    • H. Veit posted some comments and an example how to implement it using a secondary thread.
    • An (incomplete) implementation is part of [#libext libExt].
    • hrtimer.sys (version >= 1.1) with new simple open()/read() interface should make timing easy and enable writing an itimer compatible interface. Also you may read this EDM/2 article.
  • setpriority(), getpriority() (set/get process priority)
    A simple mapping to OS/2 calls should be nearly straightforward, as this [../data/priority.zip sample] shows. Also available within [#libext libext].
  • shm (shared memory between different processes): shmat(), shmctl(),shmdt(), shmget()
    Implementations come with [#x2 XFree86 OS/2] and [#libext libext] as well.
  • syslog() (send messages to system logger)
    Various ports are available on [sites.html OS/2 software sites].

un*x Process Stuff

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

The term thread has no unique meaning in the [#un*x un*x] world as opposed to OS/2. Those [#un*x 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 [sites.html 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 fork()] are being used.

When [#fork fork()]/ [#exec 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 fork()]/ [#exec exec*()] to [#spawn 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 exec*()]. The parent just closes the unused ends of the pipes and keeps those required to communicate with the child. When using [#spawn 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 fork()]/ [#exec 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 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 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 ...

  • Information about the processes on the system may be retrieved using the non-portable [#slash_proc /proc] interface.
  • You may halt a process by sending [#sigstop SIGSTOP] and make it continue by sending [#sigcont SIGCONT].

un*x Filesystem Stuff

Common "native" [#un*x 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 interesting properties:

  • File names are case-sensitive!
    Working on [#libext libExt] showed me that one has to do some search on native OS/2 APIs which can be used for case-sensitive file system stuff. DosQuery*Info() will succeed on calls for files in a case-insensitive matching! More useful is DosFindFirst() and it's friends (see Toolkit docs for sample code).
  • No drive letters are being used!
  • There are standard paths which always exist! Try out man hier on your favorite [#un*x un*x] system to get a description of the file system hierarchy being used. In the following overview I may also mention some which are not mandatory, while trying to have all the canonical ones included.
    /
    root directory. That one is unique due the absence of drive letters.
    /bin
    contains system executables
    /dev
    virtual interface to devices of all kinds (hardware, logical, ...)
    /etc
    configuration data
    /home
    directories of each user
    /opt
    optional installed stuff
    /proc
    Interface to processes on the system. By read and even write access to this virtual file system you have control over all processes. However there's no unique standard for this.
    /sbin
    system executables (administration stuff, ...)
    /tmp
    a place for temporary data
    /usr
    binaries, data for the users
    /var
    partition which contains stuff of varying size during run time (logs, mails, data caches, ...)
  • Distributed over a few places on the system you will find the man pages, the standard [#un*x un*x] online help format (a few GNU projects have chosen Texinfo instead nowadays: you shouldn't support this). Several subdirectories contain manuals which usually carry the section number as a suffix (like foo.2)
    Section 1
    user commands
    Section 2
    system calls
    Section 3
    libc calls
    Section 4
    devices (e.g. hd, sd)
    Section 5
    file formats and protocols (e.g. wtmp, /etc/passwd, nfs)
    Section 6
    games
    Section 7
    conventions, macro packages, etc.
    Section 8
    system administration
    Section n
    Tcl/Tk, Perl, etc.
  • [#un*x un*x] file systems support links, e.g. you can have multiple references to a single file or directory (see [#tvfs TVFS]). They can be created by the The [#un*x un*x] tool ln, which is therefore sometimes required by scripts. Symbolic link (also called soft link) are created by ln -s foo bar. Hard links are fortunately rarely used in applications and are very hard to fake.
    Using a replacement for symbolic links which does actually copy and also echoes a warning might be a good, but "dangerous" idea. This approach will not only miss updates on that file but might also cause a program to produce unwanted files: applications sometimes create links for temporary file access. Performing a file duplication will create trash on your harddisk which is not being cleaned up.
  • The separator of path components is a slash '/' as opposed to OS/2's backslash '\'. Many OS/2 APIs understand the '/', but cmd.exe and most apps do not.
  • Multiple paths (e.g. in environment variables like [#path_env PATH]) are separated by a colon ':'.
  • The root dir on an [#un*x un*x] system is "/".
    Often code checks whether a given path is an absolute one by comparing the beginning with "/". So grep for this string! (see _fullpath() and _abspath())
  • Using
#define getcwd _getcwd2
#define chdir _chdir2
may help to support drive letters.
  • Note that "///abc" is a valid [#un*x un*x] filename. It's equivalent to "/abc". In general multiple '/' characters won't hurt, unlike the situation on OS/2.
  • chdir ("..") is a no-op under [#un*x un*x] if the current working directory is the root directory. Under EMX it fails in the root directory.

Miscellaneous Issues

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

Various Hints

  • Static libraries on [#un*x un*x] follow the unique naming convention to carry a leading lib prefix, like libfoo.a. If you want to link against it however, the right command is -lfoo. On EMX unfortunately this prefix has been dropped, i.e. -lfoo links against foo.a (or foo.lib) instead.
  • Shared and dynamic link libraries use the suffix .so on most [#un*x un*x] systems (alternatives include .sl). There's no need for an import library usually. On [#un*x un*x]/[Standards.html#binary ELF] systems shared/dynamic libraries may contain unresolved references, on OS/2 they at least carry a 'link' to the DLL which contains those. This has both advantages and disadvantages, e.g. if you want to access symbols from a dynamically opened library (using [#dlopen dlopen()]): on OS/2 you will be able to call such a routine in any case, on [#un*x un*x]/ELF you might end up with unresolved symbols!
  • On [#un*x un*x] you can start executables having any name - given the executable file bit is set properly. On OS/2 things are a bit more complicated. You're on the safe side if you adopt the convention used by cmd.exe, i.e. you can only execute files with the endings .com, .exe, .cmd, .bat (this is the exact search order, BTW!). Most of this trouble is bound to cmd.exe and all APIs which may (or may not, see docs) interface with it (including [#popen popen()] and [#system system()]).
  • For "fast" moving targets like libpng (image format library) or nameclash examples like Xaw, Xaw3d and Xpm don't be shy to link statically ...
  • Check for those "un*xisms" (listed in this FAQ) by using grep or an equivalent command to do a recursive search. Look for all standard paths (see above), and all commands which are mentioned in this introduction.
  • Famous problems are related to the binary/text mode mess on OS/2, especially when using stdin/stdout. See _fsetmode(), fopen(), ... in the EMX docs.
  • Note that on [#un*x un*x] plain text files have a different format than on DOS, OS/2. There are many tools available to convert between them (see [#tools tools section]). This also requires much care on the [#open_calls *open()] calls.
A short list of text formats
Operating systems Line Delimiters (hex)
DOS, OS/2 0D 0A

[#un*x un*x]

0A
Macintosh 0D
  • There are some environment variables which are frequently used on [#un*x un*x], and often also on OS/2. Some [#un*x un*x] apps erroneously assume some of them to always exist, i.e. getenv() calls to return a non-NULL result. Changing this is a valuable bugfix, not a porting related change!
    EDITOR
    Your favorite editor.
    BTW, in case you got trapped inside vi [a famous [#un*x un*x] editor], feel uncomfortable, but don't know how to get out, here's the magic code:
    :q!
    HOME
    Directory which contains data specific for the current user
    HOSTTYPE
    Name of platform
    LD_LIBRARY_PATH
    On a couple of systems used to tell the loader where to look for shared libraries. Equivalent on OS/2 would be BEGINLIBPATH
    LOGNAME
    Same as USER (??)
    MACHTYPE
    Description of architecture/OS
    MAIL
    Location of your incoming mailbox
    OSTYPE
    Type of operating system
    PAGER
    Standard tool to page output. Something like "more" or "less"
    PATH
    Same as on OS/2. Except the [#pathsep delimiter character]
    PRINTER
    Default printer. Might be used in conjunction with printing tools like "lp", "lpr"
    PWD
    Current directory
    SHELL
    Standard shell to be used. Often used by Makefiles.
    TERM
    Name of the terminal type currently used (see [#termcap termcap, terminfo]). Make sure that your software runs in an OS/2 window as well as in an xterm!
    TERMCAP
    Used by termcap to find termcap.dat which describes the capabilities of the used terminal device.
    Nowadays often a different system called "terminfo" is being used for the very same purpose.
    TMP
    Usually not necessary, since all systems have a directory for temporary stuff in /tmp. On OS/2 unfortunately one sometimes runs across TEMP, TEMPDIR and other garbage.
    TMPDIR
    The environment variable which [Standards.html#posix POSIX] apps should use to determine the temporary directory.
    USER
    Name of user
    WINDOWID
    Id of current X11 window
    You may use the existence of this variable to distinguish between an xterm and an OS/2 textmode session (OS/2 window or fullscreen).
  • Usually argv[0] within main(int argc, char *argv[]) contains the name of the current executable. This is sometimes checked and used to determine the runtime behavior (e.g. egrep and grep may be the very same binary or xfoo may be the X11 GUI version of some program foo). This check will always be against "foo", so you have to add a check for foo.exe as well.
  • A famous [Standards.html#unixpfaq FAQ of un*x programming] is how to determine the name and absolute path of the current executable. While there is no simple approach, most methods include the usage of [#argv0 argv[0]] (e.g. basename(argv[0])). On OS/2 the answer is simple: EMX provides the interface _execname() which is more or less just: #include <stdlib.h> #include <os2.h> int _execname (char *dst, size_t size) { PTIB ptib; PPIB ppib; if (DosGetInfoBlocks (&ptib, &ppib) != 0) return -1; return DosQueryModuleName (ppib->pib_hmte, size, dst); }
  • Never ever name an executable test {.com, .exe, .cmd, .bat}!
    test is a standard program on [#un*x un*x], which does apparently nothing - at least if you don't have a closer look at it ... (yes, if you want to know more about the ellipses you should ask "man test" :-)
  • Unfortunately some OS/2 tools (including built-in cmd.exe commands) have their counterparts on [#un*x un*x] with exactly the same name but different semantics/syntax.
    Below's an incomplete(!) list. The "external" and "internal" is meant with respect to cmd.exe.
    External commands
    find, install, join (DOS), more, patch, sort, time, unpack
    Internal commands
    cd, date, dir, echo, exit, mkdir, rmdir, set
  • To merge a.out objects you may try something like
    ld -X -r -o darin.o foo1.o foo2.o ...
    However you will rarely need to do so. Better create static libraries/archives which collect object code in a much more convenient way.
  • You will run across many new file formats. Get the file utility for OS/2 which can identify file types using a database of file signatures (mostly some unique header which is a few bytes long). This is a standard utility on [#un*x un*x].
    Among the most important formats are [#archivformats archiver] types, which are covered elsewhere in this FAQ.
  • For better conformance to the [Standards.html#math IEEE 754] standard you may use: #include <float.h> unsigned All_Exceptions = EM_INVALID|EM_DENORMAL|EM_ZERODIVIDE|EM_OVERFLOW|EM_UNDERFLOW|EM_INEXACT; _control87(PC_53, MCW_PC); /* IEEE compatible precision */ _control87(All_Exceptions, MCW_EM); /* don't mask, i.e. hide exceptions */
  • /dev/random, a device which should deliver (pseudo) random numbers has no equivalent in the poor random number generators which are distributed with the various libc's on OS/2. For more info on random numbers visit the /dev/random Support Page and The pLab Project Home Page. And the local information about the [#random random()] and [#rand48 *rand48()] interfaces.

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.

  • Remember the cmd.exe/sh operators (which are surprisingly often identical ...):
Meaning Syntax
sh cmd.exe
execute two commands foo and bar foo ; bar foo & bar
execute foo; if successful, i.e. return code = 0 then execute bar as well foo && bar foo && bar
execute foo; if unsuccessful, i.e. return code <> 0, execute bar as well foo || bar foo || bar
execute foo and pipe its stdout to stdin of command bar foo | bar foo | bar
run foo in the background foo & detach foo
redirect stdout from foo into file bar foo >bar foo >bar
redirect stderr from foo into file bar foo 2>bar foo 2>bar
redirect both stdout and stderr from foo into file bar foo 1>bar 2>&1 foo 1>bar 2>&1
arguments inside shell script $1 $2 ... %1 %2 ...
environment variables $foo %foo%
group commands together as a single one (ls ; cd ..)

[#long_pipes (ls & cd ..)]

loop over some list for i in $PATH_LIST; do (cd $i && ls) ; done for %i in (%PATH_LIST%) do (cd %i && dir cd ..)
  • All standard [#un*x un*x] shells expand wildcard characters:
    *
    match every set of characters
    ?
    match a single character.
    To get this done on OS/2 you have to do it "manually" in your code since cmd.exe won't do it for you. However be aware that even people on OS/2 may use shells which already expand (4os2? or an un*xish shell). This shouldn't hurt at first glance, but may end up with a substantial number of command line arguments passed to your application!

EMX (and even IBM's toolsets) has it's own routine to help you getting that job done:

#include <stdlib.h>

int main (int argc, char *argv[]) {
_wildcard (&argc, &argv);
/* ... the program ... */
}
  • To avoid expansion of wildcard characters one may quote command line arguments within a "" pair. cmd.exe has a slightly different concept here. Anyway for both trivial examples include specifying file names with embedded blanks, e.g.
foo "file name with blanks.txt"
  • cmd.exe is unable to accept environment variables with include some special characters like '='. So trying to specify
set EQUATION=E=mc2
does not work. A work-around is to use a REXX wrapper:  
/* Ok, use REXX */
call Value "EQUATION", "E=MC2", "OS2ENVIRONMENT"
  • Sometimes long command pipes or those which have to transfer large amounts of data fail on cmd.exe, e.g.
    gzip -d foo.tar.gz | tar xf - | sort | bzip2 -dc >bar.bz2
    may produce an error message like
    SYS0008: There is not enough memory available to process this command.
    Then try grouping commands together as [#group_cmds shown above].

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 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 [#workarounds related interfaces] can be ported: the code needs a major rewrite.

Printing

Printing on [#un*x 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:

  • the "new" X11 printing interface (-> libXp, which in turn may be used by libs such as [#motif M*tif]). This is not supported by [#x2 XFree86OS/2] 3.x, though.
  • clever tools which trigger a conversion of "arbitrary" input data to Postscript, like a2ps.

As a common denominator usually Postscript-capable printer is supposed to be availabled 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 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 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 [sites.html 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!

  • Socket handles are not inherited across [#exec exec*()] and [#spawn spawn*()]. A process created by [#fork fork()] inherits the socket handles of its parent process, though.
  • The size of messages is restricted to 32767 bytes (this is a limitation of IBM TCP/IP for OS/2).
  • By default sockets are in binary mode. Use setmode() to switch to text mode. Text mode applies to read() and write(), only. recv() and send() always use binary mode.
  • The functions recvmsg(), sendmsg(), and socketpair() are not implemented.
  • Change all open(), fopen(), fdopen() and freopen() calls to use O_BINARY or "b", respectively, for binary files (see [#text_formats "text formats"]). If a file contains both binary and textual data, read the file in binary mode and do the conversion yourself.

Usage of the -Zbin-files (gcc) linker flag is in general a bad idea since it too often breaks handling of text files.

  • Though fseek() and ftell() now work on text files, the offsets are different from what Unix programs expect. You may have to open the files in binary mode and ignore carriage returns (this has been done in GDB).
  • Programs reading a.out files should be changed to call _seek_hdr() or _fseek_hdr() before reading the header to support .exe files. More changes are usually required.
  • The null device is called /dev/null under Unix. The __open() system call translates the filenames /dev/null and /dev/tty (lower case, with slashes) to nul and con, respectively. However,
      system ("whatever >/dev/null");

won't work as the standard OS/2 interpreter (cmd.exe) doesn't recognize "/dev/null" (see [#system system()]).

  • Do not use the PTRACE_TRACEME request of ptrace(): use P_DEBUG instead when starting the process with spawn*().
  • The shell isn't called /bin/sh. Use [#system system()].
  • Printing single characters is inefficient. A solution is to use
      setvbuf (stdout, NULL, _IOLBF, BUFSIZ);

and to use fflush(stdout); if you need the output immediately (flushing is required only after displaying prompting texts before reading input or displaying progress reports that don't end with a newline character). GDB output has been made much faster by using line buffering.

  • Note that VEOF != VMIN and VEOL != VTIME. Programs which use VEOF and VEOL to access VMIN and VTIME, respectively, should be changed to use VMIN and VTIME. emx uses separate fields for VEOF, VEOL, VMIN and VTIME.
  • To use termio, you have to reset the IDEFAULT bit of c_lflag. This does not apply to termios.

Always use the standard interface, i.e. [Standards.html#posix POSIX.1] termios in new code!

From other sources

  • When using spawn*() take care of unwanted effects when [#filehandles file handles] are inherited. Also check out the related problem of [#spawnsocket socket] handles!
  • Use termio or termios or read the keyboard with _read_kbd() if you don't want to get input line by line.

Do not use _read_kbd()! This breaks your code in [#keyinxterm xterms] and in addition it is non-portable!

  • To figure out which preprocessor #defines are in effect you can use the example batch script (for cmd.exe) below. Two [#un*x un*x] utils (touch, rm) are required, but you may easily replace them by native OS/2 calls. Advantage of the given version is obviously that you can use it almost literally on many [#un*x un*x] system and it can handle a big number of additional commandline arguments like compiler flags: "-ansi" is a candidate here.
touch __shd.c
gcc -dM -E %1 %2 %3 %4 %5 %6 %7 %8 %9 __shd.c
rm __shd.c
  • Sometimes projects link explicitly against libc (-lc). This in 95% useless and sometimes will trigger problems even on [#un*x un*x]. On EMX the situation is even worse, the required C runtime is distributed in more than a single library, consult the EMX docs on that issue.
  • The [#un*x un*x] math library (libm) is often specified in Makefiles among the linker flags. Using EMX you don't need this (the functions are already among the standard C libs). But to keep the linker happy with those Makefiles a dummy math library exists, which is linked if -lm is used. The enhanced math library from [#libext libext] is available in a stand-alone library.
  • ranlib (a tool to prepare static libraries for usage by linker) is not available and not necessary with EMX anyway. You may use the s command of ar instead, like ar s foo.a (or just forget about it completely ...).
  • A famous issue on OS/2 programming is the task to allocate more than 32MB of memory for a single object. Yes, of course this is possible, but when using EMX it may not be straight-forward. Check out the _uflags() call. Note that it interferes with [#fork fork()].

Configuration Stuff

Various build mechanisms are used in the [#un*x un*x] world: simple/complex/nested Makefiles, crazy batch files, autoconf, Imakefiles, ...
Anyway you should get all available [#un*x un*x] tools which are already ported, many of them being from GNU. More details can be found at the description of [#autotools autoconf] and in the [#tools 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.

  • Get a version of GNU make from [sites.html OS/2 software sites]. Watch out for embedded shell commands!
  • If you use [#x2 XFree86OS/2] there's a make.cmd in your %PATH% which is helpful to some extent and presents a problem in some other cases. You may call the underlying binary executable by x11make.exe. This batch file defines SHELL="" and may do other things (just currently it doesn't ...).
  • GNU make offers many useful features which are beyond the common standard (as defined by [Standards.html#posix POSIX.1], ... ?) for make on [#un*x un*x]. However since GNU make is very portable and widely available you may try to use them anyway.
  • To learn about converting sh-syntax to cmd.exe-syntax refer to the section which discusses [#shvscmd sh vs. cmd.exe] issues. Here's just another example, you may convert
for i in $(subdirs); do (cd $i; $(MAKE) bar); done

to

for %i in ($(subdirs)) do (cd %i && $(MAKE) -f Makefile.os2 & cd ..)
  • Figure out which shell is used, especially if the SHELL variable is set explicitly!
    If the Makfile contains sh commands, you may have to add a missing SHELL=/bin/sh on your own.
  • Have a couple of different make versions around!
    Below is an example of some sophisticated feature of GNUMake that x11make does not properly handle while some GNU make 3.76 from [sites.html OS/2 software sites] does:
VERSION := $(shell grep -e "^VERSION=" $(VFILE) | sed -e "s/VERSION=//")

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:

  • Try to run them in an un*x-like shell like ash, bash, csh, ksh, tcsh, zsh, ...
  • To debug shell scripts add this line near the beginning (or the interesting section)
    set -x
  • Other script language interpreters may be found in [#scriptlangs according section] of this FAQ.

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 un*x]-platform, otherwise you'll struggle way too often.

  • In case there's a configure.in file available you should try one of the existing autoconf ports:
    • [#hcchu Version 2.13 (1.4)]
    • Version 2.5x (1.5) from [sites.html OS/2 software sites]
  • Often it's used in packages which also make use of [#automake automake] and [#libtool libtool].
  • Check out the [#standardtools list of standard tools].
  • Ensure that the supplied configure.in is compatible to the current autoconf port (e.g. look for AC_PREREQ() and no fancy libtool stuff (especially dynamic or shared libraries) is being done. Then things should be as trivial as
autoconf && configure && make

The default autoconf port lacks a "-Zexe" for plain EMX and such things, but that shouldn't be real problems.

  • If you don't have the configure.in source try out the "convert_configure" or "configure-fixer" scripts from I. Zakharevich.
    Of course you can also run the "configure" script unmodified, which will at least run through if it's old and simple enough. You may have to fix the resulting files (e.g. config.h and Makefile manually). If configure just stops at some questionable code fragment you might also just drop that stuff. Often even a run with lots of wrong results produces a better set of output files than a non-expert might create ...

automake

automake is a companion to [#autoconf 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).

  • There's an OS/2 port of version 1.2d (see [#hcchu below]).
  • Doesn't work for DLLs on OS/2, or at least not in a real useful way.
  • Maintaining DLLs which entry points are explicitly using ordinals is a pain. There's a tool (currently part of the LessTif for OS/2 distribution) which does the job for you: mkdef.cmd, a powerful REXX program, reads in an old .def file, remembers all entries and their corresponding ordinals and while keeping them it assigns unique new ones. The list of the currently available symbols may be automatically created by emxexp.
  • link386 has a (documented) commandline flag /OLD which should somehow correspond to a feature of automatic matching ordinals with an older existing DLL, but I never got it to work.
  • There are other tools which do help the user to create a DLL without having to write a linker definition file manually.

Imakefile

[Standards.html#x11 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.

  • Often a sequence like
xmkmf
make Makefiles
make
is required for larger projects.
  • Unfortunately an Imakefile may also contain non-portable shell commands.
  • To address configuration issues that can't be resolved by using the "knowledge base" of the X11 installation the user sometimes has to adjust configuration files which are then included by the Imakefile.
  • Watch out for explicit settings of system-dependent variables like CFLAGS, CXXFLAGS, a common mistake by software authors!

X11 Specifics

In general you don't need to make changes specific related to the [#x2 XFree86OS/2] implementation of the X11 standard. It is very close to the level which is supplied for [#un*x un*x] platforms. In turn XFree86 is based on the official releases from the OpenGroup and therefore conforming to the standards. Similar to the [#motif 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 [#mailinglists mailinglist].

How to get a single key pressed in an xterm?
This is a real FAQ for [#un*x 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 [Standards.html#posix POSIX.1].

You should read about [#tcsetattr tcsetattr()] and check out the sample code which I provide for the [#select 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?
[#x2 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 [#itimer 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 [#libxt Xt.dll]) run foo -sync inside a debugger and [debugging_os2.html#breakonexit set a breakpoint on exit()]. Also check out the [debugging.html#xerrors 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 [#x2 XFree86 OS/2]
gl_ -lMesaGL OpenGL clone (3d API) MesaGL (OS/2 ports)
Mrm -lMrm Motif Resource Manager [#motif Motif]
PEX -lPEX PHIGS Extension for X (3d APIset) [#x2 XFree86 OS/2]
qt_, ... -lqt GUI Toolkit (C++) ?
shm -lshm Provides Shared Memory [#shm various sources]
Smc, Sms -lSM Session Management [#x2 XFree86 OS/2]
Uil -lUil User Interface Library [#motif Motif]
X -lX11 Standard X11 core routines [#x2 XFree86 OS/2]
Xau -lXau X authority database routines [#x2 XFree86 OS/2]
Xaw -lXaw Athena widgets [#x2 XFree86 OS/2] (?) (also check OS/2 ports)
Xbae -lXbae Matrix Widget Set Xbae (LessTif)
Xdmcp -lXdmcp X Display Manager Control Protocol [#x2 XFree86 OS/2]
DPMS -lXdpms X Display Power Management (DPMS) Extension [#x2 XFree86 OS/2]
Xdbe, Xext, XShape -lXext X Extensions [#x2 XFree86 OS/2]
Xie -lXie X Input Extensions [#x2 XFree86 OS/2]
Xlt -lXlt Widget Set (Motif Extensions) Xlt (LessTif)
Xm -lXm Motif (GUI toolkit) [#motif Motif]
Xmu, XEditRes -lXmu Miscellaneous X utility functions [#x2 XFree86 OS/2]
Xp -lXp X Print Server [#x2 XFree86 OS/2]
Xpm, xpm -lXpm Bitmap/Pixmap Routines [#x2 XFree86 OS/2], ports
XScreenSaver -lXss ScreenSaver Support [#x2 XFree86 OS/2]
Xt -lXt X Toolkit Intrinsics [#x2 XFree86 OS/2]
Tcl_ -lxtcl Tk (GUI for Tcl) [sites.html ports]
Tk_ -lxtk Tcl to X11 interface [sites.html ports]
XTest, XRecord -lXtst Test Extensions [#x2 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 [#x2 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 [#xapplink "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 [#x2 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 [#x2 XFree86OS/2] installed.
Actually I should better say "stand-alone, dualmode" application, therefore see also [#xappstatic "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 [../data/pibtst.zip 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 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 [#xappstatic 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 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 ...

  • There is an extraneous tutorial from me about basic debugging issues available, which is not operating system specific. See [debugging.html debugging.html].
  • Some system-specific issues might be worthwhile to mention for OS/2-EMX however. See [debugging_os2.html debugging_os2.html].
  • Information about printing from non-PM applications is collected within [printing.html printing.html].
  • A short summary about Regular Expressions is in [regex.html regex.html].
  • Sites carrying ported and native OS/2 software are listed in [sites.html sites.html].

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.