M12i.

学術書・マンガ・アニメ・映画の消費活動とプログラミングについて

macOS x NuGet v4.1で*.csprojに基づくパッケージ作成

およそ半年前の記事「maxOS環境でNuGetパッケージをつくる」を投稿した段階では、macOS上でNuGetによるパッケージ作成をしようとしたとき、nuget pack *.csproj -Build ...コマンドを実行した時点でエラーとなる状態でした。*.nuspecファイルによるパッケージングはOKですが、*.csprojファイルに基づくそれはNGだったのです(CLRはMono。Xamarin Studioとともにインストールされたもの)。

しかし数日前に公式サイトから最新版であるv4.1をダウンロードしてパッケージングを試行してみたところこの問題がすでに解消していました。

続く説明は、ターミナルでmonoコマンドが実行でき、かつ、v4.1のnuget.exeをダウンロード済みで、mono (nuget.exeのパス) (NuGetのコマンドライン)という形式で実行できる前提で進めます。

*.nuspectファイルに基づくパッケージング

例えば次のようなディレクトリ構成になっているとき、nuget pack Sample.Project.nuspecコマンドを実行すると、パッケージ(*.nupkgファイル)に封入されるNuGetパッケージ情報は純粋に*.nuspecファイルに記述された情報に基づいたものになります。*.nuspecファイルの内容にはNuGetコマンドを実行する前にプロジェクトの最新の情報を手作業で反映させておく必要があります:

─Sample.Solution
  ├Sample.Solution.sln
  ├...
  └Sample.Project
    ├Sample.Project.csproj
    ├Sample.Project.nuspec
    ├Properties
    │├...
    │└AssemblyInfo.cs
    ├...
    └bin
      ├Debug
      └Release
        ├...
        ├Sample.Project.dll
        └Sample.Project.xml

*.csprojファイルに基づくパッケージング

一方、*.nuspecファイルの内容が次のようなプレースホルダを含むものである場合、nuget pack Sample.Project.csproj -Build ...コマンドを実行すると、まずは*.csprojファイルの情報に基づきデフォルトのビルドが実行されて、成果物が所定のディレクトリに生成されます(コマンドライン...の部分には適宜オプションの引数を指定):

<?xml version="1.0"?>
<package >
  <metadata>
    <id>$id$</id>
    <version>$version$</version>
    <authors>$author$</authors>
    <description>$description$</description>
  </metadata>
</package>

NuGetはこの成果物の中のアセンブリの情報を読み取って、*.nuspecファイルの内容をプレースホルダ部分を補完した上でパッケージに封入します。「アセンブリの情報」は一般にはAssemblyInfo.csファイルに記述する[AssemblyName("Sample.Project")]などの各種の属性(Attribute)により指定されるものです。

これらの属性とプレースホルダの対応関係はMicrosoft社のドキュメント.nuspec referenceに示されています。

*.csprojのビルド設定と*.nuspecのビルド設定の関係

ところでこの*.csprojファイルによるパッケージング──正確に言えば「コマンドラインに*.csprojファイルを指定することで、*.csprojファイルと*.nupkgファイルとアセンブリ情報の定義に基づき行うパッケージング」──では、おおよそ次のような順序で処理が進められているようです:

  1. *.csprojファイルの情報に基づきデフォルトのビルドを実行
  2. *.nuspecファイルをメモリ上にロード
  3. 最前のビルド成果物に含まれるアセンブリからメタ情報を抽出
  4. メモリ上の*.nuspecファイル内容にメタ情報をマージ→パッケージZIPに追加
  5. *.nuspecファイルの<files/>タグの内容に基づきファイル特定→パッケージZIPに追加
  6. 最前のビルド成果物をコピーしパッケージZIPに追加

この最後のビルド成果物のパッケージ封入の際、*.csprojファイルで指定されたビルド・ターゲットの情報に基づき、ZIP内のパスも自動で調整されます。例えば.NET Framework v4.5.2をターゲットとしたビルド成果物の場合、ZIP内のパスはlib/net452/Sample.Project.dllのようになります。

そして*.nuspecファイルの<files/>タグの内容に基づきすでに同名のパスにファイルが存在している場合は、「警告: パッケージには既にファイル 'lib/net452/Sample.Project.dll' が含まれているため、ファイル 'Sample.Solution/Sample.Project/bin/Release/Sample.Project.dll' は追加されません」というような警告ログを出力します。

また*.nuspecファイルに<files/>タグの記述がない場合は「最前のビルド成果物をコピーしパッケージZIPに追加」しか行われないので、その結果生成されるパッケージも*.csprojファイルでターゲット指定したフレームワーク・バージョンにしか対応しないものになります。