新しもの好きプログラマの耳より情報ブログ

仕事でもあるプログラミングについて役に立ちそうな情報を発信していこうというブログです。役に立たなそうな情報はfacebookで。

.NET6で、C++/CLIやCOMが混在しているソリューションをpublishする方法

概要

.NET 6で作ったソリューション全体を発行したくなったら、dotnet publishコマンドを使うだけ。シンプルで良い。

しかし、これが通じるのはC#プロジェクトだけで完結している場合。C++/CLIやCOMを参照するプロジェクトは、dotnet publishではエラーが出て発行できない。

msbuildを使ったpublishが成功したので、その方法を紹介する。

経緯

C#C++/CLIのプロジェクトが混在し、一部でCOMモジュールを参照している、そういうソリューションを.NET Frameworkから.NET 6へ移植した。

これをスクリプトでビルドしようとして、調べてすぐに出てくるdotnet publishを実行したところ、C++プロジェクトとCOMを使っているプロジェクトでエラーが起きた。

次のようなエラーがあり、1つ解決しても次が出るので個別に解決していくのは難しいと判断したため、他の方法を探した。

  • VCTargetsPath環境変数が解決できず、VCのpropsファイルが見つからない
  • WindowsSDKのバージョン指定が入ったC#プロジェクトをC++/CLIプロジェクトから参照すると、バージョンが合わないエラーになる
  • 「error MSB4018: The "GetOutOfDateItems" task failed unexpectedly」のような、直接の原因が推測できないようなエラーが出る
  • C#プロジェクトからの)COM参照はサポートしていない、というようなエラーが出る
    • (error MSB4803: タスク "ResolveComReference" は .NET Core バージョンの MSBuild ではサポートされていません。)

どうやら、Windows限定のC++/CLIを含むプロジェクトをdotnet publishで処理しようという方針自体が間違っていそう。

続けてmsbuildでのpublishをする方法にチャレンジした。しかし、次のような問題にぶつかった。

  • ソリューションをmsbuildに渡すと
    • 全プロジェクトがpublishの対象となり、C++のプロジェクトが「publish非対応」と言ったエラーを出す
  • publishの対象となるexeなどのプロジェクトを個別にmsbuildへ渡すと
    • そのプロジェクトから参照される別のプロジェクト(ProjectReferenceで指定したプロジェクト)のプロジェクト構成が指定できず、デフォルト値のDebugなどでビルドされてしまう
    • 同様に、プラットフォームもデフォルト値になるので、C++プロジェクトはx86となりx64を選択できない
    • msbuildを実行するごとに発行先がクリーンされるため、別々のフォルダに発行して後で1つのフォルダにまとめる必要がある

プロジェクト指定した場合の参照の問題は、プロジェクト自体のProjectReferenceに条件指定を追加すれば解決できるが、すでにVisualStudioでのビルドのためにソリューションで参照条件を指定しているため、できればソリューションで解決したい。

試行錯誤の結果、msbuildでこれらの問題を解決できる方法が見つかった。

解決方法

次のように、ソリューションをmsbuildに渡して、発行対象プロジェクトだけのPublishを指定すれば良い。

msbuild ソリューション名.sln /t:"プロジェクト名1:Restore;Rebuild;Publish";"プロジェクト名2:Restore;Rebuild;Publish;

この内容だと、指定したソリューションのうち「プロジェクト名1」「プロジェクト名2」それぞれに対して「Restore」「Rebuild」「Publish」を行うという指定になる。

msbuildの呼び出し1回で実行されるため、各プロジェクトで同じ発行先フォルダを指定している場合でも、お互いの成果物を消すことなく全ての成果物が発行先フォルダに保存される。

プロジェクト名部分は、ソリューションの相対パスを指定する必要がある点に注意。例えばソリューション内にFolder1がありその中にProject1が入っている場合は、"Folder1\Project1"という書き方になる。

参考:MSBuild.exe を使ってソリューション内の特定のターゲットをビルドする

コマンド全体の一例としては、次のような感じになる。ここでは、publishの内容を各対象プロジェクト内のRelease.pubxmlで指定する方式とした。

msbuild ソリューション名.sln /t:"プロジェクト名1:Restore;Rebuild;Publish";"プロジェクト名2:Restore;Rebuild;Publish; /p:Configuration=Release /p:Platform="Any CPU" /p:PublishProfile=Release /m