Visual Studio 2019 と新 csproj への移行

2019 年 4 月 2 日、Visual Studio 2019 が正式版としてリリース (GA: General Available) されました。この記事では、 Visual Studio 2019 に関連する内容として、C# の新しいプロジェクト形式 (csproj) への移行について記載します。新 csproj 自体は Visual Studio 2017 の頃から利用可能でしたが、WinForms や WPF などのプロジェクトに対する Visual Studio 側の対応も 2019 で進んだようなので、移行するには良いタイミングではないでしょうか。

新 csproj の基本的な構成

新しい csproj 形式では、システム側が既定値を設ける事により、多くの項目が省略可能となりました。これは、Visual Studio による自動生成・更新を前提にした複雑なものから、手動による更新も想定した簡素なものへの転換と言う感じで、特にバージョン管理などの観点から見ると非常に楽になったように思います。

以下に、新 csproj において省略しない方が良い(多くの場合、初期設定とは異なる)ものを記述します。

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>net45</TargetFramework>
    <LangVersion>latest</LangVersion>
    <Platforms>AnyCPU;x86;x64</Platforms>
    <Optimize>true</Optimize>
    <EnableDefaultNoneItems>false</EnableDefaultNoneItems>
    <GenerateDocumentationFile>true</GenerateDocumentationFile>
    <DefineConstants Condition=" '$(Configuration)' == 'Debug' ">DEBUG;TRACE</DefineConstants>
  </PropertyGroup>
</Project>

TargetFramework には net45, netcoreapp3.0, netstandard2.0 などの文字列を指定します(参考:Target Frameworks Reference for NuGet)。この項目は、旧 csproj の TargetFrameworkVersion から置き換わったものです。また、新 csproj 形式では TargetFrameworks(複数形)を代わりに用いる事で、複数の TargetFramework を ";" (semicolon) で区切って列挙する事もできるようです。

LangVersion には C# のバージョンを指定します(参考:Select the C# language version)。具体的なバージョン番号を指定する事もできますが、多くの場合においては、latest または latestMajor のどちらかだと思います。Visual Studio 2019 においては LangVersion の初期設定は latest なので、この項目は省略しても問題ありません。ただ、AppVeyor 等で継続的インテグレーション (CI: Continuous Integration) を実行する際に意図しない挙動をいくつか確認したため、明記する事にしています。

PlatformsVisual Studio 上で x86 や x64 を選択可能にしたい時に明記します。C#/.NET では多くの場合において AnyCPU で良いと思いますが、Unmanaged なライブラリとの兼ね合いでプラットフォームを固定したい場合などに設定します。

GenerateDocumentationFile は、XML Documentation Comments に従って記述されたコメントに基づいて XML ファイルを生成するかどうかを決定します。尚、XML ファイル自体は後述する DocumentationFile に出力パスを記述すれば、この項目がなくても生成されます。しかし、その場合には生成された XML ファイルが NuGet パッケージ (*.nupkg) に含まれないようです。NuGet パッケージにも含める場合、この項目を true で明記する必要があります。

DefineConstants は必要なシンボルを記述するための項目ですが、省略時には TRACE のみが設定されるようです。多くの場合、Debug モード時には TRACE に加えて DEBUG シンボルの存在も想定されているので、それを明記しています。

既定の Include に関する設定

新 csproj では、ソースファイル等に関する記述をできるだけ省略可能にするために、既定では以下の規則で自動的に Include される事になっています(参考:Default compilation includes in .NET Core projects)。

Element Include Remove
Compile **/*.cs N/A
EmbeddedResource **/*.resx N/A
None **/* **/*.cs; **/*.resx

しかし、これらの Include 規則は邪魔になる事もあるため、無効にする方法もいくつか提供されています。具体的には、上記の全ての規則を無効にするには EnableDefaultItems を、Compile および None の項目のみを無効にするにはそれぞれ EnableDefaultCompileItems, EnableDefaultNoneItems を false で記述します(EnableDefaultEmbeddedResourceItems が存在するかどうかは不明)。

個人的には None の Include 規則には不安に感じる所もあるため、EnableDefaultNoneItems を false に設定した上で自力で明記する事にしています。

NuGet パッケージに関する設定

新 csproj では、従来 AssemblyInfo.cs および *.nuspec に記述されていた内容が全て csproj に統合されました。生成されるアセンブリのメタ情報、および NuGet パッケージに関する項目は下記の通りです。

<PropertyGroup>
  <Version>1.0.0</Version>
  <Authors>clown;cube-soft</Authors>
  <Company>CubeSoft</Company>
  <Description>Some description.</Description>
  <Copyright>Copyright © 2010 CubeSoft, Inc.</Copyright>
  <PackageTags>Ta1;Tag2;Tag3</PackageTags>
  <PackageLicenseExpression>Apache-2.0</PackageLicenseExpression>
  <PackageProjectUrl>https://github.com/cube-soft/$(AssemblyName)</PackageProjectUrl>
  <PackageIconUrl>https://github.com/cube-soft/$(AssemblyName)/blob/master/Icon.png?raw=true</PackageIconUrl>

  <!-- プロジェクト名と異なる場合 -->
  <Product>Cube.Custom.Product</Product>
  <AssemblyName>Cube.Custom.Product</AssemblyName>
  <AssemblyTitle>Custom Title</AssemblyTitle>
  <RootNamespace>CustomNamespace</RootNamespace>

  <!-- NuGet パッケージの生成可否を明記する場合 -->
  <IsPackable>true</IsPackable>

  <!-- 厳密な名前付けに関する設定 -->
  <SignAssembly>true</SignAssembly>
  <AssemblyOriginatorKeyFile>Cube.snk</AssemblyOriginatorKeyFile>
</PropertyGroup>

PackageLicenseExpression には、成果物(NuGet パッケージ)に適用するライセンスを指定します。指定可能な文字列に関しては SPDX License List を参照下さい。これまで、ライセンスは URL で指定していましたが、NuGet の仕様変更により deprecated となったようです。

Product, AssemblyName, AssemblyTitle, RootNamespace の 4 種類は、省略時にはプロジェクト名(csproj 拡張子を除く名前)が設定されます。

IsPackable は、プロジェクトが NuGet パッケージを生成可能かどうかを指定します。既定値は true なので明記する必要性は薄いと思いますが、AppVeyor 等の CI サービスにおいて、自動的に NuGet パッケージを生成して欲しくない時などに false を設定する事があります。

SignAssembly および AssemblyOriginatorKeyFile は、厳密な名前付けに関する項目です。これらの項目は旧 csproj と同じなので、詳細は省略します。

AnyCPU に関する設定

新 csproj は Platform が AnyCPU の場合、初期設定では(例えば)"bin/Release/net45" に出力されます(ちなみに、旧 csproj は "bin/Release")。

<PropertyGroup Condition=" '$(Platform)' == 'AnyCPU' ">
  <OutputPath>bin\Any CPU\$(Configuration)\</OutputPath>
  <DocumentationFile>bin\Any CPU\$(Configuration)\$(TargetFramework)\$(AssemblyName).xml</DocumentationFile>
</PropertyGroup>

多くの場合においては初期設定のままで問題ないと思いますが、AppVeyor 等の CI サービスにおいて意図しない挙動をいくつか確認したため、AnyCPU の OutputPath を上記のように設定しています。尚、新 csproj では OutputPath で設定された文字列に $(TargetFramework) を追加したものが実際の出力パスとなるようです。

Properties.Resources に関する設定

前述した通り、新 csproj において *.resx ファイルは EmbeddedResource として自動的に Include されます。しかし、この状態では Visual Studio 上でのリソース編集が Resources.Designer.cs に反映されません。これを反映させるには、旧 csproj で指定されていた内容を明記する必要があります。

<ItemGroup>
  <Compile Update="Properties\Resources.Designer.cs" DependentUpon="Resources.resx" AutoGen="True" DesignTime="True" />
  <EmbeddedResource Update="Properties\Resources.resx" Generator="ResXFileCodeGenerator" LastGenOutput="Resources.Designer.cs" />
</ItemGroup>

ここで重要なのは、Update 属性を使用している点です。*.resx は全て追加済みとなっているため、Include 属性で明記すると重複エラーとなります。これを回避するには、一つは前述した EnableDefaultItems に false を設定する事、そしてもう一つが Update 属性を使用する事です。

尚、パスの区切り文字を "/" (slash) にした場合、Visual Studio 上でリソースを編集したタイミングで csproj が自動的に編集されてしまいました("Properties/Resources" と "Properties\Resources" が両方とも記述される)。少なくとも .NET Framework をターゲットにしている場合、もうしばらくは "\" (backslash) を使用するほうが無難なようです。

参照に関する設定

新 csproj では、参照に関する記述方法も簡素化されています。特に、これまで packages.config と旧 csproj の 2 種類のファイルに記述されていた NuGet パッケージの参照内容が、新 csproj では PackageReference と言う項目に統合されました。

<ItemGroup>
  <ProjectReference Include="..\Another\Another.csproj" />
  <PackageReference Include="SomePackage" Version="1.0.0" />
  <Reference Include="System.For.Bar" />
</ItemGroup>

ProjectReference や PackageReference は推移的な参照をサポートしており、ProjectReference の ProjectReference や PackageReference の PackageReference などは自動的に解決してくれます。このため、新 csproj には直近のプロジェクトまたは NuGet パッケージの参照のみを追加すれば OK です。ただし、推移的なプロジェクト参照に関しては、全てのプロジェクトが新 csproj 形式でなければならないそうです(参考:新しい csproj 形式)。

削除するファイル一覧

前述したように、新しい csproj 形式では、これまでいくつかのファイルに分割して記述されていた情報が一つのファイルに統合されました。そのため、以下のファイルは必要な情報を csproj に記述した後に削除する必要があります。

  • **/Properties/AssemblyInfo.cs
  • **/packages.config
  • **/*.nuspec

WinForms

ここからは、WinForms および WPF アプリケーションの新 csproj について説明します。

基本的な構成

WinForms の基本的な設定は下記の通りです。尚、これまで記述した内容の多くを省略していますが、それらの設定も必要に応じて追加して下さい。

<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
  <PropertyGroup>
    <OutputType>WinExe</OutputType>
    <TargetFramework>net45</TargetFramework>
    <UseWindowsForms>true</UseWindowsForms>
    <EnableDefaultNoneItems>false</EnableDefaultNoneItems>
    <ApplicationIcon>App.ico</ApplicationIcon>
    <ApplicationManifest>App.manifest</ApplicationManifest>
  </PropertyGroup>
</Project>

重要な点は、Project の Sdk 属性を Microsoft.NET.Sdk.WindowsDesktop にする事と、UseWindowsForms を true で明記する事です(参考:Windows Desktop)。これらの項目の意味については、後述します。

OutputType の規定値は Library のようです。そのため、WinForms や WPF アプリケーションの場合、この項目を WinExe に設定します。

ApplicationIcon および ApplicationManifest には、アイコン等のファイルを指定します。これらの項目は旧 csproj と同じなので、詳細は省略します。

Microsoft.NET.Sdk.WindowsDesktop に関して

Visual Studio 2019 かつ .NET Core 3.0 の環境において新たに指定可能となった Microsoft.NET.Sdk.WindowsDesktop および UseWindowsForms ですが、手元の環境で確認した限り、.NET Framework では既定の参照内容に影響を及ぼすようです*1。以下の図は、UseWindowsForms の設定値と Visual Studio 2019 上で確認できる参照内容の対応関係を表したものになります。

UseWindowsForms の設定による違い

この図を見ると、UseWindowsForms が true の場合、WinForms ライブラリである System.Windows.Forms が参照に追加されている事が分かります。他に UseWPF と言う項目も存在しますが、true にした場合には同様に PresentationCore 等の WPF に必要なライブラリが参照に追加されます。ただし、これらの項目は SdkMicrosoft.NET.Sdk.WindowsDesktop の場合のみ有効で、Microsoft.NET.Sdk の場合は無視されます。

注意点として、Visual Studio 2017 では、.NET Core 3.0 SDK の有効・無効に関わらず Microsoft.NET.Sdk.WindowsDesktop を指定したプロジェクトの読み込みに失敗します。また、Visual Studio 2019 であっても .NET Core 3.0 が無効の場合、ビルドに失敗します。したがって、これらの環境との互換性を考慮する場合、SdkMicrosoft.NET.Sdk を指定した上で各種ライブラリの参照を明記する必要があります。

Include および Update 規則

WinForms におけるソースファイル等の Include および Update 規則に関する記述内容は下記になります。

<ItemGroup>
  <Compile Update="Views\**\*.cs" SubType="Form" />
  <Compile Update="Views\**\*.Designer.cs" SubType="Code" />
  <EmbeddedResource Update="Views\**\*.resx" DependentUpon="%(Filename).cs" />
  <None Include="Assets\**\*" />
  <None Include="App.config" />
</ItemGroup>

この中で最低限必要な項目は EmbeddedResource です。前述したように *.resx は自動的に Include されますが、これだけだと Form にアイコンを設定している場合などで実行時エラーが発生します。これを防止するために WinForms に関連する *.resx に対して、DependentUpon 属性を指定する形で Update します。尚、Include や Update にワイルドカードで指定した場合、"%(Filename)" で各ファイルの拡張子を除いた名前を取得できるようです。

2 種類の Compile 設定は、各種 Form を Visual Studio のデザイナ上で編集可能にするための設定です。ただし、これらの設定は Visual Studio 2017 では効果がありませんでした。

WPF

次は、WPF アプリケーションの新 csproj について説明します。

基本的な構成

WPF の基本的な設定は下記の通りです。UseWindowsForms が UseWPF に置き換わったのみで、それ以外は全て WinForms と同様です。

<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
  <PropertyGroup>
    <OutputType>WinExe</OutputType>
    <TargetFramework>net45</TargetFramework>
    <LangVersion>latest</LangVersion>
    <UseWPF>true</UseWPF>
    <EnableDefaultNoneItems>false</EnableDefaultNoneItems>
    <ApplicationIcon>App.ico</ApplicationIcon>
    <ApplicationManifest>App.manifest</ApplicationManifest>
  </PropertyGroup>
</Project>

尚、前述したように UseWindowsForms および UseWPF は各ライブラリの参照設定に関するもののようなので、併記する事も可能です。WPF の場合、GUI コンポーネントが足りない等の理由で WinForms を併用する事もあるので、その場合には UseWindowsForms も true で設定します。

Include および Update 規則

WPF におけるソースファイル等の Include および Update 規則に関する記述内容は下記になります。

<ItemGroup>
  <ApplicationDefinition Include="App.xaml" SubType="Designer" Generator="MSBuild:Compile" />
  <Page Include="Views\**\*.xaml" SubType="Designer" Generator="MSBuild:Compile" />
  <Compile Update="Views\**\*.xaml.cs" SubType="Code" DependentUpon="%(Filename)" />
  <Resource Include="Assets\**\*" />
  <None Include="App.config" />
</ItemGroup>

まず、App.xaml を ApplicationDefinition で明記する必要があります。次に、Page および Compile の項目で、それ以外の *.xaml ファイル(およびコードビハインドに当たる *.cs ファイル)を追加します。この時、App.xaml が同じディレクトリに存在すると重複エラーとなります。その場合は、Page の項目に対して Exclude="App.xaml" と言う記述を追加して下さい。個人的には、ディレクトリ階層で区分する事で解決するようにしています。

新 csproj 具体例へのリンク一覧

最後に、これまでに説明した内容を実際のプロジェクトで記述したものをサンプルとしていくつか紹介します。

*1:尚、TargetFramework を netcoreapp3.0 に設定した場合、現時点では Microsoft.NET.Sdk.WindowsDesktop と記述した時点で UseWindowsForms, UseWPF の設定に関わらず全ての WinForms/WPF ライブラリが参照に追加されるようです。

Azure Pipelines で OpenCover/NUnit を実行し Codecov に送信

CubeSoft の各種プロジェクトでは、継続的インテグレーション (CI: Continuous Integration) 用サービスとして AppVeyor を利用していますが、諸々の事情を考慮して Azure Pipelines でも同等の CI を実行できるように環境の整備を進めています。この記事では、Azure Pipelines での CI、特に OpenCover/NUnit を用いてユニットテストを実行し、結果を Codecov に送信するまでの手順について記述します。

概要

前提として、何らかの csproj (多くの場合、ユニットテスト用のプロジェクト)に対して下記の PackageReference が記述されている事とします。

<ItemGroup>
    <PackageReference Include="NUnit" Version="3.11.0" />
    <PackageReference Include="NUnit.ConsoleRunner" Version="3.10.0" />
    <PackageReference Include="OpenCover" Version="4.7.922" />
</ItemGroup>

この状態で、下記のタスクを実行するように YAML ファイルを編集していきます。

  1. NuGet Resotre
  2. Build
  3. Run OpenCover with NUnit
  4. Send to Codecov
  5. Publish test results
  6. NuGet Pack
  7. Publish pipline artifacts

ここでは、ユニットテストに関係のある 3. ~ 5. の記述を抜粋します。下記を含む全ての記述内容は AzurePipelines.yml を参照下さい。*1

- script: >
    "$(TEST_TOOL)"
    -log:Error
    -register:user
    -target:"$(TEST_CORETOOL)"
    -targetargs:"$(PROJECT_NAME).Tests.dll"
    -targetdir:"Tests\$(PROJECT_BIN)"
    -returntargetcode
    -hideskipped:All
    -output:"$(TEST_COVERAGE)"
    -filter:"$(TEST_FILTERS)"
  displayName: 'Run tests via OpenCover and NUnit'

- script: |
    pip install codecov
    codecov -f "$(TEST_COVERAGE)" -t $(CODECOV_TOKEN)
  displayName: 'Send coverage results to Codecov'

- task: PublishTestResults@2
  inputs:
    testResultsFormat: 'NUnit'
    testResultsFiles: '**\$(TEST_RESULT)'
  displayName: 'Publish test results'

最初の task (script) で OpenCover を実行し、次の task で Codecov に結果を送信します。尚、この記事の執筆時点では、Azure Pipelines から Codecov に結果を送信するためにはトークンを指定する必要があります。そのため、How to integrate codecov.io in an Azure Build Pipeline を参考にして、あらかじめ CODECOV_TOKEN と言う環境変数を作成し、必要な値を Secret 設定で追加しておいて下さい。

Azure Pipelines の環境変数

最後の task で Azure Pipelines 上にテスト結果を送信します。PublishTestResults タスクを実行すると、各ビルドの Tests タブに結果が表示されるようになります。

Azure Pipelines 上でのテスト結果

備考

これ以降は、今回 Azure Pipelines 上で CI 環境を整えるにおいて、嵌まったポイント等いくつかの関連事項を記述します。

NuGet task を利用した Restore

NuGet に関連するコマンドは NuGet task が用意されており、Restore に関しても通常はこの task を利用します。

- task: NuGetCommand@2
  inputs:
    command: 'restore'
    restoreSolution: '$(PROJECT_NAME).sln'
    #feedsToUse: 'config'
    #nugetConfigPath: 'NuGet.config'
  displayName: 'Restore NuGet packages'

しかし、NuGetCommand@2 経由で実行した場合、初期設定ではカレントディレクトリに存在する NuGet.config は無視されます。config ファイルを反映させるには feedsToUse および nugetConfigPath 引数を利用するようなのですが、実際に試した所、今度は api.nuget.org が Source として認識しないような挙動を示しました。恐らく、明示的に config を指定した場合、この辺りも含めて設定する必要があるものと予想されます。

- script: |
    nuget restore "$(PROJECT_NAME).sln"
  displayName: 'Restore NuGet packages'

以上を考慮すると、NuGet.config を用意している場合、現時点では上記のように script で実行する方が楽なようです。

GitHub Releases からダウンロード

依存するライブラリが全て NuGet パッケージとして取得できれば良いのですが、必ずしもそうではない場合もあります。例えば、CubeICE は 7z.dll と言うライブラリに依存しています。ここでは、このライブラリを Releases - cube-soft/7z から取得する事を試みます。

- task: DownloadGitHubRelease@0
  inputs:
    connection: 'cube-soft-ci'
    userRepository: 'cube-soft/7z'
    itemPattern: '7z-*-x64.zip'
    downloadPath: '$(Build.SourcesDirectory)'
  displayName: 'Download 7-Zip modules'

GitHub Releases からのダウンロードには Download GitHub Release task を利用します。userRepository に対象となるリポジトリの名前、itemPattern にダウンロードするファイルを表す文字列、downloadPath に保存ディレクトリのパスを指定します。

connection には、Service connections と呼ばれる機能で作成した文字列を記述します。作成手順は、まず Creating a personal access token for the command line を参考に、GitHub 上でトークンを生成します(生成時に指定するスコープに関しては、repo, user, admin:repo_hook が推奨されているようです)。次に、Azure Pipelines の左下にある Project settings から Service connections を選択し、New service connection で GitHub を選択します。

Service connection の新規作成

新規作成画面で Personal access token を選択し、Connection Name には適当な名前、Token には GitHub で取得したトークンを入力します。最後に、ここで設定した名前を DownloadGitHubRelease@0 の connection 引数に記述すると完了です。

Pipeline Artifacts の設定

Azure Pipelines には Artifacts と言う項目が存在します。これは、Azure DevOps の Artifacts(左側にメニューとして表示されている項目)とは別物で、各ビルド結果の右上に表示されるリンクから辿る事ができます。

Pipeline Artifacts

この Artifacts に成果物を表示するには、Publish Pipeline Artifact task を利用します。

- task: PublishPipelineArtifact@0
  inputs:
    artifactName: '$(PROJECT_NAME)'
    targetPath: '$(Build.ArtifactStagingDirectory)'
  displayName: 'Publish pipline artifacts'

NuGet Pack など多くの task において、実行結果は $(Build.ArtifactStagingDirectory) に保存されます。そのため、targetPath 引数にはこの変数を指定しておくと良いようです。

*1:Cube プロジェクトでは、取得した各種 NuGet パッケージを "../packages" に配置するように設定しています(参考:Cube のプロジェクト構成およびビルド&テスト方法)。初期設定では、これらの NuGet パッケージは "$(UserProfile)/.nuget/packages" に配置されるようなので、もしリンク先の YAML ファイルを利用する場合には、適当に置き換えて下さい。

Cube のプロジェクト構成およびビルド&テスト方法

現在、cube-soft@GitHub には CubePDFCubeICE 等の実装コードを始めとして様々なリポジトリが存在します。この記事では、これらのリポジトリを修正する際の基本的な情報について記載します。

ディレクトリ構成

<WorkDirectory>
  + Cube.Core
  + Cube.FileSystem
  + Cube.FileSystem.SevenZip
  + Cube.Forms
  + Cube.Images
  + Cube.Net
  + Cube.Pdf
  + Cube.Xui
  + packages
  + resources
    + native
      + x86
      + x64

Cube プロジェクトの各リポジトリは、ローカル環境において上記のように配置されている事を想定しています。ただし、Cube.* ディレクトリに関しては異なるリポジトリ間では NuGet パッケージ経由で参照設定を行っているので、必要な(修正したい)リポジトリのみが配置されていれば問題ありません。

packages ディレクトリには NuGet で取得したパッケージ、resources ディレクトリにはそれ以外のライブラリを配置します。packages ディレクトリに関しては、nuget コマンドまたは Visual Studio 経由でパッケージの復元を実行すれば自動的に配置されるため、特に気にする必要はありません。resources ディレクトリには、native と言うサブディレクトリを作成し、そこにアンマネージド・ライブラリを x86/x64 別に配置します。現在、Cube プロジェクトで利用しているアンマネージド・ライブラリは以下の 2 種類です。

リポジトリ ライブラリ ディレクト
Cube.Pdf Ghostscript gs
Cube.FileSystem.SevenZip 7-Zip 7z

これらのライブラリは必ずしもここに配置する必要はありませんが(最終的な実行ディレクトリに存在しておけば良い)、後述する Rakefile との兼ね合い、および Continuous Integration (CI) 環境である AppVeyor とディレクトリ配置を統一する意味で、このディレクトリ構成としています。尚、Cube プロジェクトで使用しているアンマネージド・ライブラリは cube-soft@GitHub 内の各種 GitHub Releases からもダウンロード可能です。詳細については、下記を参照下さい。

Git ブランチ構成

Cube プロジェクトには、master, stable, net35 と言う 3 種類のブランチが存在します。この中で、特に何もしなくてもビルド可能なブランチは stable ブランチとなります。そのため、通常は stable ブランチを起点にすると楽です。net35 ブランチは、stable ブランチと同等の内容を .NET Framework 3.5 ターゲットでビルド可能にしたものなので、必要な場合以外は無視して構いません。

master ブランチは、開発中のものまで含めた最新の状態であるため、NuGet でまだ公開されていないバージョンを参照する事があります。リポジトリ直下に配置している NuGet.config に開発中の NuGet パッケージを取得するための URL を記述しているため、master ブランチでも問題なくビルドできるとは思いますが、予期せぬ不都合が発生する可能性もあります。また、参照されている NuGet パッケージ自体にも、該当バージョンが NuGet パッケージとして公開されるまでに度々、修正が行われます。ビルドに失敗する等の問題が発生した場合は rake clean コマンドを実行するか、packages ディレクトリにある各種 cube.* ディレクトリを手動で削除して下さい。

ビルド&テスト方法

ビルドは Visual Studio を起動して「ビルド」メニューを選択すれば、特に難しい点はないかと思います。テストフレームワークとして NUnit を使用しているので、Visual Studio 上でユニットテストを実行する場合は拡張機能から NUnit3 Test Adapter を選択してインストールして下さい。

コマンドライン上からの各種実行に関しては Rakefile に記述しているため、Ruby および Rake の実行環境が必要となります。Rakefile に記述しているタスクは clean, build, copy, pack, test の 6 種類で(copy は存在しない場合もある)、デフォルトでは test 以外のタスクが順に実行されます。clean は対象オブジェクトを消去し、build はその名の通りビルドを実行、pack は NuGet パッケージの作成用タスクです。尚、これらのタスク実行中には stable ブランチと net35 ブランチを何度か切り替えるので注意して下さい。

copy タスクは、必要なアンマネージド・ライブラリを bin 下の各ディレクトリにコピーします。この時、コピー元のファイル群は resources/native に存在する事を想定しているので、それらのファイルは該当ディレクトリに配置して下さい。また、Architecture (x86, x64, AnyCPU), Configuration (Debug, Release), Branch (stable, net35) 毎に出力ディレクトリが異なるので、最終的に 12 種類のディレクトリにコピーされます。

test タスクは、現在のブランチを対象にして、ビルドと NUnit によるテストを実行します。これ以外のタスクは、現在のブランチが何かに関わらず stable, net35 の 2 種類のブランチを対象とするので、このタスクのみ特殊となります。尚、ユニットテストは、ローカル環境における開発中は Visual StudioGUI で確認する事が多いので、現状では net35 ブランチのテスト結果確認用と言う意味合いが強くなっています(Visual Studio の該当機能が .NET Framework 3.5 非対応となったため)。

その他、AppVeyor における CI 実行内容はリポジトリ毎に存在する AppVeyor.yml に記述しているので、こちらも何かの理解に役立つかもしれません。