MinGW编译环境下链接GLFW时出现未定义引用错误

7
我正在尝试使用minGW在Windows上使用GLEW和GLFW开发OpenGL应用程序。在当前目录project/中,我有src/bin/glfw-3.0.4.bin.WIN64/这些目录。在src/目录下有test.cppglew.hglew.cwglew.h这些文件。
目录./glfw-3.0.4.bin.WIN64/include/包含GLFW/glfw3.h头文件。
目录./glfw-3.0.4.bin.WIN64/lib-mingw/包含glfw3.dllglfw3dll.alibglfw3.a这些文件。
我的主文件test.cpp包含以下内容:
#include "glew.h"
#include "GLFW/glfw3.h"

#include <stdio.h>

int main(int argc, char** argv) {
    printf("Hello, World!\n");

    glewInit();
    glfwInit();
}

我正在从project/目录编译程序,通过运行以下命令(为了易读性分成两行):

gcc -DGLEW_STATIC -DGLFW_DLL -o ./bin/test ./src/*.cpp ./src/glew.c 
-I ./glfw-3.0.4.bin.WIN64/include/ -L ./glfw-3.0.4.bin.WIN64/lib-mingw/ -lglfw3 -lopengl32

我遇到了以下错误:

undefined reference to `_imp_glfwInit'

我认为问题与我错误地链接GLFW库有关。据我所知,包含编译器选项-lglfw3将告诉gcc链接./glfw-3.0.4.bin.WIN64/lib-mingw/glfw3.dll,其中包含glfwInit()的定义。
我已经查看了其他类似问题的解决方案,并建议执行一些操作,例如将dll文件复制到源/二进制目录并更改-l选项的顺序,但对我来说都没有解决问题。

你的gcc命令被分成了两行。这是为了可读性吗?还是说这就是你实际的命令(如果是的话,那么它是错误的)?另外,据我回忆,"-Ipath"和"-Lpath"必须不带空格书写。 - keltar
是的,抱歉,我应该注明gcc命令是为了可读性而分开的。没有空格运行命令仍然会产生相同的错误。 - recreate
不能确定,但我猜测你的库出了问题。你确定它们是mingw兼容的并且应该是64位的吗?你能用32位版本运行它吗? - keltar
啊,我真的以为那会解决问题。我一直在使用mingw来编译32位系统。我切换到使用glfw-3.0.4.bin.WIN32,但我仍然遇到相同的编译时错误。 - recreate
你能否组装一个最小化的示例(包括所有必需的源代码和库文件),并将其上传到某个地方?没有看到实际情况,很难诊断这种问题。 - keltar
当然。https://drive.google.com/file/d/0BzaMTyFoNpy3RHlCalRpM054bVE/edit?usp=sharing 这与我上面的内容有些不同。 - recreate
1个回答

7
你的问题在于gcc遵循严格的库命名规范。它试图寻找glfw3.dll.a,但找不到(因为它被命名为glfw3dll.a - 简单地重命名即可解决问题)。
接下来它查找libglfw3.a,并成功找到 - 但它是一个静态库,而头文件中声明的引用是动态的(诡异的windows DECLSPECs...这个问题在linux上不存在)。因此,它无法找到_imp__glfwInit,因为在静态库中它只被称为glfwInit,所以你会得到一个错误。
删除libglfw3.a也是其中的一个选项 - 在这种情况下,gcc将继续查找并最终找到glfw3.dll并使用它。

互联网上有很多人建议删除 Mingw 32 位版本并安装 Mingw-w64,但这并没有解决问题。我将glfw3dll.a重命名为glfw3.dll.a,程序就可以无缝启动了!第二个建议是删除libglfw3.a和glfw3.dll.a,也解决了问题!你是大师。您能解释一下为什么以及当找不到.a文件时gcc如何进一步查找必要的dll吗?所以事实上,glfw的创建者之一错误地命名了预编译二进制文件中的.a文件? - JacobTheKnitter
1
@JacobTheKnitter 我认为没有其他步骤了,使用默认设置时,它首先尝试链接动态库(在Windows上是.dll.a),如果无法链接,则尝试静态库(.a)。直接链接.dll是gcc工具链的特定添加项;据我所知,MSVC工具链不能直接链接dll,而必须使用导入库(gcc在.dll.a中拥有此功能),因此我认为它只被视为最后的选择,因为在某些情况下可能会出现问题。我认为glfw也没有做错任何事情,他们只是遵循他们的MSVC命名方案。您可以使用-lglfw3dll进行链接。 - keltar
1
@JacobTheKnitter 在 Windows 上,declspec 很重要。如果你的 include 文件中指定函数是 dllimport 的,那么它们必须在 DLL 中,尝试链接静态库将会产生错误。因此,如果 你的 程序打算以 DLL 形式使用 glfw,则必须在包含 glfw3.h 之前定义 GLFW_DLL(请注意原始问题中的 -DGLFW_DLL 标志),并且 链接 DLL;但由于你必须在构建时知道这一点,所以最好为 DLL 版本设置单独的库名称,并只链接 -lglfw3dll 以确保不会选择静态版本。在 Linux/OSX 上,你都不会遇到这些问题。 - keltar

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接