从 Nuget 包中自动提取本机和托管 DLL [英] Automatic native and managed DLLs extracting from Nuget Package

查看:24
本文介绍了从 Nuget 包中自动提取本机和托管 DLL的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这让我疯狂了几个月,但我仍然无法实现.我的托管库是从 Nuget 包中提取的,而不是本地库.

我们有一堆由另一家公司提供的托管和本机库.我们有它们的 x86x64 版本.为了在 ASP.NET Core 项目中使用它们,我必须创建一个 Nuget 包.

我的架构是:

  • 我更改为仅针对完整 .NET Framework 的 ASP.NET Core 类库.这个项目引用了我的 Nuget 包
  • 一个 ASP.NET Core 网站也面向完整的 .NET Framework 并引用类库

当然,最后,我需要将我的本机库提取到网站的正确运行时文件夹(例如:inDebug et461win7-x64).

目前我的解决方案是:

  • 将本机库放在 build 文件夹中
  • 创建一个 targets 文件,将它们复制到 $(OutputPath)(甚至不是运行时文件夹)
  • 将一些 MsBuild 命令添加到我网站的 xproj 以获取我的 $(USERPROFILE).nugetpackages 文件夹中的目标文件并执行它
  • 手动现在在 bin 文件夹中提取的本机 DLL 复制到 runtime one

我尝试使用 project.json 中的一些配置将它们直接复制到运行时文件夹(老实说,我不记得我为这部分尝试过的所有事情)但这是总是失败.此外,即使我在目标文件中指定了 SkipUnchangedFiles=true",这也会被忽略,并且我的 DLL 会在每次构建期间复制到我的 bin 文件夹中.

这是一个繁重的过程,只是为了实现 DLL 提取,现在我真的想摆脱所有 MsBuild 并获得更简单的解决方案.

我知道使用较新版本的 Nuget,它现在能够在本地提取它们,而无需添加自定义 MsBuild 命令.正如

我还尝试使用

在这种情况下,您的托管 DLL 将被复制到您项目的输出目录,而不是您的本机目录.

感谢 Jon Skeet 为我指出了好的方向,建议我看看

你的目标文件应该包含这样的内容

<项目工具版本=4.0";xmlns=http://schemas.microsoft.com/developer/msbuild/2003"><项目组条件="'$(平台)' == 'x64' "><Content Include=$(MSBuildThisFileDirectory)..
untimeswin-x64
ativeAAA64.txt"><CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory><链接>AAA64.txt</链接></内容></项目组><项目组条件="'$(Platform)' == 'x86' OR '$(Platform)' == 'AnyCPU' "><Content Include=$(MSBuildThisFileDirectory)..
untimeswin-x86
ativeAAA86.txt"><CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory><链接>AAA86.txt</链接></内容></项目组></项目>

还要确保您的 .targets 文件的名称与您的 AssemblyName 相同.因此,如果程序集的名称是 DemoPackage,则目标文件应命名为 DemoPackage.targets.否则,在另一个项目中引用包时可能不会应用 .targets 文件.

现在您需要了解的其他几件事:

1) Visual Studio 根本不在乎您选择的设置,它将始终使用虚拟 RID.(就我而言,即使我在 Windows 10 上,我也总是得到一个 win7-x64 文件夹......)

2) 平台设置 也完全没用

<代码>{构建选项":{平台":x64"}}

3)运行时设置 如果您只设置了 win 和/或 win-x64

运行时":{赢":{},win-x64":{}}

Visual Studio 将使用 win7-x64.但是如果你在 Windows 10 机器上添加 win10-x64 那么这将被使用

4) 如果您使用这样的通用 RID 编译您的应用程序

dotnet build -c debug -r win

然后你的 targets 文件将接收你机器的架构(在我的例子中是 x64)而不是我期望的 AnyCPU

5) 如果您遵循架构runtimes/RID/native

,只有本地库没有任何托管库,提取将在没有目标文件的情况下工作

6) 在我的包中只有本机库时,所选的 RID 将始终是 win-x64 使用 Visual Studio 构建,因为我告诉过您始终创建的运行时文件夹是win7-x64,无论我选择什么配置.如果我的包中只有一个 win RID,那么它会被成功选中.

最后一个有用的注意事项,在处理此类任务时,您可能会发现像这样打印出正在执行 .targets 文件的当前目录很方便

<Message Text="$(MSBuildThisFileDirectory)";重要性=高"/><消息文本="***************************************************************"重要性=高"/></目标>

您的目录将在 Visual Studio 的 Build 输出中打印出来

This is driving me crazy for several months now and I'm still not able to achieve it. My managed libraries are extracted from the Nuget package but not the natives ones.

We have a bunch of managed and native libraries provided by another company. We have both x86 and x64 version of them. In order to use them in an ASP.NET Core project I have to create an Nuget Package.

My architecture is:

  • an ASP.NET Core class library that I changed to target full .NET Framework only. This project references my Nuget Package
  • an ASP.NET Core website also targeting full .NET Framework and referencing the class library

Of course, at the end, I need my native libraries being extracted to the proper runtime folder of the Website (eg: inDebug et461win7-x64).

For the moment my solution was:

  • to put the native libs inside the build folder
  • create a targets file that copies them to the $(OutputPath) (which is even not the runtime folder)
  • add some MsBuild commands to the xproj of my website to get the targets file in my $(USERPROFILE).nugetpackages folder and execute it
  • copy by hand the native DLLs now extracted in bin folder to the runtime one

I've tried to copy them directly to the runtime folder using some configuration in project.json (I honestly don't remember all the things I've tried for this part) but this was always failing. Also even though I specified SkipUnchangedFiles="true" in my targets file, this is just ignored and my DLLs are copied to my bin folder during each build.

This is an heavy process just to achieve a DLLs extracting, now I really want to get rid of all that MsBuild and get a much simpler solution.

I know with newer versions of Nuget, it's now capable of extracting them natively without any help of adding custom MsBuild commands. As written here, C# projects don't even need a targets file

Next, C++ and JavaScript projects that might consume your NuGet package need a .targets file to identify the necessary assembly and winmd files. (C# and Visual Basic projects do this automatically.)

I kept a tab opened in my browser for several month (original link) and realize this resource has been recently removed from Nuget website. It was explaining how to use the runtimes folder to automatically extract natives DLLs. However I've never been able to get a successful result as it was explained. Now this page has been deleted and replaced by this one with so few explanations and not talking about this runtimes folder at all.

My guess is that I should use runtimes folder for native DLLs and the lib one for managed but I'm not 100% sure of that. (also should I use the build folder?)

I've tried several things (I can't recall number of attempts, as I said several months of headache...) like this architecture (I don't understand here what's the point of having build/native and also natives folders under runtimes)

I also tried to use the .NET framework version structure as described here for my managed libraries.

This seems to be also part of the solution

The architecture is ignored by the compiler when creating an assembly reference. It's a load time concept. The loader will prefer an architecture specific reference if it exists.

One trick you can use to produce an AnyCPU assembly is to use corflags to remove the architecture from your x86 assembly. EG: corflags /32BITREQ- MySDK.dll. Corflags is part of the .NET SDK and can be found in VS's developer command prompt.

That's what I did, converting both x86 and x64 DLLs to AnyCPU (don't know if it does something for x64 DLLs but I didn't get errors) and then tried several different architectures in my Nuget package but still not working.

The default runtime without any entry in project.json is win7-x64, so I decided to explicitly specify it just in case

"runtimes": {
    "win7-x64": {}
},

So this is the Runtime Identifier I'm using for all my attempts in my Nuget package. However I don't care about the windows version. I would actually prefer having win-x86 or win-x64 but it seems to be an invalid value according to this page

Windows RIDs

Windows 7 / Windows Server 2008 R2

  • win7-x64
  • win7-x86

Windows 8 / Windows Server 2012

  • win8-x64
  • win8-x86
  • win8-arm

Windows 8.1 / Windows Server 2012 R2

  • win81-x64
  • win81-x86
  • win81-arm

Windows 10 / Windows Server 2016

  • win10-x64
  • win10-x86
  • win10-arm
  • win10-arm64

However this Github source is describing more RID so which source is right?

As you can see, there is so many mysteries here, mostly because of the lack of documentation or even contradictions between different docs.

If at least I could have a working example, then I could perform my tests to answer other questions like trying generic win-x64 RID or see if I can include once my managed libs whatever the .NET Framework version.

Please pay attention to my special context: I have an ASP.NET Core project targeting the full .NET Framework

Thanks for your answers, I'm desperate to get this simple thing working.

解决方案

I will try to explain all the pain and solutions I've been through as detailed as possible. In my example I use simple text files AAA86.txt, AAA64.txt and AAAany.txt instead of native DLLs to simply demonstrate the extraction process.

First thing you need to know: If you try to mix the native NuGet's architecture with a lib folder containing some managed libraries, IT WILL NOT WORK

In that case your managed DLLs will be copied to your project's output directory but NOT your native ones.

Thanks to Jon Skeet who pointed me in the good direction, advising me to take a look at the Grpc.Core package. The trick is to create a targets file that will handle the DLL extraction.

Your targets file should contain something like this

<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

    <ItemGroup Condition=" '$(Platform)' == 'x64' ">
        <Content Include="$(MSBuildThisFileDirectory)..
untimeswin-x64
ativeAAA64.txt">
            <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
            <Link>AAA64.txt</Link>
        </Content>
    </ItemGroup>

    <ItemGroup Condition=" '$(Platform)' == 'x86' OR '$(Platform)' == 'AnyCPU' ">
        <Content Include="$(MSBuildThisFileDirectory)..
untimeswin-x86
ativeAAA86.txt">
            <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
            <Link>AAA86.txt</Link>
        </Content>
    </ItemGroup>

</Project>

Also make sure your .targets file is named the same as your AssemblyName. So if the name of your assembly is DemoPackage, your targets file should be named DemoPackage.targets. Otherwise, the .targets file might not be applied when referencing the package in another project.

Now few other things you need to know:

1) Visual Studio doesn't care at all about the settings you choose, it will always use a dummy RID. (In my case I always end up with a win7-x64 folder even though I'm on Windows 10...)

2) The platform setting in your project.json is also totally useless

{
    "buildOptions": {
        "platform": "x64"
    }
}

3) In the runtimes settings if you set only win and/or win-x64

"runtimes": {
    "win": {},
    "win-x64": {}
}

Visual Studio will instead use win7-x64. But if you add win10-x64 while you are on a Windows 10 machine then this will be used

4) If you compile your application with a generic RID like this

dotnet build -c debug -r win

Then your targets file will receive the architecture of your machine (x64 in my case) instead of AnyCPU as I was expecting

5) With only native libraries without any managed ones, the extraction will work without a target file if you follow the architecture runtimes/RID/native

6) With only native libraries in my package, the chosen RID will always be win-x64 building with Visual Studio as I told you the runtime folder always created is win7-x64, no matter the configuration I select. If I only had one single win RID in my package then it would successfully be picked.

EDIT:

As a last useful note, when working on such tasks, you might find it convenient to print out the current directory from which your .targets fle is being executed like this

<Target Name="TestMessage" AfterTargets="Build" >
    <Message Text="***********************************************************" Importance="high"/>
    <Message Text="$(MSBuildThisFileDirectory)" Importance="high"/>
    <Message Text="***********************************************************" Importance="high"/>
</Target>

Your directory will be printed out in the Build output in Visual Studio

这篇关于从 Nuget 包中自动提取本机和托管 DLL的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆