private static Type GenerateDebugProject(IAssemblyInfo assemblyInfo, bool isSetupProject, string startArguments, IDictionary <string, Type> visited, string[] defines) { string displayName = assemblyInfo.DebugProjectName; if (string.IsNullOrEmpty(displayName)) { displayName = isSetupProject ? "sharpmake_debug" : $"sharpmake_package_{assemblyInfo.Id.GetHashCode():X8}"; } Type generatedProject; if (visited.TryGetValue(assemblyInfo.Id, out generatedProject)) { if (generatedProject == null) { throw new Error($"Circular sharpmake package dependency on {displayName}"); } return(generatedProject); } visited[assemblyInfo.Id] = null; ProjectContent project = new ProjectContent { ProjectFolder = RootPath, IsSetupProject = isSetupProject, DisplayName = displayName, StartArguments = startArguments }; generatedProject = CreateProject(displayName); DebugProjects.Add(generatedProject, project); // Add sources foreach (var source in assemblyInfo.SourceFiles) { project.ProjectFiles.Add(source); } // Add references var references = new HashSet <string>(); if (assemblyInfo.UseDefaultReferences) { foreach (string defaultReference in Assembler.DefaultReferences) { references.Add(Assembler.GetAssemblyDllPath(defaultReference)); } } foreach (var assemblerRef in assemblyInfo.References) { if (!assemblyInfo.SourceReferences.ContainsKey(assemblerRef)) { references.Add(assemblerRef); } } project.References.AddRange(references); foreach (var refInfo in assemblyInfo.SourceReferences.Values) { project.ProjectReferences.Add(GenerateDebugProject(refInfo, false, string.Empty, visited, defines)); } if (defines != null) { project.Defines.AddRange(defines); } visited[assemblyInfo.Id] = generatedProject; return(generatedProject); }
public static TDelegate BuildDelegate <TDelegate>(string sourceFilePath, string fullFunctionName, Assembly[] assemblies) where TDelegate : class { FileInfo fileInfo = new FileInfo(sourceFilePath); if (!fileInfo.Exists) { throw new Error("source file name not found: {0}", sourceFilePath); } Type delegateType = typeof(TDelegate); Error.Valid(IsDelegate(delegateType), "BuildDelegate<FUNC_TYPE>(), FUNC_TYPE is not a delegate"); MethodInfo delegateMethodInfo = GetDelegateMethodInfo(delegateType); ParameterInfo[] delegateParameterInfos = delegateMethodInfo.GetParameters(); ParameterInfo delegateReturnInfos = delegateMethodInfo.ReturnParameter; Assembler assembler = new Assembler(); assembler.UseDefaultReferences = false; assembler.Assemblies.AddRange(assemblies); Assembly assembly = assembler.BuildAssembly(fileInfo.FullName); List <MethodInfo> matchMethods = new List <MethodInfo>(); foreach (Type type in assembly.GetTypes()) { MethodInfo[] methodInfos = type.GetMethods(); foreach (MethodInfo methodInfo in methodInfos) { string fullName = methodInfo.DeclaringType.FullName + "." + methodInfo.Name; if (fullFunctionName == fullName && methodInfo.IsStatic && methodInfo.GetParameters().Length == delegateMethodInfo.GetParameters().Length) { ParameterInfo[] parameterInfos = methodInfo.GetParameters(); ParameterInfo returnInfos = methodInfo.ReturnParameter; bool equal = (returnInfos.GetType() == delegateReturnInfos.GetType() && parameterInfos.Length == delegateParameterInfos.Length); if (equal) { for (int i = 0; i < parameterInfos.Length; ++i) { if (parameterInfos[i].GetType() != delegateParameterInfos[i].GetType()) { equal = false; break; } } } if (equal) { matchMethods.Add(methodInfo); } } } } if (matchMethods.Count != 1) { throw new Error("Cannot find method name {0} that match {1} in {2}", fullFunctionName, delegateMethodInfo.ToString(), sourceFilePath); } MethodInfo method = matchMethods[0]; // bind the method Delegate returnDelegate; try { returnDelegate = method.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); }
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")); 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); }
private static void Execute(Type type, object instance, string commandLine, string[] namespaces) { bool isStatic = instance == null; Parameter[] parameters = GetParameters(commandLine); if (parameters.Length == 0) { return; } HashSet <string> namespacesSet = new HashSet <string>(); namespacesSet.UnionWith(namespaces); namespacesSet.Add(type.Namespace); StringBuilder errors = new StringBuilder(); Dictionary <string, List <MethodInfo> > optionsNameMethodMapping = GetMethodsMapping(type, isStatic); // use to not call more than one for method with parameter overloading... HashSet <string> executedMethods = new HashSet <string>(); // tell to use all loaded assembly List <Assembly> assemblies = new List <Assembly>(AppDomain.CurrentDomain.GetAssemblies()); // in case of scripted c#, associated assembly may not be loaded in the current application domain. if (!assemblies.Contains(type.Assembly)) { assemblies.Add(type.Assembly); } foreach (Parameter parameter in parameters) { executedMethods.Clear(); List <MethodInfo> methodInfos; if (optionsNameMethodMapping.TryGetValue(parameter.Name, out methodInfos)) { foreach (MethodInfo methodInfo in methodInfos) { try { string uniqueExecutedMethodName = methodInfo.Name + parameter; if (executedMethods.Contains(uniqueExecutedMethodName)) { continue; } if (isStatic) { string executeCode = String.Format("{0}.{1}({2});", type.FullName.Replace("+", "."), methodInfo.Name, parameter.Args); Action execute = Assembler.BuildDelegate <Action>(executeCode, type.Namespace, DefaultNamespaces.ToArray(), assemblies.ToArray()); execute(); } else { string executeCode = String.Format("((global::{0})obj).{1}({2});", type.FullName.Replace("+", "."), methodInfo.Name, parameter.Args); Action <object> execute = Assembler.BuildDelegate <Action <object> >(executeCode, type.Namespace, DefaultNamespaces.ToArray(), assemblies.ToArray()); execute(instance); } executedMethods.Add(uniqueExecutedMethodName); } catch (Error e) { string[] parametersName = methodInfo.GetParameters().Select((ParameterInfo p) => p.ToString()).ToArray(); errors.Append(String.Format("Command line option '/{0}' have invalid parameters '({1})', maybe not compatible with '({2})'" + Environment.NewLine + "\t", parameter.Name, parameter.Args, String.Join(", ", parametersName))); errors.Append(e.Message + Environment.NewLine); } } } } if (errors.Length != 0) { throw new Error(errors.ToString()); } }