c++gcclinkermakefilertems

Undefined reference to `nfsInit`


I am currently trying to integrate an NFS server into some code running on RTEMS 4.9.2 on a POWER PC 5200. This is going to be tough to succinctly explain so bear with me.

RTEMS NFS

Currently RTEMS implements an NFS client through the nfs.c file. In order to activate the command line interface and be able to use the mount -t nfs ... option you need to add #define CONFIGURE_SHELL_MOUNT_NFS to your config file and link the rtems nfs files with -lnfs. See here for more details. Doing this correctly allows us to implement the RTEMS nfs client and from the command line we can mount a remote drive.

Using the RTEMS NFS client directly

We don't expose the RTEMS command line in our program, so we would like to be able to use the nfs interface directly. The RTEMS libs provides librtemsNfs.h which contains functions for implementing nfs clients. The implementations for these functions are in nfs.c which is compiled to create 1 of 2 libs:

  1. libnfs.a
  2. nfs.rel

Both are needed to build. As part of our code we are using the function nfsInit(... which is declared in librtemsNfs.h and defined in nfs.c.

The error

So the error is pretty obvious. When we build we get the linker error:

D:\Git\nfs_stuff\Src\RTEMS_proj/init/srvinit.cpp:453: undefined reference to `nfsInit(int, int)'
collect2: ld returned 1 exit status

Attempts to link these libraries

In order to link these we have tried multiple ways. We have a makefile but to make this easier on everyone i will show what comes out on the command line build. We have tried:


  1. The recommended method is to link with -lnfs (source - an old question) and doing so yields a nice long and complex build command:

powerpc-rtems4.9-g++ -g -Wall -g -mcpu=603e -mstrict-align -meabi -msdata -fno-common ... -MANY_PREPROCESSOR_ARGUMENTS ... -MANY_INCLUDE_FILES ... Map=./exe/srvevp.map -lc -lm --gc-sections -lnfs -mcpu=603e -mstrict-align -meabi ... -MANY_OBJECT_FILES ... ./exe/obj/srvinit.o ... -MANY_MORE_OBJECT_FILES

Our compile and link command has -lnfs, before the inclusion of the offending object file (srvinit.o). But we still get the linker error.


  1. I tried to link by path directly to the .a and .rel file. We did this by adding: /c/rtems-4.9/powerpc-rtems4.9/5200/lib/libnfs.a /c/rtems-4.9/powerpc-rtems4.9/5200/lib/nfs.rel to the command line. We added it both before and after the offending object file. We also tried with the -L command to force linking by path. All of this results in the same error.

Some other information

This is hard to describe, but when removing the direct link of the libnfs.a file we lose the ability to build even without direct nfs use. ie. the internal RTEMS files fail to link to one another. This is very odd, it seems to me you should only need to the -lnfs to build the command line options, but even without this flag it builds successfully. Without the direct include we get the error:

c:/rtems-4.9/powerpc-rtems4.9/5200/lib\librtemscpu.a(libshell_a-main_mount_nfs.o): In function `rtems_shell_nfs_mounter':
e:\CCNET\rtems-4.9\Trunk\build_5200\powerpc-rtems4.9\c\adept_5200\cpukit\libmisc/../../../../../../rtems-4.9.2/c/src/../../cpukit/libmisc/shell/main_mount_nfs.c:46: undefined reference to `rpcUdpInit'
e:\CCNET\rtems-4.9\Trunk\build_5200\powerpc-rtems4.9\c\5200\cpukit\libmisc/../../../../../../rtems-4.9.2/c/src/../../cpukit/libmisc/shell/main_mount_nfs.c:51: undefined reference to `nfsInit'
e:\CCNET\rtems-4.9\Trunk\build_5200\powerpc-rtems4.9\c\5200\cpukit\libmisc/../../../../../../rtems-4.9.2/c/src/../../cpukit/libmisc/shell/main_mount_nfs.c:58: undefined reference to `nfsMount'
collect2: ld returned 1 exit status

Which is the rtems shell code failing to link. If we add the /c/rtems-4.9/powerpc-rtems4.9/5200/lib/libnfs.a /c/rtems-4.9/powerpc-rtems4.9/5200/lib/nfs.rel to the end of the build line, then everything succeeds.

To re-iterate, to build the command line functions you need to directly include the nfs .a and .rel files, you DO NOT need to use -lnfs.

The question

So the first and most obvious question is, why is this not linking, even when i explicitly give the library files? My thoughts on this are, perhaps the files do not include the definitions for the functions i am trying to use. But this is discredited in the other information section as i need them to link the functions for the RTEMS OS itself.

I know this will be hard to give a direct answer too, since it will be very much un-reproducible without the PC and all the compiler installed etc. How can i check that the lib files include the definitions for my functions and are being linked in the correct order? The compiler is a BSP specific GCC style compiler provided by RTEMS for the Power PC 5200. It accepts most compiler options that GCC/G++ 4.2 would accept.

Finally, are there any good methods for debugging such a linker issue?.


Solution

  • To make the entire library API available to your C++ code, you could include the library header itself within the extern "C" block, like so:

    extern "C" {
        #include <librtemsNfs.h>
    }
    

    More details on why this is needed is well covered here: Why do we need extern "C"{ #include <foo.h> } in C++?