diff --git a/examples/SDL/SDL.cs b/examples/SDL/SDL.cs index 4b4968cc..d044577e 100644 --- a/examples/SDL/SDL.cs +++ b/examples/SDL/SDL.cs @@ -13,7 +13,7 @@ namespace CppSharp options.LibraryName = "SDL"; options.Headers.Add("SDL.h"); var sdlPath = Path.Combine(GetExamplesDirectory("SDL"), "SDL-2.0/include"); - options.Module.IncludeDirs.Add(sdlPath); + options.addIncludeDirs(sdlPath); options.OutputDir = "SDL"; } diff --git a/src/AST/Declaration.cs b/src/AST/Declaration.cs index 8442e8cb..9bc7f553 100644 --- a/src/AST/Declaration.cs +++ b/src/AST/Declaration.cs @@ -41,11 +41,7 @@ namespace CppSharp.AST /// /// Declaration is generated to be used internally. /// - Internal, - /// - /// Declaration was already generated in a linked assembly. - /// - Link, + Internal } /// @@ -252,8 +248,7 @@ namespace CppSharp.AST { var k = GenerationKind; return k == GenerationKind.Generate - || k == GenerationKind.Internal - || k == GenerationKind.Link; + || k == GenerationKind.Internal; } } diff --git a/src/AST/Expression.cs b/src/AST/Expression.cs index 5a9a2898..c95b801a 100644 --- a/src/AST/Expression.cs +++ b/src/AST/Expression.cs @@ -1,4 +1,6 @@ +using System; using System.Collections.Generic; +using System.Linq; namespace CppSharp.AST { @@ -7,6 +9,8 @@ namespace CppSharp.AST public string DebugText; public abstract TV Visit(IExpressionVisitor visitor); + + public abstract Expression Clone(); } public class BuiltinTypeExpression : Expression @@ -39,6 +43,19 @@ namespace CppSharp.AST { return visitor.VisitExpression(this); } + + public override Expression Clone() + { + return new BuiltinTypeExpression + { + Value = this.Value, + Type = this.Type, + DebugText = this.DebugText, + Class = this.Class, + Declaration = this.Declaration, + String = this.String + }; + } } public class BinaryOperator : Expression @@ -59,6 +76,16 @@ namespace CppSharp.AST { return visitor.VisitExpression(this); } + + public override Expression Clone() + { + return new BinaryOperator(LHS.Clone(), RHS.Clone(), OpcodeStr) + { + DebugText = this.DebugText, + Declaration = this.Declaration, + String = this.String + }; + } } public class CallExpr : Expression @@ -75,6 +102,18 @@ namespace CppSharp.AST { return visitor.VisitExpression(this); } + + public override Expression Clone() + { + var clone = new CallExpr + { + DebugText = this.DebugText, + Declaration = this.Declaration, + String = this.String + }; + clone.Arguments.AddRange(Arguments.Select(a => a.Clone())); + return clone; + } } public class CXXConstructExpr : Expression @@ -91,6 +130,18 @@ namespace CppSharp.AST { return visitor.VisitExpression(this); } + + public override Expression Clone() + { + var clone = new CXXConstructExpr + { + DebugText = this.DebugText, + Declaration = this.Declaration, + String = this.String + }; + clone.Arguments.AddRange(Arguments.Select(a => a.Clone())); + return clone; + } } public interface IExpressionVisitor diff --git a/src/Generator/Module.cs b/src/AST/Module.cs similarity index 89% rename from src/Generator/Module.cs rename to src/AST/Module.cs index 8b345c5c..dc955ff1 100644 --- a/src/Generator/Module.cs +++ b/src/AST/Module.cs @@ -1,6 +1,6 @@ using System.Collections.Generic; -namespace CppSharp +namespace CppSharp.AST { public class Module { @@ -12,6 +12,8 @@ namespace CppSharp Libraries = new List(); Defines = new List(); Undefines = new List(); + Units = new List(); + CodeFiles = new List(); } public List IncludeDirs { get; private set; } @@ -22,6 +24,9 @@ namespace CppSharp public List Undefines { get; set; } public string OutputNamespace { get; set; } + public List Units { get; private set; } + public List CodeFiles { get; private set; } + public string SharedLibraryName { get diff --git a/src/AST/SymbolContext.cs b/src/AST/SymbolContext.cs index c6beff8d..b20c97f5 100644 --- a/src/AST/SymbolContext.cs +++ b/src/AST/SymbolContext.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; namespace CppSharp.AST { @@ -79,8 +80,9 @@ namespace CppSharp.AST { foreach (var symbol in library.Symbols) { - Symbols[symbol] = library; - if (symbol.StartsWith("__")) + if (!Symbols.ContainsKey(symbol)) + Symbols[symbol] = library; + if (symbol.StartsWith("__", StringComparison.Ordinal)) { string stripped = symbol.Substring(1); if (!Symbols.ContainsKey(stripped)) diff --git a/src/AST/TranslationUnit.cs b/src/AST/TranslationUnit.cs index 17e191ab..7610ee5d 100644 --- a/src/AST/TranslationUnit.cs +++ b/src/AST/TranslationUnit.cs @@ -1,3 +1,4 @@ +using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; @@ -24,6 +25,12 @@ namespace CppSharp.AST /// Contains the macros present in the unit. public List Macros; + public Module Module + { + get { return (Module) module.Target; } + set { module = new WeakReference(value); } + } + public bool IsSystemHeader { get; set; } public bool IsValid { get { return FilePath != ""; } } @@ -75,5 +82,7 @@ namespace CppSharp.AST (fileRelativePath = Path.Combine(FileRelativeDirectory, FileName)); } } + + private WeakReference module; } } \ No newline at end of file diff --git a/src/CppParser/Bindings/ParserGen.cs b/src/CppParser/Bindings/ParserGen.cs index e31b2dba..766c1e0c 100644 --- a/src/CppParser/Bindings/ParserGen.cs +++ b/src/CppParser/Bindings/ParserGen.cs @@ -71,8 +71,8 @@ namespace CppSharp SetupLinuxOptions(options); var basePath = Path.Combine(GetSourceDirectory("src"), "CppParser"); - options.Module.IncludeDirs.Add(basePath); - options.Module.LibraryDirs.Add("."); + options.addIncludeDirs(basePath); + options.addLibraryDirs("."); options.OutputDir = Path.Combine(GetSourceDirectory("src"), "CppParser", "Bindings", Kind.ToString()); diff --git a/src/CppParser/Bootstrap/Bootstrap.cs b/src/CppParser/Bootstrap/Bootstrap.cs index 2deba5c8..4198d277 100644 --- a/src/CppParser/Bootstrap/Bootstrap.cs +++ b/src/CppParser/Bootstrap/Bootstrap.cs @@ -42,16 +42,16 @@ namespace CppSharp options.MicrosoftMode = false; options.TargetTriple = "i686-apple-darwin12.4.0"; - options.Module.Defines.Add("__STDC_LIMIT_MACROS"); - options.Module.Defines.Add("__STDC_CONSTANT_MACROS"); + options.addDefines ("__STDC_LIMIT_MACROS"); + options.addDefines ("__STDC_CONSTANT_MACROS"); var llvmPath = Path.Combine (GetSourceDirectory ("deps"), "llvm"); var clangPath = Path.Combine(llvmPath, "tools", "clang"); - options.Module.IncludeDirs.Add(Path.Combine(llvmPath, "include")); - options.Module.IncludeDirs.Add(Path.Combine(llvmPath, "build", "include")); - options.Module.IncludeDirs.Add(Path.Combine (llvmPath, "build", "tools", "clang", "include")); - options.Module.IncludeDirs.Add(Path.Combine(clangPath, "include")); + options.addIncludeDirs(Path.Combine(llvmPath, "include")); + options.addIncludeDirs(Path.Combine(llvmPath, "build", "include")); + options.addIncludeDirs (Path.Combine (llvmPath, "build", "tools", "clang", "include")); + options.addIncludeDirs(Path.Combine(clangPath, "include")); } public void SetupPasses(Driver driver) diff --git a/src/Generator.Tests/ASTTestFixture.cs b/src/Generator.Tests/ASTTestFixture.cs index da810401..43ea5862 100644 --- a/src/Generator.Tests/ASTTestFixture.cs +++ b/src/Generator.Tests/ASTTestFixture.cs @@ -15,13 +15,11 @@ namespace CppSharp.Generator.Tests Options = new DriverOptions(); var testsPath = GeneratorTest.GetTestsDirectory("Native"); - Options.Module.IncludeDirs.Add(testsPath); + Options.addIncludeDirs(testsPath); Options.Headers.AddRange(files); Driver = new Driver(Options, new TextDiagnosticPrinter()); - foreach (var includeDir in Options.Module.IncludeDirs) - Options.addIncludeDirs(includeDir); Driver.SetupIncludes(); Driver.BuildParseOptions(); if (!Driver.ParseCode()) diff --git a/src/Generator.Tests/GeneratorTest.cs b/src/Generator.Tests/GeneratorTest.cs index 5509fede..62f4e499 100644 --- a/src/Generator.Tests/GeneratorTest.cs +++ b/src/Generator.Tests/GeneratorTest.cs @@ -46,7 +46,7 @@ namespace CppSharp.Utils options.TargetTriple = Environment.Is64BitProcess ? "x86_64-apple-darwin" : "i686-apple-darwin"; var path = Path.GetFullPath(GetTestsDirectory(name)); - options.Module.IncludeDirs.Add(path); + options.addIncludeDirs(path); // Remove this hardcoded path once we update our LLVM binary packages to bundle // the built-in Clang includes. diff --git a/src/Generator.Tests/ReadNativeDependenciesTest.cs b/src/Generator.Tests/ReadNativeDependenciesTest.cs index 84629eef..cad0497b 100644 --- a/src/Generator.Tests/ReadNativeDependenciesTest.cs +++ b/src/Generator.Tests/ReadNativeDependenciesTest.cs @@ -38,11 +38,9 @@ namespace CppSharp.Generator.Tests private static IList GetDependencies(string library) { var driverOptions = new DriverOptions(); - driverOptions.Module.LibraryDirs.Add(GeneratorTest.GetTestsDirectory("Native")); + driverOptions.addLibraryDirs(GeneratorTest.GetTestsDirectory("Native")); driverOptions.Libraries.Add(library); var driver = new Driver(driverOptions, new TextDiagnosticPrinter()); - foreach (var libraryDir in driverOptions.Module.LibraryDirs) - driverOptions.addLibraryDirs(libraryDir); Assert.IsTrue(driver.ParseLibraries()); var dependencies = driver.Symbols.Libraries[0].Dependencies; return dependencies; diff --git a/src/Generator/Driver.cs b/src/Generator/Driver.cs index 5ad4bea2..ed65b101 100644 --- a/src/Generator/Driver.cs +++ b/src/Generator/Driver.cs @@ -3,7 +3,6 @@ using System.Collections.Generic; using System.Globalization; using System.IO; using System.Linq; -using System.Reflection; using System.Text; using CppSharp.AST; using CppSharp.Generators; @@ -15,6 +14,7 @@ using Microsoft.CSharp; using CppSharp.Parser; using System.CodeDom; using System; +using System.Reflection; namespace CppSharp { @@ -67,15 +67,18 @@ namespace CppSharp static void ValidateOptions(DriverOptions options) { - if (string.IsNullOrWhiteSpace(options.LibraryName)) - throw new InvalidOptionException(); + foreach (var module in options.Modules) + { + if (string.IsNullOrWhiteSpace(module.LibraryName)) + throw new InvalidOptionException("One of your modules has no library name."); + + if (string.IsNullOrWhiteSpace(module.OutputNamespace)) + module.OutputNamespace = module.LibraryName; + } if (options.NoGenIncludeDirs != null) foreach (var incDir in options.NoGenIncludeDirs) options.addIncludeDirs(incDir); - - if (string.IsNullOrWhiteSpace(options.OutputNamespace)) - options.OutputNamespace = options.LibraryName; } public void Setup() @@ -194,6 +197,21 @@ namespace CppSharp options.addLibraryDirs(lib); } + foreach (var module in Options.Modules.Where(m => m.Headers.Contains(file.Path))) + { + foreach (var include in module.IncludeDirs) + options.addIncludeDirs(include); + + foreach (var define in module.Defines) + options.addDefines(define); + + foreach (var undefine in module.Undefines) + options.addUndefines(undefine); + + foreach (var library in module.Libraries) + options.addLibraryDirs(library); + } + return options; } @@ -213,7 +231,7 @@ namespace CppSharp public void BuildParseOptions() { - foreach (var header in Options.Headers) + foreach (var header in Options.Modules.SelectMany(m => m.Headers)) { var source = Project.AddFile(header); source.Options = BuildParseOptions(source); @@ -224,7 +242,7 @@ namespace CppSharp public bool ParseLibraries() { - foreach (var library in Options.Libraries) + foreach (var library in Options.Modules.SelectMany(m => m.Libraries)) { if (this.Symbols.Libraries.Any(l => l.FileName == library)) continue; @@ -248,7 +266,6 @@ namespace CppSharp public void SetupPasses(ILibrary library) { - TranslationUnitPasses.AddPass(new CleanUnitPass(Options)); TranslationUnitPasses.AddPass(new SortDeclarationsPass()); TranslationUnitPasses.AddPass(new ResolveIncompleteDeclsPass()); TranslationUnitPasses.AddPass(new CheckIgnoredDeclsPass()); @@ -290,8 +307,8 @@ namespace CppSharp TranslationUnitPasses.AddPass(new GenerateAbstractImplementationsPass()); if (Options.GenerateDefaultValuesForArguments) { - TranslationUnitPasses.AddPass(new HandleDefaultParamValuesPass()); TranslationUnitPasses.AddPass(new FixDefaultParamValuesOfOverridesPass()); + TranslationUnitPasses.AddPass(new HandleDefaultParamValuesPass()); } } @@ -331,7 +348,7 @@ namespace CppSharp return Generator.Generate(); } - public void SaveCode(List outputs) + public void SaveCode(IEnumerable outputs) { var outputPath = Path.GetFullPath(Options.OutputDir); @@ -352,32 +369,22 @@ namespace CppSharp if (Options.GenerateName != null) fileBase = Options.GenerateName(output.TranslationUnit); - if (Options.IsCSharpGenerator && Options.CompileCode) - { - compileUnits.AddRange( - output.Templates.Select(t => new CodeSnippetCompileUnit(t.Generate()))); - compileUnits.AddRange( - Options.CodeFiles.Select(c => new CodeSnippetCompileUnit(File.ReadAllText(c)))); - } - else + foreach (var template in output.Templates) { - foreach (var template in output.Templates) - { - var fileRelativePath = string.Format("{0}.{1}", fileBase, template.FileExtension); - Diagnostics.Message("Generated '{0}'", fileRelativePath); - - var file = Path.Combine(outputPath, fileRelativePath); - File.WriteAllText(file, template.Generate()); - Options.CodeFiles.Add(file); - } + var fileRelativePath = string.Format("{0}.{1}", fileBase, template.FileExtension); + Diagnostics.Message("Generated '{0}'", fileRelativePath); + + var file = Path.Combine(outputPath, fileRelativePath); + File.WriteAllText(file, template.Generate()); + output.TranslationUnit.Module.CodeFiles.Add(file); } } } - public void CompileCode() + public void CompileCode(AST.Module module) { - var assemblyFile = string.IsNullOrEmpty(Options.LibraryName) ? - "out.dll" : Options.LibraryName + ".dll"; + var assemblyFile = string.IsNullOrEmpty(module.LibraryName) ? + "out.dll" : module.LibraryName + ".dll"; var docFile = Path.ChangeExtension(Path.GetFileName(assemblyFile), ".xml"); @@ -414,8 +421,8 @@ namespace CppSharp using (var codeProvider = new CSharpCodeProvider( new Dictionary { { "CompilerVersion", "v4.0" } })) { - compilerResults = codeProvider.CompileAssemblyFromDom( - compilerParameters, compileUnits.ToArray()); + compilerResults = codeProvider.CompileAssemblyFromFile( + compilerParameters, module.CodeFiles.ToArray()); } var errors = compilerResults.Errors.Cast().Where(e => !e.IsWarning && @@ -429,7 +436,7 @@ namespace CppSharp { Diagnostics.Message("Compilation succeeded."); var wrapper = Path.Combine(outputDir, assemblyFile); - foreach (var library in Options.Libraries) + foreach (var library in module.Libraries) libraryMappings[library] = wrapper; } } @@ -444,7 +451,6 @@ namespace CppSharp GeneratorOutputPasses.AddPass(pass); } - private readonly List compileUnits = new List(); private bool hasParsingErrors; } @@ -459,18 +465,6 @@ namespace CppSharp library.Setup(driver); - foreach (var includeDir in options.Module.IncludeDirs) - options.addIncludeDirs(includeDir); - - foreach (var libraryDir in options.Module.LibraryDirs) - options.addLibraryDirs(libraryDir); - - foreach (var define in options.Module.Defines) - options.addDefines(define); - - foreach (var undefine in options.Module.Undefines) - options.addUndefines(undefine); - driver.Setup(); if(driver.Options.Verbose) @@ -498,6 +492,8 @@ namespace CppSharp return; } + new CleanUnitPass(options).VisitLibrary(driver.ASTContext); + if (!options.Quiet) Log.Message("Processing code..."); @@ -526,7 +522,8 @@ namespace CppSharp { driver.SaveCode(outputs); if (driver.Options.IsCSharpGenerator && driver.Options.CompileCode) - driver.CompileCode(); + foreach (var module in driver.Options.Modules) + driver.CompileCode(module); } driver.Generator.Dispose(); diff --git a/src/Generator/Generator.cs b/src/Generator/Generator.cs index a31f023a..0f090d65 100644 --- a/src/Generator/Generator.cs +++ b/src/Generator/Generator.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.IO; using System.Linq; using CppSharp.AST; @@ -35,6 +36,8 @@ namespace CppSharp.Generators /// public abstract class Generator : IDisposable { + public static string CurrentOutputNamespace = string.Empty; + public Driver Driver { get; private set; } protected Generator(Driver driver) @@ -69,50 +72,59 @@ namespace CppSharp.Generators var outputs = new List(); var units = Driver.ASTContext.TranslationUnits.Where( - u => u.IsGenerated && u.HasDeclarations && !u.IsSystemHeader && u.IsValid); + u => u.IsGenerated && u.HasDeclarations && !u.IsSystemHeader && u.IsValid).ToList(); if (Driver.Options.IsCSharpGenerator && Driver.Options.GenerateSingleCSharpFile) - GenerateSingleTemplate(units, outputs); + GenerateSingleTemplate(outputs); else - foreach (var unit in units) - GenerateTemplate(unit, outputs); + GenerateTemplates(outputs, units); return outputs; } - private void GenerateSingleTemplate(IEnumerable units, ICollection outputs) + private void GenerateTemplates(List outputs, List units) { - var output = new GeneratorOutput + foreach (var unit in units) { - TranslationUnit = new TranslationUnit + var includeDir = Path.GetDirectoryName(unit.FilePath); + var templates = Generate(new[] { unit }); + if (templates.Count == 0) + return; + + CurrentOutputNamespace = unit.Module.OutputNamespace; + foreach (var template in templates) { - FilePath = string.Format("{0}.cs", Driver.Options.OutputNamespace ?? Driver.Options.LibraryName) - }, - Templates = Generate(units) - }; - output.Templates[0].Process(); - outputs.Add(output); - - OnUnitGenerated(output); - } + template.Process(); + } - private void GenerateTemplate(TranslationUnit unit, ICollection outputs) - { - var templates = Generate(new[] { unit }); - if (templates.Count == 0) - return; + var output = new GeneratorOutput + { + TranslationUnit = unit, + Templates = templates + }; + outputs.Add(output); - foreach (var template in templates) - { - template.Process(); + OnUnitGenerated(output); } + } - var output = new GeneratorOutput + private void GenerateSingleTemplate(ICollection outputs) + { + foreach (var module in Driver.Options.Modules) { - TranslationUnit = unit, - Templates = templates - }; - outputs.Add(output); - - OnUnitGenerated(output); + CurrentOutputNamespace = module.OutputNamespace; + var output = new GeneratorOutput + { + TranslationUnit = new TranslationUnit + { + FilePath = string.Format("{0}.cs", module.OutputNamespace ?? module.LibraryName), + Module = module + }, + Templates = Generate(module.Units) + }; + output.Templates[0].Process(); + outputs.Add(output); + + OnUnitGenerated(output); + } } /// diff --git a/src/Generator/Generators/CLI/CLIHeadersTemplate.cs b/src/Generator/Generators/CLI/CLIHeadersTemplate.cs index ed739be7..9d7ce3f3 100644 --- a/src/Generator/Generators/CLI/CLIHeadersTemplate.cs +++ b/src/Generator/Generators/CLI/CLIHeadersTemplate.cs @@ -99,6 +99,7 @@ namespace CppSharp.Generators.CLI { // Create a new tree of namespaces out of the type references found. var rootNamespace = new TranslationUnit(); + rootNamespace.Module = TranslationUnit.Module; var sortedRefs = typeReferences.ToList(); sortedRefs.Sort((ref1, ref2) => @@ -192,7 +193,7 @@ namespace CppSharp.Generators.CLI { PushBlock(CLIBlockKind.Namespace, @namespace); WriteLine("namespace {0}", isTopLevel - ? Options.OutputNamespace + ? @namespace.TranslationUnit.Module.OutputNamespace : @namespace.Name); WriteStartBraceIndent(); } diff --git a/src/Generator/Generators/CLI/CLIMarshal.cs b/src/Generator/Generators/CLI/CLIMarshal.cs index b8bac876..92d8e37f 100644 --- a/src/Generator/Generators/CLI/CLIMarshal.cs +++ b/src/Generator/Generators/CLI/CLIMarshal.cs @@ -313,7 +313,7 @@ namespace CppSharp.Generators.CLI public string QualifiedIdentifier(Declaration decl) { if (Context.Driver.Options.GenerateLibraryNamespace) - return string.Format("{0}::{1}", Context.Driver.Options.OutputNamespace, + return string.Format("{0}::{1}", decl.TranslationUnit.Module.OutputNamespace, decl.QualifiedName); return string.Format("{0}", decl.QualifiedName); } diff --git a/src/Generator/Generators/CLI/CLITextTemplate.cs b/src/Generator/Generators/CLI/CLITextTemplate.cs index be7092d3..733c08b4 100644 --- a/src/Generator/Generators/CLI/CLITextTemplate.cs +++ b/src/Generator/Generators/CLI/CLITextTemplate.cs @@ -84,9 +84,10 @@ namespace CppSharp.Generators.CLI if (Options.GenerateLibraryNamespace) { if (string.IsNullOrEmpty(decl.QualifiedName)) - return string.Format("{0}", Options.OutputNamespace); + return string.Format("{0}", decl.TranslationUnit.Module.OutputNamespace); - return string.Format("{0}::{1}", Options.OutputNamespace, decl.QualifiedName); + return string.Format("{0}::{1}", + decl.TranslationUnit.Module.OutputNamespace, decl.QualifiedName); } return decl.QualifiedName; diff --git a/src/Generator/Generators/CLI/CLITypePrinter.cs b/src/Generator/Generators/CLI/CLITypePrinter.cs index 659ddeb6..326f7b07 100644 --- a/src/Generator/Generators/CLI/CLITypePrinter.cs +++ b/src/Generator/Generators/CLI/CLITypePrinter.cs @@ -327,7 +327,7 @@ namespace CppSharp.Generators.CLI string rootNamespace = null; if (Options.GenerateLibraryNamespace) - names.Add(rootNamespace = Driver.Options.OutputNamespace); + names.Add(rootNamespace = decl.TranslationUnit.Module.OutputNamespace); if (!string.IsNullOrEmpty(decl.Namespace.QualifiedName)) { diff --git a/src/Generator/Generators/CSharp/CSharpExpressionPrinter.cs b/src/Generator/Generators/CSharp/CSharpExpressionPrinter.cs index 6609f528..bda589c6 100644 --- a/src/Generator/Generators/CSharp/CSharpExpressionPrinter.cs +++ b/src/Generator/Generators/CSharp/CSharpExpressionPrinter.cs @@ -40,7 +40,6 @@ namespace CppSharp.Generators.CSharp switch (callExpr.Declaration.GenerationKind) { case GenerationKind.Generate: - case GenerationKind.Link: return new CSharpExpressionPrinterResult { Value = string.Format("{0}.{1}({2})", diff --git a/src/Generator/Generators/CSharp/CSharpTextTemplate.cs b/src/Generator/Generators/CSharp/CSharpTextTemplate.cs index 18e17d0e..bdf82841 100644 --- a/src/Generator/Generators/CSharp/CSharpTextTemplate.cs +++ b/src/Generator/Generators/CSharp/CSharpTextTemplate.cs @@ -167,7 +167,7 @@ namespace CppSharp.Generators.CSharp if (Options.GenerateLibraryNamespace) { PushBlock(CSharpBlockKind.Namespace); - WriteLine("namespace {0}", Driver.Options.OutputNamespace); + WriteLine("namespace {0}", TranslationUnit.Module.OutputNamespace); WriteStartBraceIndent(); } @@ -829,9 +829,9 @@ namespace CppSharp.Generators.CSharp #endregion - private Tuple GetDeclarationLibrarySymbol(IMangledDecl decl) + private Tuple GetDeclarationLibrarySymbol(Variable decl) { - var library = Options.SharedLibraryName; + var library = decl.TranslationUnit.Module.SharedLibraryName; if (!Options.CheckSymbols) goto Out; @@ -1555,8 +1555,9 @@ namespace CppSharp.Generators.CSharp return; } var typeFullName = TypePrinter.VisitClassDecl(@class); - if (!string.IsNullOrEmpty(Driver.Options.OutputNamespace)) - typeFullName = string.Format("{0}.{1}", Driver.Options.OutputNamespace, typeFullName); + if (!string.IsNullOrEmpty(@class.TranslationUnit.Module.OutputNamespace)) + typeFullName = string.Format("{0}.{1}", + @class.TranslationUnit.Module.OutputNamespace, typeFullName); WriteLine("SetupVTables(GetType().FullName == \"{0}\");", typeFullName); } } @@ -1573,7 +1574,7 @@ namespace CppSharp.Generators.CSharp for (int i = 0; i < method.Parameters.Count; i++) { var param = method.Parameters[i]; - if (!param.IsGenerated && param.GenerationKind != GenerationKind.Link) + if (!param.IsGenerated) continue; if (param.Kind == ParameterKind.IndirectReturnType) @@ -1600,7 +1601,7 @@ namespace CppSharp.Generators.CSharp if (hasReturn) Write("var {0} = ", Helpers.ReturnIdentifier); - if (method.IsGenerated || method.GenerationKind == GenerationKind.Link) + if (method.IsGenerated) { WriteLine("{0}.{1}({2});", Helpers.TargetIdentifier, method.Name, string.Join(", ", marshals)); @@ -1682,7 +1683,8 @@ namespace CppSharp.Generators.CSharp var vTableMethodDelegateName = GetVTableMethodDelegateName(method); - WriteLine("private static {0} {1}Instance;", GetDelegateName(Driver.Delegates[method]), + WriteLine("private static {0} {1}Instance;", + GetDelegateName(method, @class.TranslationUnit.Module.OutputNamespace), vTableMethodDelegateName); NewLine(); @@ -2483,13 +2485,15 @@ namespace CppSharp.Generators.CSharp delegateId = Generator.GeneratedIdentifier(@delegate); WriteLine("var {0} = ({1}) Marshal.GetDelegateForFunctionPointer(new IntPtr({2}), typeof({1}));", - delegateId, GetDelegateName(Driver.Delegates[method]), Helpers.SlotIdentifier); + delegateId, GetDelegateName(method, method.TranslationUnit.Module.OutputNamespace), + Helpers.SlotIdentifier); } - private string GetDelegateName(DelegatesPass.DelegateDefinition @delegate) + private string GetDelegateName(Function function, string outputNamespace) { + var @delegate = Driver.Delegates[function]; if (string.IsNullOrWhiteSpace(@delegate.Namespace) || - Driver.Options.OutputNamespace == @delegate.Namespace) + outputNamespace == @delegate.Namespace) { return @delegate.Signature; } @@ -3086,7 +3090,7 @@ namespace CppSharp.Generators.CSharp PushBlock(CSharpBlockKind.InternalsClassMethod); WriteLine("[SuppressUnmanagedCodeSecurity]"); - string libName = Options.SharedLibraryName; + string libName = function.TranslationUnit.Module.SharedLibraryName; if (Options.CheckSymbols) { @@ -3102,7 +3106,7 @@ namespace CppSharp.Generators.CSharp libName = libName.Substring(3); } if (libName == null) - libName = Options.SharedLibraryName; + libName = function.TranslationUnit.Module.SharedLibraryName; if (Options.GenerateInternalImports) libName = "__Internal"; diff --git a/src/Generator/Generators/CSharp/CSharpTypePrinter.cs b/src/Generator/Generators/CSharp/CSharpTypePrinter.cs index b9344b67..518ad779 100644 --- a/src/Generator/Generators/CSharp/CSharpTypePrinter.cs +++ b/src/Generator/Generators/CSharp/CSharpTypePrinter.cs @@ -631,7 +631,7 @@ namespace CppSharp.Generators.CSharp } names.Reverse(); - if (names[0] == driver.Options.OutputNamespace) + if (names[0] == Generator.CurrentOutputNamespace) names.RemoveAt(0); return string.Join(".", names); } diff --git a/src/Generator/Options.cs b/src/Generator/Options.cs index 9adf3672..613ed72a 100644 --- a/src/Generator/Options.cs +++ b/src/Generator/Options.cs @@ -27,7 +27,7 @@ namespace CppSharp OutputDir = Directory.GetCurrentDirectory(); - Module = new Module(); + Modules = new List(); GeneratorKind = GeneratorKind.CSharp; GenerateLibraryNamespace = true; @@ -39,8 +39,6 @@ namespace CppSharp Encoding = Encoding.ASCII; - CodeFiles = new List(); - StripLibPrefix = true; ExplicitlyPatchedVirtualFunctions = new List(); @@ -59,24 +57,34 @@ namespace CppSharp /// public bool DryRun; + public List Modules { get; private set; } + + public Module MainModule + { + get + { + if (Modules.Count == 0) + Modules.Add(new Module()); + return Modules[0]; + } + } + // Parser options - public List Headers { get { return Module.Headers; } } + public List Headers { get { return MainModule.Headers; } } public bool IgnoreParseWarnings; public bool IgnoreParseErrors; - public Module Module { get; set; } - public bool IsItaniumLikeAbi { get { return Abi != CppAbi.Microsoft; } } public bool IsMicrosoftAbi { get { return Abi == CppAbi.Microsoft; } } // Library options - public List Libraries { get { return Module.Libraries; } } + public List Libraries { get { return MainModule.Libraries; } } public bool CheckSymbols; public string SharedLibraryName { - get { return Module.SharedLibraryName; } - set { Module.SharedLibraryName = value; } + get { return MainModule.SharedLibraryName; } + set { MainModule.SharedLibraryName = value; } } // Generator options @@ -84,16 +92,16 @@ namespace CppSharp public string OutputNamespace { - get { return Module.OutputNamespace; } - set { Module.OutputNamespace = value; } + get { return MainModule.OutputNamespace; } + set { MainModule.OutputNamespace = value; } } public string OutputDir; public string LibraryName { - get { return Module.LibraryName; } - set { Module.LibraryName = value; } + get { return MainModule.LibraryName; } + set { MainModule.LibraryName = value; } } public bool OutputInteropIncludes; @@ -129,7 +137,7 @@ namespace CppSharp /// /// If set to true the CLI generator will use ObjectOverridesPass to create - /// Equals, GetHashCode and (if the insertion operator << is overloaded) ToString + /// Equals, GetHashCode and (if the insertion operator << is overloaded) ToString /// methods. /// public bool GenerateObjectOverrides; @@ -158,14 +166,14 @@ namespace CppSharp public string InlinesLibraryName { - get { return Module.InlinesLibraryName; } - set { Module.InlinesLibraryName = value; } + get { return MainModule.InlinesLibraryName; } + set { MainModule.InlinesLibraryName = value; } } public string TemplatesLibraryName { - get { return Module.TemplatesLibraryName; } - set { Module.TemplatesLibraryName = value; } + get { return MainModule.TemplatesLibraryName; } + set { MainModule.TemplatesLibraryName = value; } } public bool IsCSharpGenerator @@ -178,7 +186,6 @@ namespace CppSharp get { return GeneratorKind == GeneratorKind.CLI; } } - public List CodeFiles { get; private set; } public readonly List DependentNameSpaces = new List(); public bool MarshalCharAsManagedChar { get; set; } /// @@ -201,5 +208,9 @@ namespace CppSharp public class InvalidOptionException : Exception { + public InvalidOptionException(string message) : + base(message) + { + } } } diff --git a/src/Generator/Passes/CleanUnitPass.cs b/src/Generator/Passes/CleanUnitPass.cs index e13c6257..ca0b4ac3 100644 --- a/src/Generator/Passes/CleanUnitPass.cs +++ b/src/Generator/Passes/CleanUnitPass.cs @@ -1,3 +1,6 @@ +using System; +using System.IO; +using System.Linq; using CppSharp.AST; namespace CppSharp.Passes @@ -13,9 +16,14 @@ namespace CppSharp.Passes public override bool VisitTranslationUnit(TranslationUnit unit) { - if (IsExternalDeclaration(unit) && unit.IsGenerated) - unit.GenerationKind = GenerationKind.Link; - + if (unit.IsValid && !unit.IsSystemHeader && unit.HasDeclarations) + { + var includeDir = Path.GetDirectoryName(unit.FilePath); + unit.Module = DriverOptions.Modules.FirstOrDefault( + m => m.IncludeDirs.Contains(includeDir)) ?? DriverOptions.MainModule; + unit.Module.Units.Add(unit); + } + // Try to get an include path that works from the original include // directories paths. if (unit.IsValid) @@ -64,7 +72,7 @@ namespace CppSharp.Passes foreach (var path in DriverOptions.NoGenIncludeDirs) { - if (translationUnit.FilePath.StartsWith(path)) + if (translationUnit.FilePath.StartsWith(path, StringComparison.Ordinal)) return true; } diff --git a/src/Generator/Passes/DelegatesPass.cs b/src/Generator/Passes/DelegatesPass.cs index e829a48f..1a9a4862 100644 --- a/src/Generator/Passes/DelegatesPass.cs +++ b/src/Generator/Passes/DelegatesPass.cs @@ -3,8 +3,8 @@ using System.Linq; using System.Text; using CppSharp.AST; using CppSharp.AST.Extensions; +using CppSharp.Generators; using CppSharp.Generators.CSharp; -using System; namespace CppSharp.Passes { @@ -37,8 +37,8 @@ namespace CppSharp.Passes public override bool VisitLibrary(ASTContext context) { - foreach (var library in Driver.Options.Libraries.Where(l => !libsDelegates.ContainsKey(l))) - libsDelegates.Add(library, new Dictionary()); + foreach (var library in Driver.Options.Modules.SelectMany(m => m.Libraries)) + libsDelegates[library] = new Dictionary(); var unit = context.TranslationUnits.LastOrDefault(u => u.IsValid && u.IsGenerated && !u.IsSystemHeader && u.HasDeclarations); @@ -46,12 +46,10 @@ namespace CppSharp.Passes if (unit == null) return false; - namespaceDelegates = new Namespace { Name = DelegatesNamespace, Namespace = unit }; - var result = base.VisitLibrary(context); - if (namespaceDelegates.Declarations.Count > 0) - unit.Declarations.Add(namespaceDelegates); + foreach (var module in Driver.Options.Modules.Where(m => namespacesDelegates.ContainsKey(m))) + module.Units.Last().Declarations.Add(namespacesDelegates[module]); return result; } @@ -94,6 +92,21 @@ namespace CppSharp.Passes var @params = method.GatherInternalParams(Driver.Options.IsItaniumLikeAbi, true).ToList(); var delegateName = GenerateDelegateSignature(@params, method.ReturnType); + Namespace namespaceDelegates; + if (namespacesDelegates.ContainsKey(method.TranslationUnit.Module)) + { + namespaceDelegates = namespacesDelegates[method.TranslationUnit.Module]; + } + else + { + namespaceDelegates = new Namespace + { + Name = DelegatesNamespace, + Namespace = method.TranslationUnit.Module.Units.Last() + }; + namespacesDelegates.Add(method.TranslationUnit.Module, namespaceDelegates); + } + var @delegate = new TypedefDecl { Name = delegateName, @@ -110,17 +123,20 @@ namespace CppSharp.Passes Namespace = namespaceDelegates }; + Generator.CurrentOutputNamespace = method.TranslationUnit.Module.OutputNamespace; var delegateString = @delegate.Visit(TypePrinter).Type; - var existingDelegate = GetExistingDelegate(delegateString); + var existingDelegate = GetExistingDelegate( + method.TranslationUnit.Module.Libraries, delegateString); if (existingDelegate != null) { Driver.Delegates.Add(method, existingDelegate); return true; } - existingDelegate = new DelegateDefinition(Driver.Options.OutputNamespace, delegateString); + existingDelegate = new DelegateDefinition( + method.TranslationUnit.Module.OutputNamespace, delegateString); Driver.Delegates.Add(method, existingDelegate); - foreach (var library in Driver.Options.Libraries) + foreach (var library in method.TranslationUnit.Module.Libraries) libsDelegates[library].Add(delegateString, existingDelegate); namespaceDelegates.Declarations.Add(@delegate); @@ -128,16 +144,16 @@ namespace CppSharp.Passes return true; } - private DelegateDefinition GetExistingDelegate(string delegateString) + private DelegateDefinition GetExistingDelegate(IList libraries, string delegateString) { - if (Driver.Options.Libraries.Count == 0) + if (libraries.Count == 0) return Driver.Delegates.Values.FirstOrDefault(t => t.Signature == delegateString); DelegateDefinition @delegate = null; - if (Driver.Options.Libraries.Union( - Driver.Symbols.Libraries.SelectMany(l => l.Dependencies)).Any( - l => libsDelegates.ContainsKey(l) && - libsDelegates[l].TryGetValue(delegateString, out @delegate))) + if (libraries.Union( + Driver.Symbols.Libraries.Where(l => libraries.Contains(l.FileName)).SelectMany( + l => l.Dependencies)).Any(l => libsDelegates.ContainsKey(l) && + libsDelegates[l].TryGetValue(delegateString, out @delegate))) return @delegate; return null; @@ -183,7 +199,7 @@ namespace CppSharp.Passes } } - private Namespace namespaceDelegates; + private Dictionary namespacesDelegates = new Dictionary(); private CSharpTypePrinter typePrinter; private static readonly Dictionary> libsDelegates = new Dictionary>(); diff --git a/src/Generator/Passes/FixDefaultParamValuesOfOverridesPass.cs b/src/Generator/Passes/FixDefaultParamValuesOfOverridesPass.cs index 7123b840..f6a4d090 100644 --- a/src/Generator/Passes/FixDefaultParamValuesOfOverridesPass.cs +++ b/src/Generator/Passes/FixDefaultParamValuesOfOverridesPass.cs @@ -11,7 +11,11 @@ namespace CppSharp.Passes Method rootBaseMethod = ((Class) method.Namespace).GetBaseMethod(method); for (int i = 0; i < method.Parameters.Count; i++) { - method.Parameters[i].DefaultArgument = rootBaseMethod.Parameters[i].DefaultArgument; + if (rootBaseMethod.Parameters[i].DefaultArgument != null) + { + method.Parameters[i].DefaultArgument = + rootBaseMethod.Parameters[i].DefaultArgument.Clone(); + } } } return base.VisitMethodDecl(method); diff --git a/src/Generator/Passes/GenerateInlinesCodePass.cs b/src/Generator/Passes/GenerateInlinesCodePass.cs index da5dbe44..2c8bfe13 100644 --- a/src/Generator/Passes/GenerateInlinesCodePass.cs +++ b/src/Generator/Passes/GenerateInlinesCodePass.cs @@ -14,13 +14,16 @@ namespace CppSharp.Passes private void WriteInlinesIncludes() { - var cppBuilder = new StringBuilder(); - foreach (var header in Driver.Options.Headers) - cppBuilder.AppendFormat("#include <{0}>\n", header); - var cpp = string.Format("{0}.cpp", Driver.Options.InlinesLibraryName); - Directory.CreateDirectory(Driver.Options.OutputDir); - var path = Path.Combine(Driver.Options.OutputDir, cpp); - File.WriteAllText(path, cppBuilder.ToString()); + foreach (var module in Driver.Options.Modules) + { + var cppBuilder = new StringBuilder(); + foreach (var header in module.Headers) + cppBuilder.AppendFormat("#include <{0}>\n", header); + var cpp = string.Format("{0}.cpp", module.InlinesLibraryName); + Directory.CreateDirectory(Driver.Options.OutputDir); + var path = Path.Combine(Driver.Options.OutputDir, cpp); + File.WriteAllText(path, cppBuilder.ToString()); + } } } } diff --git a/src/Generator/Passes/GenerateTemplatesCodePass.cs b/src/Generator/Passes/GenerateTemplatesCodePass.cs index c1548526..2e0287e3 100644 --- a/src/Generator/Passes/GenerateTemplatesCodePass.cs +++ b/src/Generator/Passes/GenerateTemplatesCodePass.cs @@ -34,15 +34,18 @@ namespace CppSharp.Passes private void WriteTemplateInstantiations() { - var cppBuilder = new StringBuilder(); - foreach (var header in Driver.Options.Headers) - cppBuilder.AppendFormat("#include <{0}>\n", header); - foreach (var templateInstantiation in templateInstantiations) - cppBuilder.AppendFormat("\ntemplate class {0};", templateInstantiation); - var cpp = string.Format("{0}.cpp", Driver.Options.TemplatesLibraryName); - Directory.CreateDirectory(Driver.Options.OutputDir); - var path = Path.Combine(Driver.Options.OutputDir, cpp); - File.WriteAllText(path, cppBuilder.ToString()); + foreach (var module in Driver.Options.Modules) + { + var cppBuilder = new StringBuilder(); + foreach (var header in module.Headers) + cppBuilder.AppendFormat("#include <{0}>\n", header); + foreach (var templateInstantiation in templateInstantiations) + cppBuilder.AppendFormat("\ntemplate class {0};", templateInstantiation); + var cpp = string.Format("{0}.cpp", module.TemplatesLibraryName); + Directory.CreateDirectory(Driver.Options.OutputDir); + var path = Path.Combine(Driver.Options.OutputDir, cpp); + File.WriteAllText(path, cppBuilder.ToString()); + } } private HashSet templateInstantiations = new HashSet(); diff --git a/src/Generator/Passes/GetterSetterToPropertyAdvancedPass.cs b/src/Generator/Passes/GetterSetterToPropertyAdvancedPass.cs index a82148a0..8fac269b 100644 --- a/src/Generator/Passes/GetterSetterToPropertyAdvancedPass.cs +++ b/src/Generator/Passes/GetterSetterToPropertyAdvancedPass.cs @@ -25,8 +25,7 @@ namespace CppSharp.Passes { this.log = log; foreach (var method in @class.Methods.Where( - m => !m.IsConstructor && !m.IsDestructor && !m.IsOperator && - (m.IsGenerated || m.GenerationKind == GenerationKind.Link))) + m => !m.IsConstructor && !m.IsDestructor && !m.IsOperator && m.IsGenerated)) DistributeMethod(method); } @@ -37,7 +36,7 @@ namespace CppSharp.Passes foreach (Method getter in from getter in getters - where (getter.IsGenerated || getter.GenerationKind == GenerationKind.Link) && + where getter.IsGenerated && ((Class) getter.Namespace).Methods.All(m => m == getter || !m.IsGenerated || m.Name != getter.Name) select getter) { diff --git a/src/Generator/Passes/HandleDefaultParamValuesPass.cs b/src/Generator/Passes/HandleDefaultParamValuesPass.cs index 40d51cf7..e1462d1f 100644 --- a/src/Generator/Passes/HandleDefaultParamValuesPass.cs +++ b/src/Generator/Passes/HandleDefaultParamValuesPass.cs @@ -37,9 +37,10 @@ namespace CppSharp.Passes public override bool VisitFunctionDecl(Function function) { - if (!base.VisitFunctionDecl(function)) + if (!base.VisitFunctionDecl(function) || function.TranslationUnit.IsSystemHeader) return false; + Generator.CurrentOutputNamespace = function.TranslationUnit.Module.OutputNamespace; var overloadIndices = new List(function.Parameters.Count); foreach (var parameter in function.Parameters.Where(p => p.DefaultArgument != null)) { @@ -199,14 +200,14 @@ namespace CppSharp.Passes switch (builtin.Type) { case PrimitiveType.Float: - if (statement.String.EndsWith(".F")) + if (statement.String.EndsWith(".F", System.StringComparison.Ordinal)) { result = statement.String.Replace(".F", ".0F"); return true; } break; case PrimitiveType.Double: - if (statement.String.EndsWith(".")) + if (statement.String.EndsWith(".", System.StringComparison.Ordinal)) { result = statement.String + '0'; return true; diff --git a/src/Generator/Passes/MoveFunctionToClassPass.cs b/src/Generator/Passes/MoveFunctionToClassPass.cs index 2949beb6..2b96cdac 100644 --- a/src/Generator/Passes/MoveFunctionToClassPass.cs +++ b/src/Generator/Passes/MoveFunctionToClassPass.cs @@ -17,7 +17,7 @@ namespace CppSharp.Passes return false; var @class = FindClassToMoveFunctionTo(function.Namespace); - if (@class != null) + if (@class != null && @class.TranslationUnit.Module == function.TranslationUnit.Module) { MoveFunction(function, @class); Log.Debug("Function moved to class: {0}::{1}", @class.Name, function.Name); diff --git a/src/Generator/Passes/MoveOperatorToClassPass.cs b/src/Generator/Passes/MoveOperatorToClassPass.cs index 252658ef..9fc0496e 100644 --- a/src/Generator/Passes/MoveOperatorToClassPass.cs +++ b/src/Generator/Passes/MoveOperatorToClassPass.cs @@ -18,13 +18,12 @@ namespace CppSharp.Passes Class @class = null; foreach (var param in function.Parameters) { - FunctionToInstanceMethodPass.GetClassParameter( - param, out @class); - - if (@class != null) break; + if (FunctionToInstanceMethodPass.GetClassParameter(param, out @class)) + break; } - if (@class == null) + if (@class == null || + @class.TranslationUnit.Module != function.TranslationUnit.Module) return false; // Create a new fake method so it acts as a static method. diff --git a/src/Generator/Passes/RenameRootNamespaces.cs b/src/Generator/Passes/RenameRootNamespaces.cs index 1643807c..e98eb075 100644 --- a/src/Generator/Passes/RenameRootNamespaces.cs +++ b/src/Generator/Passes/RenameRootNamespaces.cs @@ -11,21 +11,21 @@ namespace CppSharp.Passes { public override bool VisitTranslationUnit(TranslationUnit unit) { - if (!base.VisitTranslationUnit(unit)) + if (!base.VisitTranslationUnit(unit) || !unit.IsValid || + unit.IsSystemHeader || !unit.HasDeclarations) return false; var fileName = unit.TranslationUnit.FileName; if (rootNamespaceRenames.ContainsKey(fileName)) { var rootNamespace = rootNamespaceRenames[fileName]; - if (this.Driver.Options.OutputNamespace != rootNamespace) - unit.Name = rootNamespace; + unit.Name = rootNamespace; } else if (unit.GenerationKind == GenerationKind.Generate) { if (Driver.Options.IsCSharpGenerator) - unit.Name = Driver.Options.OutputNamespace; - rootNamespaceRenames.Add(fileName, Driver.Options.OutputNamespace); + unit.Name = unit.Module.OutputNamespace; + rootNamespaceRenames.Add(fileName, unit.Module.OutputNamespace); } return true; } diff --git a/src/Generator/Types/Types.cs b/src/Generator/Types/Types.cs index 1000198d..fbb9a86c 100644 --- a/src/Generator/Types/Types.cs +++ b/src/Generator/Types/Types.cs @@ -32,7 +32,8 @@ namespace CppSharp if (decl.CompleteDeclaration != null) return VisitDeclaration(decl.CompleteDeclaration); - if (decl.GenerationKind == GenerationKind.None) + if (!(decl is TypedefDecl) && (!decl.IsGenerated || + (decl is Class && decl.TranslationUnit.IsSystemHeader))) { Ignore(); return false; diff --git a/tests/NamespacesDerived/NamespacesDerived.cs b/tests/NamespacesDerived/NamespacesDerived.cs index 64869802..57ddf6db 100644 --- a/tests/NamespacesDerived/NamespacesDerived.cs +++ b/tests/NamespacesDerived/NamespacesDerived.cs @@ -19,17 +19,6 @@ namespace CppSharp.Tests driver.Options.GeneratePropertiesAdvanced = true; } - public override void Preprocess(Driver driver, ASTContext ctx) - { - foreach (TranslationUnit unit in ctx.TranslationUnits) - { - if (unit.FileName != "NamespacesDerived.h") - { - unit.GenerationKind = GenerationKind.Link; - } - } - } - public override void Postprocess(Driver driver, ASTContext ctx) { new CaseRenamePass(