私はいくつかの異なる提案があります
NMakeの代わりにMSBuildを使用して調査することをお勧めします
より複雑ですが、.Netから直接制御でき、VS 2010以降のすべてのプロジェクトおよびC#/ VB/etcのVSプロジェクトファイルの形式です。それより前のプロジェクト
小さなヘルパープログラムを使用して環境をキャプチャし、それをプロセスに注入することができます
これはおそらく少しやり過ぎですが、うまくいくでしょう。vsvarsall.batは、いくつかの環境変数を設定する以外に魔法のようなことは何もしません。したがって、実行した結果を記録し、それを作成したプロセスの環境で再生するだけです。
ヘルパープログラム(envcapture.exe)は簡単です。環境内のすべての変数を一覧表示し、それらを標準出力に出力するだけです。これはプログラムコード全体です。貼り付けますMain()
:
XElement documentElement = new XElement("Environment");
foreach (DictionaryEntry envVariable in Environment.GetEnvironmentVariables())
{
documentElement.Add(new XElement(
"Variable",
new XAttribute("Name", envVariable.Key),
envVariable.Value
));
}
Console.WriteLine(documentElement);
このプログラムの代わりに呼び出してその出力を解析するだけで解決できるかもしれませんがset
、環境変数に改行が含まれていると、それが機能しなくなる可能性があります。
メインプログラムの場合:
まず、vcvarsall.batによって初期化された環境をキャプチャする必要があります。これを行うには、のようなコマンドラインを使用しますcmd.exe /s /c " "...\vcvarsall.bat" x86 && "...\envcapture.exe" "
。vcvarsall.batは環境を変更し、envcapture.exeがそれを出力します。次に、メインプログラムはその出力をキャプチャし、辞書に解析します。(注:vsVersion
これは90または100または110のようなものになります)
private static Dictionary<string, string> CaptureBuildEnvironment(
int vsVersion,
string architectureName
)
{
// assume the helper is in the same directory as this exe
string myExeDir = Path.GetDirectoryName(
Assembly.GetExecutingAssembly().Location
);
string envCaptureExe = Path.Combine(myExeDir, "envcapture.exe");
string vsToolsVariableName = String.Format("VS{0}COMNTOOLS", vsVersion);
string envSetupScript = Path.Combine(
Environment.GetEnvironmentVariable(vsToolsVariableName),
@"..\..\VC\vcvarsall.bat"
);
using (Process envCaptureProcess = new Process())
{
envCaptureProcess.StartInfo.FileName = "cmd.exe";
// the /s and the extra quotes make sure that paths with
// spaces in the names are handled properly
envCaptureProcess.StartInfo.Arguments = String.Format(
"/s /c \" \"{0}\" {1} && \"{2}\" \"",
envSetupScript,
architectureName,
envCaptureExe
);
envCaptureProcess.StartInfo.RedirectStandardOutput = true;
envCaptureProcess.StartInfo.RedirectStandardError = true;
envCaptureProcess.StartInfo.UseShellExecute = false;
envCaptureProcess.StartInfo.CreateNoWindow = true;
envCaptureProcess.Start();
// read and discard standard error, or else we won't get output from
// envcapture.exe at all
envCaptureProcess.ErrorDataReceived += (sender, e) => { };
envCaptureProcess.BeginErrorReadLine();
string outputString = envCaptureProcess.StandardOutput.ReadToEnd();
// vsVersion < 110 prints out a line in vcvars*.bat. Ignore
// everything before the first '<'.
int xmlStartIndex = outputString.IndexOf('<');
if (xmlStartIndex == -1)
{
throw new Exception("No environment block was captured");
}
XElement documentElement = XElement.Parse(
outputString.Substring(xmlStartIndex)
);
Dictionary<string, string> capturedVars
= new Dictionary<string, string>();
foreach (XElement variable in documentElement.Elements("Variable"))
{
capturedVars.Add(
(string)variable.Attribute("Name"),
(string)variable
);
}
return capturedVars;
}
}
後で、ビルド環境でコマンドを実行する場合は、新しいプロセスの環境変数を以前にキャプチャした環境変数に置き換えるだけです。CaptureBuildEnvironment
プログラムを実行するたびに、引数の組み合わせごとに1回だけ呼び出す必要があります。ただし、実行の合間に保存しようとしないでください。保存すると古くなります。
static void Main()
{
string command = "nmake";
string args = "";
Dictionary<string, string> buildEnvironment =
CaptureBuildEnvironment(100, "x86");
ProcessStartInfo info = new ProcessStartInfo();
// the search path from the adjusted environment doesn't seem
// to get used in Process.Start, but cmd will use it.
info.FileName = "cmd.exe";
info.Arguments = String.Format(
"/s /c \" \"{0}\" {1} \"",
command,
args
);
info.CreateNoWindow = true;
info.UseShellExecute = false;
info.RedirectStandardOutput = true;
info.RedirectStandardError = true;
foreach (var i in buildEnvironment)
{
info.EnvironmentVariables[(string)i.Key] = (string)i.Value;
}
using (Process p = Process.Start(info))
{
// do something with your process. If you're capturing standard output,
// you'll also need to capture standard error. Be careful to avoid the
// deadlock bug mentioned in the docs for
// ProcessStartInfo.RedirectStandardOutput.
}
}
これを使用する場合は、vcvarsall.batが見つからないか失敗すると恐らく死ぬ可能性があり、en-US以外のロケールのシステムで問題が発生する可能性があることに注意してください。