カスタムプロジェクトを作ってみる
SPECIAL
ライブラリ用のプロジェクト
Visual Studio .NET で Visual C++ のスタティックライブラリを作っていたときのことです。
なれないスタティックライブラリをいざ組み込んでみると、膨大な量のリンク重複エラーが発生してしまいました。
調べてみたところ、スタティックライブラリの場合は、組み込むプロジェクトに応じて、シングルスレッド版 (/ML) 、マルチスレッド版 (/MT) 、マルチスレッド DLL 版 (/MD) といったようにそれぞれの分だけ用意しなくてはいけないようです。
いっそのこと DLL にしてしまえば楽かとも思ったのですけど、場合によってはスタティックライブラリの方がいいこともあるのでは…、などと考えてしまい、なかなか DLL 一本に絞ることができません ^^;
とはいえ、スタティックライブラリのビルドのたびに /MT やら /MD やらを変更して、さらに出力ファイル名を区別するのも、数をこなしているうちに絶対にミスが出てきそうです。
ならば、カスタムのウィザードを作ってみましょうか、ということで実験開始です。
新しいプロジェクト
まずは Visual Studio .NET を起動して、【Visual C++ プロジェクト】 から 【カスタム ウィザード】 を選択します。
とりあえず、プロジェクト名や作成場所はてきとうに…。
すると、カスタムウィザードが起動します。
今回は単純に、ライブラリに的を絞ったプロジェクトということもありますし、また、ユーザインターフェイスがある場合は、作成が困難なのも予想されます/爆
ということで次のような 【アプリケーションの設定】 にしてみました。
ウィザードのフレンドリ名 | EZ-NET Win32 Library プロジェクト |
---|---|
ユーザー インターフェイス | OFF |
ページ数 | [ 無効 ] |
Visual Studio .NET のライブラリを見ると、ユーザインターフェイスには HTML ファイルを使用するようです。
SYMBOL タグを使って簡単に作成できるような感じなので、ユーザーインターフェイスもそれほど難しくはないかもしれないですね。
詳しくは、Visual Studio .NET のドキュメントから、「カスタム ウィザード」 をキーワード検索して、その下の HTML ファイルの項に載っています。
登録の仕方
ウィザード情報の更新
とりあえずまず先に、Visual Studio .NET への登録方法に触れてみます。
ウィザードを作成した時点でも既に Visual C++ プロジェクトの中に作成したカスタムウィザードが登録されるようになっています。
上記で作成したカスタムウィザードの内容を更新すれば反映されるようになっていますが、一部のファイルだけはそれだけでは更新されないようです。
これは、基本的な情報は Visual Studio .NET をインストールしたフォルダの Vc7\vcprojects\ というディレクトリに複製されているためです。
*.vsz | ウィザードの基本情報 (テンプレートの保存場所も含む) |
---|---|
*.vsdir | ウィザード一覧で使用される情報と *.vsz ファイル名 |
*.ico | ウィザード一覧に表示されるアイコン (32x32 : 16 色) |
複製されているのは上記ファイルなので、これらを変更した場合には、Vc7\vcprojects\ フォルダへコピーする必要があります。
なお、Visual Studio が起動中にコピーした場合は、いったん Visual Studio を終了しないと、以前の設定のままの場合もあるようです。
既定のウィザード保存場所を使用する
このうちの *.vsz ファイルですが、既存のプロジェクトの *.vsz は ABSOLUTE_PATH 情報が省略されています。
カスタムプロジェクトにある Param="ABSOLUTE_PATH = *******" という行を消去することで、 Visual Studio .NET をインストールディレクトリの Vc7\VCWizards\ ディレクトリの中の、PROJECT_NAME と同等のフォルダ名が、既定のディレクトリになるようです。
基本情報の変更
基本情報は、Visual Studio .NET がインストールされているディレクトリから Vc7\vcprojects\ とたどった中の、*.vsdir ファイルに保存されています。
このファイルは "|" 区切りで、各々の情報が記載されています。左から順番に次のような項目が並べられています。
なお、省略可能な項目を省略する場合、通常はそこに 0 を指定するようです。
1 - RelPathName [必須]
使用する *.vsz ファイルです。この *.vsdir と同一のフォルダの場合は、パス情報は書かなくてもいいようです。
2 - {clsidPackage} [省略 = ' ']
ローカライズ済みのリソースを含む DLL を持つ製品をあらわす GUID だそうです。とりあえず、カスタムの場合は空白1字を入力して省略すればいいようです。
3 - LocalizedName [省略可]
ウィザード名やテンプレート名、[項目の追加] ダイアログボックスに表示される名前などを示すようです。
一般的な文字列の他、#ResID 形式のリソース識別名も指定できる、とのことです。
4 - SortPriority [必須]
ウィザードの並べ替え順序と、相対優先順位を示す整数値です。1 が優先順位がいちばん高いそうです。
5 - Description [必須]
ウィザードの説明です。一般的な文字列の他、#ResID 形式のリソース識別名も指定できる、とのことです。
6 - DLLPath または {clsidPackage} [必須]
DLL や EXE ファイルへのパス、またはアイコンリソースを含む DLL を持っている製品の GUID だそうです。
必ず指定するとのことですが、今回作成したカスタムプロジェクトでは空白1文字で省略されているようです…/謎
8 - IconResourceID [省略可]
表示するアイコンを指定する、DLL 内のリソース識別しだそうです。
Visual Studio .NET の文書だと7番目に登場しますけど、個人的な予想だと8番目の項目のような気がします。
7 - Flags [必須]
カスタムプロジェクトを調整するためのビットフラグです。
Visual Studio .NET の文書だと8番目に登場しますけど、個人的な良そうだと7番目のような気がします。
どのようなフラグが用意されているかは Visual Studio .NET VSDir フラグ定数 に書いてみました。
とりあえず、今回の場合のディフォルトでは 6777 、つまり VSDIRFLAG_DisableNameField (4096) | 2048 | 512 | 64 | VSDIRFLAG_DisableLocationField (32) | 16 | VSDIRFLAG_DontAddDefExtension (8) | VSDIRFLAG_NonLocalTemplate (1) が設定されていました。
リストに載っていなかった 2048, 512, 64, 16 はなんなんでしょう…。
9 - SuggestedBaseName [必須]
[プロジェクト名] フィールドに表示される既定のウィザード名です。一般的な文字列の他、#ResID 形式のリソース識別名も指定できる、とのことです。
また、一意の名前にするために、重複するプロジェクトがある場合に、自動的に末尾に番号が追加されることもあります。
ビルド構成を追加する
今回作成するカスタムプロジェクトは、Release 構成を4つ用意することにします。Debug は静的ライブラリのみとします。
Debug | デバッグ用の静的ライブラリを作成します。 |
---|---|
Release DLL | 動的ライブラリを作成します。 |
Release /ML Static | 静的ライブラリのシングルスレッド版を作成します。 |
Release /MT Static | 静的ライブラリのマルチスレッド版を作成します。 |
Release /MD Static | 静的ライブラリのマルチスレッド DLL 版を作成します。 |
default.vcproj の有効化
とりあえず構成を追加できそうなファイルを探してみたところ、default.vcproj ファイルに Configuration Name タグの値として "Debug" や "Release" がありました。
とりあえず、ここを次のように変更してみます。
<?xml version="1.0"?>
<VisualStudioProject ProjectType="Visual C++" Version="7.00">
<Platform Name="Win32"/>
<Configuration Name="Debug|Win32"></Configuration>
<Configuration Name="Release DLL|Win32"></Configuration>
<Configuration Name="Release ML Static|Win32"></Configuration>
<Configuration Name="Release MT Static|Win32"></Configuration>
<Configuration Name="Release MD Static|Win32"></Configuration>
</VisualStudioProject>
けれどこれだけでは、構成は変化してくれないようです。
他のファイルをあたってみたところ、default.js の内部で AddConfig という関数を見つけました。その中で、config = proj.Object.Configurations("Debug") なる記述を見つけました。
config = proj.Object.Configurations('Release DLL');
config.IntermediateDirectory = 'ReleaseDLL';
config.OutputDirectory = 'ReleaseDLL';
var CLTool = config.Tools('VCCLCompilerTool');
// TODO: コンパイラ設定を追加する
var LinkTool = config.Tools('VCLinkerTool');
// TODO: リンカ設定を追加する
とりあえず既存のものの一連の流れに沿って、"Release DLL" 構成を次のように設定してみました。
なお、IntermediateDirectory は中間ファイルの出力ディレクトリを、OutputDirectory は最終出力ディレクトリを意味するプロパティのようです。
そしてこのテンプレートを使ってプロジェクトを作成してみたところ、null はオブジェクトではないというようなスクリプトエラーが発生してしまいました。
おそらく、proj.Object.Configurations('Release DLL'); が適切なオブジェクトを取得できなかったのでしょう。
ためしに default.js から AddConfig を呼ばないようにしてみても、Debug 構成や Release 構成はちゃんと生成されるようなので、おそらく CreateCustomProject 関数によって、これらの構成を実装しているプロジェクトが生成されているような感じです。
CreateCustomProject 関数は default.vcproj をテンプレートとして使っています。
が、調べてみると、どうやら strProjTemplatePath の値が '' に設定されているようです。これは wizard.FindSymbol('PROJECT_TEMPLATE_PATH') にて取得していますので、このシンボルが設定されていないということでしょう。
そして、設定されていない場合のディフォルトは Visual Studio .NET インストールフォルダの Vc7\VCWizards となります。よってこちらにおいてある default.vcproj が使われてしまっていました。
よって、カスタムプロジェクトのあるディレクトリの default.vcproj を使用したい場合、default.js の CreateCustomProject 関数を修正します。
修正箇所は strProjTemplatePath の値を設定している部分です。
function CreateCustomProject(strProjectName, strProjectPath)
{
try
{
var strProjTemplatePath = wizard.FindSymbol('START_PATH');
var strProjTemplate = '';
strProjTemplate = strProjTemplatePath + '\\default.vcproj';
このように、PROJECT_TEMPLATE_PATH から拾っていた strProjTemplatePath の値を、START_PATH から取得するように変更します。
ビルドの構成を設定する
登録したビルド構成のそれぞれに、構成情報を設定します。
とりあえず、default.js の AddConfig 関数が大きくなってしまうのは苦手なので、新たに次のような AddConfigDebug / AddConfigReleaseDLL / AddConfigReleaseML / AddConfigReleaseMT / AddConfigReleaseMD という、構成ごとの関数に分割しました。
さて、後はデバッグ情報の設定とか、ビルド構成のプロパティ設定をそれぞれで行わなくてはいけません。
なにかで既定の設定にできればいいのですけど、AddCommonConfig 関数では Debug および Release を設定するだけです。
既存のものを参考にしたいので、Vc7\VCWizards\win32wiz\scripts\1041 に保存されている default.js を参考にしてみました。
この中の AddSpecificConfig 関数が Win32 プロジェクトの Debug および Release を構成する部分で、"DLL" タイプが DLL プロジェクトを、"LIB" が静的ライブラリプロジェクトの設定内容です。
これを元に若干修正を加えたところ、デバッグ版の構成は次のような感じになりました。一応、MFC のサポート関連の部分は残してみました。
function AddConfigDebug(proj, strProjectName)
{
try
{
var bMFC = wizard.FindSymbol("SUPPORT_MFC");
var config = proj.Object.Configurations('Debug');
// ----- 基本設定 ---------------
config.IntermediateDirectory = 'Debug';
config.OutputDirectory = 'Debug';
config.CharacterSet = charSetMBCS;
config.ConfigurationType = typeStaticLibrary;
// ----- コンパイラの設定 ----------
var CLTool = config.Tools('VCCLCompilerTool');
CLTool.RuntimeLibrary = (bMFC ? rtMultiThreadedDebugDLL : rtSingleThreadedDebug);
var strDefines = GetPlatformDefine(config);
strDefines += "_DEBUG";
strDefines += ";_LIB";
if (bMFC) config.UseOfMFC = useMfcDynamic;
CLTool.PreprocessorDefinitions = strDefines;
CLTool.DebugInformationFormat = debugEditAndContinue;
// ----- ライブラリアンの設定 --------
var LibTool = config.Tools("VCLibrarianTool");
LibTool.OutputFile = "$(OutDir)/" + strProjectName + "D.lib";
}
catch (e)
{
throw e;
}
}
と、こんな感じになりました。
ためしにこのテンプレートを使ったプロジェクトを作成してみると、しっかりと Debug 構成が設定された状態のプロジェクトが作成されました。
Release のほうも、似たようにやっていけば完成です
クラステンプレートの場合
クラステンプレートも、ほとんど同じ要領で作成することができます。プロジェクトと違う点としては、*.vsz *.vsdir *.ico ファイルを Vc7\vcprojects\ ではなくて Vc7\VCAddClass へ入れる程度です。
あとは必要に応じて、フォルダを作成するスクリプトを消去したりすれば出来上がりです。