如何使我的托管NuGet包支持C ++ / CLI项目?

时间:2013-09-09 09:11:02

标签: .net dll c++-cli nuget nuget-package

我已经制作了一个NuGet包,当我在C#项目中使用它时效果很好。它包含lib/net40目录中的DLL,并添加DLL作为参考。

现在NuGet支持C ++,我如何实际修改我的包,以便可以在C ++ / CLI项目中将DLL添加为托管引用?我找不到任何解释这个的教程。如果我尝试按原样添加包,则会收到以下错误:

  

您正在尝试将此软件包安装到以“Native,Version = v0.0”为目标的项目中,但该软件包不包含任何与该框架兼容的程序集引用或内容文件。

有人会认为解决方案是将文件放在lib / native下,但根据http://docs.nuget.org/docs/reference/support-for-native-projects,这是不受支持的。此外,简单地将DLL直接放在lib下似乎没有做任何事情。

显然,我应该使用构建/本机下的.props.targets文件来执行此操作,但是我需要将这些文件放入这些文件中以使其工作?

8 个答案:

答案 0 :(得分:20)

作为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的引用的步骤:

  1. 打开软件包管理器控制台(如果尚未打开)( TOOLS> NuGet软件包管理器>软件包管理器控制台)。
  2. 在软件包管理器控制台中,安装NuGet.CommandLine软件包:

    Install-Package NuGet.CommandLine
    

    (注意:在撰写本文时,NuGet.CommandLine的最新版本为2.8.6。对您而言可能有所不同。)

  3. 在项目文件夹中,现在应该有一个.nuget\packages.config XML文件,其中包含以下内容:

    <?xml version="1.0" encoding="utf-8"?>
    <packages>
      <package id="NuGet.CommandLine" version="2.8.6" />
    </packages>
    
  4. 在Notepad ++等文本编辑器中,为所需的包添加<package>元素。在这种情况下,我补充说:

    <package id="OptimizedPriorityQueue" version="1.0.0" />
    

    ..在<packages>元素内。

  5. 打开命令提示符(我打开了VS2013开发人员命令提示符,但常规命令提示符应该有效。)

  6. cd进入项目文件夹。
  7. 运行以下命令,如果不同,则更改NuGet.CommandLine的版本号:

    .\packages\NuGet.CommandLine.2.8.6\tools\NuGet.exe Install -NonInteractive -OutputDirectory packages .nuget\packages.config
    

    对我来说,输出是:

    Installing 'OptimizedPriorityQueue 1.0.0.0'.
    Successfully installed 'OptimizedPriorityQueue 1.0.0.0'.
    All packages listed in packages.config are already installed.
    
  8. 右键单击Visual Studio中的项目,然后选择属性。在公共属性&gt;下参考,点击添加新参考... 按钮。
  9. 选择左侧的浏览。在“添加引用”对话框的“确定”和“取消”按钮旁边,有一个浏览... 按钮。单击该按钮打开文件选择对话框。
  10. 导航到NuGet解压缩到项目文件夹的packages子目录的DLL,然后单击添加按钮。单击确定以关闭“添加引用”对话框。
  11. 您现在应该可以在C ++ / CLI项目中使用程序集:

    using namespace Priority_Queue;
    
    //...
    

答案 1 :(得分:5)

正如对此端口(Nuget won't install Entity Framework into C++/CLI project)的回答所述,NuGet不会为您更改C ++ / CLI项目。然而,它将为您下载和解包依赖项。我们从命令行使用它作为make依赖项的一部分。命令行看起来像这样:

/.NuGet/NuGet.exe
      Install 
      -NonInteractive 
      -ConfigFile $ENV{SRC_ROOT}/.nuget/NuGet.config 
      -OutputDirectory $ENV{SRC_ROOT}/packages 
      $ENV{SRC_ROOT}/packages.config

请注意,命令行参数将一行分隔为一行,以便于阅读。我们还决定将NuGet检入我们的源代码控制,而不是.NuGet文件夹。目标是使我们可以更轻松地为各种环境设置构建机器(并非所有环境都使用Visual Studio)。首次运行此命令后,必须手动将依赖项添加到C ++ / CLI项目中 希望有所帮助。

答案 2 :(得分:5)

似乎有可能使用以下步骤(至少使用NuGet >= 2.5)来安装和自动从C ++ / CLI项目中引用“常规”NuGet包:

  1. 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>
    
  2. 在打包项目的.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>
    
  3. 即使NuGet没有向C ++ / CLI项目添加程序集引用,它仍会插入程序包提供的任何.props.targets文件。步骤1中的自定义目标将添加对我们的打包组件的引用。

    根据我的意见,此解决方案的一个缺点是以这种方式添加的引用未显示在C ++ / CLI项目的Commpon Properties/Framework and References部分中。可能还有其他人,所以使用它需要您自担风险......

答案 3 :(得分:1)

安装程序尝试在C#启动项目中添加对自身的引用。在安装之前,将C#项目作为解决方案中的启动项目。如果没有一个

,请创建一个虚拟C#项目

答案 4 :(得分:1)

简便的解决方法是将这样的NuGet包装在常规.NET项目(C#)中,并在您的C ++ / CLI项目中引用相同的内容。

答案 5 :(得分:0)

上面的答案存在二级依赖项问题(至少在我的Visual Studio 2019中是这样的)。

为解决此问题,我通常创建一个空的c#控制台应用程序,并在此引用所有软件包。

然后,我使用此后构建代码段将项目主要工件以外的所有内容复制到解决方案文件夹中名为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项目在常规软件包升级期间将永远不会更改。

答案 6 :(得分:0)

我的解决方案并没有让为 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 类库项目中的引用添加到包/OxyPlot.Wpf.2.0.0 文件夹中。

现在我可以在 C++ 中使用 OxyPlot 了!酷!

答案 7 :(得分:-7)

凭据实际上是使用添加了包源的machinekey加密的。除非使用明文变体,否则setApiKey命令应该作为构建的一部分运行。