/// <summary> /// This method is intended to be called at executable init time. /// It let us avoid exceptions when executing sharpmake several times in loops(exception can occur in the cs compiler /// when it tries to create pdb files and some already exists. Maybe that previous sharpmake sometimes still has some handles to the file?). /// With this cleanup code active there is no exception anymore on my PC. Previously I had the exception almost 100% on the second or third iteration /// of a stability test(executing sharpmake in loop to insure it always generate the same thing). /// </summary> /// <remarks> /// Was previously having the following exception when running stability tests(on subsequents sharpmake execution runs): /// Unexpected error creating debug information file 'c:\Users\xxxx\AppData\Local\Temp\Sharpmake.Assembler_1.tmp.PDB' -- 'c:\Users\xxxx\AppData\Local\Temp\Sharpmake.Assembler_1.tmp.pdb: The process cannot access the file because it is being used by another process. /// </remarks> private static void CleanupTmpAssemblies() { // Erase any remaining file that has the prefix that will be used for temporary assemblies(dll, pdb, etc...) // This avoids exceptions occurring when executing sharpmake several times in loops(for example when running stability tests) string[] oldTmpFiles = Directory.GetFiles(GetTmpAssemblyBasePath(), GetTmpAssemblyFilePrefix() + "*.*", SearchOption.TopDirectoryOnly); foreach (string f in oldTmpFiles) { Util.TryDeleteFile(f); } }
private string GetTmpAssemblyFile() { // try to re use the same file name to not pollute tmp directory string tmpFilePrefix = GetType().FullName + "_"; string tmpFileSuffix = ".tmp.dll"; while (s_nextTempFile < int.MaxValue) { int currentTempFile = Interlocked.Increment(ref s_nextTempFile); string tmpFile = Path.Combine(Path.GetTempPath(), tmpFilePrefix + currentTempFile + tmpFileSuffix); if (!File.Exists(tmpFile) || Util.TryDeleteFile(tmpFile)) { return(tmpFile); } } return(null); }
public static TDelegate BuildDelegate <TDelegate>(string functionBody, string functionNamespace, string[] usingNamespaces, Assembly[] assemblies) where TDelegate : class { Assembler assembler = new Assembler(); assembler.UseDefaultReferences = false; assembler.Assemblies.AddRange(assemblies); const string className = "AssemblerBuildFunction_Class"; const string methodName = "AssemblerBuildFunction_Method"; // Fix : Bug with -> Path.GetTempFileName // http://msdn.microsoft.com/en-ca/library/windows/desktop/aa364991(v=vs.85).aspx // Limit of 65535 limit on files when generating the temp file. New temp file will use // a new Guid as filename and Sharpmake will clean the temporary files when done by aggregating // the temp files and deleting them. // eg. "C:\\fastbuild-work\\85f7d472c25d494ca09f2ea7fe282d50" //string sourceTmpFile = Path.GetTempFileName(); string sourceTmpFile = Path.Combine(Path.GetTempPath(), (Guid.NewGuid().ToString("N") + ".tmp.sharpmake.cs")); Type delegateType = typeof(TDelegate); Error.Valid(IsDelegate(delegateType), "BuildDelegate<TDelegate>(), TDelegate is not a delegate"); MethodInfo methodInfo = GetDelegateMethodInfo(delegateType); using (StreamWriter writer = new StreamWriter(sourceTmpFile)) { // add using namespace... foreach (string usingNamespace in usingNamespaces) { writer.WriteLine("using {0};", usingNamespace); } writer.WriteLine(); // namespace name writer.WriteLine("namespace {0}", functionNamespace); writer.WriteLine("{"); writer.WriteLine(" public static class {0}", className); writer.WriteLine(" {"); // write method signature string returnTypeName = methodInfo.ReturnType == typeof(void) ? "void" : methodInfo.ReturnType.FullName; writer.Write(" public static {0} {1}(", returnTypeName, methodName); ParameterInfo[] parameters = methodInfo.GetParameters(); for (int i = 0; i < parameters.Length; i++) { string parametersName = parameters[i].Name; string parametersType = (parameters[i].ParameterType == typeof(object)) ? "Object" : parameters[i].ParameterType.FullName; writer.Write("{0}{1} {2}", i == 0 ? "" : ", ", parametersType, parametersName); } writer.WriteLine(")"); // write method body writer.WriteLine(" {"); writer.WriteLine(" {0}" + Environment.NewLine, functionBody.Replace("\n", "\n ")); writer.WriteLine(" }"); writer.WriteLine(" }"); writer.WriteLine("}"); } // build in memory Assembly assembly = assembler.Build(builderContext: null, libraryFile: null, sources: sourceTmpFile).Assembly; InternalError.Valid(assembly != null); // Try to delete tmp file to prevent pollution, but useful while debugging //if (!System.Diagnostics.Debugger.IsAttached) Util.TryDeleteFile(sourceTmpFile); // Scan assembly to find our tmp class string fullClassName = functionNamespace + "." + className; Type buildedType = assembly.GetType(fullClassName); // get out method to bind into the delegate MethodInfo builtMethod = buildedType.GetMethod(methodName); InternalError.Valid(builtMethod != null); // bind the method Delegate returnDelegate; try { returnDelegate = builtMethod.CreateDelegate(delegateType); InternalError.Valid(returnDelegate != null); } catch (Exception e) { throw new InternalError(e); } TDelegate result = returnDelegate as TDelegate; InternalError.Valid(result != null, "Cannot cast built delegate into user delegate"); return(result); }