アジョブジ星通信

進捗が出た頃に更新されるブログ。

新しい csproj に負けないレガシーな心を持ち続けて云々

Sdk="Microsoft.NET.Sdk" なプロジェクトファイルで使える小ネタ集です。

NETStandard.Library への参照をいじる

PackageReference を何ひとつ書かなくても NETStandard.Library を勝手にダウンロードしてくるのは、手軽にコードが書けるという点ではいいかもしれないけれど、やはり無駄なパッケージ参照があるというのは許せないものなので、消していきましょう。

DisableImplicitFrameworkReferences というプロパティがあり、これを true にするとデフォルトの参照が消えます。デフォルトの参照は以下の通り(targets ファイルを漁るとでてくる)で、これらが全部消えます。つまり .NET Framework なら mscorlib だけ、 .NET Core なら無です。

  • .NETStandard (Microsoft.NET.Sdk.DefaultItems.props)
    • NETStandard.Library 1.6.1
  • .NETCoreApp (Microsoft.NET.Sdk.DefaultItems.props)
  • .NETFramework (Microsoft.NET.Sdk.BeforeCommon.targets)
    • System
    • System.Data
    • System.Drawing (マジかよ)
    • System.Xml
    • System.Core
    • System.Runtime.Serialization
    • System.Xml.Linq
    • System.Numerics
    • System.IO.Compression.FileSystem

NETStandard.Library のバージョンは NetStandardImplicitPackageVersion プロパティを、 Microsoft.NETCore.App のバージョンは RuntimeFrameworkVersion プロパティを書き換えることで、自由に変更することができます。

netcoreapp1.0 をターゲットにすると Microsoft.NETCore.App のバージョンは 1.0.4 になるけど、 1.1.1 に変えても問題なく動くんだよな……。

サンプルコードとして、 NETStandard.Library を消して、 System.Console (とその依存パッケージ)だけを参照するプロジェクトです。

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <TargetFramework>netstandard1.4</TargetFramework>
    <DisableImplicitFrameworkReferences>true</DisableImplicitFrameworkReferences>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="System.Console" Version="4.3.0" />
  </ItemGroup>

</Project>

Portable Class Library や Xamarin クラスライブラリをビルドする

プロジェクトファイルにちょっと手を加えれば、インストールされているフレームワークなら何でもビルドできます。たぶん。

TargetFramework, TargetFrameworkIdentifier, TargetFrameworkVersion、あとプロファイル指定が必要なら TargetFrameworkProfile というプロパティを設定すれば、勝手にアセンブリ解決してビルドしてくれます。

例えば、いにしえのフレームワーク軍を相手する portable40-net40+sl5+win8+wp8+wpa81 ならこんな感じ

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <TargetFramework>portable40-net40+sl5+win8+wp8+wpa81</TargetFramework>
    <TargetFrameworkIdentifier>.NETPortable</TargetFrameworkIdentifier>
    <TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
    <TargetFrameworkProfile>Profile328</TargetFrameworkProfile>
  </PropertyGroup>

  <ItemGroup>
    <Reference Include="System" />
  </ItemGroup>

</Project>

mscorlib 以外は勝手に参照されないので、必要に応じて Reference を書いてあげる必要があります。

Xamarin も同様にできますが、ファサードアセンブリを使うために ImplicitlyExpandDesignTimeFacades プロパティを true にしておく必要があるのと、 Visual Studio 2017 からアセンブリの場所が変わったので、それに対する対応を入れる必要があります。

Visual Studio 2015 までは C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework に Xamarin のアセンブリがありましたが、 2017 では C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\Common7\IDE\ReferenceAssemblies\Microsoft\Framework になりました。 Microsoft.NET.Sdk では前者のパスを探しにいくので、 2017 だけがインストールされている環境ではアセンブリが見つかりません。

その対策が入っている Xamarin.Android.Sdk.props をパクりつつ、 Xamarin クラスライブラリをつくるプロジェクトファイルはこんな感じになります。

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <TargetFramework>monoandroid70</TargetFramework>
    <TargetFrameworkIdentifier>MonoAndroid</TargetFrameworkIdentifier>
    <TargetFrameworkVersion>v7.0</TargetFrameworkVersion>
    <TargetFrameworkRootPath Condition="'$(VsInstallRoot)' != ''">$(VsInstallRoot)\Common7\IDE\ReferenceAssemblies\Microsoft\Framework\</TargetFrameworkRootPath>
    <ImplicitlyExpandDesignTimeFacades>true</ImplicitlyExpandDesignTimeFacades>
  </PropertyGroup>

  <ItemGroup>
    <Reference Include="Mono.Android" />
  </ItemGroup>

</Project>

Xamarin Android プロジェクトで、このプロジェクトを参照に加えて実行してみましたが、問題なく動作しました。

VsInstallRoot プロパティは Visual Studio についている MSBuild でしか設定されていないので、 .NET Core SDKMSBuild でビルドした場合には 2015 までのアセンブリの場所を見に行きます。