我已经为此工作了一段时间,终于设法在 Windows 上静态链接 SDL2。您可以选择使用 Cmake 或 Visual Studio 的 IDE。我更喜欢 Cmake,但使用 Visual Studio 会稍微简单一些。
先决条件
- CMake(必需)
- Visual Studio 2019(不需要,但更简单)
第 1 步:构建 SDL2
从here 下载 SDL2 源代码。如果您不想将其保存在您的下载文件夹中,我建议您将其解压缩到您的文档文件夹或除下载之外的其他文件夹中。解压缩文件后,在文件夹中打开 cmd 提示符。确保您进入解压缩文件夹内的文件夹。 (您应该看到一个文件夹和文件列表。如果您只看到一个文件夹,请进入该文件夹)您的目录应该类似于~\Documents\SDL2-2.0.14\SDL2-2.0.14。到达这里后,在此目录中打开一个 cmd 提示符。执行命令mkdir build && cd build。接下来,执行命令cmake ..。假设您有默认的 Windows 10 生成器 Visual Studio 16 2019,解决方案将在您的构建文件夹中创建。如果您使用的是不同的生成器,请像使用该生成器一样构建 SDL2。您现在可以关闭命令提示符。在您的构建文件夹中导航,然后打开 ALL_BUILD.vcxproj 文件。这将打开 Visual Studio。确保将您的配置更改为Release。现在您已经打开了它,进入 SDL2 解决方案的属性(右键单击 SDL2,然后单击对话框底部的属性)。现在您已经打开了属性面板,请确保您在General 下Configuration Properties。这应该是您自动打开的位置。将Configuration Type 属性从Dynamic Library (.dll) 更改为Static Library (.lib)。之后,转到Librarian,然后转到General。将Output File 的结尾从$(TargetExt) 更改为.lib。现在我们已经告诉 Visual Studio 创建一个静态库。单击应用,然后按确定。在构建之前,我们需要在源代码中添加一个定义,让 SDL2 我们要使用 C 库函数。如果你不这样做,那么什么都无法编译。您需要找到并打开 SDL_config.h。重要提示:确保您正在编辑正确的 SDL_config.h!那里有两个!确保您正在编辑构建文件夹中的那个。如果你打开的 SDL_config.h 只有 56 行,那你就错了。找到正确的 SDL_config.h 后,将行 #define HAVE_LIBC 1 somwehere 添加到行 #if HAVE_LIBC 上方。确保保存文件。现在右键单击 SDL2 解决方案,然后单击构建。完成后,右键单击 SDL2main,然后单击构建。这将在~\SDL2-2.0.14\SDL2-2.0.14\build\Release 中生成文件SDL2.lib 和SDL2main.lib。现在您已经有了静态库,您可以将它们包含在您的项目中。
第 2 步选项 1:使用 Visual Studio IDE 链接静态库
这种方法要简单得多,对于不熟悉 cmake 的人来说,我会推荐这种方法。请注意,您可以按照相同的说明使用任何 c/c++ IDE,但会有所不同。打开要静态链接的 Visual Studio 解决方案。现在像我们之前所做的那样转到解决方案属性。转到链接器->常规->附加库目录。通过按顺序添加以下库来编辑此列表:SDL2main.lib SDL2.lib winmm.lib version.lib Imm32.lib Setupapi.lib libcmt.lib libucrtd.lib 注意:如果您不使用 Visual Studio 提供的编辑输入法(单击 Linker->Input->Additional Dependencies 最右侧的向下箭头),那么你需要直接输入这些库,中间有分号。您可能需要也可能不需要库 libucrtd.lib 或 libcmt.lib,这取决于您的版本。确保包含 SDL2 头文件。完成后,点击应用,然后确定。重要提示:确保您的main 函数具有签名int main(int, char**),否则您的程序将无法编译。
第 2 步选项 2:使用 Cmake 链接静态库
现在我们将使用 Cmake 静态链接 SDL2。我将使用 msvc,因为 msvc 比 MinGW 更容易访问运行时二进制文件。对于 msvc,我们将通过 Visual Studio 使用 Cmake。没有必要使用 Visual Studio。您真正需要的只是记事本和编译器。如果您要使用 MinGW 而不是 msvc,那么您需要在 Windows SDK 中找到运行时二进制文件并告诉 MinGW 在哪里可以找到它们。
首先,在 Visual Studio 中新建一个 Cmake 项目。如果您看到介绍性屏幕,请随时按下按钮以创建 CMakeSettings.json 文件。所有这些都是帮助为 cmake 配置不同的构建类型。这不是必需的,但它可能很有用。如果您想要一个 CMakeSettings.json 文件,但没有选择制作一个,那么您可以右键单击解决方案资源管理器中的空白区域,然后选择 Cmake Settings for <ProjectName>。进入您的源目录,然后打开CmakeLists.txt 文件。确保它在父目录中——有两个CmakeLists.txt 文件,但现在我们关心的是父目录。将以下代码复制并粘贴到该 CMakeLists.txt 中:
cmake_minimum_required(VERSION 3.8)
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /MDd")
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MD")
project("tut")
add_subdirectory("src")
在行中
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /MDd")
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MD")
我们告诉 CMake 使用静态运行时库。 如果你想让你的程序更小,那么你可以使用“/MD”。请注意,它需要运行时 dll 才能运行,这意味着所有这些。 编辑:您需要使用 /MD 和 /MDd。 SDL2 需要它。你仍然可以静态链接。
add_subdirectory("src")
这告诉 CMake 在子目录“src”中可以找到更多信息。如果您将 src 文件夹命名为其他任何名称,请确保将“src”替换为您的文件夹名称。现在进入子目录“src”(或者你叫什么)并打开那个 CMakeLists.txt。将以下代码复制并粘贴到该 CMakeLists.txt 中:
cmake_minimum_required (VERSION 3.8)
add_executable(tut2 WIN32 "tut2.cpp")
target_include_directories(tut2 PRIVATE "${CMAKE_SOURCE_DIR}/include")
target_compile_definitions(tut2 PRIVATE "$<$<CONFIG:Debug>:" "_DEBUG" ">" "$<$<CONFIG:Release>:" "NDEBUG" ">" "WIN32;" "_CONSOLE;" "UNICODE;" "_UNICODE")
target_compile_options(tut2 PRIVATE /Oi; /Gy; /permissive-; /sdl; /W3; $<$<CONFIG:Debug>:/Z7>; ${DEFAULT_CXX_DEBUG_INFORMATION_FORMAT}; ${DEFAULT_CXX_EXCEPTION_HANDLING})
target_link_options(tut2 PRIVATE $<$<CONFIG:Debug>: /INCREMENTAL> $<$<CONFIG:Release>: /DEBUG; /OPT:REF; /OPT:ICF; /INCREMENTAL:NO> /NODEFAULTLIB:LIBCMT)
target_link_libraries(tut2 PRIVATE SDL2main SDL2 winmm version Imm32 Setupapi)
target_link_directories(tut2 PRIVATE "${CMAKE_SOURCE_DIR}/lib")
在行中
target_include_directories(tut2 PRIVATE "${CMAKE_SOURCE_DIR}/include")
我们告诉 CMake 在哪里寻找我们的包含文件。在此示例中,包含目录位于我们项目的源目录中。 (与我们原来的 CMakeLists.txt 所在的位置相同)。如果您觉得需要在目录中进行硬编码,则只需输入文件的绝对路径即可。但是请注意,这会使其他人难以构建您的代码。
target_compile_definitions(tut2 PRIVATE "$<$<CONFIG:Debug>:" "_DEBUG" ">" "$<$<CONFIG:Release>:" "NDEBUG" ">" "WIN32;" "_CONSOLE;" "UNICODE;" "_UNICODE")
target_compile_options(tut2 PRIVATE /Oi; /Gy; /permissive-; /sdl; /W3; $<$<CONFIG:Debug>:/Z7>; ${DEFAULT_CXX_DEBUG_INFORMATION_FORMAT}; ${DEFAULT_CXX_EXCEPTION_HANDLING})
在这些行中,我们告诉 cmake 我们希望它编译的所有标志。如果您想知道每个标志的作用,那么this 是您应该查看的位置。
target_link_options(tut2 PRIVATE $<$<CONFIG:Debug>: /INCREMENTAL> $<$<CONFIG:Release>: /DEBUG; /OPT:REF; /OPT:ICF; /INCREMENTAL:NO> /NODEFAULTLIB:LIBCMT)
在这些行中,我们告诉 cmake 我们想要链接我们的库的所有标志。如果您想知道每个标志的作用,那么您应该查看this。
target_link_libraries(tut2 PRIVATE SDL2main SDL2 winmm version Imm32 Setupapi)
target_link_directories(tut2 PRIVATE "${CMAKE_SOURCE_DIR}/lib")
在这些行中,我们告诉 Cmake 我们需要链接的所有库,以及查找这些库的位置。同样,${CMAKE_SOURCE_DIR}/lib 是一个相对路径,指向我放置 SDL2.lib 和 SDL2main.lib 的位置,但您可以放置任何相对或绝对路径来替换它。您现在可以构建项目,如果您做的一切正确,它应该可以成功编译。如果您收到“无法打开 projectName.exe”的错误消息,则只需重新配置您的 CMakeList.txt 文件即可。
如果这看起来比它应该的要难,那是因为它是。我最近不得不切换回 Windows 10,并且在 Linux 上花了我 2 分钟的时间度过了美好的一周。如果您可以选择,我强烈建议您尝试一下 Linux。您所要做的就是将--static-libs 传递给sdl2-config,然后瞧!您的程序是静态链接的。如果您有任何问题,或者有什么我忘了介绍,请在 cmets 中告诉我。