mono / CppSharp

Tools and libraries to glue C/C++ APIs to high-level languages
MIT License
3.13k stars 514 forks source link

Invalid generated code for variable array global variable #777

Closed ktngoykalolo closed 7 years ago

ktngoykalolo commented 7 years ago
Brief Description

I would like to generate bindings for Gammu, a C library that is freely available. when trying to do so it gives an error saying it does not find the gammu.lib file nor the headers. I suspect I am not putting them at the right place. where should I put the files so that cppsharp sees them ?

OS: Windows here is a sample of my generator

` class MyGenerator : ILibrary {

    private const string GammuRootPath = @"C:\Program Files\Gammu 1.38.1";
    private const string GammuIncludePath = GammuRootPath + @"\include\";
    private const string GammuLibPath = GammuRootPath + @"\lib\";

    public void Postprocess(Driver driver, ASTContext ctx)
    {
        //throw new NotImplementedException();
    }

    public void Preprocess(Driver driver, ASTContext ctx)
    {
        //throw new NotImplementedException();
    }

    public void Setup(Driver driver)
    {

        PrepareDriver(driver);

    }

    private static void PrepareDriver(Driver driver)
    {
        var drOptions = driver.Options;
        drOptions.GeneratorKind = GeneratorKind.CSharp;
        //drOptions.CompileCode = true;
        drOptions.OutputDir = "GammuSharp";
        drOptions.LibraryName = "libGammuSharp";

        drOptions.Libraries.Add("Gammu.lib");

        drOptions.OutputInteropIncludes = true;
        drOptions.GenerateInternalImports = true;
        //drOptions.Target = CompilationTarget.StaticLibrary;
        drOptions.Platform = TargetPlatform.Windows;
        drOptions.VsVersion = VisualStudioVersion.VS2012;
        drOptions.UseHeaderDirectories = true;

        //drOptions.OutputNamespace = "GammuSharp";

        // header files to include

        //drOptions.Headers.Add(GammuIncludePath + "gammu.h");
        //drOptions.Headers.Add(GammuIncludePath + "gammu-wap.h");
        //drOptions.Headers.Add(GammuIncludePath + "gammu-unicode.h");
        //drOptions.Headers.Add(GammuIncludePath + "gammu-types.h");
        //drOptions.Headers.Add(GammuIncludePath + "gammu-statemachine.h");
        //drOptions.Headers.Add(GammuIncludePath + "gammu-smsd.h");
        //drOptions.Headers.Add(GammuIncludePath + "gammu-settings.h");
        //drOptions.Headers.Add(GammuIncludePath + "gammu-security.h");
        //drOptions.Headers.Add(GammuIncludePath + "gammu-ringtone.h");
        //drOptions.Headers.Add(GammuIncludePath + "gammu-nokia.h");
        //drOptions.Headers.Add(GammuIncludePath + "gammu-misc.h");
        //drOptions.Headers.Add(GammuIncludePath + "gammu-message.h");
        //drOptions.Headers.Add(GammuIncludePath + "gammu-memory.h");
        //drOptions.Headers.Add(GammuIncludePath + "gammu-limits.h");
        //drOptions.Headers.Add(GammuIncludePath + "gammu-keys.h");
        //drOptions.Headers.Add(GammuIncludePath + "gammu-inifile.h");
        //drOptions.Headers.Add(GammuIncludePath + "gammu-info.h");
        //drOptions.Headers.Add(GammuIncludePath + "gammu-file.h");
        //drOptions.Headers.Add(GammuIncludePath + "gammu-error.h");
        //drOptions.Headers.Add(GammuIncludePath + "gammu-debug.h");
        //drOptions.Headers.Add(GammuIncludePath + "gammu-datetime.h");
        //drOptions.Headers.Add(GammuIncludePath + "gammu-config.h");
        //drOptions.Headers.Add(GammuIncludePath + "gammu-category.h");
        //drOptions.Headers.Add(GammuIncludePath + "gammu-callback.h");
        //drOptions.Headers.Add(GammuIncludePath + "gammu-call.h");
        //drOptions.Headers.Add(GammuIncludePath + "gammu-calendar.h");
        //drOptions.Headers.Add(GammuIncludePath + "gammu-bitmap.h");
        //drOptions.Headers.Add(GammuIncludePath + "gammu-backup.h");

    }

    public void SetupPasses(Driver driver)
    {

    }
}

`

ddobrev commented 7 years ago

Options.Headers only contains the names of headers, you need to add their containing directory to IncludeDirs. You may use our own bindings as an example: https://github.com/mono/CppSharp/blob/master/src/CppParser/ParserGen/ParserGen.cs#L59 .

ktngoykalolo commented 7 years ago

Hello @ddobrev , I have been able to successfully generate bindings for the library mentioned above. however I have also used the //driver options to compile code drOptions.CompileCode = true; but when it is compiling, CppSharp is failing to compile and gives 2 errors :


C:\Users\Kevin\documents\visual studio 2015\Projects\GammuCppSharp\GammuCppSharp.CLI\bin\Debug\GammuSharp\GammuSharp.cs(2519,15) : error CS0208: Impossible de prendre l'adresse, d'obtenir la taille ou de déclarer un pointeur vers un type managé ('GSMCodeName')
C:\Users\Kevin\documents\visual studio 2015\Projects\GammuCppSharp\GammuCppSharp.CLI\bin\Debug\GammuSharp\GammuSharp.cs(2529,15) : error CS0208: Impossible de prendre l'adresse, d'obtenir la taille ou de déclarer un pointeur vers un type managé ('GSMCodeName')
C:\Users\Kevin\documents\visual studio 2015\Projects\GammuCppSharp\GammuCppSharp.CLI\bin\Debug\GammuSharp\GammuSharp.cs(17677,37) : error CS0111: Le type 'corecrt_search' définit déjà un membre appelé 'Lfind' avec les mêmes types de paramètre
C:\Users\Kevin\documents\visual studio 2015\Projects\GammuCppSharp\GammuCppSharp.CLI\bin\Debug\GammuSharp\GammuSharp.cs(17688,37) : error CS0111: Le type 'corecrt_search' définit déjà un membre appelé 'Lsearch' avec les mêmes types de paramètre
`
any help regarding this ??? 
tritao commented 7 years ago

Seems like there is some generation bug when wrapping your library. Can you share your source code with us or try to send the minimal source code that reproduces the issue?

ktngoykalolo commented 7 years ago
using System.IO;
using CppSharp;
using CppSharp.Generators;
using CppSharp.Parser;
using CppSharp.Parser.AST;

namespace GammuCppSharp
{

    /// <summary>
    /// main generator for Gammu bindings in C#
    /// </summary>
    class MyGenerator : ILibrary
    {

        private const string GammuRootPath = @"C:\Program Files\Gammu 1.38.1";
        private const string GammuIncludePath = GammuRootPath + @"\include\gammu\";
        private const string GammuLibPath = GammuRootPath + @"\lib\";
        private const string _theotherPath = @"C:\gammu-1.38.1\libgammu";
        private const string _theotherincludepath = @"C:\gammu-1.38.1\include";

        public void Setup(Driver driver)
        {

            PrepareDriver(driver);

        }

        private void PrepareDriver(Driver driver)
        {

            //parse options configuration
            var myparseOptions = driver.ParserOptions;

            //adding include dirs
            myparseOptions.AddIncludeDirs(GammuIncludePath);
            //myparseOptions.AddIncludeDirs(_theotherincludepath);
            myparseOptions.AddIncludeDirs(@"C:/Program Files (x86)/Microsoft Visual Studio 14.0/VC/include/*");
            myparseOptions.AddIncludeDirs(@"C:/Program Files (x86)/Microsoft Visual Studio 14.0/VC/atlmfc/include");
            myparseOptions.AddIncludeDirs(@"C:/Program Files (x86)/Windows Kits/10/Include/10.0.10240.0/ucrt");
            myparseOptions.AddIncludeDirs(@"C:/Program Files (x86)/Windows Kits/10/Include/10.0.10240.0/um");
            myparseOptions.AddIncludeDirs(@"C:/Program Files (x86)/Windows Kits/10/Include/10.0.10240.0/shared");
            myparseOptions.AddIncludeDirs(@"C:/Program Files (x86)/Windows Kits/10/Include/10.0.10240.0/winrt");
            myparseOptions.AddIncludeDirs(@"C:/Program Files (x86)/Windows Kits/NETFXSDK/4.6/Include/um");

           // myparseOptions.AddIncludeDirs(GammuIncludePath);
            myparseOptions.AddLibraryDirs(GammuLibPath);
            myparseOptions.Abi = CppSharp.Parser.AST.CppAbi.Microsoft;
            myparseOptions.LibraryFile = "Gammu.lib";
           // myparseOptions.LanguageVersion = LanguageVersion.C;
            myparseOptions.SetupIncludes();
            myparseOptions.MicrosoftMode = true;

            //driveroptions configuration
            var drOptions = driver.Options;
            drOptions.GeneratorKind = GeneratorKind.CSharp;

            drOptions.OutputDir = "GammuSharp";
            drOptions.LibraryName = "GammuSharp";

            drOptions.Libraries.Add("Gammu.lib");
            drOptions.CompileCode = true;
            drOptions.MarshalCharAsManagedChar = true;
            drOptions.GenerateSupportFiles = true;
            //drOptions.DryRun = true;

            drOptions.Platform = TargetPlatform.Windows;
            drOptions.VsVersion = VisualStudioVersion.Latest;
            //drOptions.UseHeaderDirectories = true;
            //drOptions.Verbose = true;
            drOptions.OutputNamespace = "GammuSharp";

            //header files to include

            //myparseOptions.AddSourceFiles(GammuIncludePath + "gammu.h");
            //myparseOptions.AddSourceFiles(GammuIncludePath + "gammu-wap.h");
            //myparseOptions.AddSourceFiles(GammuIncludePath + "gammu-unicode.h");
            //myparseOptions.AddSourceFiles(GammuIncludePath + "gammu-types.h");
            //myparseOptions.AddSourceFiles(GammuIncludePath + "gammu-statemachine.h");
            //myparseOptions.AddSourceFiles(GammuIncludePath + "gammu-smsd.h");
            //myparseOptions.AddSourceFiles(GammuIncludePath + "gammu-settings.h");
            //myparseOptions.AddSourceFiles(GammuIncludePath + "gammu-security.h");
            //myparseOptions.AddSourceFiles(GammuIncludePath + "gammu-ringtone.h");
            //myparseOptions.AddSourceFiles(GammuIncludePath + "gammu-nokia.h");
            //myparseOptions.AddSourceFiles(GammuIncludePath + "gammu-misc.h");
            //myparseOptions.AddSourceFiles(GammuIncludePath + "gammu-message.h");
            //myparseOptions.AddSourceFiles(GammuIncludePath + "gammu-memory.h");
            //myparseOptions.AddSourceFiles(GammuIncludePath + "gammu-limits.h");
            //myparseOptions.AddSourceFiles(GammuIncludePath + "gammu-keys.h");
            //myparseOptions.AddSourceFiles(GammuIncludePath + "gammu-inifile.h");
            //myparseOptions.AddSourceFiles(GammuIncludePath + "gammu-info.h");
            //myparseOptions.AddSourceFiles(GammuIncludePath + "gammu-file.h");
            //myparseOptions.AddSourceFiles(GammuIncludePath + "gammu-error.h");
            //myparseOptions.AddSourceFiles(GammuIncludePath + "gammu-debug.h");
            //myparseOptions.AddSourceFiles(GammuIncludePath + "gammu-datetime.h");
            //myparseOptions.AddSourceFiles(GammuIncludePath + "gammu-config.h");
            //myparseOptions.AddSourceFiles(GammuIncludePath + "gammu-category.h");
            //myparseOptions.AddSourceFiles(GammuIncludePath + "gammu-callback.h");
            //myparseOptions.AddSourceFiles(GammuIncludePath + "gammu-call.h");
            //myparseOptions.AddSourceFiles(GammuIncludePath + "gammu-calendar.h");
            //myparseOptions.AddSourceFiles(GammuIncludePath + "gammu-bitmap.h");
            //myparseOptions.AddSourceFiles(GammuIncludePath + "gammu-backup.h");

            drOptions.Headers.Add(GammuIncludePath + "gammu.h");
            drOptions.Headers.Add(GammuIncludePath + "gammu-wap.h");
            drOptions.Headers.Add(GammuIncludePath + "gammu-unicode.h");
            drOptions.Headers.Add(GammuIncludePath + "gammu-types.h");
            drOptions.Headers.Add(GammuIncludePath + "gammu-statemachine.h");
            drOptions.Headers.Add(GammuIncludePath + "gammu-smsd.h");
            drOptions.Headers.Add(GammuIncludePath + "gammu-settings.h");
            drOptions.Headers.Add(GammuIncludePath + "gammu-security.h");
            drOptions.Headers.Add(GammuIncludePath + "gammu-ringtone.h");
            drOptions.Headers.Add(GammuIncludePath + "gammu-nokia.h");
            drOptions.Headers.Add(GammuIncludePath + "gammu-misc.h");
            drOptions.Headers.Add(GammuIncludePath + "gammu-message.h");
            drOptions.Headers.Add(GammuIncludePath + "gammu-memory.h");
            drOptions.Headers.Add(GammuIncludePath + "gammu-limits.h");
            drOptions.Headers.Add(GammuIncludePath + "gammu-keys.h");
            drOptions.Headers.Add(GammuIncludePath + "gammu-inifile.h");
            drOptions.Headers.Add(GammuIncludePath + "gammu-info.h");
            drOptions.Headers.Add(GammuIncludePath + "gammu-file.h");
            drOptions.Headers.Add(GammuIncludePath + "gammu-error.h");
            drOptions.Headers.Add(GammuIncludePath + "gammu-debug.h");
            drOptions.Headers.Add(GammuIncludePath + "gammu-datetime.h");
            drOptions.Headers.Add(GammuIncludePath + "gammu-config.h");
            drOptions.Headers.Add(GammuIncludePath + "gammu-category.h");
            drOptions.Headers.Add(GammuIncludePath + "gammu-callback.h");
            drOptions.Headers.Add(GammuIncludePath + "gammu-call.h");
            drOptions.Headers.Add(GammuIncludePath + "gammu-calendar.h");
            drOptions.Headers.Add(GammuIncludePath + "gammu-bitmap.h");
            drOptions.Headers.Add(GammuIncludePath + "gammu-backup.h");

            //driver.Setup();
            //driver.ParseCode();
            //driver.ParseLibraries();
            //driver.ProcessCode();
            //driver.CompileCode(drOptions.MainModule);

        }

        static string GetSourceDirectory(string dir)

        {

            var directory = new DirectoryInfo(Directory.GetCurrentDirectory());

            while (directory != null)

            {

                var path = Path.Combine(directory.FullName, dir);

                if (Directory.Exists(path) &&

                    Directory.Exists(Path.Combine(directory.FullName, "deps")))

                    return path;

                directory = directory.Parent;

            }

            throw new Exception("Could not find build directory: " + dir);

        }
        public void SetupPasses(Driver driver)
        {

        }

        public void Preprocess(Driver driver, CppSharp.AST.ASTContext ctx)
        {
            //throw new NotImplementedException();
        }

        public void Postprocess(Driver driver, CppSharp.AST.ASTContext ctx)
        {
            //throw new NotImplementedException();
        }
    }
}
ktngoykalolo commented 7 years ago

could you open this issue ?

ddobrev commented 7 years ago

@ktngoykalolo if you build C++# from source code, it's relatively easy to debug yourself. Let me know if you'd like to try.

tritao commented 7 years ago

Hey Kevin, can you also paste a gist with generated file GammuSharp.cs?

ktngoykalolo commented 7 years ago

it is a really long file. I have zipped the whole package with the generated file in this link on OneDrive

ktngoykalolo commented 7 years ago

I mostly work from the Nuget Package. I could give it shot. I don't have a deep background on C++ or how compilers are created but why not give it a try? let me try to clone the CppSharp project.

tritao commented 7 years ago

Took a quick look, minimized test case for first failure:

struct GSM_CodeName {};
extern const GSM_CodeName GSM_Countries[];
tritao commented 7 years ago

It might be related to https://github.com/mono/CppSharp/issues/744#issuecomment-275966916.

ktngoykalolo commented 7 years ago

I am on a tight deadline. what do you suggest I do to circumvent this bug ?

tritao commented 7 years ago

Try commenting the offending declarations in the header files run the generator again.

ktngoykalolo commented 7 years ago

Negative. impossible to comment those declarations as they have lots of dependencies on them. I did comment them and it made things much more worse. I suspect the issue is with the generated code itself. maybe I could configure a post-process pass to try to resolve this issue. maybe this is a mapping issue, what is your opinion ?

ktngoykalolo commented 7 years ago
    `CS0029 Impossible de convertir implicitement le type 'GammuSharp.GSMCodeName.__Internal' en 'GammuSharp.GSMCodeName*'` 

digging deeper into the errors by importing the generated bindings into another blank project

tritao commented 7 years ago

Try this:

        public void Postprocess(Driver driver, CppSharp.AST.ASTContext ctx)
        {
            foreach (var item in ctx.FindDecl<CppSharp.AST.Variable>("GSM_Networks"))
                item.GenerationKind = CppSharp.AST.GenerationKind.None;
            foreach (var item in ctx.FindDecl<CppSharp.AST.Variable>("GSM_Countries"))
                item.GenerationKind = CppSharp.AST.GenerationKind.None;
        }
tritao commented 7 years ago

Did it work?

ktngoykalolo commented 7 years ago

Hello I tried it but it didn't work. From what I understand, the thing is when cppsharp generates the classes for GSM_Networks and GSM_Countries, there is a member where instead of returning internal classes that member returns pointers, which is why it is giving that error message. I managed to clear the other error message by changing myparseOptions.AddIncludeDirs to myparseOptions.AddSystemIncludeDirs

ktngoykalolo commented 7 years ago

Hello I finally managed to do it!!! I took your processing code and put it in the Preprocess method! it worked !!!! bindings are working successfully !!!

ddobrev commented 7 years ago

@ktngoykalolo I am really glad to hear it. Still, we are going to fix the real issue as soon as time permits.

ktngoykalolo commented 7 years ago

sure sure! many thanks for the support and the assist! truly appreciated! the issue can be closed once and for all.

ktngoykalolo commented 7 years ago

this wrapper is completely raw, I get errors saying that it can only be used in an "unsafe context"

ddobrev commented 7 years ago

Have you allowed unsafe code in your project settings?

ktngoykalolo commented 7 years ago

hello, Yes I did. I am digging deeper on that subject. some types have members returning pointers instead of basic value types. I will see if I can have some preprocess passes to fix those mappings.

ddobrev commented 7 years ago

Perhaps we miss some member to mark as unsafe. Could you please paste an example?

ktngoykalolo commented 7 years ago

I will put it on pastebin, the code is quite long.

ktngoykalolo commented 7 years ago

Hello, I just realized that I had to add the "unsafe" keyword to the method I was using, now I no longer have that message. but I still need to investigate those pointers and bytes types. I currently have some connectivity issues, I will try to post the code.

realvictorprm commented 7 years ago

Great to hear that part of the issue isn't related to CppSharp. Please post the code @ktngoykalolo , I'll take a look into them too :wink: !

ktngoykalolo commented 7 years ago

here is a paste valid for a week : http://pastebin.com/QR4cSb6W

ktngoykalolo commented 7 years ago

I think I have to study the code in depth to understand its structure. then I can optimize the bindings using preprocess passes and instructions.

ktngoykalolo commented 7 years ago

what is the easiest way to customize the bindings ? I would like to modify the mappings of some functions with pointers as return type.

ddobrev commented 7 years ago

@ktngoykalolo if you want to always present that pointer as the same type, use type maps. If you only want to do it for certain functions, you need a custom pass.

ktngoykalolo commented 7 years ago

@ddobrev , yes you are right, I will need a custom pass where I could specify type mappings for certain functions. is there a particular manner to map constructors ? there is a structure that is being initialized as a pointer by a specific (global) method. I could map that using a special constructor in the wrapping code.