-
Notifications
You must be signed in to change notification settings - Fork 2k
Expand file tree
/
Copy pathCompilerVersion.cs
More file actions
139 lines (120 loc) · 4.69 KB
/
CompilerVersion.cs
File metadata and controls
139 lines (120 loc) · 4.69 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
namespace Semmle.Extraction.CSharp
{
/// <summary>
/// Identifies the compiler and framework from the command line arguments.
/// --compiler specifies the compiler
/// --framework specifies the .net framework
/// </summary>
public class CompilerVersion
{
const string csc_rsp = "csc.rsp";
readonly string specifiedFramework = null;
/// <summary>
/// The value specified by --compiler, or null.
/// </summary>
public string SpecifiedCompiler
{
get;
private set;
}
/// <summary>
/// Why was the candidate exe rejected as a compiler?
/// </summary>
public string SkipReason
{
get;
private set;
}
/// <summary>
/// Probes the compiler (if specified).
/// </summary>
/// <param name="options">The command line arguments.</param>
public CompilerVersion(Options options)
{
SpecifiedCompiler = options.CompilerName;
specifiedFramework = options.Framework;
if (SpecifiedCompiler != null)
{
if (!File.Exists(SpecifiedCompiler))
{
SkipExtractionBecause("the specified file does not exist");
return;
}
// Reads the file details from the .exe
var versionInfo = FileVersionInfo.GetVersionInfo(SpecifiedCompiler);
var compilerDir = Path.GetDirectoryName(SpecifiedCompiler);
var knownCompilerNames = new Dictionary<string, string>
{
{ "csc.exe", "Microsoft" },
{ "csc2.exe", "Microsoft" },
{ "csc.dll", "Microsoft" },
{ "mcs.exe", "Novell" }
};
var mscorlibExists = File.Exists(Path.Combine(compilerDir, "mscorlib.dll"));
if (specifiedFramework == null && mscorlibExists)
{
specifiedFramework = compilerDir;
}
if (!knownCompilerNames.TryGetValue(versionInfo.OriginalFilename, out var vendor))
{
SkipExtractionBecause("the compiler name is not recognised");
return;
}
if (versionInfo.LegalCopyright == null || !versionInfo.LegalCopyright.Contains(vendor))
{
SkipExtractionBecause($"the compiler isn't copyright {vendor}, but instead {versionInfo.LegalCopyright ?? "<null>"}");
return;
}
}
ArgsWithResponse = AddDefaultResponse(CscRsp, options.CompilerArguments).ToArray();
}
void SkipExtractionBecause(string reason)
{
SkipExtraction = true;
SkipReason = reason;
}
/// <summary>
/// The directory containing the .Net Framework.
/// </summary>
public string FrameworkPath => specifiedFramework ?? RuntimeEnvironment.GetRuntimeDirectory();
/// <summary>
/// The file csc.rsp.
/// </summary>
string CscRsp => Path.Combine(FrameworkPath, csc_rsp);
/// <summary>
/// Should we skip extraction?
/// Only if csc.exe was specified but it wasn't a compiler.
/// </summary>
public bool SkipExtraction
{
get;
private set;
}
/// <summary>
/// Gets additional reference directories - the compiler directory.
/// </summary>
public string AdditionalReferenceDirectories => SpecifiedCompiler != null ? Path.GetDirectoryName(SpecifiedCompiler) : null;
/// <summary>
/// Adds @csc.rsp to the argument list to mimic csc.exe.
/// </summary>
/// <param name="responseFile">The full pathname of csc.rsp.</param>
/// <param name="args">The other command line arguments.</param>
/// <returns>Modified list of arguments.</returns>
static IEnumerable<string> AddDefaultResponse(string responseFile, IEnumerable<string> args)
{
return SuppressDefaultResponseFile(args) || !File.Exists(responseFile) ?
args :
new[] { "@" + responseFile }.Concat(args);
}
static bool SuppressDefaultResponseFile(IEnumerable<string> args)
{
return args.Any(arg => new[] { "/noconfig", "-noconfig" }.Contains(arg.ToLowerInvariant()));
}
public readonly string[] ArgsWithResponse;
}
}