如何使我的托管 NuGet 包支持 C++/CLI 项目?
Posted
技术标签:
【中文标题】如何使我的托管 NuGet 包支持 C++/CLI 项目?【英文标题】:How can I make my managed NuGet package support C++/CLI projects? 【发布时间】:2013-09-12 17:57:18 【问题描述】:我制作了一个 NuGet 包,当我在 C# 项目中使用它时效果很好。它在lib/net40
目录中包含一个 DLL,该 DLL 被添加为引用。
既然 NuGet 支持 C++,我如何实际修改我的包,以便可以将 DLL 作为托管引用添加到 C++/CLI 项目中?我找不到任何解释这一点的教程。如果我尝试按原样添加包,则会收到以下错误:
您正在尝试将此包安装到以“Native,Version=v0.0”为目标的项目中,但该包不包含任何与该框架兼容的程序集引用或内容文件。
有人会认为解决方案是将文件放在 lib/native 下,但根据http://docs.nuget.org/docs/reference/support-for-native-projects,不支持。此外,简单地将 DLL 直接放在 lib 下似乎没有任何作用。
显然,我应该使用 build/native 下的 .props
或 .targets
文件来执行此操作,但我需要在这些文件中添加什么才能使其工作?
【问题讨论】:
我认为这更像是 NuGet 中的一个错误,而不是您需要在包中调整的内容。看到这个:nuget.codeplex.com/workitem/3665另外,这个问题是相关的:***.com/q/18786338/289770 谢谢!有趣的是,在我提出问题的第二天,错误报告是如何发布的。我现在已经投票了。尽管如此,无论有没有错误,我相信使用 NuGet 脚本可以解决这个问题,我正在寻找一个可以做到这一点的指南。 10 个月后,但也许这个 ([***.com/questions/23571241/…) 可能会对您有所帮助。 [1]:***.com/questions/23571241/… 【参考方案1】:作为Patrick O'Hara wrote,NuGet 不会为您更改 C++/CLI 项目。见GitHub Issue NuGet/Home#1121 - Cannot install managed packages into a CLI project。但是,使用 NuGet 命令行实用程序 NuGet.exe
,您可以让 NuGet 下载并解压缩所需的包。
对于一个完整的示例,以下是我在 Visual Studio 2013 C++/CLI 项目中添加对 OptimizedPriorityQueue 1.0.0 的引用的步骤:
-
如果尚未打开包管理器控制台,请打开(工具 > NuGet 包管理器 > 包管理器控制台)。
在包管理器控制台中,安装 NuGet.CommandLine 包:
安装包 NuGet.CommandLine(注意:在撰写本文时,NuGet.CommandLine 的最新版本是 2.8.6。您可能会有所不同。)
在您的项目文件夹中,现在应该有一个 .nuget\packages.config
XML 文件,其内容如下:
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="NuGet.CommandLine" version="2.8.6" />
</packages>
在 Notepad++ 等文本编辑器中,为所需的包添加 <package>
元素。在这种情况下,我补充说:
<package id="OptimizedPriorityQueue" version="1.0.0" />
.. 在<packages>
元素内。
打开命令提示符(我打开了一个 VS2013 开发者命令提示符,但应该可以使用常规命令提示符。)
cd
进入项目文件夹。
运行以下命令,如果不同,则更改 NuGet.CommandLine 的版本号:
.\packages\NuGet.CommandLine.2.8.6\tools\NuGet.exe 安装 -NonInteractive -OutputDirectory 包 .nuget\packages.config对我来说,输出是:
安装“OptimizedPriorityQueue 1.0.0.0”。 成功安装“OptimizedPriorityQueue 1.0.0.0”。 packages.config 中列出的所有软件包都已安装。 右键单击 Visual Studio 中的项目并选择 属性。在 Common Properties > References 下,点击 Add New Reference... 按钮。 选择左侧的浏览。在 Add Reference 对话框的 OK 和 Cancel 按钮旁边,有一个 Browse... 按钮。点击打开文件选择对话框。 导航到 NuGet 解压到项目文件夹的packages
子目录的 DLL,然后单击 添加 按钮。单击确定关闭“添加引用”对话框。
您现在应该可以在您的 C++/CLI 项目中使用该程序集了:
using namespace Priority_Queue;
//...
【讨论】:
@daniel-trebbien,你是如何处理包更新的? @daniel-trebbien,任何线索如何在 Visual Studio 2017 中执行步骤 8 到 10? 这在 Visual Studio 2013 中非常适合我。我更喜欢这个解决方案,而不是创建一个 C# 虚拟项目并将 dll 从一个项目复制到另一个项目。我能够添加 NLog 4.0.0。 非常有帮助,谢谢!仅供参考,当我在 VS 2019 中执行此操作时,我不得不稍微更改第 7 步命令,packages.config 是在项目的基本目录中创建的,而不是 .nuget 文件夹。此外,要在步骤 8 中将“浏览”作为选项查看,我必须确保我的项目已配置为“公共语言运行时支持 (/clr)”hth, X 第 2 步给了我与问题相同的错误。【参考方案2】:实际上似乎有可能使用以下步骤(至少使用NuGet >= 2.5
)从 C++/CLI 项目中安装和自动引用“常规”NuGet 包:
在要打包的项目中添加(或修改)build\<ProjectName>.targets
文件并将以下内容放入其中(确保将<AssemblyName>
替换为实际值):
<?xml version="1.0" encoding="utf-8" ?>
<Project ToolsVersion="4.0"
xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<!-- for C++/CLI projects only -->
<ItemGroup Condition="'$(Language)' == 'C++'">
<Reference Include="<AssemblyName>">
<!--
this .targets file is installed next to the assembly,
so we do not have to figure out any versions or paths here ourselves
-->
<HintPath>
$(MSBuildThisFileDirectory)..\lib\native\<AssemblyName>.dll
</HintPath>
</Reference>
</ItemGroup>
</Project>
在打包项目的.nuspec
中添加一个或多个file
条目以将程序集也放置在目标机器的lib\native\
目录中:
<package>
<metadata>
...
</metadata>
<files>
...
<!--
add a copy of the assembly to lib\native to prevent NuGet
from complaining about incompatible native projects
-->
<file src="bin\$configuration$\$id$.dll" target="lib\native\" />
<file src="bin\$configuration$\$id$.xml" target="lib\native\" />
<!-- don't forget about the .targets file containing the reference -->
<file src="build\$id$.targets" target="build\" />
</files>
...
</package>
即使 NuGet 不向 C++/CLI 项目添加程序集引用,它仍会插入包提供的任何 .props
和 .targets
文件。第 1 步中的自定义目标将添加对我们打包程序集的引用。
据我所知,此解决方案的一个缺点是以这种方式添加的引用未显示在 C++/CLI 项目的Commpon Properties/Framework and References
部分中。可能还有其他人,所以使用它需要您自担风险...
【讨论】:
【参考方案3】:正如对此端口 (Nuget won't install Entity Framework into C++/CLI project) 的答复中所述,NuGet 不会为您更改 C++/CLI 项目。但是,它将为您下载并解包依赖项。我们从命令行使用它作为我们的 make 依赖项的一部分。命令行将如下所示:
/.NuGet/NuGet.exe
Install
-NonInteractive
-ConfigFile $ENVSRC_ROOT/.nuget/NuGet.config
-OutputDirectory $ENVSRC_ROOT/packages
$ENVSRC_ROOT/packages.config
请注意,命令行参数是逐行分隔的,以便于阅读。我们还决定在 .NuGet 文件夹中将 NuGet 检入我们的源代码控制中。目标是更容易为我们的各种环境(并非所有环境都使用 Visual Studio)设置构建机器。首次运行此命令后,您必须手动将依赖项添加到 C++/CLI 项目中。 希望对您有所帮助。
【讨论】:
看起来如果我的 C++/CLI 项目是类库(程序集)而不是 exe,nuget 仍然失败。 @WeipengL 这是一个很老的问题。您的回复缺乏细节。也许您应该创建一个新问题来描述您的问题并参考这个问题?【参考方案4】:简单的解决方法是将此类 NuGet 包装在常规 .NET 项目 (C#) 中,并在 C++/CLI 项目中引用相同的内容。
【讨论】:
【参考方案5】:安装程序尝试在 C# 启动项目中添加对自身的引用。在安装之前将 C# 项目作为解决方案中的启动项目。如果没有,请创建一个虚拟 C# 项目
【讨论】:
C# 与 C++/CLI 不同【参考方案6】:我在这里的解决方案不会更容易为 Cli 项目添加 Nuget 包支持,但它允许我将 nuget 包添加到我的 Cli 包中。
我收到错误消息:“您正在尝试将此包安装到以 'native,Version=v0.0' 为目标的项目中,但该包不包含 任何与该框架兼容的程序集引用或内容文件。”当我尝试安装 OptiPlot.WPF 或 NuGet.Commandline 时。
这可能不是满足每个人需求的完整解决方案,但它对我有用。我发现了一种将 OptiPlot.WPF 放入示例 C++.Net 项目的“作弊”方式。我的解决方案中有一个 C# 主程序项目 - 我在那里安装了包: 安装包 OxyPlot.Wpf -Version 2.0.0
然后我将 packages.config 文件和 packages 文件夹从那里复制到我的 C++ .Net 类库项目中。然后我编辑了packages.config文件,取出了一些不适用的东西,我可能在不需要的包中取出了一个包。然后我将 C++ .Net 类库项目中的引用添加到 packages/OxyPlot.Wpf.2.0.0 文件夹。
现在我可以在 C++ 中使用 OxyPlot!酷!
【讨论】:
【参考方案7】:上面的答案存在二级依赖问题(至少在我的 Visual Studio 2019 上)。
为了解决这个问题,我通常会创建一个空的 c# 控制台应用程序并引用那里的所有包。
然后我使用这篇文章 build sn-p 将除项目主要工件之外的所有内容复制到解决方案文件夹中名为 packages
的公共存储中。
<Target Name="PostBuild" AfterTargets="PostBuildEvent">
<PropertyGroup>
<SharedLibraries>$(SolutionDir)\packages</SharedLibraries>
</PropertyGroup>
<ItemGroup>
<Artifacts Include="$(OutDir)\**" />
</ItemGroup>
<RemoveDir Condition=" Exists('$(SharedLibraries)')" Directories="$(SharedLibraries)" />
<MakeDir Condition=" !Exists('$(SharedLibraries)')" Directories="$(SharedLibraries)" />
<Copy SourceFiles="@(Artifacts)" DestinationFolder="$(SharedLibraries)\%(RecursiveDir)" />
<ItemGroup>
<ExtraFiles Include="$(SharedLibraries)\$(ProjectName).*"></ExtraFiles>
</ItemGroup>
<Delete Files="@(ExtraFiles)" />
</Target>
整个packages
文件夹随后在 c++/cli 项目中使用自定义任务进行部署。
如果引用的包以 AnyCPU
为目标,则此解决方案适用,否则需要对每个处理器架构使用不同的文件夹进行一些修改,并且可能无法正常工作。
这个解决方案并不优雅,但解决了从 c++/cli 项目可靠地使用 nuget 包(间接)的目的。
与此处发布的其他解决方案相比,此解决方案的优点是路径没有版本控制,因此在正常包升级期间不会更改 c++/cli 项目。
【讨论】:
【参考方案8】:凭据实际上是使用添加包源的机器密钥加密的。除非使用明文变体,否则 setApiKey 命令可能应该作为构建的一部分运行。
【讨论】:
以上是关于如何使我的托管 NuGet 包支持 C++/CLI 项目?的主要内容,如果未能解决你的问题,请参考以下文章
具有托管依赖项的C ++ / XAML UWP NuGet包