/// <summary> /// Runs iwyu. Blocks until finished. /// </summary> static public string RunIncludeWhatYouUse(string fullFileName, EnvDTE.Project project, IncludeWhatYouUseOptionsPage settings) { string reasonForFailure; string preprocessorDefintions = VSUtils.VCUtils.GetCompilerSetting_PreprocessorDefinitions(project, out reasonForFailure); if (preprocessorDefintions == null) { Output.Instance.ErrorMsg("Can't run IWYU: {0}", reasonForFailure); return(null); } string output = ""; using (var process = new System.Diagnostics.Process()) { process.StartInfo.UseShellExecute = false; process.StartInfo.CreateNoWindow = true; process.StartInfo.RedirectStandardOutput = true; process.StartInfo.RedirectStandardError = true; process.StartInfo.FileName = settings.ExecutablePath; process.StartInfo.Arguments = ""; // Include-paths and Preprocessor. var includeEntries = VSUtils.GetProjectIncludeDirectories(project, false); process.StartInfo.Arguments = includeEntries.Aggregate("", (current, inc) => current + ("-I \"" + inc + "\" ")); process.StartInfo.Arguments = preprocessorDefintions. Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries). Aggregate(process.StartInfo.Arguments, (current, def) => current + ("-D" + def + " ")); // Clang options // Disable all diagnostics process.StartInfo.Arguments += "-w "; // ... despite of that "invalid token paste" comes through a lot. Disable it. process.StartInfo.Arguments += "-Wno-invalid-token-paste "; // Assume C++14 process.StartInfo.Arguments += "-std=c++14 "; // MSVC specific. See https://clang.llvm.org/docs/UsersManual.html#microsoft-extensions process.StartInfo.Arguments += "-fms-compatibility -fms-extensions -fdelayed-template-parsing "; process.StartInfo.Arguments += $"-fmsc-version={VSUtils.GetMSCVerString()} "; // Architecture var targetMachine = VSUtils.VCUtils.GetLinkerSetting_TargetMachine(project, out reasonForFailure); if (!targetMachine.HasValue) { Output.Instance.ErrorMsg("Failed to query for target machine: {0}", reasonForFailure); } else { switch (targetMachine.Value) { // Most targets give an error of this form: // "error: unknown target CPU 'x86'" // It seems iwyu is only really fine with x86-64 /*case VCProjectUtils.Base.TargetMachineType.X86: * process.StartInfo.Arguments += "-march=x86 "; * break;*/ case VCProjectUtils.Base.TargetMachineType.AMD64: process.StartInfo.Arguments += "-march=x86-64 "; break; /*case VCProjectUtils.Base.TargetMachineType.ARM: * process.StartInfo.Arguments += "-march=arm "; * break; * case VCProjectUtils.Base.TargetMachineType.MIPS: * process.StartInfo.Arguments += "-march=mips "; * break; * case VCProjectUtils.Base.TargetMachineType.THUMB: * process.StartInfo.Arguments += "-march=thumb "; * break;*/ } } // icwyu options { process.StartInfo.Arguments += "-Xiwyu --verbose=" + settings.LogVerbosity + " "; for (int i = 0; i < settings.MappingFiles.Length; ++i) { process.StartInfo.Arguments += "-Xiwyu --mapping_file=\"" + settings.MappingFiles[i] + "\" "; } if (settings.NoDefaultMappings) { process.StartInfo.Arguments += "-Xiwyu --no_default_mappings "; } if (settings.PCHInCode) { process.StartInfo.Arguments += "-Xiwyu --pch_in_code "; } switch (settings.PrefixHeaderIncludes) { case IncludeWhatYouUseOptionsPage.PrefixHeaderMode.Add: process.StartInfo.Arguments += "-Xiwyu --prefix_header_includes=add "; break; case IncludeWhatYouUseOptionsPage.PrefixHeaderMode.Remove: process.StartInfo.Arguments += "-Xiwyu --prefix_header_includes=remove "; break; case IncludeWhatYouUseOptionsPage.PrefixHeaderMode.Keep: process.StartInfo.Arguments += "-Xiwyu --prefix_header_includes=keep "; break; } if (settings.TransitiveIncludesOnly) { process.StartInfo.Arguments += "-Xiwyu --transitive_includes_only "; } // Set max line length so something large so we don't loose comment information. // Documentation: // --max_line_length: maximum line length for includes. Note that this only affects comments and alignment thereof, // the maximum line length can still be exceeded with long file names(default: 80). process.StartInfo.Arguments += "-Xiwyu --max_line_length=1024 "; // Custom stuff. process.StartInfo.Arguments += settings.AdditionalParameters; process.StartInfo.Arguments += " "; } // Finally, the file itself. process.StartInfo.Arguments += "\""; process.StartInfo.Arguments += fullFileName; process.StartInfo.Arguments += "\""; Output.Instance.Write("Running command '{0}' with following arguments:\n{1}\n\n", process.StartInfo.FileName, process.StartInfo.Arguments); // Start the child process. process.EnableRaisingEvents = true; process.OutputDataReceived += (s, args) => { Output.Instance.WriteLine(args.Data); output += args.Data + "\n"; }; process.ErrorDataReceived += (s, args) => { Output.Instance.WriteLine(args.Data); output += args.Data + "\n"; }; process.Start(); process.BeginOutputReadLine(); process.BeginErrorReadLine(); process.WaitForExit(); process.CancelOutputRead(); process.CancelErrorRead(); } return(output); }
/// <summary> /// Runs iwyu. Blocks until finished. /// </summary> static public string RunIncludeWhatYouUse(string fullFileName, EnvDTE.Project project, IncludeWhatYouUseOptionsPage settings) { string reasonForFailure; string preprocessorDefintions = VSUtils.VCUtils.GetCompilerSetting_PreprocessorDefinitions(project, out reasonForFailure); if (preprocessorDefintions == null) { Output.Instance.ErrorMsg("Can't run IWYU: {0}", reasonForFailure); return(null); } string output = ""; using (var process = new System.Diagnostics.Process()) { process.StartInfo.UseShellExecute = false; process.StartInfo.CreateNoWindow = true; process.StartInfo.RedirectStandardOutput = true; process.StartInfo.RedirectStandardError = true; process.StartInfo.FileName = settings.ExecutablePath; // Clang options // Disable all diagnostics var iwyuOptions = "-w "; // ... despite of that "invalid token paste" comes through a lot. Disable it. iwyuOptions += "-Wno-invalid-token-paste "; // Assume C++14 // arguments += "-std=c++14 "; // MSVC specific. See https://clang.llvm.org/docs/UsersManual.html#microsoft-extensions iwyuOptions += "-fms-extensions -fms-compatibility -fdelayed-template-parsing "; iwyuOptions += $"-fmsc-version={VSUtils.GetMSCVerString()} "; // Architecture var targetMachine = VSUtils.VCUtils.GetLinkerSetting_TargetMachine(project, out reasonForFailure); if (!targetMachine.HasValue) { Output.Instance.ErrorMsg("Failed to query for target machine: {0}", reasonForFailure); } else { switch (targetMachine.Value) { // Most targets give an error of this form: // "error: unknown target CPU 'x86'" // It seems iwyu is only really fine with x86-64 /*case VCProjectUtils.Base.TargetMachineType.X86: * clangOptions += "-march=x86 "; * break;*/ case VCProjectUtils.Base.TargetMachineType.AMD64: iwyuOptions += "-march=x86-64 "; break; /*case VCProjectUtils.Base.TargetMachineType.ARM: * clangOptions += "-march=arm "; * break; * case VCProjectUtils.Base.TargetMachineType.MIPS: * clangOptions += "-march=mips "; * break; * case VCProjectUtils.Base.TargetMachineType.THUMB: * clangOptions += "-march=thumb "; * break;*/ } } iwyuOptions += "-Xiwyu --verbose=" + settings.LogVerbosity + " "; if (settings.MappingFiles.Length == 0) { settings.MappingFiles = new string[] { "stl.c.headers.imp", "msvc.imp", "boost-all.imp", "boost-all-private.imp" }; } for (int i = 0; i < settings.MappingFiles.Length; ++i) { iwyuOptions += "-Xiwyu --mapping_file=\"" + settings.MappingFiles[i] + "\" "; } if (settings.NoDefaultMappings) { iwyuOptions += "-Xiwyu --no_default_mappings "; } if (settings.PCHInCode) { iwyuOptions += "-Xiwyu --pch_in_code "; } switch (settings.PrefixHeaderIncludes) { case IncludeWhatYouUseOptionsPage.PrefixHeaderMode.Add: iwyuOptions += "-Xiwyu --prefix_header_includes=add "; break; case IncludeWhatYouUseOptionsPage.PrefixHeaderMode.Remove: iwyuOptions += "-Xiwyu --prefix_header_includes=remove "; break; case IncludeWhatYouUseOptionsPage.PrefixHeaderMode.Keep: iwyuOptions += "-Xiwyu --prefix_header_includes=keep "; break; } if (settings.TransitiveIncludesOnly) { iwyuOptions += "-Xiwyu --transitive_includes_only "; } // Set max line length so something large so we don't loose comment information. // Documentation: // --max_line_length: maximum line length for includes. Note that this only affects comments and alignment thereof, // the maximum line length can still be exceeded with long file names(default: 80). iwyuOptions += "-Xiwyu --max_line_length=1024 "; // Include-paths and Preprocessor. var includeEntries = VSUtils.GetProjectIncludeDirectories(project, false); var includes = includeEntries.Aggregate("", (current, inc) => current + ("-I \"" + Regex.Escape(inc) + "\" ")); var defines = " -D " + string.Join(" -D", preprocessorDefintions.Split(';')); // write support file. Long argument lists lead to an error. Support files are the solution here. // https://github.com/Wumpf/IncludeToolbox/issues/36 var supportFile = Path.GetTempFileName(); var supportContent = includes + " " + defines + " " + Regex.Escape(fullFileName); File.WriteAllText(supportFile, supportContent); process.StartInfo.Arguments = $"{iwyuOptions} {settings.AdditionalParameters} @{supportFile}"; Output.Instance.Write("Running command '{0}' with following arguments:\n{1}\n\n", process.StartInfo.FileName, process.StartInfo.Arguments); // Start the child process. process.EnableRaisingEvents = true; process.OutputDataReceived += (s, args) => { Output.Instance.WriteLine(args.Data); output += args.Data + "\n"; }; process.ErrorDataReceived += (s, args) => { Output.Instance.WriteLine(args.Data); output += args.Data + "\n"; }; process.Start(); process.BeginOutputReadLine(); process.BeginErrorReadLine(); process.WaitForExit(); process.CancelOutputRead(); process.CancelErrorRead(); } output = Regex.Replace(output, @"#include <moduleworks_dummy.*?>.*?\n", ""); return(output); }
/// <summary> /// Runs iwyu. Blocks until finished. /// </summary> static public async Task <string> RunIncludeWhatYouUse(string fullFileName, EnvDTE.Project project, IncludeWhatYouUseOptionsPage settings) { await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(); string preprocessorDefintions; try { preprocessorDefintions = VSUtils.VCUtils.GetCompilerSetting_PreprocessorDefinitions(project); } catch (VCQueryFailure e) { await Output.Instance.ErrorMsg("Can't run IWYU: {0}", e.Message); return(null); } string output = ""; using (var process = new System.Diagnostics.Process()) { process.StartInfo.UseShellExecute = false; process.StartInfo.CreateNoWindow = true; process.StartInfo.RedirectStandardOutput = true; process.StartInfo.RedirectStandardError = true; process.StartInfo.FileName = settings.ExecutablePath; // Clang options var clangOptionList = new List <string>(); // Disable all diagnostics clangOptionList.Add("-w"); // ... despite of that "invalid token paste" comes through a lot. Disable it. clangOptionList.Add("-Wno-invalid-token-paste"); // Assume C++14 clangOptionList.Add("-std=c++14"); // MSVC specific. See https://clang.llvm.org/docs/UsersManual.html#microsoft-extensions clangOptionList.Add("-fms-compatibility -fms-extensions -fdelayed-template-parsing"); clangOptionList.Add($"-fmsc-version={VSUtils.GetMSCVerString()}"); // Architecture try { switch (VSUtils.VCUtils.GetLinkerSetting_TargetMachine(project)) { // Most targets give an error of this form: // "error: unknown target CPU 'x86'" // It seems iwyu is only really fine with x86-64 /*case VCProjectUtils.Base.TargetMachineType.X86: * clangOptions.Add("-march=x86"); * break;*/ case VCHelper.TargetMachineType.AMD64: clangOptionList.Add("-march=x86-64"); break; /*case VCProjectUtils.Base.TargetMachineType.ARM: * clangOptions.Add("-march=arm"); * break; * case VCProjectUtils.Base.TargetMachineType.MIPS: * clangOptions.Add(""-march=mips"); * break; * case VCProjectUtils.Base.TargetMachineType.THUMB: * clangOptions.Add(""-march=thumb"); * break;*/ } } catch (VCQueryFailure e) { await Output.Instance.ErrorMsg($"Failed to query for target machine: {e.Message}"); } // icwyu options var iwyuOptionList = new List <string>(); iwyuOptionList.Add("--verbose=" + settings.LogVerbosity); for (int i = 0; i < settings.MappingFiles.Length; ++i) { iwyuOptionList.Add("--mapping_file=\"" + settings.MappingFiles[i] + "\""); } if (settings.NoDefaultMappings) { iwyuOptionList.Add("--no_default_mappings"); } if (settings.PCHInCode) { iwyuOptionList.Add("--pch_in_code"); } switch (settings.PrefixHeaderIncludes) { case IncludeWhatYouUseOptionsPage.PrefixHeaderMode.Add: iwyuOptionList.Add("--prefix_header_includes=add"); break; case IncludeWhatYouUseOptionsPage.PrefixHeaderMode.Remove: iwyuOptionList.Add("--prefix_header_includes=remove"); break; case IncludeWhatYouUseOptionsPage.PrefixHeaderMode.Keep: iwyuOptionList.Add("--prefix_header_includes=keep"); break; } if (settings.TransitiveIncludesOnly) { iwyuOptionList.Add("--transitive_includes_only"); } // Set max line length so something large so we don't loose comment information. // Documentation: // --max_line_length: maximum line length for includes. Note that this only affects comments and alignment thereof, // the maximum line length can still be exceeded with long file names(default: 80). iwyuOptionList.Add("--max_line_length=1024"); /// write support file with includes, defines and the targetgile. Long argument lists lead to an error. Support files are the solution here. /// https://github.com/Wumpf/IncludeToolbox/issues/36 // Include-paths and Preprocessor. var includes = string.Join(" ", VSUtils.GetProjectIncludeDirectories(project, false).Select(x => "-I \"" + x.Replace("\\", "\\\\") + "\"")); var defines = string.Join(" ", preprocessorDefintions.Split(';').Select(x => "-D" + x)); var filename = "\"" + fullFileName.Replace("\\", "\\\\") + "\""; var supportFilePath = Path.GetTempFileName(); File.WriteAllText(supportFilePath, includes + " " + defines + " " + filename); var clangOptions = string.Join(" ", clangOptionList); // each include-what-you-use parameter has an -Xiwyu prefix var iwyuOptions = string.Join(" ", iwyuOptionList.Select(x => " -Xiwyu " + x)); process.StartInfo.Arguments = $"{clangOptions} {iwyuOptions} {settings.AdditionalParameters} \"@{supportFilePath}\""; Output.Instance.Write("Running command '{0}' with following arguments:\n{1}\n\n", process.StartInfo.FileName, process.StartInfo.Arguments); // Start the child process. process.EnableRaisingEvents = true; process.OutputDataReceived += (s, args) => { Output.Instance.WriteLine(args.Data); output += args.Data + "\n"; }; process.ErrorDataReceived += (s, args) => { Output.Instance.WriteLine(args.Data); output += args.Data + "\n"; }; process.Start(); process.BeginOutputReadLine(); process.BeginErrorReadLine(); process.WaitForExit(); process.CancelOutputRead(); process.CancelErrorRead(); } return(output); }