首页 > 解决方案 > 链接失败,未定义对 Kotlin 中用于 OpenGL 的 Windows API 的 wgl 函数的引用

问题描述

当我尝试使用 Windows API 和 Kotlin 创建 OpenGL 上下文时,执行链接任务时发生错误。我在 pastebin 上发布了该任务的输出(一个月后到期),输出的这两行很突出:

...未定义对“__imp_wglCreateContext”的引用

...未定义的对“__imp_wglMakeCurrent”的引用

对于我使用的每个wgl 函数,clang(LLVM 编译器前端)都会打印出这样的行。编译工作正常,但在链接方面,任务要么失败(Kotlin 1.3.71),要么永远不会以任何事情结束(Kotlin 1.4-M1)。

请注意,这不是运行时问题,任何其他 Windows API 函数都可以正常工作,而且 Kotlin 还为 wgl 函数提供了绑定。

如果所有 wgl 函数都被删除,我制作的以下代码可以正常编译和链接,并且会按预期生成一个空白窗口(注释掉 wgl 函数):

import kotlinx.cinterop.*
import platform.windows.*

@OptIn(ExperimentalUnsignedTypes::class)
fun main() {
    memScoped {
        val className = "OpenGLLinkErrorDemo"

        // create an instance of the window class
        val wc = cValue<WNDCLASS> {
            lpfnWndProc = staticCFunction { hwnd, uMsg, wParam, lParam ->
                when (uMsg) {
                    WM_DESTROY.toUInt() -> {
                        PostQuitMessage(0)
                        0
                    }

                    WM_PAINT.toUInt() -> {
                        memScoped {
                            val ps = alloc<PAINTSTRUCT>()
                            val hdc = BeginPaint(hwnd, ps.ptr)
                            val brush = alloc<HBRUSH__> {
                                unused = COLOR_WINDOW + 1
                            }

                            FillRect(hdc, ps.rcPaint.ptr, brush.ptr)
                            EndPaint(hwnd, ps.ptr)
                        }
                        0
                    }

                    else -> DefWindowProc!!(hwnd, uMsg, wParam, lParam)
                }
            }
            hInstance = GetModuleHandle!!(null)
            lpszClassName = className.wcstr.ptr
        }

        // register the window class instance
        RegisterClass!!(wc.ptr)

        val hwnd = CreateWindowEx!!(
            0u, // optional window styles
            className.wcstr.ptr, // window class
            className.wcstr.ptr, // window text
            CS_OWNDC.toUInt(), // window style (this one in particular is needed for OpenGL)

            // size and position
            CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,

            null, // parent window
            null, // menu
            GetModuleHandle!!(null), // instance handle
            null // additional application data
        )
            ?: throw RuntimeException("Failed to create window")

        // create a pixelformat descriptor with opengl compatible settings
        val pfd = alloc<PIXELFORMATDESCRIPTOR> {
            nSize = sizeOf<PIXELFORMATDESCRIPTOR>().toUShort()
            nVersion = 1u
            dwFlags = (PFD_DRAW_TO_WINDOW or PFD_SUPPORT_OPENGL or PFD_DOUBLEBUFFER).toUInt()
            iPixelType = PFD_TYPE_RGBA.toUByte()
            cColorBits = 32u
            cRedBits = 0u; cRedShift = 0u; cGreenBits = 0u; cGreenShift = 0u; cBlueBits = 0u; cBlueShift = 0u; cAlphaBits = 0u; cAlphaShift = 0u
            cAccumBits = 0u
            cAccumRedBits = 0u; cAccumGreenBits = 0u; cAccumBlueBits = 0u; cAccumAlphaBits = 0u
            cDepthBits = 24u
            cStencilBits = 8u
            cAuxBuffers = 0u
            iLayerType = PFD_MAIN_PLANE.toUByte()
            bReserved = 0u
            dwLayerMask = 0u; dwVisibleMask = 0u; dwDamageMask = 0u
        }

        SetPixelFormat(GetDC(hwnd), ChoosePixelFormat(GetDC(hwnd), pfd.ptr), pfd.ptr)

        // the source of evil. using the function to create an opengl context, but the linker doesn't know the wgl functions
        val openGLContext = wglCreateContext(GetDC(hwnd)) ?: throw RuntimeException("Failed to create OpenGL context")
        wglMakeCurrent(GetDC(hwnd), openGLContext)

        ShowWindow(hwnd, 1)

        // run the message loop
        val msg = alloc<MSG>()
        while (GetMessage!!(msg.ptr, null, 0u, 0u) == 1) {
            TranslateMessage(msg.ptr)
            DispatchMessage!!(msg.ptr)
        }
    }
}

所以我检查了文档,当然这需要 OpenGL 库才能工作。但是platform.opengl32包中的任何其他 OpenGL 函数都可以工作,并且因为 Kotlin 在编译时会检查使用了哪些库并自动包含它们,所以一切都应该正常工作。但是,clang 仍然不喜欢它,并且找不到 wgl 函数的实现。

然后我在互联网上搜索了任何解决方案,有几个人有相同的输出,但他们的情况与我的情况并不完全一样,我根本没有找到任何人尝试使用 Kotlin 创建 OpenGL 上下文(我知道可能不会是使用高级语言来完成这样的事情的最佳选择,我可以使用另一个库来完成我想要完成的事情,但我想看看 Kotlin 能做多少)。

接下来,我检查了 Kotlin 问题跟踪器是否已经有相关信息(不),以及 Kotlin 使用的 LLVM 版本和 LLVM 变更日志,如果他们对此有任何说明(不,我知道这没有多大意义,但你永远不知道),所以我认为问题一定在我这边。

我想出了以下可能的原因:

这些都是我还没有检查的东西,因为我不能,所以我当然不知道它们是否属实。几天来我一直试图让它工作,所以现在我寻求帮助或建议。也许有人也可以尝试编译它。以下脚本是 gradle 的必要构建脚本:

@file:Suppress("UNUSED_VARIABLE")

plugins {
    kotlin("multiplatform") version "1.3.71"
}

repositories {
    mavenCentral()
}

kotlin {
    mingwX64("openGLErrorDemo") {
        binaries {
            executable {
                entryPoint = "main"
            }
        }

        val main by compilations.getting {
            kotlinOptions {
                freeCompilerArgs = listOf("-Xopt-in=kotlin.RequiresOptIn")
            }
        }
    }

    sourceSets {
        val commonMain by getting {
            dependencies {
                implementation(kotlin("stdlib-common"))
            }
        }
    }
}

将该脚本放入名为 build.gradle.kts 的文件中,然后在其旁边创建以下文件夹结构:

src
    \- openGLErrorDemoMain
        \- kotlin

并在 kotlin 文件夹中放置一个 *.kt 文件,并显示第一个代码。然后运行 ​​:runReleaseExecutableOpenGLErrorDemo 任务并查看它是否编译和链接,然后尝试注释 wgl 函数调用并再次运行它。这是使用最新版本的 IntelliJ 和 Gradle 构建的。

当然,如果有人知道问题出在哪里,请告诉我,或者如果您需要更多信息,请发表评论。还请告诉我编译上述代码的结果是什么。

提前致谢!

标签: windowskotlinopengllinker-errorskotlin-native

解决方案


推荐阅读