diff --git a/.travis.yml b/.travis.yml index 513ef77c..53be47bd 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,4 +1,5 @@ language: cpp +sudo: required os: - linux diff --git a/appveyor.yml b/appveyor.yml index d2d9275e..f7f3cff8 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -25,6 +25,7 @@ os: Visual Studio 2017 platform: - x86 + - x64 configuration: - Release diff --git a/build/Compile.sh b/build/Compile.sh index d709ee5f..c5699971 100755 --- a/build/Compile.sh +++ b/build/Compile.sh @@ -16,7 +16,7 @@ else BUILD_CONF=release_x86; fi -$PREMAKE --file=$CUR_DIR/premake5.lua gmake +$PREMAKE --file=$CUR_DIR/premake5.lua gmake "$@" config=$BUILD_CONF make -C $CUR_DIR/gmake/ BUILD_CONF_DIR="$(tr '[:lower:]' '[:upper:]' <<< ${BUILD_CONF:0:1})${BUILD_CONF:1}" diff --git a/build/Helpers.lua b/build/Helpers.lua index d80e0649..fd8d3ccb 100644 --- a/build/Helpers.lua +++ b/build/Helpers.lua @@ -84,8 +84,9 @@ function SetupNativeProject() buildoptions { msvc_buildflags } defines { msvc_cpp_defines } - filter { "action:gmake" } + filter { "system:linux" } buildoptions { gcc_buildflags } + links { "stdc++" } filter { "system:macosx", "language:C++" } buildoptions { gcc_buildflags, "-stdlib=libc++" } diff --git a/src/CLI/Generator.cs b/src/CLI/Generator.cs index af07d7cb..dff7de51 100644 --- a/src/CLI/Generator.cs +++ b/src/CLI/Generator.cs @@ -4,9 +4,11 @@ using CppSharp.Parser; using CppSharp.Passes; using System; using System.Collections.Generic; +using System.Diagnostics; using System.IO; using System.Linq; using System.Text; +using System.Text.RegularExpressions; using CppAbi = CppSharp.Parser.AST.CppAbi; namespace CppSharp @@ -193,34 +195,7 @@ namespace CppSharp private void SetupLinuxOptions(ParserOptions parserOptions) { - parserOptions.MicrosoftMode = false; - parserOptions.NoBuiltinIncludes = true; - - var headersPath = string.Empty; - - // Search for the available GCC versions on the provided headers. - var versions = Directory.EnumerateDirectories(Path.Combine(headersPath, "usr/include/c++")); - - if (versions.Count() == 0) - throw new Exception("No valid GCC version found on system include paths"); - - string gccVersionPath = versions.First(); - string gccVersion = gccVersionPath.Substring(gccVersionPath.LastIndexOf(Path.DirectorySeparatorChar) + 1); - - string[] systemIncludeDirs = { - Path.Combine("usr", "include", "c++", gccVersion), - Path.Combine("usr", "include", "x86_64-linux-gnu", "c++", gccVersion), - Path.Combine("usr", "include", "c++", gccVersion, "backward"), - Path.Combine("usr", "lib", "gcc", "x86_64-linux-gnu", gccVersion, "include"), - Path.Combine("usr", "lib", "gcc", "x86_64-pc-linux-gnu", gccVersion, "include"), - Path.Combine("usr", "include", "x86_64-linux-gnu"), - Path.Combine("usr", "include", "x86_64-pc-linux-gnu"), - Path.Combine("usr", "include") - }; - - foreach (var dir in systemIncludeDirs) - parserOptions.AddSystemIncludeDirs(Path.Combine(headersPath, dir)); - + parserOptions.SetupLinux(); parserOptions.AddDefines("_GLIBCXX_USE_CXX11_ABI=" + (options.Cpp11ABI ? "1" : "0")); } diff --git a/src/CppParser/ParserGen/ParserGen.cs b/src/CppParser/ParserGen/ParserGen.cs index 2b16cba8..8a2f6cfd 100644 --- a/src/CppParser/ParserGen/ParserGen.cs +++ b/src/CppParser/ParserGen/ParserGen.cs @@ -98,32 +98,7 @@ namespace CppSharp var headersPath = Platform.IsLinux ? string.Empty : Path.Combine(GetSourceDirectory("build"), "headers", "x86_64-linux-gnu"); - - // Search for the available GCC versions on the provided headers. - var versions = Directory.EnumerateDirectories(Path.Combine(headersPath, - "usr/include/c++")); - - if (versions.Count() == 0) - throw new Exception("No valid GCC version found on system include paths"); - - string gccVersionPath = versions.First(); - string gccVersion = gccVersionPath.Substring( - gccVersionPath.LastIndexOf(Path.DirectorySeparatorChar) + 1); - - string[] systemIncludeDirs = { - Path.Combine("usr", "include", "c++", gccVersion), - Path.Combine("usr", "include", "x86_64-linux-gnu", "c++", gccVersion), - Path.Combine("usr", "include", "c++", gccVersion, "backward"), - Path.Combine("usr", "lib", "gcc", "x86_64-linux-gnu", gccVersion, "include"), - Path.Combine("usr", "lib", "gcc", "x86_64-pc-linux-gnu", gccVersion, "include"), - Path.Combine("usr", "include", "x86_64-linux-gnu"), - Path.Combine("usr", "include", "x86_64-pc-linux-gnu"), - Path.Combine("usr", "include") - }; - - foreach (var dir in systemIncludeDirs) - options.AddSystemIncludeDirs(Path.Combine(headersPath, dir)); - + options.SetupLinux(headersPath); options.AddDefines("_GLIBCXX_USE_CXX11_ABI=" + (IsGnuCpp11Abi ? "1" : "0")); } @@ -237,4 +212,4 @@ namespace CppSharp } } } -} \ No newline at end of file +} diff --git a/src/Generator.Tests/GeneratorTest.cs b/src/Generator.Tests/GeneratorTest.cs index d77bc7ae..f882178f 100644 --- a/src/Generator.Tests/GeneratorTest.cs +++ b/src/Generator.Tests/GeneratorTest.cs @@ -28,6 +28,7 @@ namespace CppSharp.Utils options.GeneratorKind = kind; options.OutputDir = Path.Combine(GetOutputDirectory(), "gen", name); options.Quiet = true; + options.GenerateDebugOutput = true; var testModule = options.AddModule(name); testModule.SharedLibraryName = $"{name}.Native"; diff --git a/src/Generator/Generators/CSharp/CSharpSources.cs b/src/Generator/Generators/CSharp/CSharpSources.cs index 8da934c8..2538d7fb 100644 --- a/src/Generator/Generators/CSharp/CSharpSources.cs +++ b/src/Generator/Generators/CSharp/CSharpSources.cs @@ -203,6 +203,27 @@ namespace CppSharp.Generators.CSharp return true; } + private IEnumerable EnumerateClasses() + { + foreach (var tu in TranslationUnits) + { + foreach (var cls in EnumerateClasses(tu)) + yield return cls; + } + } + + private IEnumerable EnumerateClasses(DeclarationContext context) + { + foreach (var cls in context.Classes) + yield return cls; + + foreach (var ns in context.Namespaces) + { + foreach (var cls in EnumerateClasses(ns)) + yield return cls; + } + } + void GenerateNamespaceFunctionsAndVariables(DeclarationContext context) { var hasGlobalVariables = !(context is Class) && context.Variables.Any( @@ -213,7 +234,12 @@ namespace CppSharp.Generators.CSharp PushBlock(BlockKind.Functions); var parentName = SafeIdentifier(context.TranslationUnit.FileNameWithoutExtension); - WriteLine("public unsafe partial class {0}", parentName); + + var keyword = "class"; + var classes = EnumerateClasses().ToList(); + if (classes.FindAll(cls => cls.IsValueType && cls.Name == parentName && context.QualifiedLogicalName == cls.Namespace.QualifiedLogicalName).Any()) + keyword = "struct"; + WriteLine($"public unsafe partial {keyword} {parentName}"); WriteStartBraceIndent(); PushBlock(BlockKind.InternalsClass); @@ -3233,4 +3259,4 @@ namespace CppSharp.Generators.CSharp public SymbolNotFoundException(string msg) : base(msg) {} } -} \ No newline at end of file +} diff --git a/src/Generator/Generators/CodeGenerator.cs b/src/Generator/Generators/CodeGenerator.cs index bd93522d..61d5cd17 100644 --- a/src/Generator/Generators/CodeGenerator.cs +++ b/src/Generator/Generators/CodeGenerator.cs @@ -61,14 +61,6 @@ namespace CppSharp.Generators public abstract void Process(); - public override string Generate() - { - if (Options.IsCSharpGenerator && Options.CompileCode && !Options.GenerateDebugOutput) - return base.GenerateUnformatted(); - - return base.Generate(); - } - public virtual void GenerateFilePreamble(CommentKind kind, string generatorName = "CppSharp") { var lines = new List @@ -91,16 +83,19 @@ namespace CppSharp.Generators public virtual void GenerateDeclarationCommon(Declaration decl) { if (decl.Comment != null) - { GenerateComment(decl.Comment); - GenerateDebug(decl); - } + + GenerateDebug(decl); } public virtual void GenerateDebug(Declaration decl) { if (Options.GenerateDebugOutput && !string.IsNullOrWhiteSpace(decl.DebugText)) - WriteLine("// DEBUG: " + decl.DebugText); + { + var debugText = decl.DebugText; + debugText = Regex.Replace(debugText.Trim(), "\r?\n", "\n// DEBUG: "); + WriteLine($"// DEBUG: {debugText}"); + } } #endregion diff --git a/src/Generator/Passes/CleanInvalidDeclNamesPass.cs b/src/Generator/Passes/CleanInvalidDeclNamesPass.cs index 52462e7f..9851e3c3 100644 --- a/src/Generator/Passes/CleanInvalidDeclNamesPass.cs +++ b/src/Generator/Passes/CleanInvalidDeclNamesPass.cs @@ -53,7 +53,6 @@ namespace CppSharp.Passes (method == null || method.Kind == CXXMethodKind.Normal)) decl.Name = CheckName(decl.Name); - StringHelpers.CleanupText(ref decl.DebugText); return true; } diff --git a/src/Generator/Passes/DelegatesPass.cs b/src/Generator/Passes/DelegatesPass.cs index 366ab905..36e37734 100644 --- a/src/Generator/Passes/DelegatesPass.cs +++ b/src/Generator/Passes/DelegatesPass.cs @@ -187,6 +187,15 @@ namespace CppSharp.Passes ).GroupBy(d => d.Name).Where(g => g.Any(d => d.HasDeclarations)).ToList(); if (groups.Count == 1) parent = groups.Last().Last(); + else + { + foreach (var g in groups) + { + parent = g.ToList().Find(ns => ns.Name == module.LibraryName || ns.Name == module.OutputNamespace); + if (parent != null) + break; + } + } } if (parent == null) diff --git a/src/Generator/Utils/BlockGenerator.cs b/src/Generator/Utils/BlockGenerator.cs index bf4d0d0d..ee807a18 100644 --- a/src/Generator/Utils/BlockGenerator.cs +++ b/src/Generator/Utils/BlockGenerator.cs @@ -183,55 +183,6 @@ namespace CppSharp return builder.ToString(); } - public StringBuilder GenerateUnformatted() - { - if (CheckGenerate != null && !CheckGenerate()) - return new StringBuilder(0); - - if (Blocks.Count == 0) - return Text.StringBuilder; - - var builder = new StringBuilder(); - Block previousBlock = null; - - var blockIndex = 0; - foreach (var childBlock in Blocks) - { - var childText = childBlock.GenerateUnformatted(); - - var nextBlock = (++blockIndex < Blocks.Count) - ? Blocks[blockIndex] - : null; - - if (nextBlock != null) - { - var nextText = nextBlock.GenerateUnformatted(); - if (nextText.Length == 0 && - childBlock.NewLineKind == NewLineKind.IfNotEmpty) - continue; - } - - if (childText.Length == 0) - continue; - - if (previousBlock != null && - previousBlock.NewLineKind == NewLineKind.BeforeNextBlock) - builder.AppendLine(); - - builder.Append(childText); - - if (childBlock.NewLineKind == NewLineKind.Always) - builder.AppendLine(); - - previousBlock = childBlock; - } - - if (Text.StringBuilder.Length != 0) - builder.Append(Text.StringBuilder); - - return builder; - } - public bool IsEmpty { get @@ -323,11 +274,6 @@ namespace CppSharp return RootBlock.Generate(); } - public string GenerateUnformatted() - { - return RootBlock.GenerateUnformatted().ToString(); - } - #region Block helpers public void AddBlock(Block block) diff --git a/src/Generator/Utils/Utils.cs b/src/Generator/Utils/Utils.cs index c555e2d9..b8f8ed17 100644 --- a/src/Generator/Utils/Utils.cs +++ b/src/Generator/Utils/Utils.cs @@ -43,20 +43,6 @@ namespace CppSharp return ss[0]; // all strings identical } - public static void CleanupText(ref string debugText) - { - // Strip off newlines from the debug text. - if (string.IsNullOrWhiteSpace(debugText)) - { - debugText = string.Empty; - return; - } - - // TODO: Make this transformation in the output. - debugText = Regex.Replace(debugText, " {2,}", " "); - debugText = debugText.Replace("\n", ""); - } - public static string[] SplitCamelCase(string input) { var str = Regex.Replace(input, "([A-Z])", " $1", RegexOptions.Compiled); diff --git a/src/Parser/ParserOptions.cs b/src/Parser/ParserOptions.cs index fb0110cb..ad169ec1 100644 --- a/src/Parser/ParserOptions.cs +++ b/src/Parser/ParserOptions.cs @@ -1,9 +1,12 @@ -using CppSharp.Parser.AST; +using System; +using CppSharp.Parser.AST; using System.Reflection; using LanguageVersion = CppSharp.Parser.LanguageVersion; using System.Globalization; using System.Collections.Generic; +using System.Diagnostics; using System.Linq; +using System.Text.RegularExpressions; namespace CppSharp.Parser { @@ -218,6 +221,64 @@ namespace CppSharp.Parser AddArguments("-stdlib=libc++"); } + private void GetUnixCompilerInfo(out string compiler, out string longVersion, out string shortVersion) + { + var info = new ProcessStartInfo(Environment.GetEnvironmentVariable("CXX") ?? "gcc", "-v"); + info.RedirectStandardError = true; + info.CreateNoWindow = true; + info.UseShellExecute = false; + var process = Process.Start(info); + if (process == null) + throw new SystemException("GCC compiler was not found."); + process.WaitForExit(); + + var output = process.StandardError.ReadToEnd(); + var match = Regex.Match(output, "(gcc|clang) version (([0-9]+\\.[0-9]+)\\.[0-9]+)"); + if (!match.Success) + throw new SystemException("GCC compiler was not found."); + + compiler = match.Groups[1].ToString(); + longVersion = match.Groups[2].ToString(); + shortVersion = match.Groups[3].ToString(); + } + + public void SetupLinux(string headersPath="") + { + MicrosoftMode = false; + NoBuiltinIncludes = true; + NoStandardIncludes = true; + Abi = CppAbi.Itanium; + + string compiler, longVersion, shortVersion; + GetUnixCompilerInfo(out compiler, out longVersion, out shortVersion); + string[] versions = {longVersion, shortVersion}; + string[] tripples = {"x86_64-linux-gnu", "x86_64-pc-linux-gnu"}; + if (compiler == "gcc") + { + foreach (var version in versions) + { + AddSystemIncludeDirs($"{headersPath}/usr/include/c++/{version}"); + AddSystemIncludeDirs($"{headersPath}/usr/include/c++/{version}/backward"); + foreach (var tripple in tripples) + { + AddSystemIncludeDirs($"{headersPath}/usr/include/{tripple}/c++/{version}"); + AddSystemIncludeDirs($"{headersPath}/usr/include/c++/{version}/{tripple}"); + } + } + } + foreach (var tripple in tripples) + { + foreach (var version in versions) + { + AddSystemIncludeDirs($"{headersPath}/usr/lib/{compiler}/{tripple}/{version}/include"); + AddSystemIncludeDirs($"{headersPath}/usr/lib/{compiler}/{tripple}/{version}/include/c++"); + AddSystemIncludeDirs($"{headersPath}/usr/lib/{compiler}/{tripple}/{version}/include/c++/{tripple}"); + } + AddSystemIncludeDirs($"{headersPath}/usr/include/{tripple}"); + } + AddSystemIncludeDirs($"{headersPath}/usr/include"); + } + public void Setup() { SetupArguments(); @@ -291,6 +352,9 @@ namespace CppSharp.Parser case TargetPlatform.MacOS: SetupXcode(); break; + case TargetPlatform.Linux: + SetupLinux(); + break; } } } diff --git a/tests/CSharp/CSharp.cs b/tests/CSharp/CSharp.cs index 57dfa50d..c18e56ed 100644 --- a/tests/CSharp/CSharp.cs +++ b/tests/CSharp/CSharp.cs @@ -36,6 +36,7 @@ namespace CppSharp.Tests ctx.SetClassAsValueType("QPoint"); ctx.SetClassAsValueType("QSize"); ctx.SetClassAsValueType("QRect"); + ctx.SetClassAsValueType("CSharp"); ctx.SetClassAsValueType("StructTestArrayTypeFromTypedef"); ctx.IgnoreClassWithName("IgnoredTypeInheritingNonIgnoredWithNoEmptyCtor"); ctx.IgnoreClassWithName("Ignored"); diff --git a/tests/CSharp/CSharp.h b/tests/CSharp/CSharp.h index 37756251..ac3d962c 100644 --- a/tests/CSharp/CSharp.h +++ b/tests/CSharp/CSharp.h @@ -1266,3 +1266,9 @@ public: ~HasFixedArrayOfPointers(); Foo* fixedArrayOfPointers[3]; }; + +struct DLL_API CSharp +{ +}; + +static int FOOBAR_CONSTANT = 42;