10

20 を超えるプロジェクトを含む VS2010 ソリューション ファイルがあり、一部のプロジェクトは、ソリューション内の他のプロジェクトに依存しています。

また、さまざまな目的のために複数のビルド構成を設定していますが、ビルドするプロジェクトを最小限に抑えて、最小限の数のプロジェクトを含めるようにしました。

たとえば、3 つのライブラリ (A、B、および C)、Web サイト プロジェクト、Web サイト展開プロジェクト (VS2010) があります。Web サイトにはライブラリ A と B への参照があり、B には C への参照があります。私のビルド構成には、Web サイトと展開プロジェクトのみがチェックされています。ソリューションのプロパティからプロジェクトの依存関係を確認すると、Web サイトにはライブラリが正しく一覧表示され、B には期待どおり C が表示されます。

VS2010 内からビルド構成に対してビルドを実行すると、完全に正常に動作しますが、構成を指定してソリューションで MSBuild を実行すると (次のように)、一連のエラーが発生します。

msbuild.exe mysolution.sln /t:Build /p:configuration=MyConfig

これが私が得るエラーの例です:

Services\IService.cs(11,63): error CS0246: The type or namespace name 'Priority' could not be found (are you missing a using directive or an assembly reference?)

ビルド サーバー (TeamCity v7.1.2) でこれが発生していることに気付きましたが、複数のマシンで再現できるため、MSBuild 自体の問題に絞り込みました。

.NET 4.5 (および 2 つのセキュリティ パッチ) をインストールした後に発生し始めたので、それをアンインストールし、.NET 4.0 も削除されたので (パッチ付きで) 再インストールし、同じコマンドを試したところ、問題なく動作しました。

これにより、.NET 4.5 を使用した MSBuild で何かが変更または破損したと思われますが、ドキュメントにはこの種の変更については何も記載されていないようです。

MSBuild 4.5 ドキュメント: http://msdn.microsoft.com/en-us/library/hh162058.aspx

私はBuildProjectDependencies=trueMSBuild に渡そうとしましたが、他のプロジェクトが構成マネージャーで選択されていないためスキップされたと表示されますが、これは正しく意図的なものです。

MSBuild 4.5 で動作させる唯一の方法は、戻ってスキップされていたプロジェクトを選択することでしたが、実際のソリューションは依存関係のチェーンでもう少し複雑であるため、管理しようとする必要はありません。新しいプロジェクトまたは依存関係でソリューションを更新するたびに、構成を手動で変更します。それは自動であるべきです。

私がやっていることについて何かアイデアはありますか?

4

6 に答える 6

4

この問題に対する独自の回避策を作成するために多くの時間と労力を費やしたので、以前の回答を更新すると思いました。回避策は、単に問題に対処するよりももう少し包括的ですが、問題を排除し、このような将来のショックから身を守ることの両方を試みました.

MSBuild は、ソリューション、構成などの操作から降格されました。MSBuild は、プロジェクトを分離してコンパイルするよう求められるだけです。これが発生する順序は、ソリューションとプロジェクトを解析して最適なジャスト イン タイム ビルド実行計画を作成する Powershell スクリプトによって計算されます。

これの鍵となる (役立つと思うかもしれない) のは、次のスニペットです。

ソリューションの特定

私は自分のプラットフォームのすべてのソリューションのリストを持っており、基本的にこれらのそれぞれについて繰り返します。

$buildPlan = (
@{
    solutions = (
        @{
            name      = "DataStorage"
            namespace = "Platform.Databases"
        },
        @{
            name      = "CoreFramework"
        },
        @{
            namespace = "Platform.Server"
            name      = "Application1"
        },
        @{
            namespace = "Platform.Server"
            name      = "Application2"
        },
        @{
            namespace = "Platform.Client"
            name      = "Application1"
        }
     )
})

これを実際の物理パスに変換するのに役立ついくつかのロジックがありますが、これは私たちのニーズに合わせてカスタマイズされているため、ここには記載しません。このリストから、解析する必要がある .sln ファイルを見つけることができます。

プロジェクトのソリューション ファイルの解析

ソリューションごとに .sln ファイルを読み取り、後でビルドする必要があるすべてのプロジェクトを抽出しようとしました。

まず、私のすべてのプロジェクトを特定します

$solutionContent = Get-Content $solutionFile

$buildConfigurations += Get-Content $solutionFile | Select-String  "{([a-fA-F0-9]{8}-([a-fA-F0-9]{4}-){3}[a-fA-F0-9]{12})}\.(Release.*)\|Any CPU\.Build" | % {
        New-Object PSObject -Property @{
            Name = $_.matches[0].groups[3].value.replace("Release ","");
            Guid = $_.matches[0].groups[1].value
          }

    }  | Sort-Object Name,Guid -unique

そして、これをプロジェクトの素敵なリストに変換して、後で反復できるようにします。

$projectDefinitions = $solutionContent | 
      Select-String 'Project\(' |
        ForEach-Object {
          $projectParts = $_ -Split '[,=]' | ForEach-Object { $_.Trim('[ "{}]') };
          $configs = ($buildConfigurations | where  {$_.Guid -eq $projectParts[3]} | Select-Object Name)

          foreach ($config in $configs)
          {
              $santisiedConfig = if ([string]::IsNullOrEmpty($config.Name)){"Release"}else{$config.Name}
              if ($projectParts[1] -match "OurCompanyPrefix.")
              {
                  New-Object PSObject -Property @{
                    Name = $projectParts[1];
                    File = $projectParts[2];
                    Guid = $projectParts[3];
                    Config =  $santisiedConfig
                  }
              }
          }
    } 

Visual Studio プロジェクトを読み込む

ソリューション ファイルの解析から、ソリューションごとのプロジェクトのリストが得られました。これには、プロジェクトを見つけるためのソリューション ルートからの相対ファイル パスが含まれています。

$projectDefinition = [xml](Get-Content $csProjectFileName)
$ns = @{ e = "http://schemas.microsoft.com/developer/msbuild/2003" }
$references = @();

1) 外部プロジェクト参照の特定

$references += Select-Xml -Xml $projectDefinition -XPath "//e:Project/e:ItemGroup/e:Reference" -Namespace $ns | % {$_.Node} | where {$_.Include -match "OurCompanyPrefix" -and $_.HintPath -notmatch "packages"}  | % {$_.Include}

2) 内部プロジェクト参照の特定

$references += Select-Xml -Xml $projectDefinition -XPath "//e:Project/e:ItemGroup/e:ProjectReference" -Namespace $ns | % { $_.Node.Name }

3) 外部参照としての「ビルド後」イベントの追跡

$references += Select-Xml -Xml $projectDefinition -XPath "//e:Project/e:PropertyGroup/e:PostBuildEvent" -Namespace $ns | where {(!([String]::IsNullOrEmpty($_.Node.InnerText)))} | % {

            $postBuildEvents = $_.Node.InnerText.Split("`n")
            $projectsReferencedInPostBuildEvents = $postBuildEvents | Select-String "\(SolutionDir\)((\w|\.)*)" | % {$_.Matches[0].Groups[1].Value}
            if ($projectsReferencedInPostBuildEvents -ne $null)
            {
                Write-Output $projectsReferencedInPostBuildEvents | % { $matchedProject = $_; ($releaseConfiguation | ? {$_.File -match $matchedProject}).Name }  
            }

        }

そして、ここまで来たら、基本的な出力情報も取得します。

これは、出力をプッシュする場所や依存関係の出力を見つける場所を知っているので、ビルドするプロジェクトのリストを反復する場合に便利です。

$assemblyName = (Select-Xml -Xml $projectDefinition -XPath "//e:Project/e:PropertyGroup/e:AssemblyName" -Namespace $ns).Node.InnerText
$outputPath  = (Select-Xml -Xml $projectDefinition -XPath "//e:Project/e:PropertyGroup[contains(@Condition,'Release|')]/e:OutputPath" -Namespace $ns).Node.InnerText

そして、すべての終わりに

重複がないことを確認する必要があるだけなので、この特定のコード プロジェクトの個別の依存関係だけを記録します。

$dependendents = @();
if ($references -ne $null)
{
    $buildAction.project.dependencies += $references | where {(!([string]::IsNullOrEmpty($_))) -and ($_ -match "OurCompanyPrefix\.(.*)")} | % { $_.ToLower()} | Select -unique
}    

これにより、SLN ファイルと PROJ ファイルを解析するための十分な情報が得られることを願っています。この情報をどのように取得して保存するかは、完全にあなた次第だと思います。

私はこれについて非常に詳細なブログ投稿を書いている最中です。これには、上記で回避したすべてのトリミングとフレームワークが含まれます。投稿はまだ準備ができていませんが、以前の投稿からリンクします: http://automagik.piximo.me/2013/02/just-in-time-compilation.html - Microsoft によるこの変更以来、この作品を狂わせた!

乾杯。

于 2013-05-08T08:55:55.783 に答える
4

それでもこの問題が解決しない場合は、ブラインド ショットを試してみましょう。

  1. msbuild は、従う依存関係に基づいて間違ったビルド順序を生成する場合があるバグを確認しています。ソリューション全体ではなく、ビルドしたい正確なプロジェクトをビルドしてみてくださいmsbuild.exe YourWebsiteProject.csproj /t:Clean;Build /p:configuration=MyConfig。問題は解決しませんか?

  2. YourWebsiteProject とあなたのライブラリ (B と C) に適切な参照があることを確認してください - 別のプロジェクト フォルダーの dll ではなく、プロジェクト上にあることを確認します (それを修正する最も簡単な方法 - B から C への参照を削除し、再度追加します。プロジェクト参照を追加し、非常に C.dll の bin\Debug を参照しない)。問題はまだありますか?

詳細な、または診断用の msbuild ログ (msbuild コマンド ラインにスイッチ /ds /v:diag に続いて追加し、teamcity の完全なビルド ログをどこかで共有するか、コマンド ライン ログをファイルにパイプする) またはいくつかのサンプル プロジェクト セットを提供して、再現できる場合この動作 - 問題解決に大いに役立つ可能性があります。

于 2012-12-09T06:19:20.170 に答える
3

.NET 4.5 では、C:\Windows\Microsoft.NET\Framework\v4.0.30319\Microsoft.Common.targetsのOnlyReferenceAndBuildProjectsEnabledInSolutionConfigurationfalseプロパティの既定値が からに変更されましたtrue。その名前が示すように、このプロパティにより、MSBuild はビルド構成から除外されたプロジェクトへの参照を無視します。

(Microsoft は、私が MSBuild 4.0 に対して提出した Connect のバグに対応して、この変更を行った可能性があります。変更によってビルドが壊れると警告したにもかかわらずです。)

false回避策は簡単です。各プロジェクトの最初の<PropertyGroup>セクションでプロパティを元に戻します。

<PropertyGroup>
    ...
    <OnlyReferenceAndBuildProjectsEnabledInSolutionConfiguration>false</OnlyReferenceAndBuildProjectsEnabledInSolutionConfiguration>
</PropertyGroup>
于 2014-08-05T16:46:29.137 に答える
2

私はまったく同じ問題に遭遇しました。私が見つけることができた 2 つの回避策は、どちらも長期的には受け入れられませんが、古いビルド プロセスを新しい 4.5 スタックで動作させるという最初の問題を克服しています。

  1. プロジェクト参照をファイル参照と交換します
  2. 複合ビルド構成を作成する

ファイル参照は、開発者がリアルタイムのインテリセンスなどを失うことを意味するため、#2 を選択しました。

複合構成は次のとおりです。

  • リリース サーバー ->すべてのサーバー プロジェクト
  • Release Consumer -> "Release Server" + クライアント プロジェクト

問題は、プロジェクトが現在/アクティブなビルド構成に含まれていない場合、参照された依存関係として含まれないことです。したがって、依存関係を構成に追加することで、プロジェクトは少なくともコンパイルされます。

どちらも醜いですが、少なくとも窮地から抜け出すことができます。

マット

于 2013-03-08T09:13:48.150 に答える
0

MSBuild は、.sln ファイルで宣言されている順序でソリューションからプロジェクトをビルドしていることがわかりました。したがって、テキスト エディターでそれらを並べ替えると、MSBuild の順序を修正できます。

于 2017-04-06T06:46:29.377 に答える