Notes on building gcc-2.95.2 for VxWorks 5.2, 68k

Tony Farrell tjf@aaoepp.aao.GOV.AU
Wed Jul 19 22:38:00 GMT 2000

I have just managed to get everything I need working with gcc 2.95.2 
targeting VxWorks on a 68k.  The final thing was c++ exceptions, which 
I know somebody else was looking for at some stage.

So I thought I would forward my notes for anybody who is interested.  
They may also be of use for other VxWorks targets, particularly for 
VxWorks 5.2.
They highlight a couple of problems in the standard release which it 
should be possible to fix, but am not sure enough about the reasons 
behind some past decisions to prepare the relevant patches.


Reference - CrossGCC Frequently Ask Questions (Version 1.0.1, Dec 3, 1999)

1.  Fetch all components (as per section 2 in CrossGCC FAQ) into 
    the directory (tars), don't bother unpacking.

2.  Fetch the scripts

3.  Ensure you have gnu make in path before any other make.

4.  Run  (Assumes a directory called "tars" has all
        the required tar.gz files - binutils-2.9.1.tar.gz   
        gcc-2.95.2.tar.gz   gdb-4.18.tar.gz newlib-1.8.2.tar.gz

5.  Edit build-cross.  

    5.a.  Change the install prefix appropriately.  In my case


          You will also want to create that directory if it does
          not exist.

    5.b   Change the configure line to add --with-headers and
          --with-newlib.     --with-headers should point to your
          existing VxWorks include files.   In my case, the line became.

          ./src/configure --target=$target --prefix=$prefix -v --with-headers=/opt/VxWorks/vw/h --with-newlib

6.  Edit gcc-2.95.2/libio/gen-params

    To ensure HAVE_PRINTF_FP and HAVE_LONG_DOUBLE_IO are always 0.  
    (I think this should actually be conditional on use of newlib, but
     I don't know how to do this).

7.  In c++ I/O include files.  Replace occurrences of NULL by 0.   NULL was
    giving compilation errors due to invalid pointer types.  

    I only did this in these files - 


    I didn't do the other files as these were the only two where I
    had a problem, but I suspect that was because I didn't use the other
    files that used NULL.  I only hit this problem once I started to compile
    my C++ software, not when I was building the compiler.

    I would recommend not using NULL as you can never
    be sure what its definition is, I would suggest just plain
    0 (zero) or using a constant with a different name. 

8.  Changes to make exceptions and global contructors work properly.

    By default, gcc is running "collect2" with the -r option.  It is
    also complied with USE_COLLECT2 undefined.  The result of this
    combination is that the constructor stuff of collect2 is not being
    run (in fact, collect2 is doing little if anything).   

    To fix this perform the following modifications to

        8A.  Change LINK_SPEC to "-Ur"
        9B.  Add the following lines

                #ifndef USE_COLLECT2
                #define USE_COLLECT2

9.  Start the build.  The command to build is

        ./  m68k-wrs-vxworks

    This will fail with

../../../src/libiberty/fdmatch.c: In function `fdmatch':
../../../src/libiberty/fdmatch.c:59: storage size of `sbuf1' isn't known
../../../src/libiberty/fdmatch.c:60: storage size of `sbuf2' isn't known

    At this point, you should edit the supposedly fixed include file

    (Where prefix is defined to be your installation directory above).

    Insert the line

#include <types/vxTypesOld.h>

    early in the file, say about line 33.

    This should done by fixincludes, and there is already reference to this 
    in gcc-2.95.2/gcc/fixincludes, but this does not appear to work.

10.  Restart the build

        ./  m68k-wrs-vxworks

    Should now work.

11.  Install

        ./  m68k-wrs-vxworks install

12.  Create a dummy libm.a  since the default g++ link stage tries to bring
     this in but is does not exist (the functionallity is part of the
     VxWorks kernel)

     cd ./release
     echo "void ___junk() {}" > j.c
     ./bin/m68k-wrs-vxworks-gcc -c j.c
     ./bin/m68k-wrs-vxworks-ar -crv ./lib/gcc-lib/m68k-wrs-vxworks/2.95.2/libm.a
     ./bin/m68k-wrs-vxworks-ranlib ./lib/gcc-lib/m68k-wrs-vxworks/2.95.2/libm.a

     There should be some way of saying this is not needed, but I couldn't find it.

For me, that was it, except that sometimes I did not get clear rebuilds for
reasons which are not clear.


Using the system
Some things to note.  

You must explicitly invoke the global constructors and destructors
by calling "__do_global_ctor()" for the constructors and
"__do_global_dtors()" for the destructors.  Both of these have C rather
then C++ linkage.  You will have to choose the best time to do this, probably
the constructors should be invoked as part of the boot up on a production 
system, but by hand in a development system.    This should be done once for
each program loaded, by having a routine in that program to do it (say the
equivalent of main()).

If your routines have C++ linkage, it may be quite hard
to call them from the VxWorks shell.  For example, the C++ routine named
"foo" may be known as "_foo__Fv" in VxWorks and if it has arguments, things
get far more complicated.  If you are intending on calling a routine from
the VxWorks shell, consider giving it C linkage, using 'extern "C"'.

Below is a test program I wrote.  It tests in a very basic way, 
constructors/destructors, templates and optionally C++ I/O, STL and 
Exceptions.  A routine called "init" can be used to run the global
constructors whilst "bye" is used to run the destructors.  The routine
"foo_cpp" is the core, but it is called by "foo" - just to demo the
difference between C and C++ linkage.  foo_cpp() creates a couple of objects 
of type test which has a static counter which records the number of objects
created - allowing us to work out if the global constructors/destructors
are run etc.


 *  A simple program to test some features of a C++ compiler.  
 *  Entry point is "foo"
 *  Under Vxworks, you should invoke "init" before running the program
 *  to run global constructors etc.  Similary "bye" to run
 *  global destructors.

/*  Simple bourne shell script to build this program

# Compiler tree
# Compiler command
# Prefix for compiler
# The defines I want.
DEFINES="-DCPU=MC68020 -DHOST_SUN -DVxWorks -DVersion=5_2 -DVxWorks_5_2 -Uunix -U__unix__ -Usun -U__sun__"
# Compile the object
echo $COMP $BPREFIX -c -g  $DEFINES  testit.C
eval $COMP $BPREFIX -c -g  $DEFINES  testit.C

# Linker command and the libraries we need
echo $COMP $BPREFIX -o testit testit.o
eval $COMP $BPREFIX -o testit testit.o


 * Macros to select testing of particular features
 *   Exceptions (do not work)
 *   C++ I/O    (works)
 *   STL        (works).
#define TEST_CPPIO
#define TEST_STL

#include <stdio.h>
#include <iostream>
#include <map> 
#include <string> 

 *  A simple template test, returns the maximum of two arguments.
template<class T>
T maxit(T a, T b)
    if (a > b)
        return a;
        return b;

 *  This class has a static object used to count how many times the
 *  constructor and destructor have been called.  This is used to
 *  check that constructors and destructors are being called appropiately.
 *  printf is used since this is provided by VxWorks.
class test {
        void testit() { printf("Foo testit\n"); }

        test() {
            printf("testit default constructor, variable at %lx, count = %d\n",
                (long int)this,++counter);
        ~test() {
            printf("testit destructor, variable at %lx, count = %d\n",
                (long int)this,--counter);
         static int counter;

 * Initialise the static object in the test class.
int test::counter = 0;

 * Declare a global object of the test class.
test globalvar;

 * Function to test standard template library functionality.
#ifdef TEST_STL
int stl_test (void) 
    printf("Trying STL stuff\n");

    map<string,int> days; 
    days["Jan"] = 31;  days["Feb"] = 28; 
    days["Mar"] = 31;  days["Apr"] = 30; 
    days["May"] = 31;  days["Jun"] = 30; 
    days["Jul"] = 31;  days["Aug"] = 31; 
    days["Sep"] = 30;  days["Oct"] = 31; 
    days["Nov"] = 30;  days["Dec"] = 31; 
    map<string,int>::iterator d = days.begin(); 
    while (d != days.end()) 
        if (d->second == 30) printf ("%s\n",(d->first).c_str()); 
    printf("STL test complete\n");

#endif /* TEST_STL */

 *  Functions to test exceptions.
class MyException{};
void exception_throw()
    printf("About to throw exception\n");
    throw MyException();
    printf("Exception did not throw correctly\n");

void exception_test()
    printf("Trying exceptions\n");
    try {
    catch (...) {
        printf("Caught exception\n");
/*  Alternative test.  Comment out the above and add this  */
    catch (MyException e) {
        printf("Caught exception, throwing again, this should be it\n");
        throw e;
    printf("Normal functinon exit, re-throw did not work\n");
#endif /* TEST_EXCEPTIONS */

 * May test program - c++ calling semanitics.
extern  void foo_cpp()
 *  Declare variable of type myvar, we should see the contructor message
 *  output.
    test myvar;
 *  Declare a pointer to a test variable.
    test *myvar2;
    printf("Should have seen two calls of testit contructor (one by init())\n");
 *  Invoke function of testit

 *  Create a dynamic test object, we should see the contructor and
 *  destructor invoked
    printf("About to do dynamic object, should see another contructor call\n");
    myvar2 = new test;
    delete myvar2;

 *  Test templates using the maxit function.
    double a=1.0, b = 2.0;
    printf("Testing templates - Max of %g and %g is %g\n",

 *  Test standard template library.
#ifdef TEST_STL

 *  TEST C++ I/O functions
    printf("Trying C++ I/O\n");
    cout << "Hello from C++ I/O\n";

 *  Test exception handling.
#   endif

    printf("Foo function normal exit, should see 1 testit destructor\n");
    printf("  And then one more from \"bye()\"\n");


 *  C semanitics call to foo.  This is required so that we can run the
 *  test easily from the VxWorks shell.  C++ function names are mangled
 *  and hence hard to call from the VxWorks shell.
extern "C" void foo()

 *  Function declaratilons
extern "C" {
        void __do_global_ctors();
        void __do_global_dtors();


 *  init() can be called to run the global contructors and should be called
 *  once before foo is invoked.

extern "C" void init()

 *  bye() can be called to run the global destructors and should be called
 *  once after running foo.
extern "C" void bye()

Tony Farrell                  Phone +61 2 9372 4826
Software Group Leader         Fax   +61 2 9372 4880
Anglo-Australian Observatory  Email

Want more information?  See the CrossGCC FAQ,
Want to unsubscribe? Send a note to

More information about the crossgcc mailing list