Errors Linking to navx frc library

Hello,

We’ve purchased a nav mxp board and are trying to get the software library that comes with it to link with our robot code which at this point is simply trying to just create an instance of the AHRS class. But we are running into linker issues satisfying dependencies. It looks like the navx mxp library (libnavx_frc_cpp.a) is referencing classes in wpi and related libs which come up as unresolved references at link time. For example:


C:\Users\DriverStation
avx-mxp\cpp\lib\libnavx_frc_cpp.a(AHRS.o): In function `AHRS::SPIInit(SPI::Port, unsigned int, unsigned char)':
C:\Users\Scott\GitHub
avxmxp\roborio\c++
avx_frc_cpp\Debug/..\src/AHRS.cpp:830: undefined reference to `SPI::SPI(SPI::Port)'
C:\Users\DriverStation
avx-mxp\cpp\lib\libnavx_frc_cpp.a(AHRS.o): In function `AHRS::I2CInit(I2C::Port, unsigned char)':
C:\Users\Scott\GitHub
avxmxp\roborio\c++
avx_frc_cpp\Debug/..\src/AHRS.cpp:836: undefined reference to `I2C::I2C(I2C::Port, unsigned char)'
C:\Users\DriverStation
avx-mxp\cpp\lib\libnavx_frc_cpp.a(SerialIO.o): In function `SerialIO::GetMaybeCreateSerialPort()':
C:\Users\Scott\GitHub
avxmxp\roborio\c++
avx_frc_cpp\Debug/..\src/SerialIO.cpp:55: undefined reference to `SerialPort::SerialPort(unsigned int, SerialPort::Port, unsigned char, SerialPort::Parity, SerialPort::StopBits)'
C:\Users\Scott\GitHub
avxmxp\roborio\c++
avx_frc_cpp\Debug/..\src/SerialIO.cpp:56: undefined reference to `SerialPort::SetReadBufferSize(unsigned int)'
C:\Users\Scott\GitHub
avxmxp\roborio\c++
avx_frc_cpp\Debug/..\src/SerialIO.cpp:57: undefined reference to `SerialPort::SetTimeout(float)'
C:\Users\Scott\GitHub
avxmxp\roborio\c++
avx_frc_cpp\Debug/..\src/SerialIO.cpp:58: undefined reference to `SerialPort::EnableTermination(char)'
C:\Users\Scott\GitHub
avxmxp\roborio\c++
avx_frc_cpp\Debug/..\src/SerialIO.cpp:59: undefined reference to `SerialPort::Reset()'
C:\Users\DriverStation
avx-mxp\cpp\lib\libnavx_frc_cpp.a(SerialIO.o): In function `SerialIO::Run()':
C:\Users\Scott\GitHub
avxmxp\roborio\c++
avx_frc_cpp\Debug/..\src/SerialIO.cpp:128: undefined reference to `SerialPort::SetReadBufferSize(unsigned int)'
C:\Users\Scott\GitHub
avxmxp\roborio\c++
avx_frc_cpp\Debug/..\src/SerialIO.cpp:129: undefined reference to `SerialPort::SetTimeout(float)'
C:\Users\Scott\GitHub
avxmxp\roborio\c++
avx_frc_cpp\Debug/..\src/SerialIO.cpp:130: undefined reference to `SerialPort::EnableTermination(char)'
C:\Users\Scott\GitHub
avxmxp\roborio\c++
avx_frc_cpp\Debug/..\src/SerialIO.cpp:131: undefined reference to `SerialPort::Flush()'
C:\Users\Scott\GitHub
avxmxp\roborio\c++
avx_frc_cpp\Debug/..\src/SerialIO.cpp:132: undefined reference to `SerialPort::Reset()'
C:\Users\Scott\GitHub
avxmxp\roborio\c++
avx_frc_cpp\Debug/..\src/SerialIO.cpp:145: undefined reference to `SerialPort::Reset()'
C:\Users\Scott\GitHub
avxmxp\roborio\c++
avx_frc_cpp\Debug/..\src/SerialIO.cpp:146: undefined reference to `SerialPort::Write(char const*, int)'
C:\Users\Scott\GitHub
avxmxp\roborio\c++
avx_frc_cpp\Debug/..\src/SerialIO.cpp:148: undefined reference to `SerialPort::Write(char const*, int)'
C:\Users\Scott\GitHub
avxmxp\roborio\c++
avx_frc_cpp\Debug/..\src/SerialIO.cpp:149: undefined reference to `SerialPort::Flush()'
C:\Users\Scott\GitHub
avxmxp\roborio\c++
avx_frc_cpp\Debug/..\src/SerialIO.cpp:176: undefined reference to `SerialPort::Write(char const*, int)'
C:\Users\Scott\GitHub
avxmxp\roborio\c++
avx_frc_cpp\Debug/..\src/SerialIO.cpp:182: undefined reference to `SerialPort::GetBytesReceived()'
C:\Users\Scott\GitHub
avxmxp\roborio\c++
avx_frc_cpp\Debug/..\src/SerialIO.cpp:187: undefined reference to `SerialPort::Read(char*, int)'
C:\Users\Scott\GitHub
avxmxp\roborio\c++
avx_frc_cpp\Debug/..\src/SerialIO.cpp:230: undefined reference to `SerialPort::Read(char*, int)'
C:\Users\Scott\GitHub
avxmxp\roborio\c++
avx_frc_cpp\Debug/..\src/SerialIO.cpp:406: undefined reference to `SerialPort::Flush()'
C:\Users\Scott\GitHub
avxmxp\roborio\c++
avx_frc_cpp\Debug/..\src/SerialIO.cpp:407: undefined reference to `SerialPort::Reset()'
C:\Users\Scott\GitHub
avxmxp\roborio\c++
avx_frc_cpp\Debug/..\src/SerialIO.cpp:429: undefined reference to `SerialPort::Write(char const*, int)'
C:\Users\Scott\GitHub
avxmxp\roborio\c++
avx_frc_cpp\Debug/..\src/SerialIO.cpp:431: undefined reference to `SerialPort::Write(char const*, int)'
C:\Users\Scott\GitHub
avxmxp\roborio\c++
avx_frc_cpp\Debug/..\src/SerialIO.cpp:432: undefined reference to `SerialPort::Flush()'
C:\Users\Scott\GitHub
avxmxp\roborio\c++
avx_frc_cpp\Debug/..\src/SerialIO.cpp:439: undefined reference to `SerialPort::GetBytesReceived()'
C:\Users\DriverStation
avx-mxp\cpp\lib\libnavx_frc_cpp.a(RegisterIOSPI.o): In function `RegisterIO_SPI::Init()':
C:\Users\Scott\GitHub
avxmxp\roborio\c++
avx_frc_cpp\Debug/..\src/RegisterIOSPI.cpp:17: undefined reference to `SPI::SetClockRate(double)'
C:\Users\Scott\GitHub
avxmxp\roborio\c++
avx_frc_cpp\Debug/..\src/RegisterIOSPI.cpp:18: undefined reference to `SPI::SetMSBFirst()'
C:\Users\Scott\GitHub
avxmxp\roborio\c++
avx_frc_cpp\Debug/..\src/RegisterIOSPI.cpp:19: undefined reference to `SPI::SetSampleDataOnFalling()'
C:\Users\Scott\GitHub
avxmxp\roborio\c++
avx_frc_cpp\Debug/..\src/RegisterIOSPI.cpp:20: undefined reference to `SPI::SetClockActiveLow()'
C:\Users\Scott\GitHub
avxmxp\roborio\c++
avx_frc_cpp\Debug/..\src/RegisterIOSPI.cpp:21: undefined reference to `SPI::SetChipSelectActiveLow()'
C:\Users\DriverStation
avx-mxp\cpp\lib\libnavx_frc_cpp.a(RegisterIOI2C.o): In function `RegisterIO_I2C::Write(unsigned char, unsigned char)':
C:\Users\Scott\GitHub
avxmxp\roborio\c++
avx_frc_cpp\Debug/..\src/RegisterIOI2C.cpp:21: undefined reference to `I2C::Write(unsigned char, unsigned char)'
C:\Users\DriverStation
avx-mxp\cpp\lib\libnavx_frc_cpp.a(RegisterIOI2C.o): In function `RegisterIO_I2C::Read(unsigned char, unsigned char*, unsigned char)':
C:\Users\Scott\GitHub
avxmxp\roborio\c++
avx_frc_cpp\Debug/..\src/RegisterIOI2C.cpp:33: undefined reference to `I2C::Write(unsigned char, unsigned char)'
C:\Users\Scott\GitHub
avxmxp\roborio\c++
avx_frc_cpp\Debug/..\src/RegisterIOI2C.cpp:34: undefined reference to `I2C::ReadOnly(unsigned char, unsigned char*)'
collect2.exe: error: ld returned 1 exit status

We thought that all we would have to do is add what we think are all the required libraries into the project setup:
wpi, spi, i2c, navx_frc_cpp to the project Properties->C/C++ General->Paths and Symbols->Libraries tab in that order. We’ve also added the path to the navx_frc_cpp library under the Library Paths Tab. However we still get the linker errors shown above.

We did discover that by adding references to I2C, SPI, and SerialPort into our code causes the program to link without error. Obviously we don’t want to have create unnecessary references. Can someone shed light around what we need to do to get the navx library to link correctly to our code?

Below is an example that will now link without error due to the additional references in the code.

  
     // AHRS is a class that is in the navx frc library.  
     AHRS *ahrs = new AHRS(SPI::Port::kMXP);

    // These classes are in the wpi, i2c, spi libraries.
    I2C *i2c = new I2C(I2C::kOnboard, 23);
    SPI* spi = new SPI(SPI::kOnboardCS0); 
    SerialPort *sport = new 	SerialPort(1500);

Thanks,
Rob Saccone
Team 3950

You have encountered an issue with the order of the libraries specified to the linker. The linker implementation used by gcc/g++ requires them listed in an order which is opposite from what one would expect.

For details, see this stack overflow discussion, specifically in the “Linking to Static Libraries” section, where it says:

"The linker searches from left to right, and notes unresolved symbols as it go. Only a library resolves the symbol, it takes the object files of that library to resolve the symbol (b.o out of libb.a in this case).

Dependencies of static libraries against each other work the same - the library that needs symbols must be first, then the library that resolves the symbol."

In this case, since the navx_frc_cpp library is dependent upon the wpi library, the navx_frc_cpp library must be listed before the wpi library in the list in the libraries tab.

This order can be changed (in Eclipse) by bringing up the project properties, and then within the properties dialog selecting C/C++ General -> Paths and Symbols in the tree on the left. Next, within the Paths and Symbols pane, click on the libraries tab. You should see in this list the “wpi” and “navx_frc_cpp” libraries listed. Change their order (by using the move up and move down buttons) and rebuild.