提问人:Runsva 提问时间:10/9/2023 最后编辑:Runsva 更新时间:10/9/2023 访问量:107
包含带有 cl.exe 的标准库(在普通命令提示符中)?
Include Standard Libraries with cl.exe (in vanilla Command Prompt)?
问:
我正在尝试使用标准的 Windows 命令提示符命令编译一个简单的共享库 DLL 文件。
DLL 文件将从以下名为 的 C++ 文件编译:test.cpp
#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
test.cpp
test.cpp(1): fatal error C1034: iostream: no include path set
我知道常规的 Windows 命令提示符没有设置所有必需的环境变量,并且我可能必须使用链接标志等单独指定我正在使用的每个库。
我试图遵循以下类似帖子的答案,但命令和是我的命令提示符中无法识别的命令。vcvars32.bat
vcvars32
包含所有C++标准库路径和环境变量的正确方法是什么 普通 Windows 命令提示符?库的链接器标志是什么,例如?iostream
答:
虽然首选和更简单的方法是使用开发人员命令提示符(如注释中所述),但仍然可以通过直接从常规命令行调用来生成 DLL。cl.exe
为此,我建议您启动开发人员命令提示符一次,在那里键入,并记下以下环境变量中指定的路径:、以及变量 和 中指定的版本。SET
INCLUDE
LIBPATH
LIB
VCToolsVersion
WindowsSDKVersion
然后,您需要为调用构造完整的命令行。以下页面介绍了 MSVC 命令行选项:cl.exe
您已经提到使用 以编程方式执行,所以这里有一个示例程序这样做(至少需要 C++17,因为我用于路径操作):CreateProcess
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);
}
正如你所看到的,有许多常量,比如路径和版本,你必须根据你的系统找出并“配置”。在我上面的示例代码中,命令行的结尾是这样的:
"C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\VC\Tools\MSVC\14.29.30133\bin\Hostx86\x86\cl.exe" /I "C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\VC\Tools\MSVC\14.29.30133\ATLMFC\include" /I "C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\VC\Tools\MSVC\14.29.30133\include" /I "C:\Program Files (x86)\Windows Kits\10\include\10.0.19041.0\ucrt" /I "C:\Program Files (x86)\Windows Kits\10\include\10.0.19041.0\shared" /I "C:\Program Files (x86)\Windows Kits\10\include\10.0.19041.0\um" /D "WIN32" /D "_USRDLL" /D "_WINDLL" /D "_UNICODE" /D "UNICODE" /D "NDEBUG" /D "MYDLL_EXPORTS" /permissive- /W4 /WX /Zc:wchar_t /Zc:inline /Zc:forScope /fp:precise /GS /Gy /O2 /Gd /Oy- /Oi /MD /FC /EHsc /diagnostics:column /analyze- /LD /Fo"test.obj" /Fe"MyDLL.dll" "test.cpp" /link /LIBPATH:"C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\VC\Tools\MSVC\14.29.30133\ATLMFC\lib\x86" /LIBPATH:"C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\VC\Tools\MSVC\14.29.30133\lib\x86" /LIBPATH:"C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\VC\Tools\MSVC\14.29.30133\lib\x86\store\references" /LIBPATH:"C:\Program Files (x86)\Windows Kits\10\References\10.0.19041.0" /LIBPATH:"C:\Program Files (x86)\Windows Kits\10\lib\10.0.19041.0\ucrt\x86" /LIBPATH:"C:\Program Files (x86)\Windows Kits\10\lib\10.0.19041.0\um\x86" "kernel32.lib" "user32.lib" "gdi32.lib" "advapi32.lib"
但是在您的系统上,它可能会有所不同,当然,因为工具集/SDK 版本不同。
评论
CreateProcess
CreateProcess