biatheawesome
biatheawesome

Reputation: 41

Undefined reference to `__imp___glutInitWithExit' and others, but library is linked

I set up CLion, MinGW and added the appropriate freeglut files into MinGW.

Now, I'm trying to run this code:

/*
 * GL01Hello.cpp: Test OpenGL C/C++ Setup
 */
#include <windows.h>  // For MS Windows
#include <GL/glut.h>  // GLUT, includes glu.h and gl.h

/* Handler for window-repaint event. Call back when the window first appears and
   whenever the window needs to be re-painted. */
void display() {
    glClearColor(0.0f, 0.0f, 0.0f, 1.0f); // Set background color to black and opaque
    glClear(GL_COLOR_BUFFER_BIT);         // Clear the color buffer

    // Draw a Red 1x1 Square centered at origin
    glBegin(GL_QUADS);              // Each set of 4 vertices form a quad
    glColor3f(1.0f, 0.0f, 0.0f); // Red
    glVertex2f(-0.5f, -0.5f);    // x, y
    glVertex2f( 0.5f, -0.5f);
    glVertex2f( 0.5f,  0.5f);
    glVertex2f(-0.5f,  0.5f);
    glEnd();

    glFlush();  // Render now
}

/* Main function: GLUT runs as a console application starting at main()  */
int main(int argc, char** argv) {
    glutInit(&argc, argv);                 // Initialize GLUT
    glutCreateWindow("OpenGL Setup Test"); // Create a window with the given title
    glutInitWindowSize(320, 320);   // Set the window's initial width & height
    glutInitWindowPosition(50, 50); // Position the window's initial top-left corner
    glutDisplayFunc(display); // Register display callback handler for window re-paint
    glutMainLoop();           // Enter the infinitely event-processing loop
    return 0;
}

...and this is the console message I get:

====================[ Build | test | Default ]==================================
"D:\CLion 2021.1.2\bin\cmake\win\bin\cmake.exe" --build D:\test\cmake-build-default --target test -- -j 9
[ 25%] Built target libfreeglut_static.a
[ 50%] Built target libfreeglut.a
Scanning dependencies of target test
[ 75%] Building CXX object CMakeFiles/test.dir/main.cpp.obj
[100%] Linking CXX executable test.exe
CMakeFiles\test.dir/objects.a(main.cpp.obj):main.cpp:(.text+0x25): undefined reference to `__imp___glutInitWithExit'
CMakeFiles\test.dir/objects.a(main.cpp.obj):main.cpp:(.text+0x4c): undefined reference to `__imp___glutCreateWindowWithExit'
CMakeFiles\test.dir/objects.a(main.cpp.obj):main.cpp:(.text+0x72): undefined reference to `__imp___glutCreateMenuWithExit'
CMakeFiles\test.dir/objects.a(main.cpp.obj):main.cpp:(.text+0x192): undefined reference to `__imp_glutInitWindowSize'
CMakeFiles\test.dir/objects.a(main.cpp.obj):main.cpp:(.text+0x1a5): undefined reference to `__imp_glutInitWindowPosition'
CMakeFiles\test.dir/objects.a(main.cpp.obj):main.cpp:(.text+0x1b5): undefined reference to `__imp_glutDisplayFunc'
CMakeFiles\test.dir/objects.a(main.cpp.obj):main.cpp:(.text+0x1be): undefined reference to `__imp_glutMainLoop'
collect2.exe: error: ld returned 1 exit status
mingw32-make.exe[3]: *** [CMakeFiles\test.dir\build.make:106: test.exe] Error 1
mingw32-make.exe[2]: *** [CMakeFiles\Makefile2:99: CMakeFiles/test.dir/all] Error 2
mingw32-make.exe[1]: *** [CMakeFiles\Makefile2:106: CMakeFiles/test.dir/rule] Error 2
mingw32-make.exe: *** [Makefile:136: test] Error 2

And my CMakeLists.txt looks like this:

cmake_minimum_required(VERSION 3.19)
project(test)

find_package(OpenGL REQUIRED)
find_package(GLUT REQUIRED)

set(CMAKE_CXX_STANDARD 14)

set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14 -pthread -fpermissive")



add_executable(test main.cpp)

link_directories(${OPENGL_gl_LIBRARY})

add_library(libfreeglut.a SHARED ${CMAKE_SOURCE_DIR}/lib/)
set_target_properties(libfreeglut.a PROPERTIES LINKER_LANGUAGE CXX)
add_library(libfreeglut_static.a STATIC ${CMAKE_SOURCE_DIR}/lib/)
set_target_properties(libfreeglut_static.a PROPERTIES LINKER_LANGUAGE CXX)

target_link_libraries(test libfreeglut.a libfreeglut_static.a ${OPENGL_gl_LIBRARY})

I'm sure the issue is with linking the libraries, but I don't understand why some of the freeglut functions work regardless, which makes me think that I must have done something right somewhere.

The two functions that are highlighted work just fine, and they are defined in one of the freeglut libraries:

screenshot of code

Update:

As per ben10's suggestion, I enabled CMAKE_EXPORT_COMPILE_COMMANDS before modifying anything in my CMake file, and this was generated:

[
{
  "directory": "D:/test/cmake-build-default",
  "command": "D:\\minGW\\mingw64\\bin\\x86_64-w64-mingw32-g++.exe    -std=c++14 -pthread -fpermissive -std=gnu++14 -o CMakeFiles\\test.dir\\main.cpp.obj -c D:\\test\\main.cpp",
  "file": "D:/test/main.cpp"
}
]

After that, I modified CMakeLists.txt according to what ben10 recommended, and now it won't compile. The error message is below:

"D:\CLion 2021.1.2\bin\cmake\win\bin\cmake.exe" -DCMAKE_MAKE_PROGRAM=D:/minGW/mingw64/bin/mingw32-make.exe -DCMAKE_C_COMPILER=D:/minGW/mingw64/bin/x86_64-w64-mingw32-gcc.exe -DCMAKE_CXX_COMPILER=D:/minGW/mingw64/bin/x86_64-w64-mingw32-g++.exe -G "CodeBlocks - MinGW Makefiles" D:\test
-- Configuring done
CMake Error at CMakeLists.txt:22 (add_library):
  No SOURCES given to target: libfreeglut


CMake Error at CMakeLists.txt:23 (add_library):
  No SOURCES given to target: libfreeglut_static


CMake Generate step failed.  Build files cannot be regenerated correctly.

[Failed to reload]

Since it says that libfreeglut has no source (although it was pointed towards CMAKE_SOURCE_DIR/lib/), could that mean I messed up adding glut to MinGW? I reinstalled both MinGW and glut and I'm still getting the same result.

Upvotes: 4

Views: 4232

Answers (1)

ben10
ben10

Reputation: 241

I really want to spread some modern CMake practice, and who knows it may lead you to solving the issue you have.

My feeling is you're not linking with GLUT::GLUT, but I can't verify that.

I'd rewrite some of the CMakeLists.txt as follows:

cmake_minimum_required(VERSION 3.19)
project(test)

# from the docs, this gives you `OpenGL::GL`
find_package(OpenGL REQUIRED)
# from the docs, this gives you `GLUT::GLUT`
find_package(GLUT REQUIRED)
# and this `Threads::Threads` which adds the pthread flag, only when needed
find_package(Threads REQUIRED)

# why do you need permisive? seems odd, you should try to fix that instead of just using fpermissive
# set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fpermissive")

# the first argument is just the name of a target, not the name of the library, prefix and suffix get added, if needed
# I have no idea what you have in these folders, but I d consider using an OBJECT library, to not compile the code twice
add_library(libfreeglut_obj OBJECT ${CMAKE_SOURCE_DIR}/lib/)
target_link_libraries(libfreeglut_obj PUBLIC OpenGL::GL GLUT::GLUT Threads::Threads)
set_target_properties(libfreeglut_obj PROPERTIES LINKER_LANGUAGE CXX)

add_library(libfreeglut SHARED $<TARGET_OBJECTS:libfreeglut_obj>)
add_library(libfreeglut_static STATIC $<TARGET_OBJECTS:libfreeglut_obj>)

# with the version of cmake you have, you might actually be able to do just `target_link_libraries` with the object lib, or
target_link_libraries(libfreeglut PUBLIC libfreeglut_object)
target_link_libraries(libfreeglut_static PUBLIC libfreeglut_object)

# seems like it s the same code in both the shared and static lib, pick one, I picked the shared one for you

add_executable(test main.cpp)
target_link_libraries(test libfreeglut)

Now, with this (or before this) I'd activate CMAKE_EXPORT_COMPILE_COMMANDSlink and CMAKE_VERBOSE_MAKEFILElink and run the build again, just to see exactly what gets compiled/linked.

EDIT: awesome article on CMake shared/static builds link. thanks @AlexReinking!

Upvotes: 2

Related Questions