1

So, I'm trying to compile the code from the HelloWorldRender snippet in Qt Creator. What I'd like to be able to do is just step through the code in the debugger and mess with it so I can understand how to use it.

The problem, however, is that I'm getting a ton of linker errors (max error count reached is above 1400) when I try to build my project. I'm almost positive the cause is due to the order of the libraries being specified.

Key points worth mentioning

  • To those unfamiliar with QMake: Note that GCC is used to compile this; the linker order specified in QMake is one-to-one with GCC.

  • I've tried a variety of different linking orders, some which have even involved repeating certain libraries within the list...the closest I've been able to get the error count down to is around 150.

  • One required library for the HelloWorldSnippet (libRenderSnippetCHECKED.a) - which isn't part of the SDK specifically - has been compiled without any issues, and is specified in the libraries list to be linked.

  • A lot of this project info (libraries to link, defines) has literally been taken from scouring the Makefile for this snippet and deciphering what is (obviously) lines upon lines of auto-generated code.

  • Documentation for PhysX is...sparse, despite being what appears to be a popular API. I have yet to find anything which actually describes how to get this running in a Linux environment (this release is around 2 months old, to be fair).

  • Distro being used is Ubuntu 13.10. Compiling on x86_64 architecture, using an Optimus setup.

In addition to my project file, I've included the unmoddified HelloWorld files for convenience.

.pro file


TEMPLATE = app
CONFIG += console
CONFIG -= app_bundle
CONFIG -= qt

SOURCES += main.cpp

INCLUDEPATH +=  /opt/PhysX/Include \
                /opt/PhysX/Include/characterkinematic \
                /opt/PhysX/Include/cloth \
                /opt/PhysX/Include/common \
                /opt/PhysX/Include/cooking \
                /opt/PhysX/Include/extensions \
                /opt/PhysX/Include/foundation \
                /opt/PhysX/Include/geometry \
                /opt/PhysX/Include/particles \
                /opt/PhysX/Include/physxprofilesdk \
                /opt/PhysX/Include/physxvisualdebuggersdk \
                /opt/PhysX/Include/pxtask   \
                /opt/PhysX/Include/vehicle  \
                /opt/PhysX/pvd \
                /opt/PhysX/Snippets/SnippetRender

DEFINES +=  PHYSX_PROFILE_SDK \
            RENDER_SNIPPET \
            NDEBUG \
            PX_CHECKED \
            PX_SUPPORT_VISUAL_DEBUGGER


LIBS += -L/opt/PhysX/Lib/linux64

LIBS += -lPvdRuntimeCHECKED \
        -lSimulationControllerCHECKED \
        -lSceneQueryCHECKED \
        -lLowLevelCHECKED \
        -lLowLevelClothCHECKED \
        -lSnippetRenderCHECKED \
        -lPhysX3CHECKED \
        -lPhysX3VehicleCHECKED \
        -lPhysX3CookingCHECKED \
        -lPhysX3ExtensionsCHECKED \
        -lPhysX3CharacterKinematicCHECKED \
        -lPhysXProfileSDKCHECKED \
        -lPhysXVisualDebuggerSDKCHECKED \
        -lPxTaskCHECKED \
        -lPhysX3CommonCHECKED \
        -lGL \
        -lGLU \
        -lglut \
        -lX11 \
        -lrt \
        -lpthread

SnippetHelloWorld.cpp


// This code contains NVIDIA Confidential Information and is disclosed to you
// under a form of NVIDIA software license agreement provided separately to you.
//
// Notice
// NVIDIA Corporation and its licensors retain all intellectual property and
// proprietary rights in and to this software and related documentation and
// any modifications thereto. Any use, reproduction, disclosure, or
// distribution of this software and related documentation without an express
// license agreement from NVIDIA Corporation is strictly prohibited.
//
// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES
// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT,
// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE.
//
// Information and code furnished is believed to be accurate and reliable.
// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such
// information or for any infringement of patents or other rights of third parties that may
// result from its use. No license is granted by implication or otherwise under any patent
// or patent rights of NVIDIA Corporation. Details are subject to change without notice.
// This code supersedes and replaces all information previously supplied.
// NVIDIA Corporation products are not authorized for use as critical
// components in life support devices or systems without express written approval of
// NVIDIA Corporation.
//
// Copyright (c) 2008-2013 NVIDIA Corporation. All rights reserved.
// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.


#define PVD_HOST "127.0.0.1"

// ****************************************************************************
// This snippet illustrates simple use of physx
//
// It creates a number of box stacks on a plane, and if rendering, allows the
// user to create new stacks and fire a ball from the camera position
// ****************************************************************************

#include "PxPhysicsAPI.h"
#include <ctype.h>

#if defined(PX_PS3)
#include "PS3Init.h"
#endif

using namespace physx;

PxDefaultAllocator      gAllocator;
PxDefaultErrorCallback  gErrorCallback;

PxFoundation*           gFoundation = NULL;
PxPhysics*              gPhysics    = NULL;

PxDefaultCpuDispatcher* gDispatcher = NULL;
PxScene*                gScene      = NULL;

PxMaterial*             gMaterial   = NULL;

PxVisualDebuggerConnection*
                        gConnection = NULL;

PxReal stackZ = 10.0f;

PxRigidDynamic* createDynamic(const PxTransform& t, const PxGeometry& geometry, const PxVec3& velocity=PxVec3(0))
{
    PxRigidDynamic* dynamic = PxCreateDynamic(*gPhysics, t, geometry, *gMaterial, 10.0f);
    dynamic->setAngularDamping(0.5f);
    dynamic->setLinearVelocity(velocity);
    gScene->addActor(*dynamic);
    return dynamic;
}

void createStack(const PxTransform& t, PxU32 size, PxReal halfExtent)
{
    PxShape* shape = gPhysics->createShape(PxBoxGeometry(halfExtent, halfExtent, halfExtent), *gMaterial);
    for(PxU32 i=0; i<size;i++)
    {
        for(PxU32 j=0;j<size-i;j++)
        {
            PxTransform localTm(PxVec3(PxReal(j*2) - PxReal(size-i), PxReal(i*2+1), 0) * halfExtent);
            PxRigidDynamic* body = gPhysics->createRigidDynamic(t.transform(localTm));
            body->attachShape(*shape);
            PxRigidBodyExt::updateMassAndInertia(*body, 10.0f);
            gScene->addActor(*body);
        }
    }
    shape->release();
}

void initPhysics(bool interactive)
{
    gFoundation = PxCreateFoundation(PX_PHYSICS_VERSION, gAllocator, gErrorCallback);
    PxProfileZoneManager* profileZoneManager = &PxProfileZoneManager::createProfileZoneManager(gFoundation);
    gPhysics = PxCreatePhysics(PX_PHYSICS_VERSION, *gFoundation, PxTolerancesScale(),true,profileZoneManager);

    if(gPhysics->getPvdConnectionManager())
    {
        gPhysics->getVisualDebugger()->setVisualizeConstraints(true);
        gPhysics->getVisualDebugger()->setVisualDebuggerFlag(PxVisualDebuggerFlag::eTRANSMIT_CONTACTS, true);
        gPhysics->getVisualDebugger()->setVisualDebuggerFlag(PxVisualDebuggerFlag::eTRANSMIT_SCENEQUERIES, true);
        gConnection = PxVisualDebuggerExt::createConnection(gPhysics->getPvdConnectionManager(), PVD_HOST, 5425, 10);
    }

    PxSceneDesc sceneDesc(gPhysics->getTolerancesScale());
    sceneDesc.gravity = PxVec3(0.0f, -9.81f, 0.0f);
    gDispatcher = PxDefaultCpuDispatcherCreate(2);
    sceneDesc.cpuDispatcher = gDispatcher;
    sceneDesc.filterShader  = PxDefaultSimulationFilterShader;
    gScene = gPhysics->createScene(sceneDesc);

    gMaterial = gPhysics->createMaterial(0.5f, 0.5f, 0.6f);

    PxRigidStatic* groundPlane = PxCreatePlane(*gPhysics, PxPlane(0,1,0,0), *gMaterial);
    gScene->addActor(*groundPlane);

    for(PxU32 i=0;i<5;i++)
        createStack(PxTransform(PxVec3(0,0,stackZ-=10.0f)), 10, 2.0f);

    if(!interactive)
        createDynamic(PxTransform(PxVec3(0,40,100)), PxSphereGeometry(10), PxVec3(0,-50,-100));
}

void stepPhysics(bool interactive)
{
    PX_UNUSED(interactive)
    gScene->simulate(1.0f/60.0f);
    gScene->fetchResults(true);
}

void cleanupPhysics(bool interactive)
{
    PX_UNUSED(interactive)
    gScene->release();
    gDispatcher->release();
    PxProfileZoneManager* profileZoneManager = gPhysics->getProfileZoneManager();
    if(gConnection != NULL)
        gConnection->release();
    gPhysics->release();
    profileZoneManager->release();
    gFoundation->release();

    printf("SnippetHelloWorld done.\n");
}

void keyPress(const char key, const PxTransform& camera)
{
    switch(toupper(key))
    {
    case 'B':   createStack(PxTransform(PxVec3(0,0,stackZ-=10.0f)), 10, 2.0f);                      break;
    case ' ':   createDynamic(camera, PxSphereGeometry(3.0f), camera.rotate(PxVec3(0,0,-1))*200);   break;
    }
}

#ifdef PX_XBOXONE
int main(Platform::Array<Platform::String^>^)
#else
int main(int, char**)
#endif
{
#ifdef RENDER_SNIPPET
    extern void renderLoop();
    renderLoop();
#else
    static const PxU32 frameCount = 100;
    initPhysics(false);
    for(PxU32 i=0; i<frameCount; i++)
        stepPhysics(false);
    cleanupPhysics(false);
#endif
}

SnippetHelloWorldRender.cpp


// This code contains NVIDIA Confidential Information and is disclosed to you
// under a form of NVIDIA software license agreement provided separately to you.
//
// Notice
// NVIDIA Corporation and its licensors retain all intellectual property and
// proprietary rights in and to this software and related documentation and
// any modifications thereto. Any use, reproduction, disclosure, or
// distribution of this software and related documentation without an express
// license agreement from NVIDIA Corporation is strictly prohibited.
//
// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES
// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT,
// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE.
//
// Information and code furnished is believed to be accurate and reliable.
// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such
// information or for any infringement of patents or other rights of third parties that may
// result from its use. No license is granted by implication or otherwise under any patent
// or patent rights of NVIDIA Corporation. Details are subject to change without notice.
// This code supersedes and replaces all information previously supplied.
// NVIDIA Corporation products are not authorized for use as critical
// components in life support devices or systems without express written approval of
// NVIDIA Corporation.
//
// Copyright (c) 2008-2013 NVIDIA Corporation. All rights reserved.
// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.

#ifdef RENDER_SNIPPET
#include "PxPhysicsAPI.h"

#ifndef _HAS_EXCEPTIONS
#define _HAS_EXCEPTIONS 0
#endif
#include <vector>
#include "SnippetRender.h"
#include "SnippetCamera.h"

using namespace physx;

extern void initPhysics(bool interactive);
extern void stepPhysics(bool interactive);
extern void cleanupPhysics(bool interactive);
extern void keyPress(const char key, const PxTransform& camera);

namespace
{
Snippets::Camera*   sCamera;

void motionCallback(int x, int y)
{
    sCamera->handleMotion(x, y);
}

void keyboardCallback(unsigned char key, int x, int y)
{
    if(key==27)
        exit(0);

    if(!sCamera->handleKey(key, x, y))
        keyPress(key, sCamera->getTransform());
}

void mouseCallback(int button, int state, int x, int y)
{
    sCamera->handleMouse(button, state, x, y);
}

void idleCallback()
{
    glutPostRedisplay();
}

void renderCallback()
{
    stepPhysics(true);

    Snippets::startRender(sCamera->getEye(), sCamera->getDir());

    PxScene* scene;
    PxGetPhysics().getScenes(&scene,1);
    PxU32 nbActors = scene->getNbActors(PxActorTypeSelectionFlag::eRIGID_DYNAMIC | PxActorTypeSelectionFlag::eRIGID_STATIC);
    if(nbActors)
    {
        std::vector<PxRigidActor*> actors(nbActors);
        scene->getActors(PxActorTypeSelectionFlag::eRIGID_DYNAMIC | PxActorTypeSelectionFlag::eRIGID_STATIC, (PxActor**)&actors[0], nbActors);
        Snippets::renderActors(&actors[0], (PxU32)actors.size(), true);
    }

    Snippets::finishRender();
}

void exitCallback(void)
{
    delete sCamera;
    cleanupPhysics(true);
}
}

void renderLoop()
{
    sCamera = new Snippets::Camera(PxVec3(50.0f, 50.0f, 50.0f), PxVec3(-0.6f,-0.2f,-0.7f));

    Snippets::setupDefaultWindow("PhysX Snippet HelloWorld");
    Snippets::setupDefaultRenderState();

    glutIdleFunc(idleCallback);
    glutDisplayFunc(renderCallback);
    glutKeyboardFunc(keyboardCallback);
    glutMouseFunc(mouseCallback);
    glutMotionFunc(motionCallback);
    motionCallback(0,0);

    atexit(exitCallback);

    initPhysics(true);
    glutMainLoop();
}
#endif
zeboidlund
  • 9,731
  • 31
  • 118
  • 180
  • Quote the linker command as executed by `make`, and the first few errors. The .pro files are relevant, source code is *not* and you may safely remove it from the question. – n. m. could be an AI Apr 08 '14 at 15:50

1 Answers1

0

Since the libraries provided are static and have circular dependencies, you need to tell the linker to solve the dependencies. Passing --start-group and --end-group to ld should do the trick.

LIBS += -Wl,--start-group \
        -lPvdRuntimeCHECKED \
        -lSimulationControllerCHECKED \
        ... \
        -Wl,--end-group

I would also change NDEBUG to _DEBUG, but everything else looks good.