Development for VxWorks

C Source Code Compatibility Issues

VxWorks compile-time support is slightly different from ANSI C: This means that if you want to make your source code compilable on UNIX, VxWorks, and Win32, some conditional compilation is essential. I suggest defining the preprocessor symbol "VXWORKS" for VxWorks compiles, and relying on the standard definition of either "unix" or "__unix__" for UNIX compiles, and "WIN32" for Win32. Some cross-compilers for VxWorks define "unix" or "__unix__" because they don't know better, so you should ensure these are NOT defined when compiling for VxWorks. Users of the "vxcc" convenience will not have to worry about any of this; others must remember to pass their compilers something like "-DVXWORKS" and "-Uunix -U__unix__" for VxWorks.

Header File Inclusion

Using something like the following in your main source file will take care of your header file woes:

#if defined(VXWORKS)
#include "vxWorks.h"
#include "memLib.h"
#include "stdioLib.h"
#include "string.h"
#include "errnoLib.h"
#include "selectLib.h"
#include "socket.h"
/* ... */
#endif

#if defined(__unix__) || defined(unix)
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <select.h>
#include <socket.h>
/* ... */
#endif

#ifdef WIN32
#include <time.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <winsock.h>
/* ... */
#endif

Simple Function Emulations

You can also do some simple function emulations. For example, VxWorks doesn't have a sleep() call, but its taskDelay() does the same thing with a different resolution. You could add the following in the VxWorks section:

#define sleep(SltX) taskDelay(SltX*sysClkRateGet())

Entrypoints

The basic strategy here is to write your "real" main program with some name other than "main". If you need command-line arguments, this function can take C arguments which correspond somehow to command-line arguments. VxWorks shell users can then invoke it directly with C arguments. For UNIX or Win32, you compile in a "main" which processes the command line arguments and turns them into whatever C arguments your function needs. Note that this does remove some flexibility in command-line semantics, but it seems to be the only way to have true source-code compatibility. Here's a real-life example:

#if (defined(__STDC__)) || (defined(__cplusplus))
int VISIONinterrupt( int level, int vecnum, unsigned rate, char *net_name );
#else
int VISIONinterrupt();
#endif
 
 
#if (defined(__unix__) || defined(unix)) || (defined(WIN32) && defined(_CONSOLE)
)
/************************************************************************
*       Default entrypoint for UNIX programs is main, and arguments     *
*       are passed in an array of strings (argv) with (argc) elements.  *
************************************************************************/
int main( argc, argv )
  int argc;
  char *argv[];
  {
  int level, vecnum;
  unsigned rate;
  char *endptr;
 
 
#if DEBUG > 1
    printf( "argc = %d, argv = %#x, argv[0] = %#x, argv[1] = %#x\n", 
      argc, argv, argv[0], argv[1] );
    printf( "%s:\n", argv[0] );
#endif
    if ( argc < 5 ) {
        fprintf(stderr,"Syntax: %s < level > < vecNum > < rate > < server >\n",
                argv[0]);
        return 1;
    }
    /* first is the interrupt level */
    level = (int) strtol(argv[1], &endptr, 0 );
    if ( endptr == argv[1] ) {
        fprintf(stderr, "Cannot interpret as  number: %s\n", argv[1]);
        return 1;
    }
 
    vecnum = (int) strtol(argv[2], &endptr, 0);
    if ( endptr == argv[2] ) {
        fprintf(stderr, "Cannot interpret as  number: %s\n", argv[2]);
        return 1;
    }
    rate = (unsigned) strtol(argv[3], &endptr, 0);
    if ( endptr == argv[3] ) {
        fprintf(stderr, "Cannot interpret as  number: %s\n", argv[3]);
        return 1;
    }
 
    if ( VISIONinterrupt( level, vecnum, rate, argv[4] ) == -1 )
        return 1;       /* Use 1 for failure under UNIX, -1 under VxWorks. */
    return 0;
    
}
#endif
 
 
 
/************************************************************************
 *      The real interrupter.                                           *
************************************************************************/
int VISIONinterrupt( level, vecnum, rate, net_name )
  int level;
  int vecnum;
  unsigned rate;
  char *net_name;
  {
  /* code for real function; returns -1 on error, 0 on success */
  }