MinGW linking error "undefined reference to ..." Qt Creator with custom library.

Hi Guys,
I have come across a very troubling problem because I can't seem to solve it and a very nice fella at stackoverflow.com was unable to help me with it. My problem is this: I have a library that I have built in Qt Creator but compiled with MSVC 2008, it yeilded a .lib file (i.e. MyLibrary.lib) I am linking into a testing application I have built in Qt 4.8.1 using Qt Creator by adding the following line to my .pro file:
LIBS += FontSystem.lib
and I am compiling that project with MinGW (g++) and it consistantly gives me this error:
main.cpp:-1: error: undefined reference to `NGUI::CFont::CFont()'

The thing it's looking for is the constructor of the class CFont inside the NGUI namespace. I have also tried compiling this with MSVC, but to no avail.

Here is main.cpp:
1
2
3
4
5
6
7
8
9
10
11
12
#include "fontsystem.h"

int main(int argc, char *argv[])
{
    cout<< "Starting the FontSystem..."<< endl;

    NGUI::CFont *cFont = new NGUI::CFont();
    cout<< "FontSystem Started!"<< endl;

    system("PAUSE");
    return 0;
}


and here is fontsystem.h:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#ifndef FONTSYSTEM_H
#define FONTSYSTEM_H

// Include the Basic C++ headers.
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <assert.h>
#include <limits>
using namespace std;

// Include the OpenGL and Image Headers.
#include <GL/gl.h>
#include <GL/glu.h>
#include "utilities.h"

// Macros.
#define DIM(x) (sizeof(x)/sizeof(*(x)))

namespace NGUI // This namespace is used to ensure no confusion happens. This font system paints 2D fonts for GUIs.
{
    class CFont
    {
    public:
        CFont();
        ~CFont();

        template<typename tChar> char* DrawString(tChar *apString, int aiSize, int aiX, int aiY);
        template<typename tNum> char* DrawString(tNum anNumber, int aiSize, int aiX, int aiY);

    private:
        char* SetupFont(); // This function will load as many images as possible into memory.

        GLuint miTextIDs[36];
        int miDrawIDs[1024];
    };
}

#endif // FONTSYSTEM_H 


and here is fontsystem.cpp:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
#include "fontsystem.h"

namespace NGUI
{
    CFont::CFont()
    {
        SetupFont();
    }

    CFont::~CFont() {}

    template<typename tChar>
    char* CFont::DrawString(tChar *apString, int aiSize, int aiX, int aiY)
    {
        // Search the string from most significant character to least significant.
        int iSelectIndex = 0;
        for(size_t i = 0; apString[i] != NULL; ++i)
        {
            iSelectIndex = apString[i] >= '0' && apString[i] <= '9' ? (apString[i] - '0') :
                           apString[i] >= 'A' && apString[i] <= 'Z' ? (apString[i] - 'A' + 10) :
                           apString[i] >= 'a' && apString[i] <= 'z' ? (apString[i] - 'a' + 10) :
                           apString[i] == ' ' ? 36 : // This is a special case, This see's if the current character is a space or not.
                           -1;

            if(iSelectIndex == -1)
            {
                return "The String Is Corrupt! Aborting!";
            }

            // Add the current selected character to the drawing array.
            miDrawIDs[i] = iSelectIndex;
        }

        // Go through and draw each and every character.
        for(size_t i = 0; i < DIM(miDrawIDs); ++i)
        {
            // Paint each qaud with the X,Y coordinates. After each quad has been successfully drawn,
            // Add the size to the X coordinate. NOTE: Each character is square!!!

            if(miDrawIDs[i] != 36)
            {
                glBindTexture(GL_TEXTURE_2D, miDrawIDs[i]);
            }

            // The font color is always white.
            glColor4f(1.0, 1.0, 1.0, 0.0); // The alpha argument in the function call is set to 0 to allow color only where image data is present.

            glBegin(GL_QUADS);
                glTexCoord2i(0, 0);
                glVertex2i(aiX, aiY);

                glTexCoord2i(1, 0);
                glVertex2i(aiX + aiSize, aiY);

                glTexCoord2i(1, 1);
                glVertex2i(aiX + aiSize, aiY + aiSize);

                glTexCoord2i(0, 1);
                glVertex2i(aiX, aiY + aiSize);
            glEnd();

            // Now, increase the X position by the size.
            aiX += aiSize;
        }

        return "Successful Drawing of String!";
    }

    template<typename tNum>
    char* CFont::DrawString(tNum anNumber, int aiSize, int aiX, int aiY)
    {
        // Convert the supplied number to a character string via snprintf().
        char *vTempString = new char[1024];
        snprintf(vTempString, 1024, "%f", anNumber);

        // Next, run DrawString().
        return DrawString<char>(vTempString, aiSize, aiX, aiY);
    }

    char* CFont::SetupFont()
    {
        // First Load The PNG file holding the font.
        FreeImage_Initialise(false);

        FIBITMAP *spBitmap = FreeImage_Load(FIF_PNG, "Font.png", BMP_DEFAULT);

        if(!spBitmap)
        {
            return "Was Unable To Open/Decode Bitmap!";
        }

        // Do an image sanity check.
        if(!FreeImage_HasPixels(spBitmap))
        {
            return "The Image doesn't contain any pixel data! Aborting!";
        }

        // The Image will have the red and blue channel reversed, so we need to correct them.
        SwapRedBlue32(spBitmap);

        // Retrieve all the image data from FreeImage.
        unsigned char *pData = FreeImage_GetBits(spBitmap);
        int iWidth = FreeImage_GetWidth(spBitmap);

        // Cutup the PNG.
        int iFontElementSize = (32*32)*4; // The first two numbers, are the dimensions fo the element, the last number (4) is the number of color channels (Red Green Blue and Alpha)
        bool bDone = false; // This bit is only set when the entire image has been loaded.
        unsigned char *pElemBuff = new unsigned char[iFontElementSize]; // The temporary element buffer.
        int iDataSeek = 4; // Start with an offset of 4 because the first byte of image data starts there.
        int iTexIdx = 0; // This is an offset specifing which texture to create/bind to.

        // Create all 36 OpenGL texures. 0-9 and A-Z and finally space (' ')
        glGenTextures(37, miTextIDs);

        while(!bDone)
        {
            // Now load the an element into the buffer.
            for(int i = 0, iXCount = 0, iYCount = 0;
                i < iFontElementSize; ++i, ++iXCount)
            {
                if(iXCount >= (32*4))
                {
                    iXCount = 0; // Reset the column offset.
                    ++iYCount; // Move down 1 row.
                    iDataSeek += ((iWidth * 4) - (32*4)); // Set the data seek to the next corrosponding piece of image data.
                }

                if(pData[iDataSeek] == NULL)
                {
                    break;
                }

                pElemBuff[i] = pData[iDataSeek];
            }

            // Check to see if we are done loading to prevent memory corruption and leakage.
            if(bDone || iTexIdx >= 37)
            {
                break;
            }

            // Create The OpenGL Texture with the current Element.
            glBindTexture(GL_TEXTURE_2D, miTextIDs[iTexIdx]);
            gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGBA, 32, 32, GL_RGBA, GL_UNSIGNED_BYTE, pElemBuff);

            // Create the correct texture envirnment to the current texture.
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
        }

        // Do a little house cleaning!
        delete[] pElemBuff;
        delete pData;
        FreeImage_Unload(spBitmap);
        FreeImage_DeInitialise();
    }
}
Last edited on
Maybe your thread will get more attention in the UNIX or General Forums, rather than this MS Windows Forum. Even better try a Qt forum:

www.qtforum.org/
hmm, I didn't even think that this would pertain to linux/UNIX when I wrote it (which as at 3 AM) but now that you mention it, it is a GCC compiler, so it would very much apply in the linux/UNIX would. I have also notice something: All the libraries that I can link to that are built in MSVC 20xx, are Dynamic Load Libraries (DLL). So, I'm going to try and build my library to be the same way and see if that fixes the error.
Templates definitions go in headers, the code is generated per request.

Edit: but the constructor is not templatized.
¿is there compatibility from libraries between compilers?
Last edited on
I just meant that this particular part of the site is for windows specific code, but yours is Qt.

If you want you could move your thread to the "General C++ Programming" forum on this this site.

Anyway ne555 will probably be able to help you - he really knows his stuff :D
Ok, I figured it out.
It turns out that the MinGW compiler likes MinGW compiled libraries and not MSVC compiled libraries. So I simply re-compiled my project in MinGW and linked to the .a file and it works now.
Topic archived. No new replies allowed.