使用 cl.exe 包含标准库(在普通命令提示符中)?

问题描述 投票:0回答:1

我正在尝试使用标准 Windows 命令提示符命令编译一个简单的共享库 DLL 文件。

DLL 文件将从以下名为

test.cpp
的 C++ 文件编译而来:

#include <iostream>
#include <windows.h>

extern "C" __declspec(dllexport) int test_fx(void)
{
    std::cout << "test\n";
    return 0;
}

虽然我可以使用 Visual Studio 2022 本机命令提示符(它正确设置了所有环境变量)将此 C++ 文件编译为 DLL,但没有出现任何问题,但尝试在常规 Windows 命令提示符结果中执行相同操作如下:

cl.exe

我知道常规的 Windows 命令提示符没有所有必需的环境变量设置,并且我可能必须使用链接标志等单独指定我正在使用的每个库。

我试图遵循

以下类似帖子

的答案,但命令test.cpp test.cpp(1): fatal error C1034: iostream: no include path set

vcvars32.bat
在我的命令提示符中是无法识别的命令。
为普通 Windows 命令提示符包含所有 C++ 标准库路径和环境变量的正确方法是什么? 

vcvars32

等库的链接器标志是什么?

    

c++ std
1个回答
0
投票
iostream

来构建 DLL。

为此做好准备,我建议您启动一次开发人员命令提示符,在其中键入 

cl.exe

,并记下以下环境变量中指定的路径:

SET
INCLUDE
LIBPATH
,以及变量
LIB
VCToolsVersion
中指定的版本。
然后您需要为 

WindowsSDKVersion

调用构建完整的命令行。以下页面介绍了 MSVC 命令行选项:


    编译器选项
  • 编译器控制的链接器选项
  • 链接器参考
  • 链接器选项
  • 您提到过使用
cl.exe

以编程方式执行

CreateProcess
,所以这里是一个执行此操作的示例程序(至少需要 C++17,因为我使用
cl.exe
进行路径操作):
std::filesystem

如您所见,有许多常量,例如路径和版本,您必须根据您的系统找到并“配置”它们。在上面的示例代码中,命令行最终如下所示:

#include <filesystem> #include <string> #include <vector> #include "windows.h" using std::wstring; using std::vector; template <typename T> wstring concat_with_prefixes(const wstring& prefix, const vector<T>& vec) { wstring result; for (const auto& item : vec) { result += L" " + prefix + L"\"" + item.c_str() + L"\""; } return result; } int main() { using std::filesystem::path; const path my_source_code_folder{ LR"(C:\MyTestApplications\MyDLL)" }; const wstring my_cpp_file_name{ L"test.cpp" }; const wstring my_obj_file_name{ L"test.obj" }; const wstring my_dll_file_name{ L"MyDLL.dll" }; const wstring msvc_toolset_version{ L"14.29.30133" }; const wstring win_sdk_version{ L"10.0.19041.0" }; const path msvc_folder { path{LR"(C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\VC\Tools\MSVC)"} / msvc_toolset_version }; const path win_sdk_base_folder{ LR"(C:\Program Files (x86)\Windows Kits\10)" }; const path win_sdk_include_folder{ win_sdk_base_folder / L"include" / win_sdk_version}; const path win_sdk_references_folder{ win_sdk_base_folder / L"References" / win_sdk_version}; const path win_sdk_lib_folder{ win_sdk_base_folder / L"lib" / win_sdk_version}; const wstring prefix_include{ L"/I " }; const vector<path> include_folders // Normally taken from the "INCLUDE" environment variable { msvc_folder / LR"(ATLMFC\include)", msvc_folder / LR"(include)", win_sdk_include_folder / LR"(ucrt)", win_sdk_include_folder / LR"(shared)", win_sdk_include_folder / LR"(um)" }; const wstring prefix_define{ L"/D " }; const vector<wstring> preprocessor_definitions { L"WIN32", L"_USRDLL", L"_WINDLL", L"_UNICODE", L"UNICODE", L"NDEBUG", L"MYDLL_EXPORTS" }; const wstring compiler_options { L"/permissive- /W4 /WX /Zc:wchar_t /Zc:inline /Zc:forScope /fp:precise " L"/GS /Gy /O2 /Gd /Oy- /Oi /MD /FC /EHsc /diagnostics:column /analyze- /LD" }; const wstring prefix_libpath{ L"/LIBPATH:" }; const vector<path> lib_folders // Normally from the "LIBPATH" and "LIB" environment variables { msvc_folder / LR"(ATLMFC\lib\x86)", msvc_folder / LR"(lib\x86)", msvc_folder / LR"(lib\x86\store\references)", win_sdk_references_folder, win_sdk_lib_folder / LR"(ucrt\x86)", win_sdk_lib_folder / LR"(um\x86)", }; const wstring libraries{ LR"("kernel32.lib" "user32.lib" "gdi32.lib" "advapi32.lib")" }; const path cl_exe{ msvc_folder / LR"(bin\Hostx86\x86\cl.exe)" }; wstring command_line{ L'"' + cl_exe.wstring() + L'"'}; command_line += concat_with_prefixes(prefix_include, include_folders) + concat_with_prefixes(prefix_define, preprocessor_definitions) + L' ' + compiler_options + L" /Fo\"" + my_obj_file_name + L'"' + L" /Fe\"" + my_dll_file_name + L'"' + L" \"" + my_cpp_file_name + L'"' + L" /link" + concat_with_prefixes(prefix_libpath, lib_folders) + L' ' + libraries; command_line.resize(UNICODE_STRING_MAX_CHARS + 1); STARTUPINFOW si{}; si.cb = sizeof si; PROCESS_INFORMATION pi{}; if (!::CreateProcessW(cl_exe.c_str(), data(command_line), nullptr, nullptr, false, 0, nullptr, my_source_code_folder.c_str(), &si, &pi)) { ::MessageBoxW(nullptr, (L"Cannot start the compiler/linker driver process due to system error " + std::to_wstring(::GetLastError())).c_str(), nullptr, MB_OK); } ::WaitForSingleObject(pi.hProcess, INFINITE); ::CloseHandle(pi.hThread); ::CloseHandle(pi.hProcess); }


但是在您的系统上,它可能会有所不同,因为工具集/SDK 版本不同。

© www.soinside.com 2019 - 2024. All rights reserved.