-
Notifications
You must be signed in to change notification settings - Fork 4.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Produce ref assemblies from command-line and msbuild #17558
Changes from all commits
04a5c0d
49a84f5
89aede6
1243e70
86d2473
cdebcc0
43db8ac
41399cd
d0b7133
e062d96
f8139cc
56ba8c9
7258b4b
ef4ee02
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -67,6 +67,8 @@ internal sealed override CommandLineArguments CommonParse(IEnumerable<string> ar | |
string outputDirectory = baseDirectory; | ||
ImmutableArray<KeyValuePair<string, string>> pathMap = ImmutableArray<KeyValuePair<string, string>>.Empty; | ||
string outputFileName = null; | ||
string outputRefFilePath = null; | ||
bool metadataOnly = false; | ||
string documentationPath = null; | ||
string errorLogPath = null; | ||
bool parseDocumentationComments = false; //Don't just null check documentationFileName because we want to do this even if the file name is invalid. | ||
|
@@ -379,6 +381,7 @@ internal sealed override CommandLineArguments CommonParse(IEnumerable<string> ar | |
} | ||
|
||
continue; | ||
|
||
case "out": | ||
if (string.IsNullOrWhiteSpace(value)) | ||
{ | ||
|
@@ -391,6 +394,26 @@ internal sealed override CommandLineArguments CommonParse(IEnumerable<string> ar | |
|
||
continue; | ||
|
||
case "refout": | ||
value = RemoveQuotesAndSlashes(value); | ||
if (string.IsNullOrEmpty(value)) | ||
{ | ||
AddDiagnostic(diagnostics, ErrorCode.ERR_NoFileSpec, arg); | ||
} | ||
else | ||
{ | ||
outputRefFilePath = ParseGenericPathToFile(value, diagnostics, baseDirectory); | ||
} | ||
|
||
continue; | ||
|
||
case "refonly": | ||
if (value != null) | ||
break; | ||
|
||
metadataOnly = true; | ||
continue; | ||
|
||
case "t": | ||
case "target": | ||
if (value == null) | ||
|
@@ -1141,6 +1164,16 @@ internal sealed override CommandLineArguments CommonParse(IEnumerable<string> ar | |
diagnosticOptions[o.Key] = o.Value; | ||
} | ||
|
||
if (metadataOnly && outputRefFilePath != null) | ||
{ | ||
AddDiagnostic(diagnostics, diagnosticOptions, ErrorCode.ERR_NoRefOutWhenRefOnly); | ||
} | ||
|
||
if (outputKind == OutputKind.NetModule && (metadataOnly || outputRefFilePath != null)) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I would expect this condition to be intercepted on the API level as well. #Closed |
||
{ | ||
AddDiagnostic(diagnostics, diagnosticOptions, ErrorCode.ERR_NoNetModuleOutputWhenRefOutOrRefOnly); | ||
} | ||
|
||
if (!IsScriptRunner && !sourceFilesSpecified && (outputKind.IsNetModule() || !resourcesOrModulesSpecified)) | ||
{ | ||
AddDiagnostic(diagnostics, diagnosticOptions, ErrorCode.WRN_NoSources); | ||
|
@@ -1257,7 +1290,7 @@ internal sealed override CommandLineArguments CommonParse(IEnumerable<string> ar | |
|
||
var emitOptions = new EmitOptions | ||
( | ||
metadataOnly: false, | ||
metadataOnly: metadataOnly, | ||
debugInformationFormat: debugInformationFormat, | ||
pdbFilePath: null, // to be determined later | ||
outputNameOverride: null, // to be determined later | ||
|
@@ -1282,8 +1315,9 @@ internal sealed override CommandLineArguments CommonParse(IEnumerable<string> ar | |
Utf8Output = utf8output, | ||
CompilationName = compilationName, | ||
OutputFileName = outputFileName, | ||
OutputRefFilePath = outputRefFilePath, | ||
PdbPath = pdbPath, | ||
EmitPdb = emitPdb, | ||
EmitPdb = emitPdb && !metadataOnly, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Code above checks the value of emitPdb. So if we are gonna change it here the check above won't take the metadataOnly flag into account. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That's correct and that's by design. The idea is that you can just add There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. OK. I'd then add a comment. |
||
SourceLink = sourceLink, | ||
OutputDirectory = outputDirectory, | ||
DocumentationPath = documentationPath, | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2784,6 +2784,34 @@ public void ParseOut() | |
// error CS2005: Missing file specification for '/out:' option | ||
Diagnostic(ErrorCode.ERR_NoFileSpec).WithArguments("/out:")); | ||
|
||
parsedArgs = DefaultParse(new[] { @"/refout:", "a.cs" }, baseDirectory); | ||
parsedArgs.Errors.Verify( | ||
// error CS2005: Missing file specification for '/refout:' option | ||
Diagnostic(ErrorCode.ERR_NoFileSpec).WithArguments("/refout:")); | ||
|
||
parsedArgs = DefaultParse(new[] { @"/refout:ref.dll", "/refonly", "a.cs" }, baseDirectory); | ||
parsedArgs.Errors.Verify( | ||
// error CS8301: Do not use refout when using refonly. | ||
Diagnostic(ErrorCode.ERR_NoRefOutWhenRefOnly).WithLocation(1, 1)); | ||
|
||
parsedArgs = DefaultParse(new[] { "/refonly:incorrect", "a.cs" }, baseDirectory); | ||
parsedArgs.Errors.Verify( | ||
// error CS2007: Unrecognized option: '/refonly:incorrect' | ||
Diagnostic(ErrorCode.ERR_BadSwitch).WithArguments("/refonly:incorrect").WithLocation(1, 1) | ||
); | ||
|
||
parsedArgs = DefaultParse(new[] { @"/refout:ref.dll", "/target:module", "a.cs" }, baseDirectory); | ||
parsedArgs.Errors.Verify( | ||
// error CS8302: Cannot compile net modules when using /refout or /refonly. | ||
Diagnostic(ErrorCode.ERR_NoNetModuleOutputWhenRefOutOrRefOnly).WithLocation(1, 1) | ||
); | ||
|
||
parsedArgs = DefaultParse(new[] { @"/refonly", "/target:module", "a.cs" }, baseDirectory); | ||
parsedArgs.Errors.Verify( | ||
// error CS8302: Cannot compile net modules when using /refout or /refonly. | ||
Diagnostic(ErrorCode.ERR_NoNetModuleOutputWhenRefOutOrRefOnly).WithLocation(1, 1) | ||
); | ||
|
||
// Dev11 reports CS2007: Unrecognized option: '/out' | ||
parsedArgs = DefaultParse(new[] { @"/out", "a.cs" }, baseDirectory); | ||
parsedArgs.Errors.Verify( | ||
|
@@ -8845,6 +8873,164 @@ public void Version() | |
} | ||
} | ||
|
||
[Fact] | ||
public void RefOut() | ||
{ | ||
var dir = Temp.CreateDirectory(); | ||
dir.CreateDirectory("ref"); | ||
|
||
var src = dir.CreateFile("a.cs"); | ||
src.WriteAllText(@" | ||
class C | ||
{ | ||
/// <summary>Main method</summary> | ||
public static void Main() | ||
{ | ||
System.Console.Write(""Hello""); | ||
} | ||
}"); | ||
|
||
var outWriter = new StringWriter(CultureInfo.InvariantCulture); | ||
var csc = new MockCSharpCompiler(null, dir.Path, | ||
new[] { "/nologo", "/out:a.exe", "/refout:ref/a.dll", "/doc:doc.xml", "/deterministic", "a.cs" }); | ||
|
||
int exitCode = csc.Run(outWriter); | ||
Assert.Equal(0, exitCode); | ||
|
||
var exe = Path.Combine(dir.Path, "a.exe"); | ||
Assert.True(File.Exists(exe)); | ||
|
||
MetadataReaderUtils.VerifyPEMetadata(exe, | ||
new[] { "TypeDef:<Module>", "TypeDef:C" }, | ||
new[] { "MethodDef: Void Main()", "MethodDef: Void .ctor()" }, | ||
new[] { "CompilationRelaxationsAttribute", "RuntimeCompatibilityAttribute", "DebuggableAttribute" } | ||
); | ||
|
||
var doc = Path.Combine(dir.Path, "doc.xml"); | ||
Assert.True(File.Exists(doc)); | ||
|
||
var content = File.ReadAllText(doc); | ||
var expectedDoc = | ||
@"<?xml version=""1.0""?> | ||
<doc> | ||
<assembly> | ||
<name>a</name> | ||
</assembly> | ||
<members> | ||
<member name=""M:C.Main""> | ||
<summary>Main method</summary> | ||
</member> | ||
</members> | ||
</doc>"; | ||
Assert.Equal(expectedDoc, content.Trim()); | ||
|
||
var output = ProcessUtilities.RunAndGetOutput(exe, startFolder: dir.Path); | ||
Assert.Equal("Hello", output.Trim()); | ||
|
||
var refDll = Path.Combine(dir.Path, Path.Combine("ref", "a.dll")); | ||
Assert.True(File.Exists(refDll)); | ||
|
||
// The types and members that are included needs further refinement. | ||
// ReferenceAssemblyAttribute is missing. | ||
// See issue https://github.com/dotnet/roslyn/issues/17612 | ||
MetadataReaderUtils.VerifyPEMetadata(refDll, | ||
new[] { "TypeDef:<Module>", "TypeDef:C" }, | ||
new[] { "MethodDef: Void Main()", "MethodDef: Void .ctor()" }, | ||
new[] { "CompilationRelaxationsAttribute", "RuntimeCompatibilityAttribute", "DebuggableAttribute" } | ||
); | ||
|
||
output = ProcessUtilities.RunAndGetOutput(refDll, startFolder: dir.ToString(), expectedRetCode: -532462766); | ||
|
||
// Clean up temp files | ||
CleanupAllGeneratedFiles(dir.Path); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Are the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good point. I wasn't disposing stream above ( In reply to: 106547188 [](ancestors = 106547188) |
||
} | ||
|
||
[Fact] | ||
public void RefOutWithError() | ||
{ | ||
var dir = Temp.CreateDirectory(); | ||
dir.CreateDirectory("ref"); | ||
|
||
var src = dir.CreateFile("a.cs"); | ||
src.WriteAllText(@"class C { public static void Main() { error(); } }"); | ||
|
||
var outWriter = new StringWriter(CultureInfo.InvariantCulture); | ||
var csc = new MockCSharpCompiler(null, dir.Path, | ||
new[] { "/nologo", "/out:a.dll", "/refout:ref/a.dll", "/deterministic", "a.cs" }); | ||
int exitCode = csc.Run(outWriter); | ||
Assert.Equal(1, exitCode); | ||
|
||
var dll = Path.Combine(dir.Path, "a.dll"); | ||
Assert.False(File.Exists(dll)); | ||
|
||
var refDll = Path.Combine(dir.Path, Path.Combine("ref", "a.dll")); | ||
Assert.False(File.Exists(refDll)); | ||
|
||
Assert.Equal("a.cs(1,39): error CS0103: The name 'error' does not exist in the current context", outWriter.ToString().Trim()); | ||
|
||
// Clean up temp files | ||
CleanupAllGeneratedFiles(dir.Path); | ||
} | ||
|
||
[Fact] | ||
public void RefOnly() | ||
{ | ||
var dir = Temp.CreateDirectory(); | ||
|
||
var src = dir.CreateFile("a.cs"); | ||
src.WriteAllText(@" | ||
class C | ||
{ | ||
/// <summary>Main method</summary> | ||
public static void Main() | ||
{ | ||
error(); // semantic error in method body | ||
} | ||
}"); | ||
|
||
var outWriter = new StringWriter(CultureInfo.InvariantCulture); | ||
var csc = new MockCSharpCompiler(null, dir.Path, | ||
new[] { "/nologo", "/out:a.dll", "/refonly", "/debug", "/deterministic", "/doc:doc.xml", "a.cs" }); | ||
int exitCode = csc.Run(outWriter); | ||
Assert.Equal(0, exitCode); | ||
|
||
var refDll = Path.Combine(dir.Path, "a.dll"); | ||
Assert.True(File.Exists(refDll)); | ||
|
||
// The types and members that are included needs further refinement. | ||
// ReferenceAssemblyAttribute is missing. | ||
// See issue https://github.com/dotnet/roslyn/issues/17612 | ||
MetadataReaderUtils.VerifyPEMetadata(refDll, | ||
new[] { "TypeDef:<Module>", "TypeDef:C" }, | ||
new[] { "MethodDef: Void Main()", "MethodDef: Void .ctor()" }, | ||
new[] { "CompilationRelaxationsAttribute", "RuntimeCompatibilityAttribute", "DebuggableAttribute" } | ||
); | ||
|
||
var pdb = Path.Combine(dir.Path, "a.pdb"); | ||
Assert.False(File.Exists(pdb)); | ||
|
||
var doc = Path.Combine(dir.Path, "doc.xml"); | ||
Assert.True(File.Exists(doc)); | ||
|
||
var content = File.ReadAllText(doc); | ||
var expectedDoc = | ||
@"<?xml version=""1.0""?> | ||
<doc> | ||
<assembly> | ||
<name>a</name> | ||
</assembly> | ||
<members> | ||
<member name=""M:C.Main""> | ||
<summary>Main method</summary> | ||
</member> | ||
</members> | ||
</doc>"; | ||
Assert.Equal(expectedDoc, content.Trim()); | ||
|
||
// Clean up temp files | ||
CleanupAllGeneratedFiles(dir.Path); | ||
} | ||
|
||
public class QuotedArgumentTests | ||
{ | ||
private void VerifyQuotedValid<T>(string name, string value, T expected, Func<CSharpCommandLineArguments, T> getValue) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are we testing
/refonly:value
?