Using the .cs files generated by CppSharp

957 views
Skip to first unread message

Voidpointer Linden

unread,
May 6, 2014, 4:21:06 PM5/6/14
to cppsha...@googlegroups.com
For win32, I currently have a generator project that runs and generates a bunch of .cs files.  These .cs files are then made into another project whose output is a c# class library.   So far, this all works, and the generated files compile and create a dll.

At that point, I set up a third project to actually use the bindings and test them out.   I create a test method that exercises some of the C++/C# bindings, add a reference to the class library dll from the second project, and this compiles fine.

Ecstatic, I then run the test project and sigh as the first time it tries to access any of the bindings, it fails with an exception like this:

A first chance exception of type 'System.EntryPointNotFoundException' occurred in LLCS.dll
An unhandled exception of type 'System.EntryPointNotFoundException' occurred in LLCS.dll
Additional information: Unable to find an entry point named '?GetMask@LogicVector@LLCore@@SAABV12@W4Mask@12@@Z' in DLL 'LLCS'.

It seems logical that I need to include the C++ library as well as the C# dll, so I try this and run into another problem: The C++ code is in a .lib file and I cannot add a reference to a .lib.   Does this mean that any C++ code I want to use with CppSharp needs to be in a dll?  If not, what is the voodoo I need to do to give access to the C++ code?

João Matos

unread,
May 6, 2014, 5:20:10 PM5/6/14
to Voidpointer Linden, cppsha...@googlegroups.com
Either the native library is not properly exporting the symbol of MSVC name mangling in Clang could be buggy, though as of late it has improved dramatically.

Some tools that can be helpful in tracking down which problem is happening here are DLL Export Viewer (http://www.nirsoft.net/utils/dll_export_viewer.html)
and undname (Microsoft C++ Name Undecorator).

First I'd check if the symbol is being properly exported to the DLL with the DLL Exports Viewer. You can also precisely check which declaration it's trying to import by demangling the name, invoke undname like this from a VS shell:

C:\Development>undname ?GetMask@LogicVector@LLCore@@SAABV12@W4Mask@12@@Z
Microsoft (R) C++ Name Undecorator
Copyright (C) Microsoft Corporation. All rights reserved.
Undecoration of :- "?GetMask@LogicVector@LLCore@@SAABV12@W4Mask@12@@Z"
is :- "public: static class LLCore::LogicVector const & __cdecl LLCore::LogicVector::GetMask(enum LLCore::LogicVector::Mask)"

You do not need to reference the C++ .lib from the project that uses CppSharp code. You can pass the .lib to CppSharp's generator itself though. In that case you can activate in options a check for symbols, CppSharp will load your .lib and check that all generated symbols are present in the lib.

What could be happening is that this particular method is defined inline, in which case you need to move its definition out of the class declaration.



--
You received this message because you are subscribed to the Google Groups "CppSharp" group.
To unsubscribe from this group and stop receiving emails from it, send an email to cppsharp-lis...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.



--
João Matos

Voidpointer Linden

unread,
May 6, 2014, 5:23:11 PM5/6/14
to João Matos, cppsha...@googlegroups.com
eeek, that's rather scary if CppSharp is unable to handle inlined methods as a large portion of the libraries I'm dealing with are intentionally inlined functions.   Are problems with inlined methods a general rule for CppSharp or a rare exception?

--

Lee Wilson | Senior Engineer

O None | C 425.890.5463 | Skype devnullicus | Second Life Voidpointer Linden


Linden Lab | Makers of Shared Creative Spaces

Check out what we're working on!

João Matos

unread,
May 6, 2014, 5:29:29 PM5/6/14
to Voidpointer Linden, cppsha...@googlegroups.com
CppSharp in C# mode is limited by what's callable from a P/Invoke. It's not really a CppSharp limitation but rather a C++'s compiler limitation IMHO. GCC provides a "-fkeep-inline-functions" that can be used to keep them. We have some work-in-progress option to generate some extra C++ code that can be used to explicitly export missing inline methods, but this is a work-in-progress and I'm not sure what the state of it is, it was community contributed. IIRC you enable it via a GenerateInlines option or something.

Another option is to use the C++/CLI backend which works perfectly for inline stuff but you'll be limited to Windows/MSVC for the time being. We're working on a Clang-based C++/CLI compiler but it might be a few years before this is a viable option.

--
João Matos

Voidpointer Linden

unread,
May 6, 2014, 6:42:22 PM5/6/14
to João Matos, cppsha...@googlegroups.com
Setting GenerateInlines doesn't seem to help.   Setting checksymbols to true reveals that a LOT of symbols are not found (in fact, I would hazard a guess that most of them, if not ALL, are not found).  This also seems to cut down the generated C# code, but even the methods that it does include at that point are still not found.   I've tried disabling inline expansion when compiling the C++ lib, but that doesn't seem to help at all.

Can you clarify a bit what you mean by "limited to Windows/MSVC"?   Currently, that's what I'm using and we have no plans to change that at the moment as the rest of the project is set up around that combo.

My ultimate goal here is to allow a bunch of C++ modules/classes to be used from C# tools and have the bindings be generated automatically as the C++ code changes.   If I can do that from a nice C# generator project, I'm happy, but if I need to use a CLI to generate the bindings, I'll deal with that too.   My main concern is that there is absolutely no documentation about how to use the CLI.


João Matos

unread,
May 6, 2014, 7:27:15 PM5/6/14
to Voidpointer Linden, cppsha...@googlegroups.com

On Tue, May 6, 2014 at 11:42 PM, Voidpointer Linden <voidp...@lindenlab.com> wrote:
Can you clarify a bit what you mean by "limited to Windows/MSVC"?   Currently, that's what I'm using and we have no plans to change that at the moment as the rest of the project is set up around that combo.

When I refer to CLI I am referring to C++/CLI, aka Managed C++. I say it's only compatible to Windows/MSVC because managed C++ code will only work on the MS's compiler since we not yet have a production-quality compiler that generates code that works on Mono. You can still call the bindings from C# of course, or any .NET compatible language, but instead of C# bindings code we generate C++/CLI bindings code.

If you don't mind being restricted to calling the generated bindings only from Windows/.NET for the time being, then it's a good option. You can change CppSharp to generate C++/CLI by changing the generator kind in the options.

--
João Matos

Voidpointer Linden

unread,
May 7, 2014, 12:59:04 PM5/7/14
to João Matos, cppsha...@googlegroups.com

​Hmm, well, when I change the generator kind to "CLI", I then get crash exceptions while trying to generate the bindings.

Generating code...
Error: Object reference not set to an instance of an object.
   at CppSharp.Types.CppTypePrinter.VisitPointerType(PointerType pointer, TypeQualifiers quals) in <CppSharp>src\Generator\Types\CppTypePrinter.cs:line 78
   at CppSharp.AST.PointerType.Visit[T](ITypeVisitor`1 visitor, TypeQualifiers quals) in <CppSharp>src\AST\Type.cs:line 246
   at CppSharp.Types.CppTypePrinter.VisitParameter(Parameter arg, Boolean hasName) in <CppSharp>src\Generator\Types\CppTypePrinter.cs:line 215
   at CppSharp.Types.CppTypePrinter.VisitParameterDecl(Parameter parameter) in <CppSharp>src\Generator\Types\CppTypePrinter.cs:line 274
   at CppSharp.AST.Parameter.Visit[T](IDeclVisitor`1 visitor) in <CppSharp>src\AST\Function.cs:line 59
   at CppSharp.Types.TypeMapDatabase.FindTypeMap(Declaration decl, Type type, TypeMap& typeMap) in <CppSharp>src\Generator\Types\TypeMap.cs:line 152
   at CppSharp.Types.TypeMapDatabase.FindTypeMap(Declaration decl, TypeMap& typeMap) in <CppSharp>src\Generator\Types\TypeMap.cs:line 202
   at CppSharp.Generators.CLI.CLITypeReferenceCollector.GenerateInclude(ASTRecord`1 record) in <CppSharp>src\Generator\Generators\CLI\CLITypeReferences.cs:line 106
   at CppSharp.Generators.CLI.CLITypeReferenceCollector.Process(Namespace namespace, Boolean filterNamespaces) in <CppSharp>src\Generator\Generators\CLI\CLITypeReferences.cs:line 94
   at CppSharp.Generators.CLI.CLIHeadersTemplate.GenerateIncludeForwardRefs() in <CppSharp>src\Generator\Generators\CLI\CLIHeadersTemplate.cs:line 57
   at CppSharp.Generators.CLI.CLIHeadersTemplate.Process() in <CppSharp>src\Generator\Generators\CLI\CLIHeadersTemplate.cs:line 38
   at CppSharp.GenThe thread 0x2c98 has exited with code 259 (0x103).
The thread 0x2d90 has exited with code 259 (0x103).
The program '[9596] LLCS.vshost.exe' has exited with code 0 (0x0).
erators.Generator.Generate() in <CppSharp>src\Generator\Generator.cs:line 82
   at CppSharp.Driver.GenerateCode() in <CppSharp>src\Generator\Driver.cs:line 325
   at CppSharp.ConsoleDriver.Run(ILibrary library) in <CppSharp>src\Generator\Driver.cs:line 456
   at LLCSGen.Program.Main(String[] args) in <BaseDir>LLCSGen\Program.cs:line 17
Done

Looking at that line, it appears that the .Pointee param is null, but the code isn't expecting it to be.


João Matos

unread,
May 7, 2014, 1:21:02 PM5/7/14
to Voidpointer Linden, cppsha...@googlegroups.com
It's hard to say what it is from just a stack trace.

I'll need a repro to take a look myself.
--
João Matos

Voidpointer Linden

unread,
May 7, 2014, 10:48:38 PM5/7/14
to João Matos, cppsha...@googlegroups.com
OK, took me a while to narrow down the culprit lines of code that were causing the stack trace, but here they are:

Test1.h:
======
namespace LLCore
{
    class TrueType { public: typedef TrueType Type; typedef TrueType TrueOnlyType; static const bool cValue = true; static bool Value() { return true; } };
    class FalseType { public: typedef FalseType Type; typedef FalseType FalseOnlyType; static const bool cValue = false; static bool Value() { return false; } };
    template<bool T_VALUE> class BoolType { };
    template<> class BoolType<true> : public TrueType{};
    template<> class BoolType<false> : public FalseType{};

    #define LLCORE_INTERNAL_DECLARE_HASOPERATOR(ExpectedOperator, ExpectedOperatorName) template<typename T> \
    struct InternalHasOperator_ ## ExpectedOperatorName \
    { \
        template<class U> static char (&test(decltype(U::operator ExpectedOperator) const*))[1]; \
        template<class U> static char (&test(...))[2]; \
        static const bool cValue = (sizeof(test<T>(0)) == 1); \
    }; \
    template<typename T> class HasMember_ ## ExpectedOperatorName : public LLCore::BoolType<InternalHasOperator_ ## ExpectedOperatorName<T>::cValue> {};

    LLCORE_INTERNAL_DECLARE_HASOPERATOR(== , Equals);
}


C# Generator Project:
================
With a ILibrary Setup like this:

        public void Setup(Driver driver)
        {
            var options = driver.Options;
            options.GeneratorKind = CppSharp.Generators.GeneratorKind.CLI;
            options.LibraryName = "LLCS";
            options.Verbose = true;
            options.IncludeDirs.Add(".");
            options.LibraryDirs.Add("../../../../Output/Win32/Debug/LLCore");
            options.OutputDir = "../../../LLCS/LLCore";
            options.Libraries.Add("LLCore.lib");
            options.Headers.AddRange(new String[]
            {
                "../../../LLCore/Test1.h"
            });
        }


Output:
=====
Has the following output and then crashes the generator with the following stack trace:

Parsing libraries...
Parsed 'LLCore.lib'
Indexing library symbols...
Parsing code...
Parsed '../../../LLCore/Test1.h'
Processing code...
Pass 'CppSharp.Passes.CleanUnitPass'
Pass 'CppSharp.Passes.SortDeclarationsPass'
Pass 'CppSharp.Passes.ResolveIncompleteDeclsPass'
Pass 'CppSharp.Passes.CheckIgnoredDeclsPass'
    Decl 'BoolType' was ignored due to dependent context
    Decl 'InternalHasOperator_Equals' was ignored due to dependent context
    Function 'test' was ignored due to incomplete param
    Decl 'HasMember_Equals' was ignored due to dependent context
Pass 'CppSharp.Passes.FindSymbolsPass'
Pass 'CppSharp.Passes.CheckStaticClass'
Pass 'CppSharp.Passes.MoveOperatorToClassPass'
Pass 'CppSharp.Passes.MoveFunctionToClassPass'
Pass 'CppSharp.Passes.CheckAmbiguousFunctions'
Pass 'CppSharp.Passes.CheckOperatorsOverloadsPass'
    Invalid operator overload TrueType::Equal
    Invalid operator overload TrueType::Equal
    Invalid operator overload FalseType::Equal
    Invalid operator overload FalseType::Equal
Pass 'CppSharp.Passes.CheckVirtualOverrideReturnCovariance'
Pass 'CppSharp.Passes.FieldToPropertyPass'
Pass 'CppSharp.Passes.CleanInvalidDeclNamesPass'
Pass 'CppSharp.Passes.CheckIgnoredDeclsPass'
    Function 'test' was ignored due to incomplete param
Pass 'CppSharp.Passes.CheckFlagEnumsPass'
Pass 'CppSharp.Passes.CheckDuplicatedNamesPass'
Generating code...
A first chance exception of type 'System.NullReferenceException' occurred in CppSharp.Generator.dll
Error: Object reference not set to an instance of an object.
   at CppSharp.Types.CppTypePrinter.VisitPointerType(PointerType pointer, TypeQualifiers quals)
   at CppSharp.AST.PointerType.Visit[T](ITypeVisitor`1 visitor, TypeQualifiers quals)
   at CppSharp.Types.CppTypePrinter.VisitParameter(Parameter arg, Boolean hasName)
   at CppSharp.Types.CppTypePrinter.VisitParameterDecl(Parameter parameter)
   at CppSharp.AST.Parameter.Visit[T](IDeclVisitor`1 visitor)
   at CppSharp.Types.TypeMapDatabase.FindTypeMap(Declaration decl, Type type, TypeMap& typeMap)
   at CppSharp.Types.TypeMapDatabase.FindTypeMap(Declaration decl, TypeMap& typeMap)
   at CppSharp.Generators.CLI.CLITypeReferenceCollector.GenerateInclude(ASTRecord`1 record)
   at CppSharp.Generators.CLI.CLITypeReferenceCollector.Process(Namespace namespace, Boolean filterNamespaces)
   at CppSharp.Generators.CLI.CLIHeadersTemplate.GenerateIncludeForwardRefs()
   at CppSharp.Generators.CLI.CLIHeadersTemplate.Process()
   at CppSharp.Generators.Generator.Generate()
   at CppSharp.Driver.GenerateCode()
   at CppSharp.ConsoleDriver.Run(ILibrary library)
   at LLCSGen.Program.Main(String[] args) in LLTest\src\LLCSGen\Program.cs:line 17
Done


I also have a standalone sln with all the relevant code, projects, etc. that you can use if you like - just let me know.

João Matos

unread,
May 8, 2014, 10:49:33 AM5/8/14
to Voidpointer Linden, cppsha...@googlegroups.com
Tracked this down to lack of support for decltypes in the AST. I've pushed a fix.

Thanks for the short repro, that makes it easier :)
--
João Matos

Voidpointer Linden

unread,
May 8, 2014, 6:31:33 PM5/8/14
to João Matos, cppsha...@googlegroups.com
Well, you did fix the error from before, it seems.  Unfortunately, on that same block of code, I now get a different crash:

Parsing libraries...
Parsed 'LLCore.lib'
Indexing library symbols...
Parsing code...
Parsed '../../../LLCore/Test1.h'
Processing code...
Generating code...
A first chance exception of type 'System.NotSupportedException' occurred in CppSharp.Generator.dll
Error: Specified method is not supported.
   at CppSharp.Types.CppTypePrinter.VisitPrimitiveType(PrimitiveType primitive) in <CppSharp>\src\Generator\Types\CppTypePrinter.cs:line 119
   at CppSharp.Types.CppTypePrinter.VisitBuiltinType(BuiltinType builtin, TypeQualifiers quals) in <CppSharp>\src\Generator\Types\CppTypePrinter.cs:line 94
   at CppSharp.AST.BuiltinType.Visit[T](ITypeVisitor`1 visitor, TypeQualifiers quals) in <CppSharp>\src\AST\Type.cs:line 698
   at CppSharp.Types.CppTypePrinter.VisitPointerType(PointerType pointer, TypeQualifiers quals) in <CppSharp>\src\Generator\Types\CppTypePrinter.cs:line 78
   at CppSharp.AST.PointerType.Visit[T](ITypeVisitor`1 visitor, TypeQualifiers quals) in <CppSharp>\src\AST\Type.cs:line 246
   at CppSharp.Types.CppTypePrinter.VisitParameter(Parameter arg, Boolean hasName) in <CppSharp>\src\Generator\Types\CppTypePrinter.cs:line 215
   at CppSharp.Types.CppTypePrinter.VisitParameterDecl(Parameter parameter) in <CppSharp>\src\Generator\Types\CppTypePrinter.cs:line 274
   at CppSharp.AST.Parameter.Visit[T](IDeclVisitor`1 visitor) in <CppSharp>\src\AST\Function.cs:line 71
   at CppSharp.Types.TypeMapDatabase.FindTypeMap(Declaration decl, Type type, TypeMap& typeMap) in <CppSharp>\src\Generator\Types\TypeMap.cs:line 152
   at CppSharp.Types.TypeMapDatabase.FindTypeMap(Declaration decl, TypeMap& typeMap) in <CppSharp>\src\Generator\Types\TypeMap.cs:line 202
   at CppSharp.Generators.CLI.CLITypeReferenceCollector.GenerateInclude(ASTRecord`1 record) in <CppSharp>\src\Generator\Generators\CLI\CLITypeReferences.cs:line 106
   at CppSharp.Generators.CLI.CLITypeReferenceCollector.Process(Namespace namespace, Boolean filterNamespaces) in <CppSharp>\src\Generator\Generators\CLI\CLITypeReferences.cs:line 94
   at CppSharp.Generators.CLI.CLIHeadersTemplate.GenerateIncludeForwardRefs() in <CppSharp>\src\Generator\Generators\CLI\CLIHeadersTemplate.cs:line 57
   at CppSharp.Generators.CLI.CLIHeadersTemplate.Process() in <CppSharp>\src\Generator\Generators\CLI\CLIHeadersTemplate.cs:line 38
   at CppSharp.Generators.Generator.Generate() in <CppSharp>\src\Generator\Generator.cs:line 82
   at CppSharp.Driver.GenerateCode() in <CppSharp>\src\Generator\Driver.cs:line 330
   at CppSharp.ConsoleDriver.Run(ILibrary library) in <CppSharp>\src\Generator\Driver.cs:line 462
   at LLCSGen.Program.Main(String[] args) in LLCSGen\Program.cs:line 17
Done




--
You received this message because you are subscribed to the Google Groups "CppSharp" group.
To unsubscribe from this group and stop receiving emails from it, send an email to cppsharp-lis...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.



--

João Matos

unread,
May 9, 2014, 9:52:35 AM5/9/14
to Voidpointer Linden, cppsha...@googlegroups.com
My bad, I didn't re-test your example after the first fix. I've now pushed another fix for the last problem.
--
João Matos
Reply all
Reply to author
Forward
0 new messages