web-dev-qa-db-ja.com

ソリューション全体のビルド前イベント?

Visual Studioには、いくつかのプロジェクトを含むソリューションがあります。どのプロジェクトが関係しているか、プロジェクトが最新かどうかに関係なく、すべてのビルドの最初にコマンドを実行したいと思います。

基本的に、ソリューション全体のビルド前イベントに似たものが必要ですが、残念ながらVSはこれらをサポートしていないようです。誰かが私が必要とするものを達成する別の方法を知っていますか?

64
user200783

異常な要件。しかし、それはできます。ソリューションに新しいプロジェクトを追加し、Visual C++>一般> Makefileプロジェクトテンプレートを使用します。 NMake> Build Command Line設定を実行するコマンドに設定します。 [プロジェクト]> [プロジェクトの依存関係]を使用して、他のすべてのプロジェクトをそれに依存させます。

41
Hans Passant

以下の私の亜種の簡単な概要

ただのメモ:それはすべての既存の不完全なリストです(他の回答なども参照してください)、実際の状態で元のトリックのみをサポートしています...

summary

ノート:

  • 1 -追加の拡張機能は必要ありません。ただし、プロジェクトレベルでしか機能しない可能性があるため、ソリューションレベルをエミュレートするために使用します。一般的なソリューションでは困難で不便ですが、バリアントです。下記参照。
  • 2 -vsSolutionBuildEventの元のエンジンは、VSおよびmsbuild.exeの統合サポートのいくつかの方法を提供します。 targets modeがmsbuild.exeでのみ利用可能な after.<name>.sln.targets を呼び出す簡単な方法(これは追加のステップを必要とせず、単にアクションを実行するだけです)。ただし、元のエンジン(inc。vsCommandEvent)のみが、たとえば(7Zipアーカイバ、nuget.exeなしのnugetパッケージのパッキング、リモートサーバーなど)をサポートする追加のスクリプトを許可する場合があります。ただし、質問/問題にとって重要ではないため、上記の+が表示されている場合は、利用可能なオプションを使用してソリューションレベルをサポートできます。

バリアント1:Microsoft.VisualStudio.Shell.Interop

このバリアントは、VSの単純なユーザー向けではありません。ただし、完全なソリューションなどには役立ちます。

たとえば、実装する必要があります。

例えば:

public sealed class YourPackage: Package, IVsSolutionEvents, IVsUpdateSolutionEvents2
{
...
    public int UpdateSolution_Begin(ref int pfCancelUpdate)
    {
        //TODO:
    }
}

次に、ハンドラを優先リスナーとして「Advise」メソッドで登録します。つまり、 IVsUpdateSolutionEvents2 を使用する必要があります AdviseUpdateSolutionEvents

重要です、なぜならBuildEventsEnvDTE を参照)-おそらく役に立たず、動作が遅すぎる可能性があります-

AdviseUpdateSolutionEventsを使用したサンプル:

// http://msdn.Microsoft.com/en-us/library/Microsoft.visualstudio.Shell.interop.ivssolutionbuildmanager2.aspx
private IVsSolutionBuildManager2 sbm;

// http://msdn.Microsoft.com/en-us/library/bb141335.aspx
private uint _sbmCookie;
...

sbm = (IVsSolutionBuildManager2)ServiceProvider.GlobalProvider.GetService(typeof(SVsSolutionBuildManager));
sbm.AdviseUpdateSolutionEvents(this, out _sbmCookie);

Where:

  • sbmフィールドは、GCから保護するためのクラスの一部である必要があります。
  • SVsSolutionBuildManagerサービスを取得するにはServiceProviderが使用されますが、必要に応じて使用できます。 msdnを参照してください

これで、ソリューションレベルのすべてのプロジェクトを一度に処理できます。

バリエーション2:プロジェクトのターゲットとマップ。

わかりました、あなたはこのようなものを愛しています- MSBuild:ソリューションビルドの拡張 ですが、このバリアントは、VS IDEではなくmsbuild.exeからのビルドプロセスで動作する可能性があります...

ただし、VSは、ビルド操作の開始時にプロジェクトファイル(* .csproj、*。vcxproj、..)でターゲット(ビルド、リビルド、クリーン、..)も使用します。したがって、これを試すこともできますが、覚えておいてください:

  • VSは、驚くべき.slnファイルも無視します。 EnvDTEなどを使用して、ロードされた環境からすべての最終ターゲットを形成します。
  • .slnは、msbuild.exeで次のようにのみ処理する必要があります。「デフォルトでメモリに」.metaprojを自動的に生成します。存在する場合は、すべてのプロジェクトに共通のターゲットを含めます。たとえば、次のとおりです。
...
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\SolutionFile\ImportAfter\*" Condition="'$(ImportByWildcardBeforeSolution)' != 'false' and exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\SolutionFile\ImportAfter')" />
<Import Project="D:\tmp\p\after.name.sln.targets" Condition="exists('D:\tmp\p\after.name.sln.targets')" />
<Target Name="Build" />
<Target Name="Rebuild" />
<Target Name="Clean" />
<Target Name="Publish" />
  • そして、はい、.metaprojもVS IDEで表示できません。

したがって、VS IDEからの一般的なターゲットでの作業には、何らかの制限のあるプロジェクトファイルのみを使用できます(VSの変更/拡張なし、という意味です)。

そのため、共通のソリューションが必要な場合(つまり、プロジェクトなどについて知らない場合があります。-これは、たとえば、一部のボックスソリューションなど)です。

  • 共通の.targetsファイルをすべてのプロジェクトに追加します(任意のツールで自動的に作成できます NuGetイベント など)。例:<Import Project="..\<SolutionFile>.targets" />
  • 次に、次の制限を使用する必要があります。
    • 「のみ-すべてのプロジェクトの前」
    • 「のみ-すべてのプロジェクトの後」

そして、例えば、はい、それは「プロジェクトの地図」になることができます:

  • 'プロジェクトのマップ' は、Visual Studioからのビルド操作のソリューション全体のPRE/POST 'イベント'を示していますIDE(つまり、VS IDEからのプライマリ)
...
<Target Name="_Build" BeforeTargets="Build" DependsOnTargets="ProjectsMap">
    <CallTarget Targets="_BuildPRE" Condition="$(ScopeDetectFirst)" />
    <CallTarget Targets="_BuildPOST" Condition="$(ScopeDetectLast)" />
</Target>
<Target Name="_BuildPRE">
    <!-- ... -->
</Target>
<Target Name="_BuildPOST">
    <!-- ... -->
</Target>
...

一般に、プロジェクトのマップを使用し、「何を、いつ」行うべきかを理解します。すべてまたはほとんどの場合(ビルド順序の変更またはソリューションからのプロジェクトの削除)で安全です。しかしながら!最初の初期化で新しいプロジェクトの<Import>セクションを管理する必要があります。これは本当に不便ですが、バリアントでもあります...

バリアント3:プラグインvsSolutionBuildEvent

今日では、イベントキャッチャーとして、プロジェクトとライブラリのメンテナンス、Visual StudioとMSBuild Toolからの実行時のプロセスとプロセスの構築のためのさまざまな高度なアクションを備えた多くのイベントを処理するための最も完全なソリューションです。

Solution-Eventsとしてソリューション内のすべてのサブプロジェクトに一度に、またはそれぞれ個別に異なるアクションタイプ。

https://visualstudiogallery.msdn.Microsoft.com/0d1dbfd7-ed8a-40af-ae39-281bfeca2334/

plugin - vsSolutionBuildEvent

内部での仕組み

上記の Variant 1 を使用する場合、またはShell.Interop、EnvDTE、IVsUpdateSolutionEvents2、MSBuild Engineなどの操作方法を確認する必要がある場合は、 here を参照してください。

scheme

バリアント4. EnvDTE.CommandEvents

このバリアントは、VSの単純なユーザー向けでもありません。ただし、 Variant 1 に関しては、ボックスソリューションなどに役立ちます。

同じではありませんが、はい、上記の Variant 1 のように EnvDTE.CommandEvents でも可能です。

this solution について既に知っている必要があります(ビルドアクションの現在のタイプでの優先作業の場合)。

_cmdEvents.BeforeExecute += (string guid, int id, object customIn, object customOut, ref bool cancelDefault) => {

    if(UnifiedTypes.Build.VSCommand.existsById(id)) {
        // ... your action
    }

};

場所:Description | guid | id |In |Out| --------------------------|---------------------------------------|-----|---|---| Started: Build Solution |{5EFC7975-14BC-11CF-9B2B-00AA00573819} | 882 | | | Started: Rebuild Solution |{5EFC7975-14BC-11CF-9B2B-00AA00573819} | 883 | | | Started: Clean Solution |{5EFC7975-14BC-11CF-9B2B-00AA00573819} | 885 | | |

http://vsce.r-eg.net/doc/Features/Solution-wide/

さらに、必要に応じて、このコマンドを省略できます。 以下のバリアントでは、この方法の完全なソリューションが表示されます。

バリアント5.プラグインvsCommandEvent

https://visualstudiogallery.msdn.Microsoft.com/ad9f19b2-04c0-46fe-9637-9a52ce4ca661/

また、ほとんどのイベントの高度なハンドラーも提供しますが、最初のイベントとは異なり、すべてのコマンドと出力データを使用した高度な作業を行うためのMS Visual Studioに特化しています。プロジェクトとソリューションだけでなく、Visual Studio IDE全体も対象です。

一般的に、これは Variant 4 の一般的なソリューションであり、上記のすべてのコマンドをオーバーライドしてこの問題を解決できます。

そして、vsSolutionBuildEventのような同じイベントアクションモデルでは、ほとんどの場合に役立ちます。

scheme

「バリアントのヘルプ」

これらすべてのバリアントのオープンな実装があります。こちらと笑顔をご覧ください:

41
Denis Kuzmin

この記事をご覧ください: MSBuild:ソリューションビルドの拡張

まさにあなたが必要とするもののようです。

18
Andriy K

これを行うには、空のプロジェクトを追加し、このプロジェクトのビルドイベントを設定します。次に、この空のプロジェクトに各プロジェクトの依存関係を与えて、毎回ビルドされるようにします。

9
erelender

それからしばらく経ち、.Netインフラストラクチャのいくつかのことが変更され、新しいオプションが提供されました。今、この問題の王様を解決するための私の選択は、nugetパッケージです。ビルド手順をパッケージに入れ、それをすべてのプロジェクトに含めました。 Visual Studioパッケージマネージャーはソリューションレベルでパッケージの概要を提供するため、このルールを簡単に確認できます。

0
Andriy K

もう1つの古い投稿ですが、@ regソリューションに触発されて、ソリューションビルドの経過時間を記録する単純なビルドタイマーを実行したいと考えました。 Visual Studio IDEの起動時にパッケージマネージャーコンソールから読み込むpowershellモジュールを使用して、ビルドイベントが機能するようにしました。

BuildEvents.psm1のようなpowershellモジュールを作成します:

<#
.SYNOPSIS
    Register solution build events

.DESCRIPTION
    Registers the OnBuildBegin and OnBuildDone events for the entire solution
    De-registers the events if called multiple times.

.EXAMPLE
    RegisterBuildEvents
#>
function RegisterBuildEvents{
  try {
    Unregister-Event -SourceIdentifier "OnBuildBegin" -Force
  } catch {
    #we don't care if this doesn't work
  }
  try {
    Unregister-Event -SourceIdentifier "OnBuildDone" -Force
  } catch {
    #we don't care if this doesn't work
  }
  $obj = [System.Runtime.InteropServices.Marshal]::CreateWrapperOfType($dte.Application.Events.BuildEvents, [EnvDTE.BuildEventsClass])
  Register-ObjectEvent -InputObject $obj -EventName OnBuildBegin -Action {
    # do stuff here on build begin
    Write-Host "Solution build started!"
  } -SourceIdentifier "OnBuildBegin"
  Register-ObjectEvent -InputObject $obj -EventName OnBuildDone -Action {
    # do stuff here on build done
    Write-Host "Solution build done!" 
  } -SourceIdentifier "OnBuildDone"
}

# export the functions from the module
export-modulemember -function RegisterBuildEvents

パッケージマネージャーホストの初期化時にモジュールをインポートします。

  1. パッケージマネージャーコンソールで$ profileと入力して、PowerShellプロファイルの場所を取得します
  2. ディスク上のそのディレクトリを参照します。ファイルがない場合は、上記のコマンドで返された名前でファイルを作成します(例:NuGet_profile.ps1
  3. メモ帳でファイルを開き、次の行を追加します

    Import-Module -Name <Path to your ps module>\BuildEvents -Force
    RegisterBuildEvents
    
0
James Close