Search code examples
cudanvcc

Unable to decipher nvlink error


I'm attempting to build a project with nvcc. I am getting the most vexing nvlink error: messages I've ever seen.

Here is the link statement:

nvcc    -rdc=true -arch=sm_21 -O3 -Xcompiler -fPIC -I"/usr/local/ACE_wrappers" -I"/usr/local/ACE_wrappers/TAO" -I"/usr/local/DDS" -I"/usr/include/Qt" -I"/usr/include/QtCore" -I"/usr/include/QtGui" -I"../../include" -I"../../include/DDS" -I"../../include/CoordinateTransforms" -I"../../include/DDS/IDLBrokerTemplates" -I"../../def/IDL" -I"../../def/CMD" -I"../../def/XSD" -I"../../src/NetAcquire" -I"/usr/local/ACE_wrappers/TAO/orbsvcs" -I"/usr/local/include/lct.7.5.4" -L"." -L"/usr/local/ACE_wrappers/lib" -L"/usr/local/DDS/lib" -L"/usr/lib64" -L"/usr/local/lib64" -L"../../def/IDL/lib" -L"../../def/XSD" -L"/usr/local/lib" .obj/../../src/Component.o .obj/../../src/COM.o .obj/../../src/DDS/EntityManager.o .obj/../../src/IDLBrokerTemplates/CommandManager.o .obj/../../src/IDLBrokerTemplates/OptionManager.o .obj/../../include/ApplicationProcessStateReporter_moc.o .obj/../../src/Application.o .obj/../../src/CoordinateTransforms/Site.o .obj/../../src/CoordinateTransforms/Geodesy.o .obj/../../src/CoordinateTransforms/Earth.o .obj/../../src/CoordinateTransforms/StateVector.o .obj/../../src/CoordinateTransforms/KeplerianImpact.o .obj/../../src/CoordinateTransforms/GeodeticPosition.o .obj/../../src/IDLBrokerTemplates/MeasurandSubscription.o .obj/../../src/NetAcquire/NetAcquire.o .obj/DataLossFlightTimeImpl.o .obj/DataLossFlightTime.o .obj/DftTable.o .obj/OptionListener.o .obj/PrimaryListener.o .obj/MissionTimeListener.o .obj/DeadMan.o .obj/main.o .obj/../../src/XML/spline.o .obj/../../src/XML/FpTable.o -l"naps-x86_64" -l"naio-x86_64" -l"nalct-x86_64" -l"curl" -l"TAO_Messaging" -l"TAO_Valuetype" -l"TAO_PI_Server" -l"TAO_PI" -l"TAO_CodecFactory" -l"TAO_CosNaming" -l"armadillo" -l"boost_filesystem" -l"boost_system" -l"xerces-c" -l"jarssXSD" -l"OpenDDS_Tcp" -l"JARSSRTv10" -l"QtNetwork" -l"fontconfig" -l"QtGui" -l"QtCore" -l"OpenDDS_Rtps_Udp" -l"OpenDDS_Rtps" -l"OpenDDS_Multicast" -l"OpenDDS_Udp" -l"OpenDDS_InfoRepoDiscovery" -l"OpenDDS_Dcps" -l"TAO_PortableServer" -l"TAO_AnyTypeCode" -l"TAO" -l"ACE"  -o "DFT"

And I'm getting

nvlink error   : Undefined reference to '_ZN5JARSS15KeplerianImpactC1ERKdS2_S2_S2_S2_S2_'
nvlink error   : Undefined reference to '_ZNK5JARSS15KeplerianImpact9getStatusEv'
nvlink error   : Undefined reference to '_ZNK5JARSS15KeplerianImpact13getImpactTimeEv'
nvlink error   : Undefined reference to '_ZNK5JARSS15KeplerianImpact11getPlhStateEv'
nvlink error   : Undefined reference to '_ZN5JARSS15KeplerianImpactD1Ev'
nvlink error   : Undefined reference to '_ZN5JARSS7Geodesy12EFG2GeodeticERKdS2_S2_PdS3_S3_'

I'm certain that these functions/files are included in the compile. You can see from the compile that KeplerianImpact.cpp and Geodesy.cpp are in there.

Is there any way to make the link output easier to read so I can debug this?


Solution

  • I figured this out.

    I needed to define my functions in the correct files. For example, in Foo.h:

    class Foo {
    public:
        __host__ __device__
        Foo();
    }
    

    and the function definition in Foo.cu not Foo.cpp as I originally thought.

     Foo::Foo() {}
    

    For the constant variables, I needed to implement a slightly different strategy.

    Here is an example of the C++ class that I started with:

    class Foo {
    public:
        static double const epsilon;
        static void functionThatUsesEpsilon();
        /**/
    }
    

    Had to be converted to use the global namespace as the epsilon def'n

    namespace foo {
        extern __constant__ double epsilon;
    } 
    
    class Foo {
    public:
        // same stuff as before with the addition of this function
        __host__ __device__
        static inline double getEpsilon() {
    #ifdef __CUDACC__
             return foo::epsilon;
    #else
             return epsilon;
    #endif
        }  
    
        static void functionThatUsesEpsilon() {
            if (bar < getEpsilon()) { // etc }
        }
    };
    

    The ifdef above will return the correct version of the variable for either the host or the device code. Everywhere I had referenced Foo::epsilon I needed to replace with Foo::getEpsilon() so the correct epsilon was returned.

    Hope this helps someone in the future. Thanks to @RobertCrovella for getting me thinking.