LJ Archive

Porting from IRIX to Linux

George Koharchik

Brian Roberts

Issue #82, February 2001

Coding for portability to Linux: examples from the ACRT land vehicle port.

Linux is a superset of the POSIX (Portable Operating System Interface for X) specification. It runs on commodity PC hardware, MIPS systems, Suns, Macintoshes and even IBM mainframes. It's sufficiently UNIX-like that much UNIX code can be ported over with little change.

The Advanced Concepts Research Tool (ACRT) is a descendant of the ARPA Reconfigurable Simulator Initiative (ARSI). It's primarily IRIX but has NT versions for many of its modules. ACRT is a vehicle simulator that can be reconfigured into different vehicles. Raytheon supplies the land vehicle simulators, which currently are the M1A1 and M1A2 tanks, M2 armored personnel carrier, M113, M577, HMMWV and the Future Scout. Reconfigurability is done by using “Erector Set”® type hardware, soft panels for controls, serial line inputs for grips and a common set of core software.

The Erector Set hardware looks like a scaled-up version of its namesake. This allows the crew seats, controls and monitors that can be placed in a variety of positions to emulate the vehicle interiors.

We use the term soft panels to refer to touch-screen activated control panels that are used in place of the real buttons and switches in the actual vehicles. These are designed to place the controls as close as possible to the real vehicle. This minimizes the amount of hardware that is vehicle-specific (currently only grips).

Grips are either actual crew station hardware from the vehicle or copies with simplified interior wiring. These provide switches and analog outputs used to control some vehicle functions. The outputs from these are converted to voltages in the range of zero to five volts DC and fed through a BG Systems Cereal Box. The Cereal Box acts as an analog to the digital converter and feeds values through serial lines to the host computer. Finally, the core set of software used by all vehicles makes it easier to develop a new vehicle or modify existing vehicle-specific modules.

At startup, the system runs different software modules on different hosts. These different modules include things like ground motion (how does the vehicle move), weapons models (how does a weapon behave, where does the round go) and control panels for the crew to interact with. The system is kicked-off from a single host and then starts up process managers (host_mgr) on other hosts through the UNIX rsh command. These host_mgr processes then parse through configuration files to see what runs on their local host.

The system uses message passing to move information between the different modules. Between modules on the same host, the messages are buffered in a memory-mapped file as a form of shared memory. Between hosts, UDP sockets are used to pass information. A gateway system translates between Defense Interactive Simulation (DIS) messages and the internal vehicle messages. This allows the simulator to interact with other simulators using the DIS protocol (see Figure 1).

Figure 1

Objectives:

A) Demonstrate an image generator using Performer Linux (Mongoose)

What started this project was SGI's release of its Performer visualization/simulation tool for Linux (this version is called “Mongoose”). Since our simulator's image generator (the part of the system that draws the out-the-window and sensor views) is based on Performer, the largest part of the work for a Linux port was done for us. What remained was to port the code that used Performer, the libraries and tools common to all vehicles (known as the Tiger core), and enough of the vehicle so that it can interact with its environment (to move, see other vehicles and utilize special effects like weapons fire and detonation).

B) Dual-compile whenever possible to shrink codebase

To make it easier to maintain, we decided to maximize the amount of code that would compile under either IRIX or Linux. This shrinks the codebase to a more manageable size. The theory is that each module would have a directory containing source code and under it would be subdirectories for architecture-specific items (compiled object files, libraries and executables). A Makefile in with the source files uses the OSNAME environment variable to bounce any make commands to the correct subdirectory depending on the architecture of the host (see Figure 2).

Figure 2

C) Arrange files so that machines of different architectures use the same directories

To keep the configurations as similar as possible across platforms, the files are arranged so that machines of different architectures use the same directories. For distinctions that can be made at compile time, there are different directories for compiled libraries with which modules link and where the executables are kept. Using environment variables for the BIN and LIB directories that incorporate the architecture name can help with that. For instance, on the IRIX systems, the binary directory (stored in $ARSI_BIN) might be /apps/projects/ACRT/bin/IRIX64. On Linux systems, it might be /apps/projects/ACRT/bin/Linux. Since the path is stored in the same environment variable, scripts and Makefiles can use it without regard for which type of system they are running (see Figure 3). Environment variables are also available at runtime to allow code to make decisions that can't be made at compile time. By embedding environment variables in configuration files, we can use the same configuration file for different architectures.

Figure 3

Portability of source files was an issue for the include files and modules that dual-compiled IRIX/NT. For IRIX to use the files, they had to be in UNIX format (the CR/LF issue) instead of DOS format. Fortunately, MS Studio accepts files in UNIX format, so we settled on that. Adding Linux didn't change this equation since Linux handles both DOS and UNIX formats. Note, however, that shell script files must be in UNIX format.

D) Overcome incompatibilities

We first tried to use POSIX functionality. When that was not applicable, we opted for the greatest common denominator.

E) Simplify maintenance

To keep maintenance simpler, we tried to avoid convoluted #ifdef-ed regions of code, be careful about variables used and set in each branch of code and verify that the flow of control was not drastically different between branches. When possible, #ifdef-ed code was moved to a separate file to minimize the scope of its effect on variables.

Finally, different compilers are sensitive to different things. A condition that goes unremarked on one compiler may cause a warning on another. Investigate and understand your compiler's warnings. They may lead you to an error (in which case it's easier to fix at compile time than to track down at runtime). Warnings may show you where intent differed from implementation. Warnings can also hide errors. Picking out the serious message in the midst of a page of warnings about unused variables is harder than taking out the unused variables.

Software and Hardware Used

This section reflects what we did in March of 2000. See the Afterward section for more current information.

A) Red Hat 6.1

The KDE Workstation installation option provides most of the packages you need.

B) Metrolink Motif

We experimented with Lesstif. While it works well for Performer and lets us compile our other tools, it didn't handle updating some of our scrolling windows correctly. The developer's console (a tool for tracking messages) has a scrolling window that should update with message traffic even without mouse interaction. The Lesstif version didn't, but the Motif version did.

C) Mesa Graphics Library

We used the Mesa Graphics Library as an OpenGL look alike. Make sure that you follow their directions for making the widget set after you install Mesa.

D) Viper V770 Graphics Card.

We used the Diamond Viper V770 graphics card and the hardware accelerated Mesa drivers and libraries. At that time (January 2000) the GeForce 256 card was supported under Linux, but there were no hardware accelerated OpenGL drivers for it. More recently, XFree86 version 4.0 is out and while hardware-accelerated OpenGL is available for the GeForce card, setting it up can be tricky.

E) XFree86 Drivers for Hardware Acceleration

We used the XFree86 SVGA server and the XFree86-rivaGL-3.3.3.1-49riva drivers in January. OpenGL Linux drivers for the GeForce card are available from nVidia (see Resources).

F) SGI's Performer Package

Downloaded and installed per their instructions (see Resources web pages).

G) ACRT Version 1.06 (our simulator)

See Specifies for details about architecture and operation.

Tool “Equivalents”

SGIs generally offer a cushier environment than Linux. They're also working on porting more of IRIX's tools and features to Linux. For those accustomed to the SGI environment and new to Linux, here are some of the corresponding tools that we used when porting:

A) Xdiff -> Mgdiff

Do a Web search for this one. My recollection is that it requires Motif, and Lesstif won't work.

B) dbx -> gdb

Your basic command-line debugger.

C) cvd -> xxgdb

SGI Casevision debugger has a nice graphical interface to a whole suite of tools. While there is no Linux equivalent for Casevision, the xxgdb front end for dbx provides a similar debugging environment. There is also a tool called “DDD” (the data display debugger) available that we didn't use because we're already familiar with xxgdb.

D) gr_osview -> xosview

SGI's system monitoring and status tool, gr_osview, encompasses more than xosview, but xosview is similar in the ability to see processor and memory status, system load, etc.

E) editors, shells, etc.

Emacs, vi, edit, tcsh, bash and the like are all pretty much what you'd expect (I imagine there are some differences in the dark corners of the shells, but our system didn't use enough of them to run into the differences).

F) xwsh -> xterm

I can only say “equivalent” here with the proviso that the xwsh “-hold” option (which causes the window to persist even after the command running in it with “-e” has ended) is not available for xterm.

G) PCNFS -> SAMBA

The original system shared files over NFS (requiring an add-on package for NT). In this work we shared files between Linux and IRIX over NFS and used SAMBA to share with the NT systems.

H) Lint

The lint debugging tool is bundled as part of IRIX but is not bundled with Linux, though commercial versions of lint are available for Linux. There is also a package called LCLint that seemed like overkill for our work (porting legacy code). For our purposes, we used gcc and its options for better debugging and error detection:

gcc -ansi -Wall -Wstrict-prototypes
        -Wmissing-prototypes \
        -fsyntax_only -pedantic -O2

Larch C Lint is available for Linux and does have better debugging than this, if you want to go the extra mile (see Resources).

I) ICS' Builder Xcessory (BX PRO)

The C-code generated by the IRIX version 4 (and probably newer versions) of ICS's BX GUI builder compiles on Linux. Code generated by older versions needs to be tweaked. There is also a Linux version of BX available (see Resources).

J) Virtual Prototypes' VAPS

VAPS is a control panel building tool. There is no Linux version yet but VAPS does have an NT version. So my group ported IRIX VAPS panels to NT, but that is a separate story.

Specifics

A) Scripts and Shell Environment

It looks like Linux (or the tcsh shell) resets the processes limits when you “rsh” to another host. This kept me from getting core files. To get around this, I added a few lines to my .tcshrc file:

limit coredumpsize 1000000 kbytes <----
source ~/environment
setenv PATH ${PATH}:.

The environment file referenced here is a collection of environment variables for the simulator that is set at shell start up. [Due to the length of Listing 1 it could not be printed here, but is available for downloading at our FTP site: ftp.linuxjournal.com/pub/lj/listings/issue82.]

Using the results of uname, we can transparently point environment variables at the architecture-specific directories for binaries. Scripts, Makefiles and programs can then use those environment variables without each having to check the architecture type themselves. When we added Linux into the mix, we had to add some additional variables:

* $ARSI_SERIAL_PORT_ONE, $ARSI_SERIAL_PORT_TWO

The names of the serial port devices differ between IRIX and Linux. IRIX /dev/ttyd[N] roughly corresponds to Linux /dev/ttyS[N-1],

* $ARSI_CTDB_FILE_SUFFIX
the suffix of a binary data file that is different between big-endian (SGI MIPS) and little-endian (Intel X86) systems.

B)Makefiles

Makefiles are the part of the system that got beat up the most with this port. The IRIX Makefiles are moved from the directory with the source code to the IRIX64 subdirectory, and VPATH is added to point back up to them.

VPATH (“view path”) in a Makefile is like the -I directives that tell the compiler where to look for include files. VPATH tells make where to look for source files—in our case, up one level. Another consequence of moving the Makefiles is that you probably have to change directories before some of the regular shell commands in Makefile (cp, lint, etc.) that operate on the source files will work.

We recommend using SGI's smake for the IRIX Makefiles that need to use VPATH. We'd started using GNU Make hoping to integrate it with NT. However MS Studio uses Nmake instead, so that payoff never occurred. Smake understands VPATH and the common IRIX Makefile macros. The only anomaly we can report is one that occured with some of the clean options. If the make clean option is set up like this:

clean:
    -rm -f *.o $(TARGET) *.a *~*

and rm can't find anything to remove, smake will sometimes (incorrectly) exit with an error about “exit badly formed number”. We don't know why it does that, but adding an explicit “exit” statement fixes the problem:

clean:
    -rm -f *.o $(TARGET) *.a *~* ; exit 0
IRIX has a handy feature that lets you specify an alternate make program to run. The name of the program is put on the first line of the Makefile following a “#!” (much like the way script files name their interpreters). So making the first line of the IRIX Makefile:
#! smake
will cause the default make program to invoke smake to process the Makefile.

Dependencies are also tracked differently between IRIX Makefiles and GNU Makefiles. The IRIX Makefiles generate a single Make.depend file that lists all the dependencies for all the source files. In the version of GNU make that ships with Red Hat 6.1, dependencies are kept in separate files for each source file. For instance, if you have a file ground_motion.c, there will be a corresponding dependency file ground_motion.d. These can be automatically generated with a .d.c rule. (See the GNU Make documentation for details and how you can combine the .d extentions into a Make.depend file.)

Compiler options are also different between the IRIX and GNU compilers. Here's the changes we made:

For IRIX: Use GNU: Purpose: --------- -------- --------fullwarn -Wall -Extra warnings, error checks-MDupdate -MD -Update dependencies-xansi -ansi -Support ANSI C

Using the -g option with the compiler for debugging is serious now. The IRIX debugger was still able to give you information even if the -g option wasn't specified. For GNU, you really need to include the -g. On the Linux side, -D_BSD_SOURCE may be needed if you're doing something that uses BSD functions (like strncasecmp).

The permitted ordering of compiler options is different. IRIX seems to like the libraries to be last, gcc doesn't seem to care.

One of the handiest Makefile macros, $$(@F), is only partially available under GNU make. Make allows you to use $(@F) to extract the file name of a target. IRIX make and smake allow you to use $$(@F) on the dependency line of the Makefile. GNU make allows this only in the action clause, but it does allow you to use the pattern-matching macros to get the same effect (compare the IRIX and Linux Makefiles in Listings 2 and 3, which can be seen at ftp.linuxjournal.com/pub/lj/listings/issue82).

There are some additional directories in Linux for libraries, and they include files that may need to be added to your Makefile:

  • X libs in /usr/X11R6/lib

  • X headers in /usr/X11R6/include

  • OpenGL in /usr/include/GL, /usr/X11R6/GL

Make sure that CFLAGS has -c if you have separate compile and link steps. Otherwise GNU defaults to trying to do it in one step. If you get “storage size not known” error when compiling, try removing the -ansi specifier from the command line.

You can use the same Makefiles for IRIX and Linux, use xmkmf to generate architecture-specific Makefiles in both IRIX and Linux.

Let's turn our attention from Makefiles to C source code. As a general rule, the SGI compilers are more tolerant than the GNU compilers. Expect your code to have to be closer to the standard to pass the GNU compilers.

The following are items we modified from the IRIX code when porting to Linux.

1. Bstring.h, bcopy and bzero are not POSIX. We replaced them with their POSIX counterparts:

bstring.h -> string.h
bcopy(a, b, nbytes) -> memcpy (b, a, nbytes)
bzero(a, nbytes) -> memset(a, 0, nbytes)

GNU does have these in string.h instead of bstring.h, so this is not strictly necessary (though if you don't, you'll need to conditionally include “bstring.h”). Note that IRIX keeps “select” in bstring.h, while Linux puts in unistd.h.

2. Here are some things that generate warnings. Since the GNU compiler is more vocal than the IRIX, we fixed these:

  • Main should return int.

  • Watch for uninitialized vars.

  • Parenthesize defensively.

  • Format specs in printf/scanf: args not matching var types -scanf using the wrong type can get you in trouble

  • sprintf(astring, "") -> astring[0] = 0;

  • 2D array initializers need braces to be ansi -int a[2][2] = { {1, 2}, {3, 4} };

3. There is no “recalloc” in POSIX:

  • Replace recalloc with realloc and use memset to zero out the additional memory.

4. Added NULL timezone as second argument to gettimeofday
  • gettimeofday is not POSIX, but SGI, Linux and NT all accept it and timezone as the second argument.

5. Change sginap to POSIX usleep:
  • sginap (hundredths) -> usleep (hundredths * 10000).

6. Linux “select” decrements timeval structure:
  • The documentation for some other UNIX systems say they may modify timeval in the future: with Linux, the future is now

  • Don't use the same timeval struct on successive calls to “select” without refreshing it.

7. Added __ANSI_C__ parseargs.h for Linux:
  • Parseargs was an argument parsing library last maintained by Brad Appelton in 1991. It supports multiple platforms and tries to figure out what's available on each system (sort of a primitive precursor of the GNU configure utility).

8. Code involving the font manager (fmclient.h and variables of type fmfonthandle) was commented out—I'm not sure if this was an IrisGL holdover.

9. Ulocks.h is commented out. Possibly another IrisGL hold over?

10. Code involving sproc (SGI's lightweight process model) is migrated to POSIX threads (pthreads):

  • Use -D_REENTRANT on Linux compile.

  • Add library -Lpthread to link step.

  • Use XInitThreads() if threads are used in an X application.

  • Get the patches for gdb from the LinuxThreads page.

  • Be aware that the LinuxThreads Library uses SIGUSR1 and SIGUSR2 for its own purposes. If your application uses these signals you might have to look at some other mechanism. In the worst case scenario, use the Linux clone function.

11. Serial port handling used for grips and touch screens migrates to the POSIX interface.

  • See man termios for overview.

12. IRIX has a high-speed malloc library -lmalloc.
  • No high-speed malloc lib on Linux (that I'm aware of) so lmalloc is dropped.

13. Fabs, fsqrtf, fmod are not in math.h but are in the library.
  • Fabs is POSIX, fsqrtf is not

  • We suggest simply using sqrt

  • fmodf

  • use -D_BSD_SOURCE to get at M_PI, etc.

14. fabsf -> fabs in Linux.

15. fsin -> sin in Linux.

16. fcos -> cos in Linux.

17. fceil -> ceil & do math in double.

18. Socket level differences in your header files:

  • ioctl in IRIX unistd.h, Linux has it in sys/ioctl.h.

  • SIOCGIFCONF in IRIX sys/sockio.h.

19. fcntl FNONBLK --> POSIX O_NONBLOCK for both IRIX and Linux.

20. sigsend -> kill for both IRIX and Linux

21. There is sysconf shell-command in Linux

  • Our spatial database tries to obtain RAM size to know how much memory it can afford to use.

  • In Linux, use the contents of /proc/meminfo instead.

22. Non-POSIX IRIX flock_t vs. Linux struct flock:

  • Use “struct flock” on Linux.

23. Linux mmap doesn't autogrow.
  • Autogrow is an optional part of standard (IRIX implements it, but Linux does not).

  • Fill the file with zeros to the right size before mmap-ing.

24. prctl PR_TERMCHILD becomes PR_SET_DEATHSIG.

25. POSIX signal handling is different from the BSD signal handling we were using.

  • Move to POSIX; man sigaction for details.

26. IRIX oserror Ý POSIX errno.

27. There is no sysmp command for Linux multiprocess control.

28. There are no Performer arenas in 2.3 (Mongoose)

  • All performer in one process.

  • Arena pointers will be NULL.

  • pfMalloc and company allocate off the stack.

29. xtouchmouse (a touch-screen driver that turns touch-screen data into X mouse events) works, but can do no button presses on the KDE root window, just on regular windows.

  • Unmatched button presses and releases on the root window cause the window manager to hang—tip 'o the hat to John Mellby for solving that

  • We chose not to use the built-in touch-screen driver support so that we could interoperate with the IRIX systems at that level. Once, when we integrated Future Scout with FBCB2 running on an SCO PC with no compiler, we were able to send the SCO's display to a monitor and plug that monitor's touch-screen into an IRIX system. The touch-screen inputs to xtouchmouse generated X events that were sent to the SCO system allowing us to interact with it.

30. Touch-screen calibration program that figures out the mapping from touch-screen device coordinates to X coordinates is converted from IrisGL to OpenGL.
  • If you still have IrisGL code, try SGI's toogl program to help with the conversion. You might have to convert to Motif if you want to suppress the window borders.

31. Replace Iris GL window management with the X Windows System. Here are some things that either the SGI compiler just let us get away with or are a function of different versions of Motif:
  • In order to use glwMDrawingAreaWidgetClass (instead of glwDrawingAreaWidgetClass) you need to include a library that defines __GLX_MOTIF to make sure the Motif libraries are included or just use the glwDrawingAreaWidgetClass if no Motif functionality is required. “M” indicates Motif and has the additional functionality of Motif's XmPrimitive widget class.

  • In XtPopup, you cannot use NULL for second param. Use XtGrabNone instead. This parameter specifies the way in which X events should be constrained.

  • Use the X Toolkit Intrinsics method for setting up a window instead of the X Lib method in order to create a borderless window. The borderless window needs to use resources to let the window manager know that it doesn't need to manage the border. The resources are not accessible with the X Lib method.

  • Remove IrisGL device.h.

  • Use -lMesaGLw instead of -lGLw for library in the Makefile. This library has the OpenGL draw area widgets.

  • Note that there seems to be a bug in the current (as of February 2000) alpha TNT2 drivers that keeps glColorMask from working. If you're working on this now, I'd suggest switching to the newer drivers for XFree86 version 4 and the latest drivers.

32. Finally, if you do need to compile something conditionally, there is an automatically defined symbol for #ifdef (no -D needed):
#ifdef __linux__
    Linux specific stuff
#else
    IRIX specific stuff
#endif /* __linux__ */
The bulk of the data our simulator dealt with wasn't a problem. Much of the configuration files are ASCII and need only minor tweaks (like environment variables) to be simultaneously usable on IRIX, Linux and NT. In the case of Mongoose, the loaders did the byte swapping for me, so it didn't matter if I was on a big-endian SGI or a little-endian Intel box—the same visual models worked.

There were a few cases where endianness became an issue. We use the Compact Terrain Database (CTDB) files produced by the US Army Topographic Engineering Center. The database files we used were binary. Fortunately they came in big and little-endian versions with different suffixes. We could tell the system which to use by storing that suffix in an environment variable that's evaluated at runtime. The S1000 libraries are not implemented in Linux, just because they are larger and more complex than time allowed. Our Spatial Database has a binary representation of the shapes of different vehicles, so that needed to be converted. Finally, we use the BG Systems Cereal boxes to read our crewstation controls (grips). The Cereal box reads analog voltages from the crewstation controls and transmits its data over a serial line to the host computer. Since the data was assembled byte-wise into floats a little bit of their library needed to be modified. BG Systems was very helpful in that effort.

Once we had everything compiled, there were some surprises at runtime. A runtime error from the GNU compiler helped us find a case where we were accessing memory after it had been freed. IRIX will sometimes let you access memory even after you have freed it (see the IRIX mallopt function for different settings of their memory allocator). There is a mallopt function in Linux, though the man pages don't list it. You'll have to use the GNU “info” pages for that. Another feature of the GNU C library useful for tracking memory errors is mcheck. It's also detailed in the info pages.

The second thing is that the serial port device files have different names between IRIX and Linux:

IRIX: Linux: ---- ------/dev/ttyd1 /dev/ttyS0 serial port one/dev/ttyd2 /dev/ttyS1 serial port two... ...

The grip calibration programs decide based on architecture, and look for the value of $ARSI_GRIP_CALIBRATE_PORT as an optional override.

Was a case where the we had a different results from local variables in a function. We had a string next to an array of longs. The code contained an error where the string was overflowed. On the IRIX systems, the code worked fine. On the Linux systems, it did not. On further investigation, we found that the string was terminating against bytes in the array of longs. In the bigendian systems, those bytes happened to be zeros (making the system appear to work properly), while on the little-endian systems, they were nonzero, causing the string to appear to be corrupted. (Jim King gets the credit for finding that one.)

Finally, there is an error in the Flight loader that comes with Mongoose 2.3. MultiGen-Paradigm says that will be fixed in the next release. (A tip 'o the hat to Karen Davidson for tracking that one down.)

Status

Right now you can drive, shoot the weapons and interact with DIS entities in Paradigm's Atlantis database (credit goes to John Powers and Lori Shearer for helping with the CTDB files). The system can talk to VAPS panels running on another host under Windows NT (credit goes to Kay Chao, Kathy Jones and Vince Golubic).

Afterward

Much has changed since this work was done (first quarter 2000). ACRT can now use the newer High Level Architecture (HLA), a successor to DIS. SGI is continuing to make contributions to the world of Linux, including releasing the reference implementation of OpenGL. A new version of Mongoose is out, and we're experimenting with it now. By the time you read this, version 2.4 should be out, unifying IRIX and Linux distributions. nVidia has come out with new graphics cards and Linux drivers. The long-awaited XFree86 version 4 is out with direct rendering of OpenGL. (Prior versions took a performance hit when they had to first render to X and then to the screen.) Motif is now free on Linux systems.

A Linux version of the VAPS tool we used for soft panels is due out in first quarter of 2001.

Resources

George Koharchik mourns the passing of lisp machines and works at Raytheon. He can be reached at g-koharchik@raytheon.com.

Brian Roberts joined Raytheon Systems Company in 1995 as a full-time member of the Visualization and Simulation Technologies team. His main responsibilities consisted of design and development of new software for a reconfigurable visual simulation. He now works at Texas Instruments.

LJ Archive