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

15

我创建了一个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项目中,我可以按预期使用托管类。

该项目可以通过四种方式构建:x86x64作为debugrelease版本。 它没有托管依赖项。

现在我想要一个(如果需要多个)NuGet软件包,我可以上传到我的Feed中,并轻松地在任何我想要的.NET 4.6.1兼容项目中使用包装器程序集。我该如何实现这一点?


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

首先,我创建了一个.autopkg文件,根据这篇博客文章提供本机DLL的方法。该文件的files部分如下所示:

files {
  // include: { *.h }; 
  [x86,v120,release] {
     symbols: { ..\Release\*.pdb; }
     bin:     { ..\Release\*.dll; }
  };
  [x86,v120,debug] {
     symbols: { ..\Debug\*.pdb; }
     bin:     { ..\Debug\*.dll; }
  };
};
这个过程会生成三个.nupkg文件,我可以上传到我的资源库。但是当我尝试将该包安装到.NET 4.6.1项目时,会出现以下错误信息:

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


所以我重新考虑了一下是否应该使用托管程序集的方式来创建.nupkg,因为该程序集具有我想要从托管代码使用的托管类。我创建了一个.nuspec(使用nuget spec),并提供了元数据。然后我尝试按照以下方式创建我的包:
nuget pack MyCppCliWrapper.nuspec -Prop Configuration=Release -Prop Platform=x86 -Build

然而,这会生成一个包含整个项目的所有源文件和临时文件的软件包,就像该文件夹的 zip 文件一样。

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

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

请指定一个 nuspec、project.json 或 project 文件以供使用

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

我需要手动构建并在 .nuspecfiles 部分提供所有文件吗? 如果是的话,他如何知道此行中的 DLL 是哪个 .NET 框架加平台的文件?

<file src="bin\**\*.dll" target="lib" />

我相信Hans Passant是正确的,这只是一个普通的托管nuget包,但打包程序不处理.vcxproj文件,所以我自己编写了.nuspec文件:

<?xml version="1.0"?>
<package >
  <metadata>
  ...
  </metadata>
  <files>
    <file src="readme.txt" target="" />
    <file src="bin\Win32\Release\*.dll" target="lib\net461" />
    <file src="bin\Win32\Release\*.pdb" target="lib\net461" />
  </files>
</package>

这种生成的软件包可行。

还有一个问题:我是否需要制作两个软件包,一个用于32位系统,另一个用于64位系统?或者是可以将它们包含在一个软件包中(我更喜欢这种方式),并且让使用者根据目标架构(any-cpu mostly 32bit)使用其中之一?


1
可能是如何使我的托管NuGet包支持C++/CLI项目?的重复问题。 - Hans Passant
@HansPassant,我倾向于回答不行,因为我的包中没有普通托管程序集,只有带托管类的C++/CLI。但我也会尝试一些这篇帖子中的方法,并做出反馈。 - ZoolWay
2
你只是跟错了教程,它只适用于纯本地C++项目。在IDE中也不能添加对本地DLL的引用。无论如何,C++/CLI程序集仍然是.NET程序集,并像其他任何.NET程序集一样具有元数据,这很重要。要解决Nuget打包程序无法处理.vcxproj文件的限制,需要采取特定措施。 - Hans Passant
@HansPassant 是的,看起来你是对的。我用我的.nuspec编辑了问题 - 我可以为32位和64位架构拥有一个软件包吗? - ZoolWay
@ZoolWay - "还有一个问题未解决:这样做,我是否需要制作两个包,一个32位,一个64位的?" - 你解决了这个问题吗?或者找到了答案吗? - Dave Thieben
1个回答

10

我不知道这是否仍然能帮到您,但我已经成功打包了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

项目文件.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>

项目目标:

<?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构建时所放置的平台名称,这就是我将C++ DLLs分别放在与Visual Studio中平台同名的文件夹中的原因。

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

针对本地的NuGet包会提供位于\build、\content和\tools文件夹中的文件;这种情况下不使用\lib(NuGet无法直接向C++项目添加引用)。包还可以在\build中包括目标文件和属性文件,NuGet将自动导入到消费该包的项目中。这些文件的名称必须与软件包ID相同,并带有.targets和/或.props扩展名。

因此,只需根据.NET项目支持的平台调整文件夹名称即可。


1
如果存在一些翻译文件(依赖于语言),它们应该放在NuGet路径的哪里?在我的情况下,我有几个XML文件,分别为英语和德语提供本机库/应用程序。我将基于x64的应用程序放置在build\native\x64*.dll下,所以翻译文件应该放在哪里呢?谢谢 - Zenwalker
1
这是本地的C++还是CLI?你能告诉我更多关于包装器的信息吗? - Jakub Pawlinski
你会如何在AnyCPU平台上支持消费者? - Jakub Pawlinski
@Zenwalker 我相信你可以将这些文件放在 content* 目录下。根据 .nuspec 的文档,任何放在那里的东西 "都会被复制到项目根目录。将 content 文件夹视为最终使用该包的目标应用程序的根目录。要让包在应用程序的 /images 文件夹中添加图像,请将其放置在包的 content/images 文件夹中。" - nilsonneto
@JakubPawlinski 我的包装器是基于C#构建的,用于C++ DLL,并将平台设置为AnyCPU,因为控制它将访问的DLL是.nuspec。 至于对AnyCPU平台的支持,我不太确定您的意思,因为它基本上与x86相同(有关详细信息,请参见此处:http://blogs.microsoft.co.il/sasha/2012/04/04/what-anycpu-really-means-as-of-net-45-and-visual-studio-11/) - nilsonneto
这并不是使用C++/CLI,因此它并不是帖子作者要寻找的答案。封装器内部有一些未说明的魔法来解决不同体系结构和Debug/Release差异的问题。 - Andrew Robinson

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接