mono / CppSharp

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

How to explicitly set Calling convention for code generation #1088

Open QuantumDeveloper opened 6 years ago

QuantumDeveloper commented 6 years ago

I want to set calling convention explicitly to stdcall, but I dont see where I can set it. Generator set calling convention to cdecl, whick is wrong. Is it possible somehow to change this?

Also interesting how tell generator not to add [SuppressUnmanagedCodeSecurity] to each method?

tritao commented 6 years ago

Functions/methods AST entities provide a CallingConvention property, have you tried changing it for those declarations that you say are wrong?

By the way, it would be good to know why the generator cannot figure out why they are not StdCall which you say is the right calling convention for your code.

Do you have an example of your input native code that causes this mismatch?

About SuppressUnmanagedCodeSecurity, we do not provide an option for this right now.

Do you want to send a pull request adding this functionality?

You would need to add a new option for it, and guard the generation code with an if statement here:

https://github.com/mono/CppSharp/blob/695a7538d11db4fe7fef6c1f1d77dd0284267ce7/src/Generator/Generators/CSharp/CSharpSources.cs#L3062

QuantumDeveloper commented 6 years ago

@tritao I tied to generate C# bindings from Vulkan headers. In header vk_platform.h there is a define

#define _WIN32
#if defined(_WIN32)
    // On Windows, Vulkan commands use the stdcall convention
    #define VKAPI_ATTR
    #define VKAPI_CALL __stdcall
    #define VKAPI_PTR  VKAPI_CALL

And as far as I understand this should tell CppSharp to use stdcall instead of cdecl, but it doesnt on some reason.

QuantumDeveloper commented 6 years ago

@tritao Could you please give an example with just few lines of code to see how to correctly change all calls from cdecl to stdcall?

tritao commented 6 years ago

Here is a way to do it:

class CallConvPass : TranslationUnitPass
{
    public override bool VisitFunctionDecl(Function function)
    {
        function.CallingConvention = CallingConvention.StdCall;
        return base.VisitFunctionDecl(function);
    }
}

// In SetupPasses()
driver.Context.TranslationUnitPasses.AddPass(new CallConvPass());
ddobrev commented 6 years ago

@QuantumDeveloper @tritao 's code is going to do the job but we might have a bug here. We do not parse anything ourselves, in a way, we have Clang do it. So that #define should not be ignored. Could you please try something for me:

options.Defines.Add("_WIN32");

and see if you get the correct conventions.

QuantumDeveloper commented 6 years ago

@ddobrev I made as you asked and unfortunately it didnt help. CallingConvention is still cdecl :( Workaround proposed by @tritao works, but only for methods. Is there anything similar for delegates? For example I have generated code like this:

namespace Vulkan
{
    [SuppressUnmanagedCodeSecurity, UnmanagedFunctionPointer(global::System.Runtime.InteropServices.CallingConvention.Cdecl)]
    public unsafe delegate global::Vulkan.Result PFN_vkCreateWin32SurfaceKHR(global::System.IntPtr instance, global::System.IntPtr pCreateInfo, global::System.IntPtr pAllocator, global::System.IntPtr pSurface);
}

How can I apply changing calling convention for such delegates?

tritao commented 6 years ago

Try adding this to the pass:

public override bool VisitFunctionType(FunctionType function, TypeQualifiers quals)
{
    function.CallingConvention = CallingConvention.StdCall;
    return base.VisitFunctionType(function, quals);
}
QuantumDeveloper commented 6 years ago

@tritao unfortunately exactly for this case with delegates it didnt help

QuantumDeveloper commented 6 years ago

@ddobrev @tritao Any updates or comments here?

tritao commented 6 years ago

Your best bet at this point is just to hardcode StdCall convention in the generator. Either that or try to get us a test case for your issue that we can reproduce to fix the issue.

QuantumDeveloper commented 6 years ago

@ddobrev @tritao Here is the link to my one drive with test project. You can build it and see that it generate cdecl instead of stdcall even when I add a define "_WIN32". https://1drv.ms/u/s!AhSjdR9cNA9lhI57kZrZavXhl92txg

You can find info about stdcall in the very beginning of the vk_platform.h file

ddobrev commented 6 years ago

I've downloaded your code and I'll try as soon as possible. Meanwhile, you could build CppSharp from source code which is quite easy, and debug to see why the defines are ignored.

QuantumDeveloper commented 6 years ago

@ddobrev Did you try to run a test project already? BTW, defines are not ignored. I added 2 defines there and second define was applied absolutely correctly. So, this is quite strange.

ddobrev commented 6 years ago

@QuantumDeveloper I did but I tried checking why define is ignored. I need to work some more on that since I need to replace the references from the NuGet with the source code in order to debug it. I will let you know as soon as I've had the chance.

tritao commented 6 years ago

I don't think the problem is on the defines being @ddobrev, at least there is nothing so far that leads me to think that.

I would say the issue is Clang for some othe reason not picking up the stdcall convention.

@QuantumDeveloper What parser triple are you targeting? I ask because I think for certain non-Windows platforms the stdcall notation is possibly ignored.

QuantumDeveloper commented 6 years ago

@ddobrev OK, thanks for that.

@tritao What do you mean for "parser triple"? Could you please explain a little?

tritao commented 6 years ago

Parser triple is what controls which target architecture the parser is using.

https://github.com/mono/CppSharp/blob/2a53e079aaecc2611b583d6e1dfccf3d467c6ac4/src/CLI/Generator.cs#L44

QuantumDeveloper commented 6 years ago

@tritao Hmm... As I can see my TargetTriple is: "x86_64-pc-windows-msvc". So, I suppose my parser triple is correct. But what I see now in debug mode that defines count is 0. So, maybe defines really not applying just because the list is empty on some reason?

QuantumDeveloper commented 6 years ago

@ddobrev still no progress on this issue?

ddobrev commented 6 years ago

Hello @QuantumDeveloper . I am afraid I haven't had any time to check this for free. I'll let you know as soon as I can.

QuantumDeveloper commented 6 years ago

@ddobrev @tritao Yesterday I downloaded latest build from git and try to figure out why is the issue with defines is happening and suddenly found out that issue is gone. Seems this fix fixed it: https://github.com/mono/CppSharp/commit/6881a583d8f2b2561bdf0c3fd17e3d885309f8d5

Could you please make new nuget package, because attaching cppsharp as sources to code is not so convenient :)

ddobrev commented 6 years ago

Hello, there has been a new NuGet for a few weeks now.

QuantumDeveloper commented 6 years ago

@ddobrev Thanks a lot.

ddobrev commented 6 years ago

@QuantumDeveloper is this one still a problem?

QuantumDeveloper commented 6 years ago

@ddobrev Seems issue is still present with latest nuget.

driver.ParserOptions.Defines.Add("_WIN32");
driver.ParserOptions.Defines.Add("VK_USE_PLATFORM_WIN32_KHR");

Defines ignoring and because of that:

  1. c# bindings generating with incorrect calling convention (Cdecl instead of StdCall)
  2. Not all files converted

Need to add defines manually to header file to have full C# bindings, but calling convention is still incorrect.

Can this be fixed?

QuantumDeveloper commented 6 years ago

@ddobrev @tritao any feedback?

ddobrev commented 6 years ago

@QuantumDeveloper I am going to update the NuGet later today, this release uses much newer Clang which might be able to properly handle these defines.

QuantumDeveloper commented 6 years ago

@ddobrev Thanks, Then I will update to latest nuget, re-check my issue and give you feedback.

QuantumDeveloper commented 6 years ago

@ddobrev Hi. Tried the same scenario with new version. Nothing changed. Exactly the same result. Are you sure this is clang issues? I cant believe that such common thing like parsing defines could be broken in sources of clang.

QuantumDeveloper commented 6 years ago

@ddobrev any comments?

ddobrev commented 6 years ago

@QuantumDeveloper I am sorry for this delay and I am even more sorry I cannot help you. I have had little time to work on C++# to begin with, let alone detect a specific bug. A reduced test case might be useful, if you would come up with one.

strentler commented 3 years ago

Looks like this bug is still there in CppSharp-0.11 Any solution to this?