Adding x86 and x64 libraries to NuGet package

我的梦境 提交于 2019-11-30 01:57:01

After fiddling with this for way too long time I figured it out.

Apparently the build.prop and build.target files need to have the exact same name as the NuGet package has, otherwise it will not be added in the csproj file.

EDIT:

I have created a small github repository showing how to use this for your own project.

It demonstrates a solution with 3 projects, one for iOS one for Android and a Net45 which targets both x86 and x64.

Notice, in the .props file. The paths are pointing at the folder structure of the unpacked NuGet. So these paths map to what you have put in your nuspec file.

So as in the repo, you define a nuspec like:

<?xml version="1.0"?>
<package>
  <metadata>
    <id>My.Awesome.Library</id>
    <version>1.0.0</version>
    <title>My Awesome Library</title>
    <description>Herpa Derpa</description>
  </metadata>
  <files>
    <file src="My.Awesome.Library.Droid\bin\Release\My.Awesome.Library.*"
      target="lib\monodroid70" />

    <file src="My.Awesome.Library.iOS\bin\Release\My.Awesome.Library.*"
      target="lib\xamarin.ios10" />

    <file src="My.Awesome.Library.Net45\bin\x64\Release\My.Awesome.Library.*"
      target="build\x64" />

    <file src="My.Awesome.Library.Net45\bin\x86\Release\My.Awesome.Library.*"
      target="build\x86" />
    <file src="My.Awesome.Library.Net45\bin\x86\Release\My.Awesome.Library.*"
      target="lib\net45" />

    <file src="My.Awesome.Library.props" target="build\net45" />
  </files>
</package>

I put my x86 files in build\x86 and x64 files into build\x64. The name of the folder build could essentially be anything in this case, for these files. What matters here is that the props file, below points at these folders for the respective platforms.

I am not sure whether putting the x86 lib into lib\net45 even matters. You can experiment with that. The props file should pick the correct one for you anyways.

<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <ItemGroup>
    <Reference Include="My.Awesome.Library" Condition="'$(Platform)' == 'x86'">
      <HintPath>$(MSBuildThisFileDirectory)..\x86\My.Awesome.Library.dll</HintPath>
    </Reference>
    <Reference Include="My.Awesome.Library" Condition="'$(Platform)' == 'x64'">
      <HintPath>$(MSBuildThisFileDirectory)..\x64\My.Awesome.Library.dll</HintPath>
    </Reference>
  </ItemGroup>
</Project>

In this case $(MSBuildThisFileDirectory) would be the build\net45\ folder, make sure your path correctly points at the dll's. The build\net45 folder is important here. This is how NuGet automatically imports targets and props files.

Also notice the name My.Awesome.Library is pretty consistent all around. What is important here is that the name of your props file, matches the NuGet package ID. Otherwise it seems like NuGet won't import it.

There are a few things that I disagree with from the above solution. The nuspec file does not have to have any <Files> information if you use the default file structure by adding the files into a nuget folder. But if you want to run the nuget files from your solution folder then it is needed

better nuspec content:

<?xml version="1.0"?>
<package>
  <metadata>
    <id>YourProjectName</id>
    <version>1.0.0</version>
    <authors>John Doe</authors>
    <title>Your Project Name</title>
    <description>Herpa Derpa</description>
  </metadata>
</package>

I also disagree that he has the .dll in the build folder, these should go in your lib folder and in the build folder should contain your .targets and .props files. The documentation for nuget here mentions this.

Also the lib folder are for .dll's that are in your references. Secondly, .dlls added to your build folder are supplementary dll's that might are needed in some cases-similar to how SQlite does it for it's interop dll. So in this case, the better place to keep them is in the lib folder.

Better folder structure:

- nuget
-- project.nuspec
-- build 
---- YourProjectName.props
---- YourProjectName.targets
-- lib 
--- <x64>
---- YourProjectName.dll
--- <x86>
---- YourProjectName.dll

.props file content:

<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <ItemGroup>
    <Reference Include="YourProjectName" Condition="'$(Platform)' == 'x86'">
          <HintPath>$(MSBuildThisFileDirectory)x86\YourProjectName.dll</HintPath>
        </Reference>
        <Reference Include="YourProjectName" Condition="'$(Platform)' == 'x64'">
          <HintPath>$(MSBuildThisFileDirectory)x64\YourProjectName.dll</HintPath>
        </Reference>
      </ItemGroup>
    </Project>

.targets file content:

<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <Target Name="PlatformCheck" BeforeTargets="InjectReference"
    Condition="(('$(Platform)' != 'x86') AND  ('$(Platform)' != 'x64'))">
    <Error  Text="$(MSBuildThisFileName) does not work correctly on '$(Platform)' platform. You need to specify platform (x86 or x64)." />
  </Target>
  <Target Name="InjectReference" BeforeTargets="ResolveAssemblyReferences">
    <ItemGroup Condition="('$(Platform)' == 'x86' or '$(Platform)' == 'x64') and '$(TargetFrameworkVersion)'=='v4.6'">
      <Reference Include=" YourProjectName ">
        <HintPath>$(MSBuildThisFileDirectory)..\..\lib\net46\$(Platform)\ YourProjectName.dll</HintPath>
      </Reference>
    </ItemGroup>
  </Target>
</Project>

You can check that the above worked by opening your nuspec file with the Nuget Package Manager APP and checking all the files you added are picked up. Now when you add these to a project it will load the dll according to the architecure selected for the project it was referenced in. Also notice in the targets file it will raise an error if "Any CPU" is selected, and inform the user they must choose between x86 and x64

EDIT:

One point that was not clarified well was the naming of the .target and .props needs to be the same as the nuget package file name (meaning the version as well). As without this the double reference would appear when re-opening visual studio.

To clarify the whole solution this is the way how it workes perfectly for me

.nuspec file

 <?xml version="1.0"?>
<package>
  <metadata>
    <id>YourProjectName</id>
    <version>1.0.0</version>
    <authors>John Doe</authors>
    <title>Your Project Name</title>
    <description>Herpa Derpa</description>
  </metadata>
</package>

Folder Structure

-- project.nuspec
-- build 
---- YourProjectName.props
---- YourProjectName.targets
-- tools
--- <x64>
---- YourProjectName.dll
--- <x86>
---- YourProjectName.dll

.props file

<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <ItemGroup>
    <Reference Include="YourProjectName" Condition="'$(Platform)' == 'x86'">
          <HintPath>$(MSBuildThisFileDirectory)..\tools\x86\YourProjectName.dll</HintPath>
        </Reference>
        <Reference Include="YourProjectName" Condition="'$(Platform)' == 'x64'">
          <HintPath>$(MSBuildThisFileDirectory)..\tools\\x64\YourProjectName.dll</HintPath>
        </Reference>
      </ItemGroup>
    </Project>

.targets file

<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <Target Name="PlatformCheck" BeforeTargets="BuildOnlySettings"
    Condition="(('$(Platform)' != 'x86') AND  ('$(Platform)' != 'x64'))">
    <Error  Text="$(MSBuildThisFileName) does not work correctly on '$(Platform)' platform. You need to specify platform (x86 or x64)." />
  </Target>

</Project>

That's 100% working solution.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!