Development for VxWorks
C Source Code Compatibility Issues
VxWorks compile-time support is slightly different from ANSI C:
- No "main" is allowed; you must choose another name as your entrypoint
- this is because VxWorks has a single global
namespace (symbol table) shared by all users and processes,
so people's main's would collide.
Also, the limitations of the VxWorks shell prevent argc/argv support.
- System header files must be included with the double-quote syntax
instead of the angle-bracket syntax, and some files have slightly
different names and locations.
This is actually an artifact of cross-compilation.
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 */
}