web-dev-qa-db-ja.com

NuGetパッケージへのx86およびx64ライブラリの追加

特定のプラットフォーム用のライブラリを構築する必要があるCEFsharpに依存するライブラリを作成しました。そのため、AnyCPUサポートはありません。

これをNuGetにパックします。私が理解している限り、これらのファイルをビルドフォルダーに入れ、参照する正しいdllを選択する.targetsファイルを用意する必要があります。だから私は次のようなNuGetパッケージになりました:

lib
    monodroid
        MyLib.dll
    xamarin.ios10
        MyLib.dll
    net45
        MyLib.dll (x86)
build
    net45
        x86
            MyLib.dll (x86)
        x64
            MyLib.dll (x64)
        MyLib.targets

.targetsファイル内に次のコードを挿入しました:

<?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'">
      <Reference Include="MyLib">
        <HintPath>$(MSBuildThisFileDirectory)$(Platform)\MyLib.dll</HintPath>
      </Reference>
    </ItemGroup>
  </Target>
</Project>

ここまでは順調ですね。今問題に。このNuGetを新しいWPFプロジェクトに追加すると、次のように.csprojファイルにライブラリへの参照が表示されます。

<Reference Include="MyLib, Version=1.0.0.0, Culture=neutral, PublicKeyToken=d64412599724c860, processorArchitecture=x86">
  <HintPath>..\packages\MyLib.0.0.1\lib\net45\MyLib.dll</HintPath>
  <Private>True</Private>
</Reference>

.targetsファイルに関する言及はありません。これはまだNuGet 3でそれを行う方法ですか?私は何か間違ったことをしましたか?現在、これはx86 libへの参照のため、x64を実行しているときに実行時に失敗します。

17
Cheesebaron

あまりにも長い間これをいじった後、私はそれを理解しました。

どうやらbuild.propおよびbuild.targetファイルは、NuGetパッケージとまったく同じ名前を持つ必要があります。そうでない場合、csprojファイルに追加されません。

編集:

私は 小さなgithubリポジトリ を作成しました。これを独自のプロジェクトで使用する方法を示しています。

3つのプロジェクトを含むソリューションを示しています。1つはiOS用、もう1つはAndroid用で、Net45はx86とx64の両方を対象としています。

.propsファイルに注意してください。パスは、解凍されたNuGetのフォルダー構造を指しています。したがって、これらのパスは、nuspecファイルに入力したものにマップされます。

したがって、リポジトリと同様に、次のようなnuspecを定義します。

_<?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>
_

X86ファイルを_build\x86_に入れ、x64ファイルを_build\x64_に入れました。この場合、これらのファイルの場合、フォルダービルドの名前は基本的に何でもかまいません。ここで重要なのは、以下のpropsファイルがそれぞれのプラットフォームのこれらのフォルダーをポイントしていることです。

X86 libを_lib\net45_に入れても問題ないかどうかはわかりません。それを試すことができます。小道具ファイルはとにかくあなたのために正しいものを選ぶはずです。

_<?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>
_

この場合、$(MSBuildThisFileDirectory)は_build\net45\_フォルダになります。パスがDLLを正しく指していることを確認してください。ここでは、_build\net45_フォルダーが重要です。これは、NuGetがターゲットとpropsファイルを自動的にインポートする方法です。

また、_My.Awesome.Library_という名前は、ほぼ一貫しています。ここで重要なのは、propsファイルの名前がNuGetパッケージIDと一致することです。そうでなければ、NuGetはそれをインポートしないようです。

18
Cheesebaron

上記の解決策から私が同意しないことがいくつかあります。 nugetフォルダーにファイルを追加してデフォルトのファイル構造を使用する場合、nuspecファイルに<Files>情報を含める必要はありません。しかし、ソリューションフォルダーからnugetファイルを実行する場合は、それが必要です。

より良いnuspecコンテンツ:

<?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>

私はまた、彼が.dllをbuildフォルダーに持っていることに同意しません。これらはlibフォルダーに移動し、buildフォルダーには.targetsおよび.propsファイル。 nugetのドキュメント here はこれについて言及しています。

また、libフォルダーは、参照内にある.dll用です。第2に、buildフォルダに追加された.dllは、SQliteがinterop dllに対して行う方法と同様に、場合によっては必要になる可能性がある補足dllです。したがって、この場合、それらを保持するためのより良い場所はlibフォルダー内です。

より良いフォルダー構造:

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

.propsファイルの内容:

<?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ファイルの内容:

<?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>

Nuget Package Manager APPでnuspecファイルを開き、追加したすべてのファイルが選択されていることを確認することで、上記が機能したことを確認できます。これらをプロジェクトに追加すると、参照先のプロジェクトで選択されたアーキテクチャに従ってDLLがロードされます。また、「Any CPU」が選択されている場合はターゲットファイルでエラーが発生し、ユーザーに通知されます。 x86とx64のどちらかを選択する必要があります

編集:

明確にされなかった点の1つは、.targetおよび.propsの名前がnugetパッケージファイル名と同じである必要があることです(バージョンも意味します)。 これがないと、ビジュアルスタジオを再び開くときに二重参照が表示されます

5
JohnChris