LinuxQuestions.org
Review your favorite Linux distribution.
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices


Reply
  Search this Thread
Old 05-24-2005, 03:53 AM   #1
BBB
Member
 
Registered: Aug 2004
Location: sweden
Distribution: Slackware 10.2 and Win2k
Posts: 127

Rep: Reputation: 15
Why doesn't my shared lib load?


Im writing a modular 3D engine and want to put all OpenGL specific stuff
in a shared lib (so i can write another renderer lib using software rendering
or whatever and just plug it in without recompiling the rest of the program).
Ive been able to do this in Windows but now that I have
migrated to a better OS so ofcourse I want to port my engine to it .

Everything compiles fine but when i try to load the lib it returns NULL so
something is screwed up with my lib and I have no idea what.

[crash course in factory design pattern and C++ shared libs]
Basicly i have a interface called "Irenderer_x11" which both the program
and the shared lib knows about and there is no GL code in the interface
or the program. I then have a child-class of Irenderer_x11 called
cRenderer_glx which i create in the shared lib and then send to the main
program. And since this is in C++ i need a C-function (that i load from
the lib) called x11_renderer_factory that returns the C++ cRenderer_glx
object.
[/crash course in factory design pattern and C++ shared libs]

Here is the source ( cheers to NeHe and Mihael Vrbanec )

Code:
# Makefile


CC = g++
LD = g++

CFLAGS = -fPIC -Wall -pedantic -ansi

#CFLAGS = -fPIC -Wall -pedantic -ansi

DYNLINKFLAGS = -fPIC -Wall -pedantic -ansi -shared -rdynamic

#DYNLINKFLAGS = -fPIC -shared -nostdlib -rdynamic


default: lesson04 glx_renderer.so

lesson04: lesson04.o
	$(CC) $(CFLAGS) -o lesson04 lesson04.o -L/usr/X11R6/lib -lXxf86vm
	
lesson04.o: lesson04.cc i_renderer_x11.hpp
	$(CC) $(CFLAGS) -c lesson04.cc

glx_renderer.so: glx_renderer.o
	$(LD) $(DYNLINKFLAGS) -o glx_renderer.so glx_renderer.o -L/usr/X11R6/lib -lGL -lGLU -lXxf86vm

glx_renderer.o: glx_renderer.cc glx_renderer.hpp i_renderer_x11.hpp
	$(CC) $(CFLAGS) glx_renderer.cc -c


clean:
	@echo Cleaning up...
	@rm ./lesson04
	@rm ./lesson04.o
	@rm ./glx_renderer.o
	@rm ./glx_renderer.so
	@echo Done.





Code:
// lesson04.cc

/*
 * This code was created by Jeff Molofee '99 
 * (ported to Linux/GLX by Mihael Vrbanec '00)
 *
 * If you've found this code useful, please let me know.
 *
 * Visit Jeff at http://nehe.gamedev.net/
 * 
 * or for port-specific comments, questions, bugreports etc. 
 * email to Mihael.Vrbanec@stud.uni-karlsruhe.de
 */
 
#include <stdio.h>


#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/extensions/xf86vmode.h>
#include <X11/keysym.h>


#include <iostream>
using namespace std;

#include <dlfcn.h>

#include "i_renderer_x11.hpp"

bp_x11_window g_x11_window;
Irenderer_x11 *g_x11_renderer = NULL;

bool done;

void keyPressed(KeySym key)
{
    switch (key)
    {
        case XK_Escape:
            done = true;
            break;

        case XK_q:
            done = true;
            break;

        case XK_F1:
            g_x11_renderer->m_kill_x11_window();
            g_x11_window.m_fullscreen = !g_x11_window.m_fullscreen;
            g_x11_renderer->m_create_x11_window(g_x11_window);
            break;
    }
}

int main(int argc, char **argv)
{
    XEvent event;
    KeySym key;
    
    done = false;
    // default to fullscreen
    g_x11_window.m_fullscreen = false;
    
    // This returns NULL!!!
    void *x11_renderer_lib = dlopen("./glx_renderer.so", RTLD_LAZY);

    if (!x11_renderer_lib)
     { cout << "Could not load renderer lib!\n"; return 1; }

    x11_renderer_factory_ptr *x11_renderer_factory =
     (x11_renderer_factory_ptr*) dlsym(x11_renderer_lib, "x11_renderer_factory");

    g_x11_renderer = x11_renderer_factory();




    g_x11_renderer->m_create_x11_window(g_x11_window);

    // wait for events
    while (!done)
    {
        // handle the events in the queue
        while (XPending(g_x11_window.m_display) > 0)
        {
            XNextEvent(g_x11_window.m_display, &event);
            switch (event.type)
            {
                case Expose:
	                if (event.xexpose.count != 0)
	                    break;
                    g_x11_renderer->m_render();
         	        break;
	            case ConfigureNotify:
	            // call resizeGLScene only if our window-size changed
	                if ((event.xconfigure.width != g_x11_window.m_width) || 
	                    (event.xconfigure.height != g_x11_window.m_height))
	                {
	                    g_x11_window.m_width = event.xconfigure.width;
	                    g_x11_window.m_height = event.xconfigure.height;
                        printf("Resize event\n");
	                    g_x11_renderer->m_resize(event.xconfigure.width, event.xconfigure.height);
	                }
	                break;
                // exit in case of a mouse button press
                case ButtonPress:
                    done = True;
                    break;
                case KeyPress:
                    key = XLookupKeysym(&event.xkey, 0);
                    keyPressed(key);
                    break;
                case ClientMessage:
                    if (*XGetAtomName(g_x11_window.m_display, event.xclient.message_type) == 
                        *"WM_PROTOCOLS")
                    {
                        printf("Exiting sanely...\n");
                        done = True;
                    }
                    break;
                default:
                    break;
            }
        }
        g_x11_renderer->m_render();
    }
    cout << "Killing X11 window\n";
    g_x11_renderer->m_kill_x11_window();

    cout << "Releasing X11 renderer\n";
    g_x11_renderer->m_release();

    cout << "Closing X11 renderer lib\n";
    dlclose(x11_renderer_lib);

    return 0;
}

Code:
// i_renderer_x11.hpp

#ifndef _I_RENDERER_X11_HPP_
#define _I_RENDERER_X11_HPP_

#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/extensions/xf86vmode.h>
#include <X11/keysym.h>

class bp_x11_window
 {
    public:
    Display *m_display;
    int m_screen_id;
    Window m_win;
    //GLXContext ctx;
    XSetWindowAttributes m_attr;
    bool m_fullscreen;
    XF86VidModeModeInfo m_deskMode;
    int m_x, m_y;
    unsigned int m_width, m_height;
    unsigned int m_depth;      
 }; // end struct bp_x11_window

class Irenderer_x11
 {
  public:
  virtual bool m_pure_virtual(void) { return true; }
  virtual bool m_create_x11_window(bp_x11_window &a_bp_x11_window) { return false; }

  virtual bool m_render(void) { return false; }
  virtual bool m_resize(unsigned int a_width, unsigned int a_height) { return false; }

  virtual bool m_kill_x11_window(void) { return false; }
  virtual void m_release(void) { delete this; }
 }; // end class Irenderer_x11

typedef Irenderer_x11* x11_renderer_factory_ptr();

#endif // #ifndef _I_RENDERER_X11_HPP_








Code:

// glx_renderer.hpp

#ifndef _GLX_RENDERER_HPP_
#define _GLX_RENDERER_HPP_

#include "i_renderer_x11.hpp"

#include <GL/glx.h>
#include <GL/gl.h>
#include <GL/glu.h>

class cRenderer_glx : public Irenderer_x11
 {
  protected:
  GLXContext m_ctx;
  bp_x11_window *m_x11_window;

  int m_attrListSgl[10];

  int m_attrListDbl[11];

  bool m_done;
  GLfloat m_rotTri, m_rotQuad;

  float m_red_color;
  float m_green_color;
  float m_blue_color;

  public:
  cRenderer_glx();

  // Irenderer_x11 interface
  virtual bool m_pure_virtual(void) { return false; }
  virtual bool m_create_x11_window(bp_x11_window &a_bp_x11_window);

  virtual bool m_render(void);
  virtual bool m_resize(unsigned int a_width, unsigned int a_height);

  virtual bool m_kill_x11_window(void);
  virtual void m_release(void) { delete this; }

  // cRenderer_glx interface
  virtual int  m_initGL(void);
  virtual void m_killGLWindow(void);

 }; // end class cRenderer_glx : public Irenderer_x11


#endif // #ifndef _GLX_RENDERER_HPP_









Code:
// glx_renderer.cc

#include "glx_renderer.hpp"

cRenderer_glx::cRenderer_glx()
 {
  m_attrListSgl[0] = GLX_RGBA;
  m_attrListSgl[1] = GLX_RED_SIZE;
  m_attrListSgl[2] = 4;
  m_attrListSgl[3] = GLX_GREEN_SIZE;
  m_attrListSgl[4] = 4;
  m_attrListSgl[5] = GLX_BLUE_SIZE;
  m_attrListSgl[6] = 4;
  m_attrListSgl[7] = GLX_DEPTH_SIZE;
  m_attrListSgl[8] = 16;
  m_attrListSgl[9] = None;
  //= {GLX_RGBA, GLX_RED_SIZE, 4, 
  //  GLX_GREEN_SIZE, 4, 
  //  GLX_BLUE_SIZE, 4, 
  //  GLX_DEPTH_SIZE, 16,
  //  None};
  m_attrListDbl[0] = GLX_RGBA;
  m_attrListDbl[1] = GLX_DOUBLEBUFFER;
  m_attrListDbl[2] = GLX_RED_SIZE;
  m_attrListDbl[3] = 4;
  m_attrListDbl[4] = GLX_GREEN_SIZE;
  m_attrListDbl[5] = 4;
  m_attrListDbl[6] = GLX_BLUE_SIZE;
  m_attrListDbl[7] = 4;
  m_attrListDbl[8] = GLX_DEPTH_SIZE;
  m_attrListDbl[9] = 16;
  m_attrListDbl[10] = None;

  //m_attrListDbl[] = { GLX_RGBA, GLX_DOUBLEBUFFER, 
  //  GLX_RED_SIZE, 4, 
  //  GLX_GREEN_SIZE, 4, 
  //  GLX_BLUE_SIZE, 4, 
  //  GLX_DEPTH_SIZE, 16,
  //  None };
 } // end cRenderer_glx::cRenderer_glx()

bool cRenderer_glx::m_create_x11_window(bp_x11_window &a_bp_x11_window)
 {
   m_x11_window = &a_bp_x11_window;
   m_red_color = 1.0f;
   m_green_color = 0.5f;
   m_blue_color = 0.5f;

    char* title = "BBB´ & NeHe´s glx tutorial\0";
    int width = 800;
    int height = 600;
    //int bits = 24;

    XVisualInfo *vi;
    Colormap cmap;
    int dpyWidth, dpyHeight;
    int i;
    int glxMajorVersion, glxMinorVersion;
    int vidModeMajorVersion, vidModeMinorVersion;
    XF86VidModeModeInfo **modes;
    int modeNum;
    int bestMode;
    Atom wmDelete;
    Window winDummy;
    unsigned int borderDummy;
    
    //a_bp_x11_window.m_fullscreen = fullscreenflag;
    // set best mode to current
    bestMode = 0;
    // get a connection
    a_bp_x11_window.m_display = XOpenDisplay(0);
    a_bp_x11_window.m_screen_id = DefaultScreen(a_bp_x11_window.m_display);

    XF86VidModeQueryVersion(a_bp_x11_window.m_display, &vidModeMajorVersion,
        &vidModeMinorVersion);

    //printf("XF86VidModeExtension-Version %d.%d\n", vidModeMajorVersion,
    //    vidModeMinorVersion);

    XF86VidModeGetAllModeLines(a_bp_x11_window.m_display, a_bp_x11_window.m_screen_id, &modeNum, &modes);
    // save desktop-resolution before switching modes
    a_bp_x11_window.m_deskMode = *modes[0];
    // look for mode with requested resolution
    for (i = 0; i < modeNum; i++)
    {
        if ((modes[i]->hdisplay == width) && (modes[i]->vdisplay == height))
        {
            bestMode = i;
        }
    }
    // get an appropriate visual
    vi = glXChooseVisual(a_bp_x11_window.m_display, a_bp_x11_window.m_screen_id, m_attrListDbl);
    if (vi == NULL)
    {
        vi = glXChooseVisual(a_bp_x11_window.m_display, a_bp_x11_window.m_screen_id, m_attrListSgl);
        //printf("Only Singlebuffered Visual!\n");
    }
    else
    {
        //printf("Got Doublebuffered Visual!\n");
    }
    glXQueryVersion(a_bp_x11_window.m_display, &glxMajorVersion, &glxMinorVersion);
    //printf("glX-Version %d.%d\n", glxMajorVersion, glxMinorVersion);
    // create a GLX context
    m_ctx = glXCreateContext(a_bp_x11_window.m_display, vi, 0, GL_TRUE);
    // create a color map
    cmap = XCreateColormap(a_bp_x11_window.m_display, RootWindow(a_bp_x11_window.m_display, vi->screen),
        vi->visual, AllocNone);
    a_bp_x11_window.m_attr.colormap = cmap;
    a_bp_x11_window.m_attr.border_pixel = 0;

    if (a_bp_x11_window.m_fullscreen)
    {
        XF86VidModeSwitchToMode(a_bp_x11_window.m_display, a_bp_x11_window.m_screen_id, modes[bestMode]);
        XF86VidModeSetViewPort(a_bp_x11_window.m_display, a_bp_x11_window.m_screen_id, 0, 0);
        dpyWidth = modes[bestMode]->hdisplay;
        dpyHeight = modes[bestMode]->vdisplay;
        //printf("Resolution %dx%d\n", dpyWidth, dpyHeight);
        XFree(modes);
    
        // create a fullscreen window
        a_bp_x11_window.m_attr.override_redirect = true;
        a_bp_x11_window.m_attr.event_mask = ExposureMask | KeyPressMask | ButtonPressMask |
            StructureNotifyMask;
        a_bp_x11_window.m_win = XCreateWindow(a_bp_x11_window.m_display, RootWindow(a_bp_x11_window.m_display, vi->screen),
            0, 0, dpyWidth, dpyHeight, 0, vi->depth, InputOutput, vi->visual,
            CWBorderPixel | CWColormap | CWEventMask | CWOverrideRedirect,
            &a_bp_x11_window.m_attr);
        XWarpPointer(a_bp_x11_window.m_display, None, a_bp_x11_window.m_win, 0, 0, 0, 0, 0, 0);
		XMapRaised(a_bp_x11_window.m_display, a_bp_x11_window.m_win);
        XGrabKeyboard(a_bp_x11_window.m_display, a_bp_x11_window.m_win, True, GrabModeAsync,
            GrabModeAsync, CurrentTime);
        XGrabPointer(a_bp_x11_window.m_display, a_bp_x11_window.m_win, True, ButtonPressMask,
            GrabModeAsync, GrabModeAsync, a_bp_x11_window.m_win, None, CurrentTime);
    }
    else
    {
        // create a window in window mode
        a_bp_x11_window.m_attr.event_mask = ExposureMask | KeyPressMask | ButtonPressMask |
            StructureNotifyMask;
        a_bp_x11_window.m_win = XCreateWindow(a_bp_x11_window.m_display, RootWindow(a_bp_x11_window.m_display, vi->screen),
            0, 0, width, height, 0, vi->depth, InputOutput, vi->visual,
            CWBorderPixel | CWColormap | CWEventMask, &a_bp_x11_window.m_attr);
        // only set window title and handle wm_delete_events if in windowed mode
        wmDelete = XInternAtom(a_bp_x11_window.m_display, "WM_DELETE_WINDOW", true);
        XSetWMProtocols(a_bp_x11_window.m_display, a_bp_x11_window.m_win, &wmDelete, 1);
        XSetStandardProperties(a_bp_x11_window.m_display, a_bp_x11_window.m_win, title,
            title, None, NULL, 0, NULL);
        XMapRaised(a_bp_x11_window.m_display, a_bp_x11_window.m_win);
    }       
    // connect the glx-context to the window
    glXMakeCurrent(a_bp_x11_window.m_display, a_bp_x11_window.m_win, m_ctx);
    XGetGeometry(a_bp_x11_window.m_display, a_bp_x11_window.m_win, &winDummy, &a_bp_x11_window.m_x, &a_bp_x11_window.m_y,
        &a_bp_x11_window.m_width, &a_bp_x11_window.m_height, &borderDummy, &a_bp_x11_window.m_depth);
    //printf("Depth %d\n", GLWin.depth);
    if (glXIsDirect(a_bp_x11_window.m_display, m_ctx)) 
        { } //printf("Congrats, you have Direct Rendering!\n");
    else
      { } // printf("Sorry, no Direct Rendering possible!\n");
    m_initGL();
    return True;    
 } // end bool cRenderer_glx::m_create_x11_window(bp_x11_window a_bp_x11_window)

bool cRenderer_glx::m_render(void)
 {
    float red_color, green_color, blue_color = 0.5f;
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glLoadIdentity();
    glTranslatef(-1.5f, 0.0f, -6.0f);
    glRotatef(m_rotTri, 0.0f, 1.0f, 0.0f);
    glBegin(GL_TRIANGLES);
        glColor3f(red_color, green_color, blue_color);
        glVertex3f(0.0f, 1.0f, 0.0f);
        glColor3f(red_color, green_color, blue_color);
        glVertex3f(-1.0f, -1.0f, 0.0f);
        glColor3f(red_color, green_color, blue_color);
        glVertex3f(1.0f, -1.0f, 0.0f);
    glEnd();
    glLoadIdentity();
    glTranslatef(1.5f, 0.0f, -6.0f);
    glRotatef(m_rotQuad, 1.0f, 0.0f, 0.0f);
    glColor3f(0.5f, 0.5f, 1.0f);
    glBegin(GL_QUADS);
        glVertex3f(-1.0f, 1.0f, 0.0f);
        glVertex3f(1.0f, 1.0f, 0.0f);
        glVertex3f(1.0f, -1.0f, 0.0f);
        glVertex3f(-1.0f, -1.0f, 0.0f);
    glEnd();
    m_rotTri += 0.5f;
    m_rotQuad -= 0.15f;
    glXSwapBuffers(m_x11_window->m_display, m_x11_window->m_win);

    //Sleep(40);

    return True;    
 } // end bool cRenderer_glx::m_render(void)

bool cRenderer_glx::m_kill_x11_window(void)
 {
    if (m_ctx)
    {
        if (!glXMakeCurrent(m_x11_window->m_display, None, NULL))
        {
            //printf("Could not release drawing context.\n");
        }
        glXDestroyContext(m_x11_window->m_display, m_ctx);
        m_ctx = NULL;
    }
    /* switch back to original desktop resolution if we were in fs */
    if (m_x11_window->m_fullscreen)
    {
        XF86VidModeSwitchToMode(m_x11_window->m_display, m_x11_window->m_screen_id, &m_x11_window->m_deskMode);
        XF86VidModeSetViewPort(m_x11_window->m_display, m_x11_window->m_screen_id, 0, 0);
    }
    XCloseDisplay(m_x11_window->m_display);
    return true;
 } // end bool cRenderer_glx::m_kill_x11_window(void)

int  cRenderer_glx::m_initGL(void)
 {
    glShadeModel(GL_SMOOTH);
    glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
    glClearDepth(1.0f);
    glEnable(GL_DEPTH_TEST);
    glDepthFunc(GL_LEQUAL);
    glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
    /* we use resizeGLScene once to set up our initial perspective */
    m_resize(m_x11_window->m_width, m_x11_window->m_height);
    /* Reset the rotation angles of our objects */
    m_rotTri = 0;
    m_rotQuad = 0;    
    glFlush();
    return True;
 } // end int  cRenderer_glx::m_init_gl(void)
bool cRenderer_glx::m_resize(unsigned int a_width, unsigned int a_height)
 {
    if (a_height == 0)    /* Prevent A Divide By Zero If The Window Is Too Small */
        a_height = 1;
    glViewport(0, 0, a_width, a_height);    /* Reset The Current Viewport And Perspective Transformation */
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective(45.0f, (GLfloat)a_width / (GLfloat)a_height, 0.1f, 100.0f);
    glMatrixMode(GL_MODELVIEW);
    return true;
 } // end void cRenderer_glx::m_resizeGLScene(unsigned int width, unsigned int height)

extern "C" Irenderer_x11* x11_renderer_factory()
 {
  return new cRenderer_glx;
 }
 
Old 05-24-2005, 05:16 AM   #2
keefaz
LQ Guru
 
Registered: Mar 2004
Distribution: Slackware
Posts: 6,552

Rep: Reputation: 872Reputation: 872Reputation: 872Reputation: 872Reputation: 872Reputation: 872Reputation: 872
see this page about dlopen and c++ and the problem with Name Mangling
http://www.ibiblio.org/pub/Linux/doc...++-dlopen.html
 
Old 05-26-2005, 07:16 AM   #3
BBB
Member
 
Registered: Aug 2004
Location: sweden
Distribution: Slackware 10.2 and Win2k
Posts: 127

Original Poster
Rep: Reputation: 15
I know, ive read that tutorial.
The namemangling is not a problem, ive solved that problem with the technic mentioned in the tutorial.
The problem is that i can't even LOAD the lib, dlopen returns null so something is screwed up with the lib and its not
namemangling since I don't even get a chance to dlsym() something from it.
 
Old 05-26-2005, 11:31 AM   #4
Harmaa Kettu
Member
 
Registered: Apr 2005
Location: Finland
Posts: 196

Rep: Reputation: 30
First, let's make the error message a bit more descriptive...
Code:
    if (!x11_renderer_lib)
     { cout << "Could not load renderer lib!" << dlerror() << "\n"; return 1; }
After recompiling:
Code:
./lesson04 
Could not load renderer lib:./glx_renderer.so: undefined symbol: _ZN13cRenderer_glx14m_killGLWindowEv

grep -rnH m_killGL *
glx_renderer.hpp:44:  virtual void m_killGLWindow(void);
Binary file glx_renderer.o matches
Binary file glx_renderer.so matches
Commenting out that line from glx_renderer.hpp solves the problem.
 
Old 05-30-2005, 03:08 AM   #5
BBB
Member
 
Registered: Aug 2004
Location: sweden
Distribution: Slackware 10.2 and Win2k
Posts: 127

Original Poster
Rep: Reputation: 15
LoL, talk about a no-brainer-error :P .
Anyway that worked, thx!
 
  


Reply


Thread Tools Search this Thread
Search this Thread:

Advanced Search

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
Apache + SSL + Upgrading OpenSSL shared lib TruckStuff Linux - Security 2 07-06-2005 05:41 PM
shared lib orlymeir Linux - Software 1 11-28-2004 05:50 AM
Linking whole archive into shared lib mj_ Programming 0 07-23-2004 06:00 AM
vncserver error loading shared lib. WeBoat Linux - Software 2 06-22-2004 08:19 AM
generic C/C++: memory leak in shared lib/DLL oldbee Programming 0 07-08-2002 02:08 PM

LinuxQuestions.org > Forums > Non-*NIX Forums > Programming

All times are GMT -5. The time now is 05:23 PM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration