use*_*036 3 static-linking visual-c++ sdl-2
我正在使用 Microsoft Visual Studio 2013 Express for Windows Desktop,用 C++ 编写并使用 SDL 2.0.3 库。我正在尝试构建一个独立的.exe,它可以在其他计算机上运行而无需安装任何东西。
我已经按照TwinklebearDev 第 0 课:设置 SDL设置了我的项目。我链接到该库的 x86 版本,并将 x86 版本的 SDL2.dll 放置在 Debug 文件夹和 Release 文件夹中。这是源代码:
#include <iostream>
#include <SDL.h>
int main(int argc, char **argv){
if (SDL_Init(SDL_INIT_EVERYTHING) != 0){
std::cout << "SDL_Init Error: " << SDL_GetError() << std::endl;
return 1;
}
SDL_Quit();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
这工作完美并返回 0,直到我尝试静态链接。我尝试通过右键单击项目并单击属性,然后设置以下内容来静态链接:
配置属性 > C/C++ > 代码生成 > 运行时库 > 多线程 (/MT)
然后我收到一堆错误:
警告 1 警告 LNK4098:defaultlib 'msvcrt.lib' 与其他库的使用冲突;使用 /NODEFAULTLIB:库 C:\SDLtest\Project1\Project1\LIBCMT.lib(crt0init.obj) Project1
错误 2 错误 LNK2005:“私有:__thiscall type_info::type_info(class type_info const &)”(??0type_info@@AAE@ABV0@@Z) 已在 LIBCMT.lib(typinfo.obj) C:\SDLtest\Project1 中定义\Project1\msvcrt.lib(ti_inst.obj) 项目1
错误3错误LNK2005:“private:class type_info & __thiscall type_info::operator=(class type_info const &)”(??4type_info@@AAEAAV0@ABV0@@Z)已在LIBCMT.lib(typinfo.obj)中定义C: \SDLtest\Project1\Project1\msvcrt.lib(ti_inst.obj) Project1
错误 4 错误 LNK2005:_exit 已在 LIBCMT.lib(crt0dat.obj) C:\SDLtest\Project1\Project1\msvcrt.lib(MSVCR120.dll) Project1 中定义
错误 5 错误 LNK2005: ___iob_func 已在 LIBCMT.lib(_file.obj) C:\SDLtest\Project1\Project1\msvcrt.lib(MSVCR120.dll) Project1 中定义
错误 6 错误 LNK1169:找到一个或多个多重定义符号 C:\SDLtest\Project1\Release\Project1.exe 1 1 Project1
如何静态链接 SDL 2.0.3 以构建可在大多数计算机上运行而无需安装任何内容的独立可执行文件?
Jcs*_*sq6 22
我为此工作了一段时间,最终成功在 Windows 上静态链接 SDL2。您可以选择使用 Cmake 或 Visual Studio 的 IDE。我更喜欢 Cmake,但使用 Visual Studio 则稍微简单一些。
先决条件
第 1 步:构建 SDL2从此处
下载 SDL2 源代码。如果您不想将其保留在下载文件夹中,我建议将其解压缩到文档文件夹或下载之外的其他文件夹中。解压缩文件后,在文件夹中打开 cmd 提示符。确保进入解压文件夹内的文件夹。(您应该看到文件夹和文件的列表。如果您只看到一个文件夹,则进入该文件夹)您的目录应该类似于. 到达此处后,在此目录中打开 cmd 提示符。执行命令。接下来,执行命令。假设您有默认的 Windows 10 生成器,解决方案将在您的构建文件夹中创建。如果您使用不同的生成器,则像使用该生成器一样构建 SDL2。您现在可以关闭命令提示符。导航到构建文件夹中,然后打开文件。这将打开 Visual Studio。确保将您的配置更改为. 现在您已打开它,进入 SDL2 解决方案的属性(右键单击 SDL2,然后单击对话框底部的属性)。现在您已打开属性面板,请确保您位于. 这应该是您自动打开的位置。将属性从更改为。之后,转到,然后。将from的结尾更改为。现在我们已经告诉 Visual Studio 创建一个静态库。单击“应用”,然后按“确定”。在构建之前,我们需要在源代码中添加一个定义,以便让SDL2我们想要使用C库函数。如果你不这样做,那么什么都无法编译。您需要找到并打开SDL_config.h。重要提示:确保您正在编辑正确的 SDL_config.h!那里有两个!确保您正在编辑构建文件夹内的文件。如果您打开的 SDL_config.h 只有 56 行,那么您就错了。找到正确的 SDL_config.h 后,在行上方添加行 somwehere 。确保保存文件。现在右键单击 SDL2 解决方案,然后单击构建。完成后,右键单击SDL2main,然后单击构建。这将生成文件和。现在您已经有了静态库,您可以将它们包含在您的项目中。~\Documents\SDL2-2.0.14\SDL2-2.0.14mkdir build && cd buildcmake ..Visual Studio 16 2019ALL_BUILD.vcxprojReleaseGeneralConfiguration PropertiesConfiguration TypeDynamic Library (.dll)Static Library (.lib)LibrarianGeneralOutput File$(TargetExt).lib#define HAVE_LIBC 1#if HAVE_LIBCSDL2.libSDL2main.lib~\SDL2-2.0.14\SDL2-2.0.14\build\Release
步骤 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 提供的编辑输入法(单击“链接器”->“输入”->“其他依赖项”最右侧的向下箭头),那么您需要直接输入这些库,中间用分号。您可能需要也可能不需要库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")
Run Code Online (Sandbox Code Playgroud)
在行中
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /MDd")
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MD")
Run Code Online (Sandbox Code Playgroud)
我们告诉 CMake 使用静态运行时库。如果你想让你的程序更小,那么你可以使用“/MD”。请注意,它需要运行时 dll 才能运行,以及所有这些暗示。编辑:您需要使用 /MD 和 /MDd。SDL2 需要它。不过,您仍然可以静态链接。
add_subdirectory("src")
Run Code Online (Sandbox Code Playgroud)
这告诉 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")
Run Code Online (Sandbox Code Playgroud)
在行中
target_include_directories(tut2 PRIVATE "${CMAKE_SOURCE_DIR}/include")
Run Code Online (Sandbox Code Playgroud)
我们告诉 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})
Run Code Online (Sandbox Code Playgroud)
在这些行中,我们告诉 cmake 我们希望它编译时使用的所有标志。如果您想知道每个标志的作用,那么您应该查看这里。
target_link_options(tut2 PRIVATE $<$<CONFIG:Debug>: /INCREMENTAL> $<$<CONFIG:Release>: /DEBUG; /OPT:REF; /OPT:ICF; /INCREMENTAL:NO> /NODEFAULTLIB:LIBCMT)
Run Code Online (Sandbox Code Playgroud)
在这些行中,我们告诉 cmake 我们想要链接我们的库的所有标志。如果您想知道每个标志的作用,那么您应该查看这里。
target_link_libraries(tut2 PRIVATE SDL2main SDL2 winmm version Imm32 Setupapi)
target_link_directories(tut2 PRIVATE "${CMAKE_SOURCE_DIR}/lib")
Run Code Online (Sandbox Code Playgroud)
在这些行中,我们告诉 Cmake 我们需要链接的所有库,以及查找这些库的位置。同样,${CMAKE_SOURCE_DIR}/lib 是一个相对路径,指向我放置 SDL2.lib 和 SDL2main.lib 的位置,但您可以放置任何相对或绝对路径来替换它。您现在可以构建该项目,如果一切正确,它应该会成功编译。如果您收到错误消息“无法打开projectName.exe”,则只需重新配置您的CMakeList.txt 文件。
如果这看起来比应有的困难得多,那是因为事实确实如此。我最近不得不切换回 Windows 10,并且在 Linux 上花费了 2 分钟的时间度过了愉快的一周。如果可以的话,我强烈建议您尝试一下 Linux。您所要做的就是传递--static-libs到sdl2-config,瞧!您的程序是静态链接的。如果您有任何疑问,或者有任何我忘记提及的内容,请在评论中告诉我。