如何在使用Visual C++编译器在Windows上构建库时正确设置目标操作系统版本

Coo*_*Cat 7 c++ windows winapi cmake visual-c++

我正在使用Visual C++ 2013编译器在Windows平台上构建一个跨平台库,特别是使用CMake(NMake生成器)构建系统.我正在使用Windows 7.

我的库使用一些仅在Windows 8/7中可用的函数/枚举值/结构成员.

我希望能够为Windows XP,Windows Vista,Windows 7和Windows 8/8.1操作系统版本以及x86,x64和arm架构构建库,即不是仅针对Windows XP并且可以在任何地方工作的单个构建,但是许多不同针对特定操作系统的构建,因为较新的操作系统版本具有我的库可以提供的更多有用功能.

我的问题是:

  1. 如何告诉编译器针对特定的OS版本(即XP,Vista,7,8,8.1等)?

  2. 如何告诉编译器针对特定架构(即x86,x64,arm等)?

  3. 如果我使用仅在Windows 8/7中可用的函数/枚举值/结构成员但是构建面向Windows XP的库,会发生什么?编译器会警告我在Windows XP上不存在这样的东西吗?或者它是否实际编译但无法在Windows XP系统上运行?

  4. 我怎么做到这一点,当我为Windows XP编译时,我的代码跳过Windows XP中不存在的东西(Windows 7/8函数等)?

  5. 在定位不同的操作系统版本时,我使用哪个Windows SDK版本是否重要?我似乎安装了8.1,8.0和7.1 Windows SDK.如果我总是使用最新的SDK版本,即使面向Windows XP,也没关系?

以下是我找到的一些答案,我不确定是正确还是完整:

  1. 我只需要设置_WIN32_WINNTWINVER定义目标系统的适当值,就是这样,我不需要设置任何东西,我的应用程序将在指定的系统(即Windows XP)上运行.

    • 使用"C:\ Program Files(x86)\ Microsoft Visual Studio 12.0\VC\vcvarsall.bat"设置编译器环境变量时,我需要使用适当的选项,即"C:\ Program Files(x86)\ Microsoft Visual Studio 12.0"\VC\vcvarsall.bat amd64"for 64 bit.
    • 我还需要指定适当的/SUBSYSTEM给连接器,即/SUBSYSTEM:WINDOWS,5.02/SUBSYSTEM:WINDOWS,6.00针对x64.但是5.02和之间有什么区别6.00?为什么两个值指定相同的东西(64位)?同为5.016.00,为什么他们都规定32位元?我想用64/32位的单个值就足够了.

      • 这些值(5.01,5.026.00)看起来类似于WINVER来自(1)的平台值.除了架构之外,他们还设置了目标操作系统吗?但是WINVER=502从(1)用于定位Windows Server 2003,它根据维基百科以64位和32位版本发布,但在这里5.02严格代表64位,这没有意义......
  2. 编译器将无法编译,因为WINVER(1)中的define将排除目标操作系统中不存在的函数和内容(Windows头文件使用定义的#ifdef东西).

  3. 我应该#ifdef基于WINVER我自己的代码,比如Windows标题,并在需要时为缺少的功能提供替代方案.

  4. 不知道.

请注意,我没有使用Visual Studio IDE,因此告诉我在IDE中设置选项X有点无意义.

我来自Linux开发,所以Windows对我来说有点新鲜.

Jam*_*lis 6

您对自己问题的回答大部分是正确的.一些澄清和更正:

子系统版本与目标体系结构正交.什么/subsystem文档说的是最低子系统版本的x86是5.01和最低子系统版本X64的是5.02.对于控制台和Windows应用程序,子系统版本与内部操作系统版本号相同.5.01是x86 Windows XP; 5.02是x64 Windows XP.Windows XP有两种不同的版本号,因为x64 Windows XP的版本晚于x86 Windows XP.较新的操作系统具有相同版本号的所有体系结构(例如,Windows Vista是x86和x64的6.0版).

请注意,通过设置子系统版本,您可以限制运行程序的操作系统集.例如,如果将子系统版本设置为6.2,则程序将仅在Windows 8及更高版本上运行.如果您尝试在Windows 7上运行该程序,它将无法运行.(对于DLL来说也是如此:如果你的DLL的目标是比你运行的操作系统更新的操作系统,那么加载器将不会加载DLL,至少不会加载代码.)

有关操作系统版本的列表,请参阅Wikipedia的页面"Microsoft Windows版本列表".Windows XP是Visual Studio 2013支持的最旧版本的Windows.

Windows 8 SDK仅支持向Windows Vista开发软件.如果要为Windows XP 设置_WIN32_WINNTWINVER构建,则需要使用Windows 7 SDK(Visual Studio 2013将安装两个SDK).

除非您的程序对于每个目标操作系统有很大的不同,否则构建一个在您想要支持的最旧操作系统(Windows XP)上运行的二进制文件可能要简单得多,并且可以延迟加载或动态加载(通过LoadLibrary/ GetProcAddress)任何当该功能可用时,您希望在较新的操作系统中使用的功能.


Fra*_*yne 6

抱歉,这会很长:-(

\n\n
\n

1.如何告诉编译器针对特定操作系统版本(即 XP、Vista、7、8、8.1 等)?

\n
\n\n

通常,您不会告诉编译器针对特定的操作系统版本。相反,您可以使用WINVER 和 _WIN32_WINNT从 SDK 定制头文件。头文件sdkddkver.h提供了有用的命名常量

\n\n

如果您将 WINVER 和 _WIn32_WINNT 设置得足够高,头文件将声明仅在更高版本的操作系统版本中可用的函数(假设您使用的 SDK 足够新,可以声明这些函数)。

\n\n

但现在您有一个程序可以调用旧操作系统版本上可能不存在的函数。如果你幸运的话,有某种兼容性垫片可以帮助你。如果你运气不好,调用未知函数的尝试就会失败。或者做一些比失败更糟糕的事情。但这是我的观点,我找不到具体的内容可以引用。

\n\n
\n

2.如何告诉编译器针对特定架构(即x86、x64、arm等)?

\n
\n\n

你不知道。您可以为每个目标平台使用不同的编译器。如果你往下看,C:\\Program Files (x86)\\Microsoft Visual Studio 12.0\\VC\\你会发现这个bin目录和七个子目录:

\n\n

amd64
\n amd64_arm
\n amd64_x86
\n 臂
\n x86_amd64
\n x86_arm

\n\n

您可以使用适当目录中的编译器来为该平台构建代码。在 Win32 版本的 Windows 上,从上面的路径中删除“(x86)”。

\n\n
\n

3.如果我使用仅在 Windows 8/7 中可用的函数/枚举值/结构成员会发生什么...

\n
\n\n

我不确定这是定义的行为。如果您将 _WIn32_WINNT 设置为 _WIN32_WINNT_WIN8,您几乎是在说“我打算在 Windows 8 及更高版本上运行它”。但这是我的观点,并非确定的事实。可能是我没有仔细阅读文档。

\n\n
\n

4.如何使我的代码在针对 Windows XP 进行编译时跳过 Windows XP 中不存在的内容(Windows 7/8 函数等)?

\n
\n\n

您必须明确地为其编码,我不相信有任何东西可以为您解决这个问题。您可以在编译时使用#ifdef_WIN32_WINNT 来执行此操作,也可以在运行时通过确定是否可以调用该函数来执行此操作,然后根据情况调用该函数或避免调用该函数。

\n\n

在所有可能的世界中(不太可能)最糟糕的情况下,将会发生重大更改,例如,结构参数的 Windows 8 格式与该函数的早期实现不兼容。在这种情况下,您必须弄清楚在调用函数时要使用哪个版本的结构 - 并且标头只会根据 _WIN32_WINNT 值提供一个结构定义。

\n\n
\n

5.针对不同操作系统版本时,我使用哪个 Windows SDK 版本重要吗?

\n
\n\n

大概。旧版本的 SDK 可能不包含更高版本操作系统的函数定义。例如,当创建 Vista 版本的 SDK 时,Windows 8 中引入的大多数功能可能并不存在。

\n\n
\n

即使针对 Windows XP,如果我始终使用最新的 SDK 版本,可以吗?

\n
\n\n

这可能是最安全的做法。如果您使用最新的 SDK 并将 _WIN32_WINNT 设置为 _WIN32_WINNT_WINXP,那么可能会发生正确的事情 - 假设您想在 XP 上运行。

\n\n

我说“可能”是因为 XP 是一个特殊情况。它不受支持。最新的 SDK 可能已经或可能未通过将 _WIN32_WINNT 设置为 XP 值进行测试。

\n\n
\n

1.我只需要设置_WIN32_WINNT和WINVER定义...

\n
\n\n

这应该会为您提供一个代码文件,该文件将在 _WIN32_WINNT 值标识的操作系统版本上正确执行。它很可能也适用于更高版本的操作系统(微软在推出更新的操作系统版本时会尽力不破坏现有程序)。它可能会也可能不会在早于 _Win32_WINNT 识别的操作系统版本上正确运行 - 我不会冒险。

\n\n
\n

\xe2\x80\xa2我在设置编译器环境变量时需要使用适当的选项

\n
\n\n

由于您使用的是 NMAKE,我不确定这个问题的答案。vcvarsall.bat 文件设置各种环境变量(除其他外)可以控制使用哪一组编译器(通过控制 MSBUILD 在何处查找编译器等二进制文件)。但我不知道NMAKE是否运行MSBUILD或关注那些环境变量或有自己不同的变量集或什么。

\n\n
\n

\xe2\x80\xa2I 还需要为链接器指定适当的 /SUBSYSTEM 值,即 x64 的 /SUBSYSTEM:WINDOWS,5.02 或 /SUBSYSTEM:WINDOWS,6.00

\n
\n\n

SUBSYSTEM 主要/次要值与平台类型(ARM、x86、x64 等)没有直接关系。它们指定代码文件运行的最低操作系统级别。因此,SUBSYSTEM 5.01 表示“此代码文件将在 XP 上运行”,而 SUBSYSTEM 5.02 表示“此代码文件将在 Windows Server 2003 上运行,但不能在 XP 上运行”。理想情况下,您应该将子系统主要/次要与 _WIN32_WINNT 匹配,以避免文件在不支持它的旧操作系统版本上运行的风险。

\n\n

至少我记得是这样的 - 我没有可以用来确认我是否正确记得这一点的 XP 环境。

\n