为C ++ / CLI(混合)程序集创建NuGet包

时间:2016-11-30 16:18:41

标签: c++-cli nuget

我创建了一个C ++ / CLI(混合)程序集,它有一个围绕某些非托管C ++代码的托管包装类。托管部分以.NET 4.6.1为目标,我得到了一个文件entry.cpp只有这一行来做到这一点:

[assembly:System::Runtime::Versioning::TargetFrameworkAttribute(L".NETFramework,Version=v4.6.1", FrameworkDisplayName = L".NET Framework 4.6.1")];

当我现在在.NET 4.6.1项目中手动包含已编译的程序集时,我可以按预期使用托管类。

此项目可以通过以下四种方式构建: x86 x64 ,作为 debug release 构建。它没有托管依赖项。

现在我想要一个(或者如果需要多个)NuGet包,我可以上传到我的feed并在我希望的每个.NET 4.6.1兼容项目中轻松使用包装器组件。 我如何实现这一目标?

到目前为止,我尝试了两种方法:

首先,我创建了一个.autopkg文件,该文件符合this blog post提供本机DLL的方式。该文件的files部分如下所示:

files {
  // include: { *.h }; 
  [x86,v120,release] {
     symbols: { ..\Release\*.pdb; }
     bin:     { ..\Release\*.dll; }
  };
  [x86,v120,debug] {
     symbols: { ..\Debug\*.pdb; }
     bin:     { ..\Debug\*.dll; }
  };
};

此过程会生成三个.nupkg个文件,我可以将其上传到我的Feed中。但是当我尝试将该软件包安装到.NET 4.6.1项目时,我收到此错误消息:

  

无法安装软件包' MyCppCliWrapper.redist 1.0.0.2'。您正在尝试将此软件包安装到针对.NETFramework,Version = v4.6.1'的项目中,但该软件包不包含任何与该框架兼容的程序集引用或内容文件。有关更多信息,请与软件包作者联系。

所以我重新考虑是否应该使用托管程序集的方式来创建.nupkg,因为程序集有一个我想从托管代码中使用的托管类。我创建了.nuspec(使用nuget spec)并提供了元数据。然后我尝试像这样创建我的包:

nuget pack MyCppCliWrapper.nuspec -Prop Configuration=Release -Prop Platform=x86 -Build

但是这会产生一个包含整个项目的包,包含所有源文件和临时文件,就像该文件夹的zip文件一样。

显然,也缺少有关目标框架的元信息。

当我尝试使用项目文件来创建包时(就像使用C#程序集一样),这也失败了:

  

请指定要使用的nuspec,project.json或项目文件

NuGet似乎不支持C ++项目文件.vcxproj(我正在使用NuGet 3.5.0.1938命令行实用程序)。

我是否需要手动构建并在files的{​​{1}}部分中提供所有文件?如果是的话,他怎么会从这一行知道哪个DLL是针对哪个.NET框架加平台的呢?

.nuspec

我相信Hans Passant是对的,这只是一个常规托管的nuget包,但是包装程序不处理<file src="bin\**\*.dll" target="lib" /> 文件,所以我编写了自己的.vcxproj

.nuspec

以这种方式生成的包有效。

还有一个问题:这样,我是否必须做两个包,一个用于32位,一个用于64位 - 或者是否可以将它们包含在一个包中(我更喜欢)并使用消耗项目一个或另一个取决于目标架构(any-cpu大多是32位)?

1 个答案:

答案 0 :(得分:5)

我不知道这是否仍然可以帮到你,但我已经成功地打包了x64和x86 C ++代码,以及在AnyCPU上编译的C#包装器。

在我的C#项目中,我有两个平台:“x86”和“x64”。

在我的Nuget文件夹中,我有以下结构:

\Project
    \Project.1.0.nuspec
    \build
        \x64
            \*.dll
            \*.pdb
        \x86
            \*.dll
            \*.pdb
        \Project.targets
    \lib
        \net452
            \Wrapper.dll
            \Wrapper.pdb

Project.nuspec:

<?xml version="1.0" encoding="utf-8"?>
<package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
    <metadata>
        <id>Project</id>
        <version>1.0</version>
        <authors>nilsonneto</authors>
        <owners>nilsonneto</owners>
        <requireLicenseAcceptance>false</requireLicenseAcceptance>
        <description>Example.</description>
        <references>
            <reference file="Wrapper.dll" />
        </references>
    </metadata>
    <files>
        <file src="build\Project.targets" target="build\Project.targets" />

        <file src="build\x64\**" target="build\x64" />
        <file src="build\x86\**" target="build\x86" />

        <file src="lib\net452\Wrapper.dll" target="lib\net452\Wrapper.dll" />
        <file src="lib\net452\Wrapper.pdb" target="lib\net452\Wrapper.pdb" />
    </files>
</package>

Project.targets:

<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
 <ItemGroup>
    <NativeLibs Include="$(MSBuildThisFileDirectory)\$(Platform)\*.*" />
    <Content Include="@(NativeLibs)">
      <Link>%(RecursiveDir)%(FileName)%(Extension)</Link>
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </Content>
  </ItemGroup>
</Project>

注意$(Platform),这是在Visual Studio上构建的Platform的名称,这就是为什么我将文件夹中的C ++ DLL与Visual Studio中的平台同名。

根据文档(https://docs.microsoft.com/en-us/nuget/create-packages/native-packages),所有本机DLL都必须放在\ build目录中。

  

以native为目标的Native NuGet包然后在\ build,\ content和\ tools文件夹中提供文件;在这种情况下不使用\ lib(NuGet不能直接添加对C ++项目的引用)。包中还可能包含\ build中的目标和props文件,NuGet会自动导入到使用该包的项目中。这些文件的名称必须与包含.targets和/或.props扩展名的包ID相同。

因此,只需根据您在.NET项目和设置上支持的平台调整文件夹名称。