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!
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.
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!
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.
tcsetattr()
#ifdef __EMX__ ... #endifclause (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
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.
%PATH%
before any other
incompatible versions!
ln, ls, mkdir, mv, rm)
yacc replacement)
lex replacement)
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, ...).
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 -SPerl 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.
| 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 |
hello.tar.gz refers to a file hello.tar
which is an archive file produced by tar which has finally
been packed by gzip.
| 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 |
dos2unix/unix2dos, recode, tr,
trans, ...
chk4dlls somewhere. It lists all DLLs required
by an executable/DLL and is an equivalent to the
ldd
utility available on many un*x systems.
DosLoadModule(), dlopen(), etc.
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.
#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) /* seestat(), 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 outfsync(), 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 */
ecvt(), fcvt(), gcvt()
*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.
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*()
fork()
and the section about process handling.
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()
fcntl()
F_SETLK is not supported.
fcntl() or add code which makes use of an existing
flock*() implementation. Or watch
libext.
flock()
DosSetFileLocks().
Also see libext.
fork()
exec*()
and the section about
process handling.
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.
fork() doesn't work in
link386 (-Zomf) created executables!
XTHREADS if you are going to use
fork() or threads within an X11 application.
getenv()
getrlimit()
ulimit(3), sysconf(3),
emxdev: chapter "7 Customizing".
mlock(), munlock(), munlockall()
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()
select().
Check out
libExt for an emulation using this relationship.
popen()
system().
random()
random() is superior to
rand(), so try to use this instead. It's hidden in
libbsd.
realpath()
rename()
rename() doesn't replace existing targets.
remove().
remove()
remove() fails on open files.
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()
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 .
sigaction()
and
signal()
are used together.
signal()
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.
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!
| 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()
lstat() may be mapped to stat(),
but for compatibility with future enhancements it should have it's
own wrapper (see libext).
system()
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()
tcsetattr() switches to Posix
mode. This related to the
unlink()
remove() instead.
usleep()
_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().
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);
#define foo bar
dlopen()/dlfcn()
(access to dynamic link libraries)
drand48(), srand48()
(random numbers)
rand()
or even better random().
Just be aware of the slightly different interface.
gettext()
(National Language Support library from GNU)
mmap(), munmap(), etc. (mapping files into memory)
mkfifo(3)
(a named-pipe mechanism using the file system)
Octave
(on OS/2 software sites).
pthreads (POSIX threads)
(on OS/2 software sites
and on
ftp.everblue.org)
readline
(provides simple editing features in an input line on terminals)
regex (regular expressions)
(on OS/2 software sites;
also part of
libext)
rpc
(Remote Procedure Call) interfaces are supplied
with libExt.
scandir()
(read directory entries)
setitimer()/getitimer()
(timer functions)
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)
shm (shared memory between different processes):
shmat(), shmctl(),shmdt(),
shmget()
syslog() (send messages to system logger)
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.
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:
dup())
dup2())
spawn*())
dup2()) and close()
unused file handles
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).
SIGSTOP and make it continue
by sending SIGCONT.
Let's have a look at some of the interesting properties:
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).
man hier on your favorite 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.
foo.2)
ln is sometimes required by
scripts. Usually the purpose is to create a symbolic link
(also called soft link) by ln -s foo bar.
Hard links are fortunately rarely used in applications and are
very hard to fake.
cmd.exe and most apps do not.
PATH) are separated by a colon ':'.
_fullpath() and _abspath())
#define getcwd _getcwd2 #define chdir _chdir2may help to support drive letters.
chdir ("..") is a no-op under un*x
if the current working directory is the root directory.
Under EMX it fails in the root directory.
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.
.so on most
un*x systems (alternatives include .sl).
There's no need for an import library usually.
On un*x/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. A nice example for an advantage is
if you want to access symbols from a dynamically opened library (using
dlopen()):
on OS/2 you will be able to call such a routine in any case,
on un*x/ELF you might end up with unresolved symbols!
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() and system()).
stdin/stdout.
See _fsetmode(), fopen(), ... in the
EMX docs.
*open() calls.
| Operating systems | Line Delimiters (hex) | |
|---|---|---|
| DOS, OS/2 |
0D 0A
| |
| un*x |
0A
| |
| Macintosh |
0D
| |
getenv() calls to return a non-NULL
result. Changing this is a valuable bugfix, not a porting related change!
:q!
BEGINLIBPATH
/tmp. On OS/2 unfortunately one sometimes
runs across TEMP, TEMPDIR and other garbage.
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.
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);
}
test
{.com, .exe, .cmd, .bat}!
test is a standard program on 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" :-)
cmd.exe.
find, install, join (DOS),
more, patch, sort,
time, unpack
cd, date, dir, echo,
exit, mkdir, rmdir, set
ld -X -r -o darin.o foo1.o foo2.o ...
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() and
*rand48() interfaces.
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.
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 ..)
|
(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 ..)
|
*
?
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 commandline arguments passed to your application!
#include <stdlib.h>
int main (int argc, char *argv[]) {
_wildcard (&argc, &argv);
/* ... the program ... */
}
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=mc2does not work. A work-around is to use a REXX wrapper:
/* Ok, use REXX */ call Value "EQUATION", "E=MC2", "OS2ENVIRONMENT"
cmd.exe, e.g.
gzip -d foo.tar.gz | tar xf - | sort | bzip2 -dc >bar.bz2
SYS0008: There is not enough memory available to process this command.
\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.
libXp,
which in turn may be used by libs such as
M*tif).
This is not supported by
XFree86OS/2 3.x, though.
lpr and lpd tools
(shipped with Warp 4) to access the Postscript printer queues from the
commandline.
/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.
exec*()
and
spawn*().
A process created by
fork()
inherits the socket handles of its parent process, though.
setmode()
to switch to text mode.
Text mode applies to read() and write(),
only. recv() and send() always use binary mode.
recvmsg(), sendmsg(), and
socketpair() are not implemented.
open(), fopen(), fdopen()
and freopen() calls to use O_BINARY or
"b", respectively, for binary files (see
"text formats").
If a file contains both binary and textual data, read the file in binary mode
and do the conversion yourself.
-Zbin-files (gcc) linker flag is in general
a bad idea since it too often breaks handling of text files.
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).
_seek_hdr() or _fseek_hdr() before reading the
header to support .exe files. More changes are usually required.
/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()).
PTRACE_TRACEME request of ptrace():
use P_DEBUG instead when starting the process with
spawn*().
/bin/sh.
Use system().
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.
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.
IDEFAULT bit of
c_lflag. This does not apply to termios.
termios in new code!
spawn*() take
care of unwanted effects when
file handles are inherited.
Also check out the related problem of
socket handles!
_read_kbd()
if you don't want to get input line by line.
_read_kbd()! This breaks your code in
xterms and in addition it is non-portable!
#defines are in effect
you can use the example batch script (for cmd.exe) below.
Two 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 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
libc
(-lc). This in 95% useless and sometimes will
trigger problems even on 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.
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 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 ...).
_uflags() call. Note that it interferes
with
fork().
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 ...).
make on un*x.
However since GNU make is very portable and widely available
you may try to use them anyway.
for i in $(subdirs); do (cd $i; $(MAKE) bar); doneto
for %i in ($(subdirs)) do (cd %i && $(MAKE) -f Makefile.os2 & cd ..)
SHELL
variable is set explicitly!
SHELL=/bin/sh on your own.
x11make does not properly handle
while some GNU make 3.76 from
OS/2 software sites
does:
VERSION := $(shell grep -e "^VERSION=" $(VFILE) | sed -e "s/VERSION=//")
EXTPROC
which cmd.exe recognizes) while you can also write some commands for the
current shell without that header:
#! /bin/sh
ash, bash, csh,
ksh, tcsh, zsh, ...
set -x
/* Define if you have the "useless.h" header */ #undef HAVE_USELESS_H /* Define if your libc has the strange() function */ #define HAVE_STRANGE 1
configure.in file available
you should try one of the existing autoconf ports:
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 && makeThe default autoconf port lacks a "-Zexe" for plain EMX and such things, but that shouldn't be real problems.
configure.in source try out the
"convert_configure" or "configure-fixer" scripts
from I. Zakharevich.
configure
should process have to carry the .in postfix.
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.
dllar.cmd from pgcc
xmkmf
(mxmkmf exists for LessTif systems; the OS/2 port lacks
this so far) to create a Makefile from an input Imakefile.
xmkmf make Makefiles makeis required for larger projects.
CFLAGS, CXXFLAGS,
a common mistake by software authors!
tcsetattr() and check out the sample code
which I provide for the select()
call or have a look at some other
sample code.
SIGWINCH?
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().
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.
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.
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.
| 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
-lsocket) is another candidate here.
It provides e.g. gethostname() or connect().
-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 -lsocketBe 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 ...
-Zmtd.
-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.
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.