Calling go function from c#

I’m trying to call a golang dll from c#, and comparing the results and performance against calling c dll from c#, so I did the below:

I started with building the c dll and calling it
step 1: Writting the c code

// cmdll.c
// Compile with: -LD
int __declspec(dllexport) SampleMethod(int i)
{
  return i*10;
}

step 2: Compiling the c code:

  • Open the Visual Studio x64 Native Tools Command Prompt
  • Run the command: cl -LD cmdll.c

step 3: Writting the c# code

// cm.cs
using System;
using System.Runtime.InteropServices;
public class MainClass
{
    [DllImport("Cmdll.dll")]
    public static extern int SampleMethod(int x); // function signature, must have a return type

    static void Main()
    {
        Console.WriteLine("SampleMethod() returns {0}.", SamplMethod(5));
    }
}

step 4: Compile the c# file and build the exe as:

  • Open the Visual Studio x64 Native Tools Command Prompt
  • Run the command: csc -platform:x64 cm.cs

The things above run smoothly

I wanted to do the same using golang, and followed the below:

step 1: Write the go code:

//lib.go
package main

import "C"

//export SamplMethod
func SamplMethod(i int) int {
	return i * 10
}

func main() {
	// Need a main function to make CGO compile package as C shared library
}

step 2: Build the dll file, by compiling the above code as:

go build -ldflags="-s -w" -o lib.dll -buildmode=c-shared lib.go

I used the -ldflags="-s -w" to reduce the resulting file size, and not sure what -buildmode shall i use, so randomly selected c-shared instead of c-archive
update: I tried also with go build -ldflags="-s -w" -o lib.dll -buildmode=c-archive lib.go and got the same result

step 3: Write a c code that combine the .dll and .h file generated from the go to generate an equivalent c dll

//goDll.c
#include <stdio.h>
#include "lib.h"
// force gcc to link in go runtime (may be a better solution than this)
GoInt SamplMethod(GoInt i);

void main() {
}

step 4: Compile the goDll.c file as:

gcc -shared -pthread -o goDll.dll goDll.c lib.dll -lWinMM -lntdll -lWS2_32

step 5: Build the c# code to call the generated dll, same code as above, but changing the dll file name:

// cm.cs
using System;
using System.Runtime.InteropServices;
public class MainClass
{
    [DllImport("goDll.dll")]
    public static extern int SampleMethod(int x); // function signature, must have a return type

    static void Main()
    {
        Console.WriteLine("SampleMethod() returns {0}.", SamplMethod(5));
    }
}

step 4: Compile the c# file and build the exe as:

  • Open the Visual Studio x64 Native Tools Command Prompt
  • Run the command: csc -platform:x64 cm.cs

Then tried to run the generated ./cm.exe file, but got the below error:

Unhandled Exception: System.EntryPointNotFoundException: Unable to find an entry point named 'SampleMethod' in DLL 'goDll.dll'.
   at MainClass.SampleMethod(Int32 i)
   at MainClass.Main()

I found that I’m doing an necessary step in the process, here how it worked smoothly with me:

step 1: Write the go code:

// main.go
package main

import "C"
import "fmt"

//export HelloWorld
func HelloWorld() {
	fmt.Printf("hello world from GO\n")
}

func main() {}

// compile the code as:
// go build -ldflags="-s -w" -buildmode=c-shared -o libgo.dll main.go

step 2: Write the c# code as:

// main.cs
using System;
using System.Runtime.InteropServices;
public class MainClass
{
    [DllImport("libgo.dll")]
    public static extern void HelloWorld(); // function signature, must have a return type

    static void Main()
    {
        HelloWorld();
    }
}

// compile as:
// open:
// Visual Studio x64 Native Tools Command Prompt
// csc -platform:x64 cm.cs

step 3: Compile both files, start by compiling the go file

step 4: Run the executable file:

1 Like