Friday, August 06, 2010

VTK Installation on Windows 64-bit for Visual Studio

VTK Installation on Windows 64-bit for Development in Visual Studio

VTK installation in Windows 32-bit is typically painless, as the platform was already tested by many developers and became mature.  (Yet, if you have a problem with it, the troubleshooting note at the end of this page might help.)  For Windows and VTK 64-bit, however, we may encounter a few issues.  This note describes what I did to install VTK 5.6 on my MS Windows 7 Home Premium 64-bit.  This note should be applicable to those who need to do the same thing.

The first part is for installation with default VTK build options.  These options are VTK_USE_CHARTS, VTK_USE_GEOVIS, VTK_USE_INFOVIS, VTK_USE_N_WAY_ARRAYS, VTK_USE_RENDERING, and VTK_USE_VIEWS.
  1. Download VTK 5.6 source from http://vtk.org/VTK/resources/software.html.
  2. Extract it to create a source folder.
  3. Open CMake (I used 2.8.1, and it is supposed to work with the most recent version at cmake.org).
  4. In CMake, choose a source and binary folders (Figure 1).


    Figure 1.  CMake 2.8.1 after source code and binary folder selected.

  5. Click the 'Configure' button.
  6. CMake asks about generator (compiler) we want to use (Figure 2).  The one we want to use is Visual Studio 9 2008 Win64 (the one without suffix Win64 is 32-bit) with 'Use default native compiler'.  We can also use Visual Studio 10 Win64 if a target development platform is Visual Studio 10.  Using MinGW will generate incompatible binary for Visual Studio development.  In addition, 64-bit MinGW is quite tricky to use as of Aug 2010.


    Figure 2. 'Choose compiler' dialog

  7. If initial configuration goes fine, there will be no critical errors and VTK build options will be available for us to choose (Figure 3).

    Figure 3.  Build options for VTK after the initial configuration.  Red regions in CMake highlight new options since the previous configuration.  As this is the first time, every option is new and highlighted.

  8. I used the default options.  This option builds a static libraries, which is what I prefer.
  9. I think options VTK_USE_PARALLEL may help speed up processing in a multi-core system, but I need to learn more about it.  Also, VTK_USE_QT is probably good for me, as I have used Qt a lot recently.  Yet, I need to know what it does first.
  10. Click the 'Configure' button again when options are settled.
  11. Click the 'Generate' button to generate a proper visual studio solution tree.
  12. Go to the output folder specified earlier, you should see 'VTK.sln'.
  13. Open the solution and 'Build Solution'.  It will take a while to finish (around 5-10 minutes).  Note that if you only want to use VTK and do not intend to debug into its source code, it is recommend to build it in the release mode.
  14. In the solution tree, right click on the 'INSTALL' project and 'Build'.  Update Dec 15, 2011: some systems may experience a build error due to write permission to C:\Program Files (x86).  This depends on your Windows settings.  One way to solve this issue is to close Visual Studio and run it 'as administrator' (credit to Alex Southern, see his comment below).
  15. The outputs are kept in C:\Program Files (x86)\VTK.  Both include and lib folders are what we are going to use in further software development.
  16. If you want to build both 32- and 64-bit packages, move the outputs to another folder and repeat the process.  Only the generater in step 6 is needed to change.  We have to move the current outputs because new outputs will be saved to the same folder.

Build VTK with parallel-processing and Qt-support options

Next, I will discuss installation of VTK with additional options for Visual Studio 2008.  These options are VTK_USE_QT and VTK_USE_PARALLEL.  We can jump to step 7 discussed in the last section. At this point, we only need to check the QT and PARALLEL options and then, hit the 'Configure' button the project again.  CMake will configure the project and comes up with two new options highlighted in red (Figure 4).  Once you set QT_QMAKE_EXECUTABLE to your target version, hit the 'Configure' button for the third time.  If every thing goes fine, you will get a refreshed dialog with message "Configuring done", as depicted in Figure 5.  There are chances that you did not succeed or get a wrong Qt version.  If the latter is your problem, read the caption of Figure 4.  If it fails for other reason, please see the troubleshooting note at the end of this document.  I hope it has what you need.

The rest of the process is generally the same.  If you encounter linking errors when you build VTK in Visual Studio, see Topic 2 in the troubleshooting note provided below.


Figure 4.  CMake after the second configuration with QT and PARALLEL.  QT_QMAKE_EXECUTABLE is selected by what you do with Qt integration for Visual Studio.  In other words, CMake checks the path of default Qt version you set in Visual Studio and use it here.  In fact, CMake and VTK build script strictly use the default Qt version.  You cannot effectively change Qt version here, as it will be eventually reset to the VS default version. Therefore, you may need to open VS and change Qt default version to set QT_QMAKE_EXECUTABLE.


Figure 5. A successful configure dialog.

Troubleshooting Note for Qt Option

1. Problem: "I specified qmake path correctly, but it seems that CMake looks for qmake in a wrong path."

Solution:
You may set QT_QMAKE_EXECUTABLE to point to qmake correctly, but this problem may arise since CMAKE will use outdated qmake properties, such as QT_INSTALL_PREFIX and QT_INSTALL_BINS.  For example, you build Qt in one path and later on you move it to another.  The properties, however, is fixed at the time you build Qt.  You can confirm this issue by going to qmake's make folder and using the command prompt to type 'qmake -query' to see all qmake properties.

If the issue is confirmed, you need to compile qmake again (not the whole Qt library set).  Alternatively, you can just move or copy your Qt directory to the old place to resolve the issue.  If moving or copying Qt folder is not an option, you can quickly re-compile qmake by
  • Rename the bin and qmake folders of Qt to something else.
  • Copy the pristine bin and qmake folders from the Qt source to the Qt folder.
  • Configure Qt from Visual Studio command prompt.  For example, by using 'configure -platform win32-msvc2008 -release -static -opensource -nomake demo -nomake examples -no-qt3support -fast'.  You probably did this before when you compiled Qt libraries.
  • Copy things from the old bin and qmake folders to your current bin and qmake folders, but make sure you do not replace the new qmake you just compiled.
  • Now, you have qmake with updated qmake properties.  I hope you can configure VTK in CMake as usual from this point.


2. Problem: "I got linking errors when I build VTK in Visual Studio.  It complained about PlaySoundW, WSAAsyncSelect, and many more."

Solution:
Based on my experience, this problem is platform specific.  You may encounter this issue if you use static library version of Qt and the problems in 32-bit and 64-bit platforms are not the same.  These linking problems, however, are related to Windows libraries and occurs when your VTK build script does not correctly include them.

Fortunately, you can include corresponding libraries yourself with ease by following the guidelines described below.
  • Identify problematic projects.  Potential problematic projects are QVTKWidgetPlugin, QVTK, QtChartCxxTests, ChartCxxTests, and QVTKCxxTests.
  • Search the Internet (or use your prior knowledge, or your MSDN documents) to identify corresponding libraries.  For example, the corresponding library of PlaySoundW is Winmm.lib and that of WSAAsyncSelect is Ws2_32.lib.
  • Add the libraries to the Visual Studio project properties, as you do normally.  Basically, you can right click the project in the Solution Explorer of Visual Studio and select 'Properties'.  Then, go to node 'Configuration Properties -> Linker -> Input' and insert the library name to 'Additional Dependencies'.


3. Problem: I checked 'VTK_WRAP_PYTHON' and CMake errors occurred.  It complaint about PYTHON_INCLUDE_DIR AND PYTHON_LIBRARY.

The error message looked like:
CMake Error: The following variables are used in this project, but they are set to NOTFOUND.

Please set them or make sure they are set and tested correctly in the CMake files:

PYTHON_INCLUDE_DIR

PYTHON_LIBRARY

Solution:
The two CMake variables seem to come and go and not consistent over VTK versions.  You might want to add them yourself to CMakeLists.txt.
First, locate IF(VTK_WRAP_PYTHON).  Then, modify the section to something like

IF(VTK_WRAP_PYTHON)
  SET(VTK_LANGUAGES ${VTK_LANGUAGES} PYTHON)
  #Addition by Pinyo
  SET(PYTHON_INCLUDE_DIR "C:/Python31/include")
  SET(PYTHON_LIBRARY "C:/Python31/libs/python31.lib")
ENDIF(VTK_WRAP_PYTHON)

Please note that PYTHON_LIBRARY is the actual library file, not just a folder (although you sometimes see the term python libraries and think that it is a lot of libraries, not a single file.).
Finally, configure and generate make files as usual.


4. Problem: I used VS 2010 64-bit and CMake 2.8.3 and got Q4VTKWidgetPlugin.h(57): error : Undefined interface.  This corresponds to line Q_INTERFACES(QDesignerCustomWidgetCollectionInterface).

Solution
:
This is, in fact, a CMake problem.  To be exact, the QT_QTDESIGNER_INCLUDE_DIR is not set correctly.  An example of the value is include/QtDesigner/.  This option is available if we want to generate MinGW Makefiles.  This option also was automatically set in the past and it was correct.  For an unknown reason, it does not work on some machines (VTK 5.6.1 as of Feb 18, 2011).

To solve the problem, go to folder GUISupport\Qt and open CMakeLists.txt.  Then, add a line
SET (QT_QTDESIGNER_INCLUDE_DIR "G:/Workspace/Qt/qt-release-4.7.1-vs2010/include/QtDesigner")
Make sure you adjust the ad hoc path to what suits your computer.

The above line should be added right after FIND_PATH(QT_QTDESIGNER_INCLUDE_DIR QDesignerComponents ...), as the function FIND_PATH may not work correctly in your build.

Hope this helps,
Pinyo Taeprasartsit
(Aug 2010, Feb 2011)


Saturday, June 12, 2010

GL_TEXTURE_2D

GL_TEXTURE_2D

In this part, we continue with a convenient and powerful method for 2D OpenGL, 2D texture.
The strength of using OpenGL 2D texture over glDrawPixels is that linear filtering can be selected.
Moreover, the task is systematic and not tedious.

I, however, do not know if using RGBA is better in terms of performance or not, but I used it in this example.
Thus, we have to modify a way to create a texture image.  The A element can be set to 255, as shown below.

texImage[nColorBytes*(h*m_nWidth + w) + 3] = (GLubyte) 255;

To initialize 2D texture with linear filtering, the following code can be used to make a texImage an OpenGL texture.

void GLTexture2D::initializeGL()
{
    // Basic initialization
    glClearColor(0.0, 0.0, 0.0, 0.0);
    glShadeModel(GL_FLAT);
    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);

    // Texture initialization
    glGenTextures(1, &textureName);
    glBindTexture(GL_TEXTURE_2D, textureName);

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);    // GL_NEAREST is another choice
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, m_nWidth, m_nHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, texImage);
}



To draw a 2D image as a texture, we have to map image coordinates to texture coordinates when we draw GL_QUADS.
In the following function, we map the texture created in initializeGL to rectangular coordinates -1.0 to 1.0.

void GLTexture2D::paintGL() {
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glEnable(GL_TEXTURE_2D);
    glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
    glBindTexture(GL_TEXTURE_2D, textureName);

    glBegin(GL_QUADS);
        glTexCoord2f(0.0, 0.0);    glVertex3f(-1.0, -1.0, 0.0);
        glTexCoord2f(0.0, 1.0);    glVertex3f(-1.0,  1.0, 0.0);
        glTexCoord2f(1.0, 1.0);    glVertex3f( 1.0,  1.0, 0.0);
        glTexCoord2f(1.0, 0.0);    glVertex3f( 1.0, -1.0, 0.0);
    glEnd();
    glDisable(GL_TEXTURE_2D);
}


===================================

An example project for Eclipse CDT / Qt on Linux is stored at a public folder here.
The project file is valid for Eclipse CDT on Linux with Qt integration (Ubuntu 9.04 Juanty), but the main part should be applicable to most C++ environment.


Pinyo Taeprasartsit
Octobor 2009

glDrawPixels + Qt (Part 3)

glDrawPixels + Qt (Part 3)

In this part, we will discuss the use of a pixel buffer in OpenGL.  A pixel buffer is an advanced feature, which is aimed at increasing screen draw rate.
For OpenGL 2.1, this pixel buffer is a part of a standard extension and not in OpenGL core. 

To use this extension, things become much more complicated, but can still be explained step by step, as follows.
  1. We need to include <GL/glew.h> before any other OpenGL context.  In Qt, we can normally include it in a header file before we include any QGLWidget.
    For your information, this extension is OpenGL Extension Wrangler Library (GLEW).

  2. Since GLEW is a library, we have to declare its use in a .pro file.  Open a .pro file and add a line

    LIBS    += -lGLEW


    Your project can now link to this library properly.

  3. Initialize GLEW before any other OpenGL work.  This should be done in the initializeGL method of QGLWidget.
    Initializing GLEW, however, may fail, especially if we try to initialize it for the second time.
    Thus, it is recommended to prepare for initialization error, as shown below.

    GLenum initStatus = glewInit();
    if (initStatus != GLEW_OK) {
        cout << "Cannot initialize glew." << endl;
        exit(1);
    } else
        cout << "glew is successfully initialized." << endl;


  4. Bind data to a buffer.  We need to provide a non-local GLuint to be employed as a buffer ID.  This may be a class-member or global variable.
    Assume that we declare the ID variable as a class member by

    GLuint pixelBuffer;

    Next, bind the buffer to it.  Note that chkImage contains pixel data and must be already filled.
    These patch of code is still in initializeGL.

    glGenBuffers(1, &pixelBuffer);
    glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pixelBuffer);
    glBufferData(GL_PIXEL_UNPACK_BUFFER, 3* m_nWidth * m_nHeight, chkImage,
            GL_STATIC_DRAW);

  5. Draw pixels in paintGL by

    GLubyte* nBuffOffset = 0;
    glDrawPixels(m_nWidth, m_nHeight, GL_RGB, GL_UNSIGNED_BYTE, nBuffOffset);


    Note that instead of providing a pointer to chkImage, we provide an offset in a buffer.  The zero offset means that we are going to use the first byte of the buffer and so on.

    To make this matter more understandable in terms of actual implementation, methods for initialization and painting are shown below.

    void GLImage2_2::initializeGL()
    {
        GLenum initStatus = glewInit();
        if (initStatus != GLEW_OK) {
            cout << "Cannot initialize glew." << endl;
            exit(1);
        } else
            cout << "glew is successfully initialized." << endl;

        // Set coordinate system
        glOrtho(0, m_nWidth, 0, m_nHeight, 0, 1);

        // Basic initialization
        glClearColor(0.0, 0.0, 0.0, 0.0);
        glShadeModel(GL_FLAT);
        glPixelStorei(GL_UNPACK_ALIGNMENT, 1);

        // Using buffer objects
        glGenBuffers(1, &pixelBuffer);
        glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pixelBuffer);
        glBufferData(GL_PIXEL_UNPACK_BUFFER, 3* m_nWidth * m_nHeight, chkImage,
                GL_STATIC_DRAW);
    }




    void GLImage2_2::paintGL() {
        glClear(GL_COLOR_BUFFER_BIT);
        glRasterPos2i(0, 0);

        GLubyte* nBuffOffset = 0;
        glDrawPixels(m_nWidth, m_nHeight, GL_RGB, GL_UNSIGNED_BYTE, nBuffOffset);
    }


So, what if we have several buffers?  In that case, we have to prepare more buffer-ID variables, bind them, and populate them. 
At the painting time, we specify our target buffer.  For concreateness, see the code below.

void GLImage2_2::paintGL() {
    glClear(GL_COLOR_BUFFER_BIT);
    glRasterPos2i(0, 0);

    if (target = 0)
        
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pixelBuffer1);
    else
        
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pixelBuffer2);

    GLubyte* nBuffOffset = 0;
    glDrawPixels(m_nWidth, m_nHeight, GL_RGB, GL_UNSIGNED_BYTE, nBuffOffset);
}

===================================

An example Eclipse CDT / Qt project is stored at a public folder here.
The project file is valid for Eclipse CDT on Linux with Qt integration (Ubuntu 9.04 Juanty), but the main part should be applicable to most C++ environment.


Pinyo Taeprasartsit
September 2009

glDrawPixels + Qt (Part 2)

glDrawPixels + Qt (Part 2)

In this part, we are going to use Qt to load an image from a file and display it with QGLWidget by using glDrawPixels.
The process is generally the same, except the order of function calls and the use of Qt to load an image file.

First, take a look at the constructor

GLImage2_1::GLImage2_1(QGLWidget *parent)
    : QGLWidget(parent)
{
    makeImage();
    m_nCurrWidth = m_nWidth;
    m_nCurrHeight = m_nHeight;
}


The function makeImage() is called early because we want to know image dimensions and give a correct size hint to a QGLWidget.
initializeGL is, therefore, leaner.

void GLImage2_1::initializeGL()
{
    // Set coordinate system
    glOrtho(0, m_nWidth, 0, m_nHeight, 0, 1);

    // Basic initialization
    glClearColor(0.0, 0.0, 0.0, 0.0);
    glShadeModel(GL_FLAT);
    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
}


Now, let's get to makeImage(), the most important part of this article.

void GLImage2_1::makeImage() {
    string fileName("/home/pinyo/temp/beach.jpg");

    QImage qImage;
    qImage.load(QString(fileName.c_str()));

    m_nWidth = qImage.width();
    m_nHeight = qImage.height();

    chkImage = new GLubyte[m_nHeight * m_nWidth * 3];

    for (int h = 0; h < m_nHeight; ++h) {
        int nImgH = m_nHeight - h - 1;

        for (int w = 0; w < m_nWidth; ++w) {
            QRgb color = qImage.pixel(w, nImgH);

            chkImage[3* (h *m_nWidth + w) + 0] = (GLubyte) qRed(color);
            chkImage[3*(h*m_nWidth + w) + 1] = (GLubyte) qGreen(color);
            chkImage[3*(h*m_nWidth + w) + 2] = (GLubyte) qBlue(color);
        }
    }

    return;
}

There are a few things we have to pay attention to.
  1. QImage is used and (declared in qimage.h)
  2. We have no need to explicitly supply the image file type to its load function.  Qt first relies on file extension (.jpg, .png, for example).  If it fails or there is no file extension, Qt will make a guess based on file header.
  3. Notice the use of int nImgH = m_nHeight - h - 1;  This is essential because the image coordinate system in OpenGL is different from most computer imaging systems, including Qt.  In Qt the origin is at top left and the y-axis points downward, while in OpenGL, the origin is at bottom left and the y-axis points upward.  Since the x-axes in Qt and OpenGL are the same, there is no need to convert x-coordinates.


========================================

An example Eclipse CDT / Qt project is stored at a public folder here.
The project file is valid for Eclipse CDT on Linux with Qt integration (Ubuntu 9.04 Juanty), but the main part should be applicable to most C++ environment.


Pinyo Taeprasartsit
September 2009

glDrawPixels + Qt (Part 1)

glDrawPixels + Qt (Part 1)

This is an article following GL_POINTS + Qt.  As mentioned earlier, we can use glDrawPixels with glPixelZoom to deal with 2D graphics.
Although it appears to be more complicated than GL_POINTS, glDrawPixels is still another simple method.

The strength of glDrawPixels is its ability to scale an image in a way most people expect.  For example, a pixel in the original scale may occupy more than one pixel in a window, if the window is scaled up.
We can also increase draw rate by using buffer, but Part 1 will not cover that topic.

Now, let's see how to draw an image by using glDrawPixels and glPixelZoom.  Recall that the coordinate system of OpenGL may be different from most imaging systems.  OpenGL set the origin at the bottom left by default.

The major difference between GL_POINTS and glDrawPixels is that GL_POINTS is based on a call list, while glDrawPixels is based on an array.
This array is a flatten 3D or 4D array.  Namely, RGB(A) data is kept together in a 1D array.  We have to tell OpenGL a color model we want to use.

Assume that we want to use the RGB color model and the image is of size 128x128 pixels.  Therefore, we have to create a 1D array of size 128x128x3.  RGB values of one pixels are packed at contiguous array cells, as shown below.

/// Build a checker board, each grid cell is of size 16 x 16 pixels.
///
0x10 is a base-16 number equal to 16.
void GLImage::makeImage() {
    chkImage = new GLubyte[m_nHeight * m_nWidth * 3];

    int c;
    for (int h = 0; h < m_nHeight; ++h)
        for (int w = 0; w < m_nWidth; ++w) {
            c = ( ((h&0x10) == 0)^((w&0x10) == 0) )*255;
            chkImage[3*(h*m_nWidth + w) + 0] = (GLubyte) c;
            chkImage[3*(h*m_nWidth + w) + 1] = (GLubyte) c;
            chkImage[3*(h*m_nWidth + w) + 2] = (GLubyte) c;
        }

    return;
}


The drawing process is super easy.

void GLImage::paintGL() {
    glClear(GL_COLOR_BUFFER_BIT);
    glRasterPos2i(0, 0);
    glDrawPixels(m_nWidth, m_nHeight, GL_RGB, GL_UNSIGNED_BYTE, chkImage);
}

The resize process needs to specify zoom factors for both x- and y-axes.  Note that we may not need to use m_nCurrWidth and m_nCurrHeight, if we do not intend to use them for other proposed.

void GLImage::resizeGL(int width, int height) {
    glViewport(0, 0, width, height);
    m_nCurrWidth = width;
    m_nCurrHeight = height;

    glPixelZoom(m_nCurrWidth / (double) m_nWidth, m_nCurrHeight / (double) m_nHeight);
}


The way for initialization may be a bit more complicated than usual, but it is a pattern we can just follow (somewhat blindly).

void GLImage::initializeGL()
{
    glClearColor(0.0, 0.0, 0.0, 0.0);

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(0, m_nWidth, 0, m_nHeight, 0, 1);
    glMatrixMode(GL_MODELVIEW);

    glShadeModel(GL_FLAT);
    makeImage();
    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
}


Notice the use of glShadeModel(GL_FLAT).  glPixelStorei is employed to specify the way we store color data.  The parameter 1 indicates that it is 1-btye alignment.  Basically, there is no restriction of the beginning position of each row with this parameter.  If it is 2, each row must start on even-numbered byte.


========================================

An example Eclipse CDT / Qt project is stored at a public folder here.
The project file is valid for Eclipse CDT on Linux with Qt integration (Ubuntu 9.04 Juanty), but the main part should be applicable to most C++ environment.


Pinyo Taeprasartsit
September 2009

Tuesday, May 25, 2010

Eclise + MinGW + FreeGlut (2)

Eclipse CDT + MinGW + FreeGlut (2)

This tutorial starts with building freeglut to create a simple working application with Eclipse and MinGW in both 32-bit and 64-bit versions.  This tutorial refers to a few other tutorials so that readers can jump to the part they want to know conveniently.  Follow the instructions below is relatively a simple task.

  1. The first task is to obtain Eclipse CDT.  This tutorial is based on Eclipse CDT Galieo (SR2 Build ID:2010 02 18-1602).  You can download it from this link, but the most recent version on the Eclipse server may be your preferred choice.

  2. Obtain your preferred MinGW version.  I prepared 32-bit MinGW 4.5.0 and 64-bit MinGW 4.6.0 (2010-April-16 Experimental) packages for you to download.  Note that the include paths within the packages are different.  This is the default settings of the two packages.  Eclipse, however, knows the 32-bit folder paths well, but does not aware of the include paths for the 64-bit version.  Probably, this is because the 64-bit version is still experimental.

  3. Download freeglut.  This tutorial uses freeglut 2.6.0.  If you want to use a pre-compiled binary package, try the following links.
    1. freeglut 32-bit, compiled with 32-bit MinGW 4.5.0 (O2 optimization).  libfreeglut32.a and freeglut32.dll are for dynamic linking, while libfreeglut32_static.a is for static linking.  Header files are included.  I built this package myself.  Feel free to contact me if you have any problem (use the comment in my blog)

    2. freeglut 64-bit, compiled with 64-bit MinGW 4.6.0 (2010-April-16 Experimental) (O2 optimization).  libfreeglut64.a and freeglut64.dll are for dynamic linking, while libfreeglut64_static.a is for static linking.  Header files are included.  I built this package myself.  Feel free to contact me if you have any problem (use the comment in my blog)

    3. From other source

  4. Build freeglut (If you get the binary package from Step 3, ignore this step).  Instructions are available in my post and in another web site.

  5. Putting things together.  If you use MinGW and freeglut 32-bit, this step is quite simple, as Eclipse knows MinGW 32-bit settings well, provided that you save MinGW at C:\MinGW. If you choose a 64-bit path, follow a common instruction for building and running 64-bit applications with Eclipse + MinGW 64-bit in my post.
    1. Put freeglut library in a proper place.
    2. Set compiler and linker flags.  This can be done by going to 'Project->Properties'.  Then, in C/C++ Build, go to 'Settings'.  The flags for static and dynamic links are different.  I assume that you are going to build a C++ application.
      1. For static link:
        In 'GCC C++ Compiler', go to 'Preprocessor' and add a defined symbol FREEGLUT_STATIC.  Also, make sure that your compiler see your freeglut and OpenGL headers.

        In 'MinGW C++ Linker', go to 'Libraries' and add the following libraries (-l): winmm, gid32, opengl32, and freeglut64_static.  Note that the name for freeglut64_static must be consistent with your actual library file name.  Also, it is important to omit the prefix 'lib' and suffix '.a'.  It is crucial, however, that the library file name must come with the prefix and suffix.  Next, add library search path (-L).  This is where you have placed your freeglut library.  For example, in my case, I add a path "C:\MinGW_x64\x86_64-w64-mingw32\lib\freeglut" (with double quotes).

      2. For dynamic link:
        There is no need to add any thing to the preprocessor section, but make sure that your compiler see your freeglut and OpenGL headers.

        Now, go to 'MinGW C++ Linker' and its library section.  Then, do exactly the same thing as discussed for the static link, except that you have to change freeglut64_static to the one for your dynamic link.

    3. Build application.  Try starting with a simple one.  A good example is given from other www.transmissionzero.co.uk.

    4. Run your application.  This seems to be trivial at first, but it can be a bit tricky because you also have to set your MinGW library path.  In addition, if you dynamically link to freeglut, you need to set up its library path.  Whether or not you are building an 64-bit application, please see Section 'Change Run-Time Setting' in my previous post.  It shows you how to set run-time library paths in Eclipse and Windows command to set a library path in case that you are going to run your application outside Eclipse.  If you feel not understand how to do it, you might want to check some figures in my even older post (Figures 6 and 7).

Pinyo Taeprasartsit
(May 2010)

This document can be viewed at my blog and my Google docs.  I welcome questions, comments, and suggestions.  Please leave a message in my blog if you have any.  Thank you.



Build FreeGlut with MinGW

Build FreeGlut with MinGW

(updated Jan 21, 2011: new FreeGlut 64-bit pre-compiled binary is now available. This solves a naming issue caused by an earlier version of MinGW. Thank you James for pointing out the issue.)

FreeGlut 2.6.0 comes with Visual Studio 2008 solution files. If you use Visual Studio, you can probably build the package easily. If you, however, want to use MinGW to build FreeGlut (either or both 32-bit and 64-bit versions), you may not know where to start. Thus, I wrote this document, so that you can build FreeGlut yourself. If you prefer, there are several binary packages ready to use in some web sites. Example of these web sites are http://www.transmissionzero.co.uk/software/freeglut-devel/ and this web site itself.

32-Bit FreeGlut

Use MSYS to build 32-bit freeglut shared library [ref: http://netsuperbrain.com/blog/posts/freeglut-windows-hopengl-hglut/]
  1. gcc -O2 -c -DFREEGLUT_EXPORTS *.c -I../include
  2. gcc -shared -o freeglut32.dll *.o -Wl,--enable-stdcall-fixup,--out-implib,libfreeglut32.a -lopengl32 -lglu32 -lgdi32 -lwinmm

Use MSYS to build 32-bit freeglut static library
  1. gcc -O2 -c -DFREEGLUT_STATIC *.c -I../include (same as above, except the flag is changed from FREEGLUT_EXPORTS to FREEGLUT_STATIC)
  2. ar rcs libfreeglut32_static.a *.o [ref: http://www.adp-gmbh.ch/cpp/gcc/create_lib.html]

If you want to use a pre-compiled binary package, instead of building it yourself, get a pre-compiled binary package here.

64-Bit FreeGlut

This tutorial show a way to build 64-bit FreeGlut by using the Windows command prompt (cmd.exe). Almost every thing is the same as using MSYS for the 32-bit version. In this case, I assume that the current directory is the freeglut source directory and MinGW x64 is at C:\MinGW_x64\bin\.

First of all, set PATH to MinGW in the command prompt:
set PATH=%PATH%;C:\mingw_x64\bin

For a shared library (note that actual prefix gcc-related file names may be different from distribution to distribution)
  1. x86_64-w64-mingw32-gcc -O2 -c -DFREEGLUT_EXPORTS *.c -I../include
  2. x86_64-w64-mingw32-gcc -shared -o freeglut64.dll *.o -Wl,--enable-stdcall-fixup,--out-implib,libfreeglut64.a -lopengl32 -lglu32 -lgdi32 -lwinmm

For a static library
  1. x86_64-w64-mingw32-gcc -O2 -c -DFREEGLUT_STATIC *.c -I../include (same as above, except the flag is changed from FREEGLUT_EXPORTS to FREEGLUT_STATIC)
  2. x86_64-w64-mingw32-ar rcs libfreeglut64_static.a *.o

If you want to use a pre-compiled binary package, instead of building it yourself, get a pre-compiled binary package here. This package was built with sezero's build MinGW GCC 4.4.5 20101001.

Pinyo Taeprasartsit
(May 2010, Jan 2011)

This document can be viewed at my blog and my Google docs. Please leave a message in my blog if you have any questions, comments, and suggestions. Thank you.

Eclipse MinGW x64

Eclipse CDT with MinGW w64

This tutorial discusses how you can use MinGW 64-bit and Eclipse to build an application.  This tutorial is based on 64-bit MinGW (probably version 4.5--the version is not clear from the download page) and Eclipse Galieo (SR2 Build ID:2010 02 18-1602) and Eclipse Helios (SR1 for Windows 64 bit, eclipse-cpp-helios-SR1-win32-x86_64). The following parts of this tutorial assume that you already installed Eclipse and MinGW 64-bit at your preferred paths and will only discuss how you can change Eclipse settings to build and run your applications.

Get Compiler

The first task is to obtain a proper MinGW w64 compiler.  Although our target platform is Windows 64-bit, the compiler may be a 32-bit application that performs cross-compilation for you.  You can choose your preferred version from here.  There are some significant different for personal and automated builds (as of Dec 2010).  For example, the sezero build I used (mingw-w64-bin_x86_64-mingw_20101003_sezero) is 64-bit binary producing 64-bit application, while a binary from the automated build (mingw-w64-1.0-bin_i686-mingw_20101129) is 32-bit binary generating 64-bit application.  Technically, the automated build performs cross-compilation, while the sezero build performs native compilation.  As sezero build has a conventional directory structures and file names (same as MinGW 32-bit), I recommend using the sezero build.  It will save you a lot of time and you will not encounter some naming troubles in later steps.

In summary, from the link provided above, it is best if you go to the 'Personal Builds' section and download the latest sezero build.  This is probably the best way to use Windows 64-bit to generate 64-bit applications.

Change Compiler Settings (Galieo SR2)

  1. Go to menu Project->Properties.

  2. Go to node C/C++ Build->Environment.

  3. Update the path variable according to your MinGW w64 installation.  For example, change it to C:\MinGW_w64\bin. 

  4. Switch to topic C/C++ Build->Settings.

  5. [update (Dec 27, 2010): some recent MinGW versions (native compilation) come with 'as', 'g++', and 'gcc' commands. This step may be unnecessary for your MinGW build. However, some versions (cross-compilation) still have this issue and this step is required.  If you use sezero build, this step is probably unnecessary.]

    There are four commands to update: GCC Assembler, GCC C++ Assembler, GCC C Compiler, and MinGW C++ Linker.  Correct commands depends on the platform of MinGW w64 you choose.  No worry.  It is quite obvious to know what commands to use, as the command names are in the format [platform prefix]-[default command].exe.  For example, we need to update the command 'as', 'g++', 'gcc', and 'g++' for GCC assembler, C++ compiler, C compiler and C++ linker, respectively.  The correct commands may be 'x86_64-w64-mingw32-as', 'x86_64-w64-mingw32-g++', 'x86_64-w64-mingw32-gcc', and 'x86_64-w64-mingw32-g++', respectively.

Change Compiler Settings (Helios SR1)

Eclipse Helios is virtually blank regarding compiler configurations, but it seems to be compatible with various GCC toolchains (Mac, Solaris, Cygwin, MinGW, and Linux).  Our first task is to choose a proper toolchain as follows.
  1. Go to menu Project->Properties.
  2. Go to node 'Tool Chain Editor.' (The spelling of toolchain in Eclipse is not consistent.  There are both 'tool chain' and 'toolchain.')
  3. Set the current toolchain to 'MinGW GCC.'
  4. Set the current builder to 'CDT Internal Builder.'  You are free to use 'GNU Make Builder' if you prefer.
  5. Go to node 'Settings.'
  6. Change the path of compiler/assembler commands.  For example, highlight 'GCC C++ Compiler' and change the command to 'C:\MinGW_64bit\bin\g++' if you save MinGW at C:\MinGW_64bit.
     
There is no path variable any more, but there is a new node called 'Discovery Options' inside 'C/C++ Build.'  If we check 'Automate discovery paths and symbols,' most path settings are not necessary during program compilation.

If you employ OpenMP, you might want to see more detail at this site.  Basically, you have to change the miscellaneous flag of GCC C++ Compiler and MinGW C++ Linker to include -fopenmp.  Remember, however, that we have to change run-time settings, as OpenMP requires additional run-time libraries.

Change Default Include Folders

(This step is required for Galieo, but not for Helios.  If you use Helios and choose 'Automate discovery paths and symbols' in 'C/C++ Build,' the defualt include folders should be correct right of the beginning.)

It is quite painful in this part, as Eclipse uses the C:/mingw by default.  If you have multiple versions of MinGW, you have to change them.  Fortunately, (almost) all include files are all the same among versions.  Therefore, if we add header files to the default MinGW installation path, things should work across versions.  These are, however, the include paths for the Eclipse editor.  This means that Eclipse source-code editor can parse and show some hints if we add header files to the default 32-bit MinGW path, even though we are going to use 64-bit MinGW to perform actual program compilation.  Therefore, for actual compilation, we need true addendum to an include folder that a compiler uses.  See an example below.

Example: add OpenGL header files to Eclipse for actual compilation.
If we want to add header files to a 'global' include folder, such as GL, the include folder that will make things work has a platform prefix, say 'x86_64-w64-mingw32\include'.  This is the case when we call gcc with the same prefix from a bin directory, such as 'x86_64-w64-mingw32-gcc.exe'.  Addition of header files in other directories has no effect in actual compilation.

Change Run-Time Settings

At this step, you can build your 64-bit application, but you probably see that you cannot run it, even within the Eclipse environment itself.  Your program might just be terminated without any reported error message.  To deal with the problem, you also need to change run-time settings as follows.
  1. Go to menu 'Run->Run Configurations...'
  2. Go to tab 'Environment'.
  3. Create a environment variable by using the 'New' button.
  4. In a new popup window, set 'Name' to PATH and 'Value' to $PATH;C:\MinGW_64bit\bin, provided that C:\MinGW_64bit is the installation folder for your 64-bit MinGW.  Note: if you have more paths to include, separate them with a semi-colon.

Alternatively, you can set Windows environment path variable to include the MinGW path.  Nonetheless, if you have both 32-bit and 64-bit MinGW in the paths, some DLL names may cause DLL conflict and you may get 32-bit library instead of 64-bit library when you call your program.  If your machine, however, has only 64-bit MinGW, using the Windows path variable is probably the most convenient way because you will have no need to create a path variable in Eclipse run-time settings for this purpose again.  Nevertheless, dealing with Eclipse run-time settings does not need admin previlage to execute and it is always a viable option.

Because setting the Eclipse environment variable does not change any path variable outside Eclipse, we cannot run the application by double clicking on it or calling at command prompt, unless path variable for the executable session is set.  To temporarily change Windows path variable, a command 'set path=%path$;C:\MinGW_64bit\bin' may be used [ref:http://vlaurie.com/computers2/Articles/environment.htm].  Again, separate library paths with a semi-colon if you have multiple library paths to add.  This effectively appends the MinGW path to the existing path variable, specifically for the command prompt session.  Therefore, it may be a bit awkward if we want to call an executable file from Windows Explorer, as a batch file may need to be created.

OpenMP Note: for sezero's MinGW build, you may need to unpack pthreads-w64.zip into the root of your MinGW folder (C:\MinGW_64bit) so that required OpenMP run-time libraries are available in a proper place.

Tips: some error messages from Windows may not show up in Eclipse when we run or debug our programs within Eclipse environment.  Try using a command prompt (cmd.exe) and you may see more informative error messages.

Optional: Using MSYS to check if the compiled application is 64-bit

There are at least two ways to check if an application is 64-bit or 32-bit.  The easiest way is to run it and see its process name in the Windows Task Manager.  If the process name has a suffix *32, it is 32-bit.  If there is no such suffix, it is 64-bit.  There is another way.  It is less convenient in my opinion, but you can probably use it to check your application programmatically without running it at all.  This is possible if you use MSYS as discussed below.

  1. Copy the executable file to a place where MSYS environment can reach.  This is probably your home folder in C:\msys.

  2. Enter 'file my_executable.exe'.  For MSYS 1.0.11 32 bits (I ran it on 64-bit Windows 7), a 64-bit executable will get a message 'my_executable.exe: PE executable for MS Windows'.  There is nothing about 32-bit or 64-bit tags showing up.  A 32-bit executable, however, will get a message 'my_executable.exe: PE executable for MS Windows (console) Intel 80386 32-bit'.  Namely, a 32-bit executable gets a clear description about its platform, while a 64-bit executable does not get any definite description.  This is analogous to what the Task Manager does.

    For more recent version of MSYS, the file command gives PE32 for a 32-bit executable and PE32+ for a 64-bit executable.


Pinyo Taeprasartsit
(May, Dec 2010)

This document can be viewed at my blog and my Google docs.  I welcome questions, comments, and suggestions.  Please leave a message in my blog if you have any.  Thank you.






Saturday, February 06, 2010

Redistributable Documents

Redistributable Documents

This web page hosts redistributable documents.  The aim of this web page is to make things more convenient for those who want to access the document off-line or to obtain some software bundles in a convenient way.  Documents that are not redistributable are noted and links to the official web sites are provided, instead.

OpenGL 2.1 Reference Pages (Man Pages)

(Feb 2010)
These man pages are a slightly modified version provided by the Khronos group.  Typically, we have to SVN to get these man pages.  The official package of the man pages, however, contain more information than what I need (most people may feel the same).  If you want only HTML man pages, you might want to download my package (2MB).  There is only one addition, index_frame.html, which is a frame version of the man page we see in this official web site.  I hope this helps those who do not want to deal with SVN and want the frame version.

MinGW 32-bit

(May 17, 2010)
Since MinGW installer is not finalized yet, it is awkward to get GCC 4.5.0 from the server.  Therefore, I gathered all files that are downloaded by mingwdl.sh discussed in MinGW web site and made a package that is ready to use.  Just download the package if you don't need anything newer than the April-16-2010 release (GCC 4.5.0).  With the package, there is no need to bother with wget or bash.


Pinyo Taeprasartsit

(This document can be viewed at my blog and my Google docs)





Thursday, February 04, 2010

Dealing with Build Errors in Visual C++ Project

Dealing with Build Errors in Visual C++ Project

Warning C4251 for vector type in DLL build

When we build a shared library, it is possible that container specialization type is not available outside the scope of the shared library, as the caller may not know such type.
This, however, generates only warning for an STL container.  We can deal with this warning by explicit declaration of the library interface.

For example: template class DLL_IMEXPORT_DEF std::vector<int>;

Unfortunately, there may be another warning if the type in the STL container is a class or a pointer to an object, not a primitive type.
For example: template class DLL_IMEXPORT_DEF std::vector<XmlNode>;
causes a warning about std::allocator<_Ty,_Alloc>.

This problem can be solved (sort of, see the note below) by adding a dll interface of the problematic allocator in front of the export of the intended STL container.
That is, we have to write (order of declaration is important).
template class XML_MANAGER_IMEXPORT std::allocator<XmlNode>;
template class XML_MANAGER_IMEXPORT std::vector<XmlNode>;
to be free of the warning.

A vector of CString has some special requirements for its DLL interface.  I need to have additional interface declaration, as shown below.
template class XML_MANAGER_IMEXPORT std::allocator<CString>;
template class XML_MANAGER_IMEXPORT std::_Container_base_aux_alloc_real< std::allocator<CString> >;
template class XML_MANAGER_IMEXPORT std::vector<CString>;


Note: exporting STL template specialized class may cause link error with multiply defined class.  Microsoft discusses about a way to deal with STL export in this link

More info is available at:
http://www.unknownroad.com/rtfm/VisualStudio/warningC4251.html

Polymorphism with Boost shared_ptr

Using a shared_ptr is a great way to avoid almost all kinds of memory leak.  Moreover, we have no need to find out the last owner of an object.  Therefore, complexity in programming logic is reduced.  Unfortunately, it is not straightforward to employ polymorphism with a shared_ptr, as we cannot just cast the pointer in a typical C++ fashion, e.g. dynamic_cast.  Thus, Boost library comes with a special way to cast its smart pointers.

boost::shared_ptr<T_A> testPtr(new T_A(blah));

boost::shared_ptr<T_B> anotherTestPtr = boost::dynamic_pointer_cast<
T_B>(testPtr));

That is 'boost::dynamic_pointer_cast' is a way to solve this issue.

More info can be found here and there.

====================

If you deal with the polymorphism in a vector.  For example, we want to have std::vector< boost::shared_ptr<T_Base> > to hold shared_ptr of T_Child1 and T_Child2.  In this example, we can do it as follows.

std::vector< boost::shared_ptr<T_Base> > vecPoly;
boost::shared_ptr<T_Base> childPtr1( new T_Child1() );
boost::shared_ptr<T_Base> childPtr2( new T_Child2() );

vecPoly.push_back( childPtr1 );
vecPoly.push_back( childPtr2 );

There is nothing to worry about calling virtual functions.  They will be called properly as usual.

Definition of a template class in a DLL cannot be found

If a template class is not employed within the DLL itself, its actual binary may not be created at a compile time or link time.
Also, if we inline everything in the template class and use the class inside the DLL, its actual binary may not be created and accessible by other DLLs or applications.
We can deal with the problem by specialization of the template class and avoiding inlining constructors and destructors of the class.  Performances may decrease, but it solves the problem.

Error with afximpl.h

When a project incude afximpl.h (typically in stdafx.h), compile errors may show up in Visual Studio 2008 (Visual C++ 9.0).  The error message looks like:
1>c:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\include\..\atlmfc\src\mfc\afximpl.h(635) : error C2059: syntax error : '<L_TYPE_raw>'
1>c:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\include\..\atlmfc\src\mfc\afximpl.h(635) : error C2238: unexpected token(s) preceding ';'

It seems that Microsoft did not purge this error yet, but there is a workaround that is effective.

"place the following line in your code before including afximpl.h:
DECLARE_HANDLE(HRAWINPUT); "

Reference: http://connect.microsoft.com/VisualStudio/feedback/details/276404/windows-2000-settings-incompatible-with-afximpl-h#details

error LNK2005: "void * __cdecl operator new(unsigned int)" (??2@YAPAXI@Z) already defined in ...

Cause:
"The CRT libraries use weak external linkage for the new, delete, and DllMain functions. The MFC libraries also contain new, delete, and DllMain functions. These functions require the MFC libraries to be linked before the CRT library is linked." [Reference]

This can be fixed by forcing the order of library linking.  This is shown in the above reference and directly quoted here:

"Visual C++ does not contain this header file. To create this file, follow these steps:
  1. Open Msdev\Mfc\Include\Afx.h.
  2. Select the lines between #ifndef _AFX_NOFORCE_LIBS and #endif //!_AFX_NOFORCE_LIBS.
  3. Copy the selection to the Windows Clipboard.
  4. Create a new text file.
  5. Paste the contents of the Clipboard into this new file.
  6. Save the file as Msdev\Mfc\Include\Forcelib.h."

Separate inline function declaration and definition

In Visucal C++, separating an inline function declaration and definition across header and source files is not possible, unless the inline function is virtual.  However, we can separate declaration and definition in the same header file.  The only difference is that we should add a keyword inline in front of the definition.  Example:

"When you declare an inline member function, it looks just like a normal member function:

 class Fred {
 public:
   void f(int i, char c);
 };

But when you define an inline member function, you prepend the member function's definition with the keyword inline, and you put the definition into a header file:

 inline
 void Fred::f(int i, char c)
 {
   ...
 }

It's usually imperative that the function's definition (the part between the {...}) be placed in a header file. If you put the inline function's definition into a .cpp file, and if it is called from some other .cpp file, you'll get an "unresolved external" error from the linker."  [This is quoted from another web site.]




------------------------------------
Pinyo Taeprasartsit

(This document can be viewed at my blog and Google docs)


Building and Debugging Tips in Visual C++

Building and Debugging Tips in Visual C++

(Jan 2010-Present)
This document compile my ongoing experience with Visual C++.  There are many more tips I know, but they are related to generic C++.  I'm thinking about creating a separate document for them or just put them here.

Can we debug a DLL project?  Why can we set a DLL project as a startup project, even though it is not executable per se?

Yes, we can debug a DLL project.  Plus, it does make sense to make it a startup project.  In fact, setting it as a startup project is a way to debug the DLL project, provided that we have any executable file to call the DLL.

Complete info is a available in this link.  Here, I quoted the essential information for Visual C++.

"

To specify the calling application in a C++ project

  1. In Solution Explorer, select the DLL project.

  2. On the View menu, choose Property Pages.

  3. In the Project Property Pages window, in the Configuration drop-down list, choose Debug.

  4. Open the Configuration Properties folder, and select the Debugging category.

  5. In the Debugger to launch list, choose Local Windows Debugger or Remote Windows Debugger.

  6. In the Command or Remote Command box, click the drop-down arrow, and select Browse from the list to locate the application. Alternatively, type the path and name of the application.

  7. Type any necessary program arguments in the Command Arguments box.

"

What if a break point cannot be hit because 'no symbol has been loaded for this document'.

In Visual C++, this seems to be a common problem.  First of all, we have to check if we have debugging symbols loaded or not.  Go to the 'Output' window (this is typically one of the tabs at the bottom of your VC++ window).   Then, look for a line telling about loading DLL.  For example,  there should be a line like this

'TesterConsole.exe': Loaded 'F:\Work\A.dll', [IMPORTANT MESSAGE HERE]

Next, check what your IMPORTANT MESSAGE HERE is.   If it is 'Binary was not built with debug information', we have to check a few points in our project properties.  Go to the project properties.  In the tab 'Configuration Properties -> C/C++ -> General', it is best that 'Debug Information Format' is a good one, which is 'Program Database (/Zi)' and 'Program Database for Edit & Continue (/ZI)'.  Then, go to a neigboring tab 'Optimization', it is highly recommended to set 'Optimization' to 'Disabled (/Od)'.

The final step is check your linker option.  Go to the tab 'Configuration Properties -> Linker -> Debugging'.  Next, set 'Generate Debug Info' to 'Yes (/DEBUG)'.
(Some additional information is in this link.)

If your IMPORTANT MESSAGE HERE is NOT about 'Binary was not built with debug information', chances are your debugging information is not synchronized with your DLL or your PDB (program data base) file is corrupt.  Try cleaning and rebuilding the affected DLL project.

Stand Between Debug and Release Modes

In some cases, it is too time consuming to debug a program in the Debug mode for a computationally intensive application, especially if we only want to see a crash site and call stack.  In such cases, we can choose to create another configuration.  Let's call the configuration 'Release w Assertion Enabled'.  This is actually a release mode without a preprocessor symbol NDEBUG.  Without NDEBUG, all assertion mechanisms are performed like in a debug mode, but the code is optimized.  If your program crashes, you can see the crash site and call stack, even though you cannot see accurate values of variables.  This is significantly useful when we need to get some idea about the problem. 

At this point, you might ask, 'Why do we need another configuration?' and 'Why don't we just remove NDEBUG during debugging process and insert it back when debugging is done?'  The answer is if we change any preprocessor symbol, the compiler must re-compile everything.  This is very time consuming if your project is large.  Moreover, in most cases, the debugging process never ends.  We have to go back and forth between release and debug builds all the time.  Creating a separate build, therefore, is a better way for a large and computationally intensive project in the long run.

Playing around with Visual C++, I found that Visual C++ might behave strangely if I modify a debug mode by just removing the preprocessor symbol _DEBUG and letting the executable call another library built in a release mode.  In the scenario, the run-time check might find that the heap or stack around a variable from the library is corrupted, but there is actually nothing wrong.

String Conversion

String conversion is usually necessary when we work with XML data, as XML uses Unicode character set by default.  Most parts of our work, however, may mainly use the ANSI character set.  This typically requires us to employ CA2W to convert an ANSI text to a Unicode text.  The usage of CA2W, however, may be quite unnatural to most of us.

For example, the use LPCWSTR szr = CA2W(szReplaceFile); is actually invalid because LPCTSTR becomes a pointer to a temporary string created during a conversion.  Therefore, it will be scrapped immediately after CA2W returns.  The correct use is CA2W szr(szReplaceFile);.  Look strange, right?  No doubt, a macro is usually strange.

Assertion Failed at the line ASSERT(AfxGetThread() == NULL)

This assertion is at the line 380 in appcore.cpp of Visual C++ 2008--version 9.0.  (Note that other versions may have this assertion at different lines.)  This issue arises if there are multiple MFC-application threads running at the same time (to be more specific, they are generated by CWinApp objects).  It is usually caused by calling MFC DLLs that comes with their own 'theApp', an object derived from CWinApp.  When these DLLs are initialized, they may start their own MFC-application threads, while we expect to have only one MFC-application thread--the one from our executable project. 

There is a discussion about this issue in this link.  Unfortunately, it does not tell us much about any practical approach for a solution. Thus, we have to figure this out ourselves.  If your application involves many DLLs, you probably have no idea what DLLs are culprits.  After trying for hours, I finally come up with a systematic method to identify the problematic DLLs and, of course, I have a solution for this problem.

To begin, set a break point at the assertion line ASSERT(AfxGetThread() == NULL).  Then, start the debugger.  At the break point, check 'Call Stack'.  (Those who are not familiar with debugging and the call stack might want to see this reference.)  If the call stack involves a DLL that is not mfcXXd.dll, such a DLL is likely to be a culprit, especially if it uses MFC in a shared library.  

Next, check the source code of the library and look for the file with 'theApp' in the suspect library.  Then, check its InitInstance() function.  If you find no AFX_MANAGE_STATE(AfxGetStaticModuleState( )); at the beginning of InitInstance(), insert it at the very beginning of the function.  Then, continue this process until every involved CWinApp DLL is properly equipped with AFX_MANAGE_STATE(AfxGetStaticModuleState( )).  

If the AFX_MANAGE_STATE causes linker errors, you might have an invalid preprocessor symbol.  The CWinApp DLL is usually configured with _USRDLL, not _LIB, because it is a dynamically linked library.  You may find that changing _LIB to _USRDLL helps solve your linker errors.

Halt at First-Chance Exceptions

First-chance exceptions in Visual C++ are a kind of access violation with code c0000005.  Many of them are not critical and we can possibly ignore them.  However, it is better, if we can get rid all of them, as your customers may demand that no compiler/linker warnings and no such exceptions are present when you ship your product.  

Visual C++, nonetheless, may not stop at the problematic point and just continue.  This makes it hard to tackle the problem.  So, we might want to force break for all exception.  The exception sheet can be accessed from menu Debug -> Exceptions (also by Ctrl-Alt-E, see Figure FCE1) in Visual Studio 2008.

If all exceptions are to be tackled, check all of the check boxes there so that all exception will be thrown (and we are forced to handle or get rid of them from the first place).  See Figure FCE2.  If only first chance exceptions, which are in fact a kind of access violtion, are to be handled, go to Win32 Exceptions and check Access Violation (Figure FCE3). 

Note that there is a button on the right that can reset exception settings to default and can even add a new one to the list (Figure FCE 4).  Adding a new one can possibly add our custom exceptions to the list, I belive (not try it myself yet).

Figure FCE1.  Exeption setting menu


Figure FCE2.  Set to throw all exceptions known by Visual C++.

Figure FCE3. Focus on first-chance exception.  However, it is recommended to (finally) handle all kinds of exceptions that come into your way.

Figure FCE4.  Remember that we can reset the settings or add a new exception to the list.

Acknowledgement: Peter Kellner

Program Exits with Code 0, but Unexpectedly

Typically, a program exiting with code 0 means there is nothing wrong.  However, sometimes a program exits in this way unexpectedly.  Also, nothing shows up at all.  I encountered this problem when I tried to build a program that uses a statically linked library.  That library, nonetheless, was created as a dynamically linked library before.  Therefore, there is a variable theApp inside its main file.

In general, this does not cause any problem and we can switch between dynamic-lib and static-lib configurations any time we want.  Nevertheless, there is one thing we need to be careful.  In a static-lib configuration, we are not supposed to let the program execution see theApp.  Why?  Because theApp will be initialized and start an instance of an MFC application thread.  Subsequently, theApp just exits with code 0.  This problem arises if we add something to the library main file and that file is in a part of compilation/execution.

To check if that is the actual cause of the problem, set a break point at the beginning of InitInstance() in a suspect library.  If the function is called, theApp is initialized in a wrong way.  Therefore, we need to find a way to prevent theApp to get involved.  This can be done by removing things that you add to the library main file.  If that means a lot of work, try using the macro to exclude theApp. 

For example:
#ifdef _NO_THEAPP
CLibApp theApp;
#endif

The above lines of code should effectively deal with the problem, provided that _NO_THEAPP is defined properly (as a preprocessor, for example).


Pinyo Taeprasartsit

(This document is viewable at pinyotae.blogspot.com and docs.google.com)

Thursday, January 14, 2010

The Way of DLL and Lib

(Jan 14, 2010)

Why do we need both .lib and .dll at the same time?

Today, I helped my friends figure some build and run-time problems in Visual Studio 2008.  I'm not familiar with these problems at all, but I can draw some important conclusions that I earlier did not realized.  It is about the usage of lib and DLL with and without source code of the library.  Earlier, I created several projects and made them static libraries.  Then, a few executable projects utilized them inside the same solution tree within Visual Studio 2008 development environment.  These executable projects can be run without the presence of DLL at all.

However, when I worked with freeglut.lib, a tool kit for OpenGL, I needed freeglut.dll during run-time, even though I planned to statically linked my project with freeglut.lib.  This is opposite to what I expected, but understandable.  If we do not have source code in the same solution tree, the compiler/linker does not have enough information about what should be incorporated into an executable file.  Therefore, only .lib stub/proxy is employed during linking and actual implementation is found during run-time.


Another question is "So, why can't we have only .dll and throw away all .lib files when we are going to use the .dll via dynamic linking?"

A few reasons are elaborated at 'stackoverflow' website.  The strongest reason may be '.lib manifest files allow us to work with different versions of DLLs in our system' and 'Native DLL's do not have strong names, so it may be possible to pick up the wrong version of the DLL'.  However, it seems possible to link with only DLL by using some other work (shown in the same page of stackoverflow).  The limitation of stand-alone DLL probably comes from an old design of compiler/linker/operating system (run-time platform), as it is pointed out that MS .Net can do this.


Tuesday, January 12, 2010

C++ Template in Shared Library/DLL

(Jan 12, 2010)



Using a C++ template in a shared library or DLL across the library boundary is not permitted, as all class and method definition must be available at the compile time if a template class or method is to be exported.  Therefore, the template class/method must be exclusively utilized within the shared library/DLL and should not declared AFX_EXT_CLASS or __declspec( dllexport ) for Visual C++.


For your information, Macro AFX_EXT_CLASS does not have the same meaning all the time.  In fact, it depends on preprocessor symbols.  From MSDN, it is stated that



"This macro is defined by MFC as __declspec(dllexport) when the preprocessor symbols _AFXDLL and _AFXEXT are defined. But the macro is defined as __declspec(dllimport) when _AFXDLL is defined and _AFXEXT is not defined. When defined, the preprocessor symbol _AFXDLL indicates that the shared version of MFC is being used by the target executable (either a DLL or an application). When both _AFXDLL and _AFXEXT are defined, this indicates that the target executable is an extension DLL."



This may be a good idea to have one header that can work as both dllexport and dllimport, depending on usage.  However, this may cause confusion to a new comer until he or she realizes how AFX_EXT_CLASS works.  Moreover, I still wonder what will happen if a DLL uses another DLL because header files from both DLLs have AFX_EXT_CLASS, but it has different meaning due to dual contexts. 

Microsoft discusses this in their own web site: http://support.microsoft.com/kb/128199.  In short, this is a limitation for the use of AFX_EXT_CLASS.  The issue in the above example can be solved by using a directive for each library.  For example, suppose there are two DLLs: abc.dll and def.dll.  Header files for abc.dll has a directive #define ABC_DLL_IMEXPORT __declspec(dllexport) or __declspec(dllimport), depending on usage context, while header files for def.dll has #define DEF_DLL_IMEXPORT __declspec(dllexport) or __declspec(dllimport). 

Monday, December 14, 2009

RIP DVD or create ISO image of DVD in Linux

(Dec 13, 2009)

I tried to rip a DVD in Linux.  Mostly, I followed the instructions available at instructables.com.  There are notes I want to jot down here.
  1. We need dvd::rip, as instructed in the website.  Do not, however, bother with the dvd::rip's website.  Just grab it directly from Ubuntu's Synaptic package manager.  This is the easiest way to do.

  2. We probably still need mplayer and rar.  Get them from Synaptic again.

  3. At this point, we are ready to rip a DVD, as shown at instructables.com.

  4. If you want to transcode the vob files from dvd::rip, try using vlc.


If you want to create an ISO image of your DVD, using k3b or GnomeBaker is a way to go.

Friday, November 13, 2009

Fix Ubuntu ATI driver problem caused by kernel upgrade

(Nov 13, 2009)

Updating kernel can cause some headache to Ubuntu users who use a proprietary video driver.  In my case, I used ATI's driver and upgraded kernel from 2.6.26 to 2.6.28.  Once kernel upgrade was complete, a display screen became garbage.  The best way to solve this issue is probably purging the old driver and reinstall it from scratch.

The procedure is well described here.  I followed the procedure in Section 'Need to fully remove -fglrx and reinstall -ati from scratch'.  Note that when we have the driver problem, we cannot access X server and need to boot the Ubuntu into a recover mode to maintain the system.

If the process is successful, we will be able to boot to the X server again.  However, the proprietary ATI driver may not be fully reinstalled as we expect.  There is no critical problem here.  Just download and reinstall it again from its script.


sudo /usr/share/ati/fglrx-uninstall.sh # (if it exists)
sudo apt-get remove --purge fglrx*
sudo apt-get remove --purge xserver-xorg-video-ati xserver-xorg-video-radeon
sudo apt-get install xserver-xorg-video-ati
sudo apt-get install --reinstall libgl1-mesa-glx libgl1-mesa-dri xserver-xorg-core
sudo dpkg-reconfigure xserver-xorg


Pinyo Taeprasartsit

Saturday, September 19, 2009

GL_POINTS + Qt

GL_POINTS + Qt

There are a few ways to do 2D OpenGL: GL_POINTS, glDrawPixels/glPixelZoom, and 2D texture.

The strength of GL_POINTS is its simplicity, while its weakness is inability to scale in a way most people intend.
Basically, each point occupied exactly one pixel of the screen.  If a window size increase, the point is still drawn as a single pixel.
Therefore, some pixels in a window become background color.

Consequently, GL_POINTS can be a strong candidate for 2D graphics if the window will not be resized.

The following function shows the a call list function, as an example.

/// This example draw a red horizontal line made of individual points at
///   the very middle of its window.
GLuint GLPoint::makeCallList() {
    glClear(GL_COLOR_BUFFER_BIT);

    GLuint list = glGenLists(1);
    glNewList(list, GL_COMPILE);

    glColor3f(1.0f, 0.25f, 0.25f);
    glBegin(GL_POINTS);
    {
        int nRow = m_nHeight / 2;
        for (int i = 0; i < m_nWidth; ++i)
            glVertex2s(i, nRow);
    }
    glEnd();

    glEndList();

    return list;
}


Since we are doing 2D graphics, it is recommended to disable depth test, as shown in the following initialized function.

void GLPoint::initializeGL()
{
    glClearColor(0.0, 0.0, 0.0, 0.0);
    glDisable(GL_DEPTH_TEST);    // we are going to do 2D OpenGL
    glClear(GL_COLOR_BUFFER_BIT);

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(0, m_nWidth, 0, m_nHeight, 0, 1);
    glMatrixMode(GL_MODELVIEW);

    callList = makeCallList();
}

An example Eclipse CDT / Qt project is stored at a public folder here.
The project file is valid for Eclipse CDT on Linux with Qt integration (Ubuntu 9.04 Juanty), but the main part should be applicable to most C++ environment.

Pinyo Taeprasartsit
August-September 2009