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

Include Standard Libraries with cl.exe (in vanilla Command Prompt)?

提问人:Runsva 提问时间:10/9/2023 最后编辑:Runsva 更新时间:10/9/2023 访问量:107

问:

我正在尝试使用标准的 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.batvcvars32

包含所有C++标准库路径和环境变量的正确方法是什么 普通 Windows 命令提示符?库的链接器标志是什么,例如?iostream

C++ 标准

评论

1赞 Some programmer dude 10/9/2023
在“开始”菜单中,应该有一个用于启动 VS 命令提示符的条目,其中所有路径等都已设置。试试吧。
0赞 john 10/9/2023
我认为正确的方法是使用开发人员命令提示符。但这是我能从Microsoft找到的最好的文档
0赞 Runsva 10/9/2023
我想使用原版命令提示符的原因是因为我是通过 Windows API 函数启动它的,该函数只能启动原版 CMD。我无法启动 VS 本机命令提示符,因此我必须自己设置所有环境变量。CreateProcessCreateProcess
1赞 Alan Birtles 10/9/2023
您需要在 Visual Studio 安装中找到 vcvars bat 文件并运行它们(这就是开发人员命令提示符所做的全部操作)
0赞 john 10/9/2023
@Runsva 也许您可以创建一个项目文件(或解决方案文件)并启动 msbuild。这似乎容易得多。

答:

0赞 heap underrun 10/9/2023 #1

虽然首选和更简单的方法是使用开发人员命令提示符(如注释中所述),但仍然可以通过直接从常规命令行调用来生成 DLL。cl.exe

为此,我建议您启动开发人员命令提示符一次,在那里键入,并记下以下环境变量中指定的路径:、以及变量 和 中指定的版本。SETINCLUDELIBPATHLIBVCToolsVersionWindowsSDKVersion

然后,您需要为调用构造完整的命令行。以下页面介绍了 MSVC 命令行选项:cl.exe

您已经提到使用 以编程方式执行,所以这里有一个示例程序这样做(至少需要 C++17,因为我用于路径操作):CreateProcesscl.exestd::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 版本不同。