Сбой связывания с неопределенными ссылками на функции wgl Windows API для OpenGL в Kotlin - PullRequest
0 голосов
/ 10 апреля 2020

Когда я пытался создать контекст OpenGL с помощью Windows API и Kotlin, произошла ошибка при выполнении задачи связывания. Я разместил вывод этой задачи на pastebin (срок действия истекает через месяц), и эти две строки вывода выделяются:

... undefined ссылка на __imp_wglCreateContext '

... неопределенная ссылка на '__imp_wglMakeCurrent'

Для каждой функции wgl , которую я использую, clang (фронтенд компилятора LLVM) печатает такие строки. Компиляция работает нормально, но когда дело доходит до компоновки, задача либо не выполняется (Kotlin 1.3.71), либо никогда не заканчивается ни с чем (Kotlin 1.4-M1).

Обратите внимание, что это не проблема времени выполнения и любая другая функция API Windows работает правильно, а также то, что 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 для работы. Но любая другая функция OpenGL из пакета platform.opengl32 работает, и поскольку Kotlin проверяет при компиляции, какие библиотеки используются и включает их автоматически, все должно работать нормально. Однако clang все равно это не понравилось, и он не смог найти реализации функций wgl.

Затем я искал в inte rnet какие-либо решения, и несколько человек получили такой же вывод, но их случаи не были полностью похожи на мои, и я не нашел никого, кто бы вообще пытался создать контекст OpenGL с Kotlin (я знаю, что это может быть не лучший выбор для использования языка высокого уровня для чего-то подобного, и что я мог бы использовать другую библиотеку для того, что я пытаюсь выполнить sh, но я хочу посмотреть, на что способен Kotlin).

Далее я проверил, имеет ли средство отслеживания проблем Kotlin что-то об этом уже (нет) и версия LLVM Kotlin использует и журналы изменений LLVM, если они что-то говорят об этом (нет, и я знаю, что это не имеет особого смысла, но вы никогда не знаете), поэтому я решил, что проблема должна быть на моей стороне.

Я нашел следующие возможные причины:

  • Я использую неправильную версию OpenGL (должна быть последней для моей графики s карта, я обновил свой графический драйвер)
  • Мне нужно сделать что-то дополнительно с зависимостями
  • Я использую устаревший API
  • Я слишком тупой
  • Мне не повезло, и это просто не работает на моем P C

Это все, что я еще не проверял, потому что я не мог, поэтому, конечно, я не не знаю, правда ли это. Я пытался заставить это работать в течение пары дней, так что теперь я обращаюсь за помощью или советом. Может быть, кто-то может попытаться скомпилировать это тоже. Следующий скрипт является необходимым скриптом сборки для 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

и поместите файл * .kt в папку kotlin с первым показанным кодом. Затем запустите задачу: runReleaseExecutableOpenGLErrorDemo и посмотрите, скомпилируется ли она и скомпонована ли она, затем попробуйте комментировать вызовы функции wgl и запустить ее снова. Это было построено с использованием последних версий IntelliJ и Gradle.

Конечно, если кто-то знает, в чем проблема, дайте мне знать или прокомментируйте, если вам нужна дополнительная информация. И, пожалуйста, также скажите мне, каков был результат компиляции вышеуказанного кода.

Заранее спасибо!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...