cmake + vcpkg:如何验证VC/Windows构建的平台工具集?

huangapple go评论147阅读模式
英文:

cmake + vcpkg : how to verify platform toolset for VC/Windows builds?

问题

我有一个CMake项目,目标是同时在Windows和Linux上运行。对于Windows版本的构建,我正在使用VCPKG_TARGET_TRIPLET指定v142平台工具集,使用自定义三元组来指定适当的VCPKG_PLATFORM_TOOLSET,因为我的库的用户仍然使用VS2019和v142工具集进行构建。

这是我的自定义三元组:

set(VCPKG_TARGET_ARCHITECTURE x86)
set(VCPKG_CRT_LINKAGE dynamic)
set(VCPKG_LIBRARY_LINKAGE static)
set(VCPKG_PLATFORM_TOOLSET "v142")

通过将VCPKG_TARGET_TRIPLET缓存变量设置为我的自定义三元组的名称,将其传递给CMake,以便传递给vcpkg(是的,我在构建之前删除了CMake缓存并重新运行了配置)。

我的项目中的所有内容都构建正常,vcpkg的输出显示它正在使用我的三元组。但是,在尝试将我的静态库链接到使用它的应用程序时,调试构建可以正常工作,但发布构建失败,并显示以下错误:

1>LINK:致命错误 C1007:在“p2”中的未识别标志“-Zc:nrvo”
1>LINK:致命错误 LNK1257:代码生成失败

我没有明确设置此标志,但根据此文档,当使用permissive-(我正在使用它)时,它会在最新的工具集版本中自动启用(仅在VS2022版本17.4或更高版本的v143工具集中支持)。因此,我只能得出结论,我的库以某种方式使用了错误的工具集。

有没有关于如何排除/修复这个问题的想法?我尝试过使用--debug参数来调试vcpkg,但当我查看vcpkg-manifest-install.log时,我没有看到任何指示发生了什么的内容。在构建目标时,它似乎使用了我的自定义三元组。我甚至尝试为VCPKG_HOST_TRIPLET变量指定我的自定义三元组,但这似乎对我得到的错误没有产生任何影响(尽管它删除了出现在日志中的与v143工具集相关的引用)。

英文:

I have a cmake project that targets both windows and linux. For the windows build, I'm specifying the v142 platform toolset using VCPKG_TARGET_TRIPLET, with a custom triplet that specifies the appropriate VCPKG_PLATFORM_TOOLSET, because the users of my library are still building with VS2019 and v142 toolset.

This is my custom triplet:

set(VCPKG_TARGET_ARCHITECTURE x86)
set(VCPKG_CRT_LINKAGE dynamic)
set(VCPKG_LIBRARY_LINKAGE static)
set(VCPKG_PLATFORM_TOOLSET "v142")

It's getting passed to vcpkg via cmake by setting the VCPKG_TARGET_TRIPLET cache variable equal to the name of my custom triplet. (yes, I deleted the cmake cache and ran configure before building again).

Everything in my project builds fine, and vcpkg output shows that it's using my triplet. When attempting to link my static library into the application using it, it works for Debug builds; but release builds are failing with the following error:

1>LINK : fatal error C1007: unrecognized flag '-Zc:nrvo' in 'p2'
1>LINK : fatal error LNK1257: code generation failed

I'm not explicitly setting this flag, but according to this documentation it's auto-enabled in the latest toolset versions when using permissive- (which I am using). This particular linker flag is only supported in VS2022, version 17.4 or later (v143 toolset). So I can only conclude that somehow my library is getting built with the wrong toolset.

Any thoughts on how to troubleshoot/fix this? I've tried passing --debug to vcpkg to troubleshoot, but when I look in vcpkg-manifest-install.log I don't see anything that would indicate what's going on. The v143 toolset only shows up in the logfile in relation to the host triplet vcpkg uses for compiler detection stuff. When building targets it appears to be using my custom triplet. I even tried specifying my custom triplet for the VCPKG_HOST_TRIPLET var, but that didn't seem to make any difference in the error I'm getting (although it did remove the reference to v143 toolset that was showing up in the log).

答案1

得分: 0

我现在为您提供翻译好的部分,不包括代码:

"所以,现在我大部分都已经解决了这个问题,我想记录一下我的发现,因为关于这个主题在网络上几乎没有什么信息。

第一个问题是,当使用CMakePresets.json时,像VSCode或Visual Studio这样的IDE打开项目时,它们会根据预设中的属性配置构建环境。因此,如果预设中没有告诉IDE使用什么工具集,那么它将使用已安装的最新工具集。

第二个更大的问题是,尽管VCPKG知道如何正确配置平台工具集和其他变量,但在使用cmake/ninja/vcpkg构建的情况下,它实际上并没有这样做。VCPKG将使用现有的环境,并以错误的平台工具集进行静默构建。据我所知,在使用ninja进行cmake构建时,在三重体系中设置VCPKG_PLATFORM_TOOLSET/VCPKG_PLATFORM_TOOLSET_VERSION对构建没有影响。

我不知道是否有一些复杂的解释,为什么必须这样,还是这只是一个错误。但至少,我认为VCPKG应该在检测到当前构建环境与指定的三重体系不匹配时创建警告或错误。

对于IDE的情况,我找到了一些不起作用的不同建议,还有一个起作用的。如果您想指定平台工具集,您需要向您的CMakePreset添加以下部分(使用适用于您需求的版本号 - 在我的情况下,这是来自VS2019的最新v142平台工具集):

"toolset": {"value": "version=14.29", "strategy": "external"}

这是唯一一种使IDE知道您需要什么构建环境的方式。

从命令提示符构建要困难一些。例如,如果您安装了VS2022,并且有v142和v143工具集,那么通过Visual Studio Installer创建的任何开发人员命令提示符快捷方式都无法实现使用v142进行构建。我找到的唯一使正确环境加载的方法是执行:

%ProgramFiles%\Microsoft Visual Studio22\Professional\Common7\Tools\VsDevCmd.bat -vcvars_var=\"14.29\"

在这一点上,您可以使用正确的工具集进行构建。

不幸的是,没有简单的方法将这些变量加载到Powershell中。"Launch-VsDevShell.ps1"不支持"-vcvars_var"参数;运行"VsDevCmd.bat"将您放在"cmd.exe"命令提示符中,这意味着当您退出返回到Powershell时,环境变量就消失了。

由于我在命令行(以及在CI中)使用Powershell脚本进行构建,这真的很麻烦。我找到的唯一方法是使用Powershell用户社区扩展中的"Invoke-Batchfile" cmdlet。这基本上可以工作,尽管它似乎比必要的要麻烦。

VCPKG还有一个"cmd"命令,它将为您加载构建环境,但它会启动一个新的cmd.exe会话来创建环境,这意味着无法从脚本中使用这个功能(除非将脚本分开并传递一个"内部"脚本给vcpkg命令,但这只是一种我认为应该更好地工作的丑陋的解决方法)。

总之,要总结一下,如果您想使用cmake/ninja/vcpkg构建,而不是使用最新安装的平台工具集,您需要执行以下操作:

  • 向您的CMakePreset添加"toolset"属性,以便IDE知道要加载哪个工具集。
  • 调用VsDevCmd.bat -vcvars_var="14.xx"来设置命令行构建的环境。
  • 不要费心设置三重体系中的VCPKG_PLATFORM_TOOLSET/VCPKG_PLATFORM_TOOLSET_VERSION,它们不起作用。"
英文:

So I've mostly got this working now, figured I'd document my findings since there's very little on the web about this topic.

The first issue is that when using CMakePresets.json, when IDE's such as VSCode or Visual Studio open your project, they're going to configure the build environment based on the properties in the preset. So if there's nothing in the pre-set telling the IDE what toolset to use, you're going to get the latest one installed.

The second, and larger, issue is that even though VCPKG knows how to configure the platform toolset and other variables correctly, it doesn't actually do so in the case of a cmake/ninja/vcpkg build. VCPKG will use the existing environment and silently build with wrong platform toolset. As far as I can tell, setting VCPKG_PLATFORM_TOOLSET/VCPKG_PLATFORM_TOOLSET_VERSION in your triplet has no effect on the build when using cmake with ninja.

I don't know if there's some long and complicated explanation why it has to be that way, or if it's just a bug. But at the very least, I really think VCPKG should create a warning or error if it detects that the current build environment doesn't match what's in the specified triplet.

For the IDE scenario, I found a few different recommendations that didn't actually work, and one that did. If you want to specify the platform toolset, you need to add the following section to your CMakePreset (use the version number appropriate for your needs - in my case, this is the latest v142 platform toolset from VS2019):

"toolset": { "value": "version=14.29", "strategy": "external" }

This is the only way the IDE will know what build environment you need.

Building from the command prompt is a little more difficult. For instance, if you have VS2022 installed with v142 and v143 toolsets, getting to a command prompt for building with v142 isn't possible with any of the Developer Command Prompt shortcuts created by the Visual Studio Installer. The only way I've found to get the correct environment loaded is by calling:

%ProgramFiles%\Microsoft Visual Studio22\Professional\Common7\Tools\VsDevCmd.bat -vcvars_ver="14.29"

At this point, you're on a command prompt that can build with the correct toolset.

Unfortunately, there's no easy way to load these variables into Powershell. Launch-VsDevShell.ps1 doesn't support the "-vcvars_ver" parameter; and running VsDevCmd.bat will put you in a cmd.exe command prompt, which means when you exit back to Powershell the environment variables are gone.

Since I use Powershell scripts for building on the command line (and in CI), this was a real hassle to get around. The only way I found was by using the Invoke-Batchfile cmdlet from the Powershell User Community extensions. This mostly works, although it seems like more trouble than should be necessary.

VCPKG also has a "cmd" command that will load a build environment for you, but it starts a new cmd.exe session to create the environment, which means this functionality can't be used from scripts (unless you break your scripts up and pass an "inner" script to the vcpkg command, but that's just an ugly hack for something that should work better IMHO).

TLDR: So to summarize, if you want to build with cmake/ninja/vcpkg using a platform toolset other than the latest installed, you need to do the following:

  • Add the "toolset" property to your CMakePreset so IDE's know which toolset to load
  • Call VsDevCmd.bat -vcvars_var="14.xx" to set up the environment for command-line building.
  • Don't bother with setting VCPKG_PLATFORM_TOOLSET/VCPKG_PLATFORM_TOOLSET_VERSION in your triplet, they don't work.

huangapple
  • 本文由 发表于 2023年2月27日 08:05:04
  • 转载请务必保留本文链接:https://go.coder-hub.com/75575785.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定