83

当我从 C# 项目中使用它时,我制作了一个运行良好的 NuGet 包。它在目录中包含一个 DLL lib/net40,并且该 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 下的.propsor.targets文件来执行此操作,但是我需要在这些文件中添加什么才能使其正常工作?

4

8 回答 8

34

As Patrick O'Hara wrote, NuGet will not make changes to a C++/CLI project for you. See GitHub Issue NuGet/Home#1121 - Cannot install managed packages into a CLI project. However, using the NuGet command line utility, NuGet.exe, you can have NuGet download and unpack the desired package(s).

For a complete example, here were steps that I took to add a reference to OptimizedPriorityQueue 1.0.0 in a Visual Studio 2013 C++/CLI project:

  1. Open the Package Manager Console if not already open (TOOLS > NuGet Package Manager > Package Manager Console).
  2. In the Package Manager Console, install the NuGet.CommandLine package:

    Install-Package NuGet.CommandLine
    

    (Note: As of this writing, the latest version of NuGet.CommandLine is 2.8.6. It may be different for you.)

  3. Within your project folder, there should now be a .nuget\packages.config XML file with the following contents:

    <?xml version="1.0" encoding="utf-8"?>
    <packages>
      <package id="NuGet.CommandLine" version="2.8.6" />
    </packages>
    
  4. In a text editor such as Notepad++, add a <package> element for the desired package. In this case, I added:

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

    .. within the <packages> element.

  5. Open a command prompt (I opened a VS2013 Developer Command Prompt, but a regular command prompt should work.)

  6. cd into the project folder.
  7. Run the following command, changing the version number of NuGet.CommandLine if different:

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

    For me, the output was:

    Installing 'OptimizedPriorityQueue 1.0.0.0'.
    Successfully installed 'OptimizedPriorityQueue 1.0.0.0'.
    All packages listed in packages.config are already installed.
    
  8. Right click on the project in Visual Studio and select Properties. Under Common Properties > References, click the Add New Reference… button.
  9. Select Browse on the left hand side. Next to the Add Reference dialog's OK and Cancel buttons, there is a Browse… button. Click that to open a file selection dialog.
  10. Navigate to the DLLs that NuGet unpacked to the packages subdirectory of your project folder and click the Add button. Click OK to close the Add Reference dialog.
  11. You should now be able to use the assembly in your C++/CLI project:

    using namespace Priority_Queue;
    
    //...
    
于 2015-11-03T17:11:45.170 回答
7

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

  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>
    

即使 NuGet 不向 C++/CLI 项目添加程序集引用,它仍会插入包提供的任何.props.targets文件。步骤 1 中的自定义目标将添加对我们打包程序集的引用。

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

于 2016-01-28T17:39:26.130 回答
6

如对此端口的回答中所述(Nuget 不会将实体框架安装到 C++/CLI 项目中),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 项目中。
希望有帮助。

于 2014-10-21T13:47:57.660 回答
3

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

于 2020-04-21T03:29:14.253 回答
1

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

于 2016-11-22T12:50:26.190 回答
1

我的解决方案不会更容易为 Cli 项目添加 Nuget 包支持,但它允许我将 nuget 包添加到我的 Cli 包中。

我收到错误消息:“您正在尝试将此包安装到以 'native,Version=v0.0' 为目标的项目中,但该包不包含任何与该框架兼容的程序集引用或内容文件。” 当我尝试安装 OptiPlot.WPF 或 NuGet.Commandline 时。

这可能不是满足每个人需求的完整解决方案,但它对我有用。我发现了一种将 OptiPlot.WPF 放入示例 C++.Net 项目的“作弊”方式。我的解决方案中有一个 C# 主程序项目 - 我在那里安装了包:Install-Package OxyPlot.Wpf -Version 2.0.0

然后我将 packages.config 文件和 packages 文件夹从那里复制到我的 C++ .Net 类库项目中。然后我编辑了packages.config文件,取出了一些不适用的东西,我可能在不需要的包中取出了一个包。然后我将 C++ .Net 类库项目中的引用添加到 packages/OxyPlot.Wpf.2.0.0 文件夹。

现在我可以在 C++ 中使用 OxyPlot!凉爽的!

于 2021-06-25T00:00:15.390 回答
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 项目。

于 2020-06-17T11:35:39.200 回答
-8

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

于 2014-10-20T01:05:07.363 回答