This is the 8th day of my participation in the November Gwen Challenge. Check out the event details: The last Gwen Challenge 2021

This article continues to optimize the call C++ function in Golang on the basis of “Golang practice record: call C++ function”.

The cause of

The previous article introduced the way, at run time need to specify the location of the dynamic library, or put the dynamic library into the system directory, for the author, or a little trouble, this article will use dl series of functions, load the dynamic library at run time, so as to remove the dependency of path.

implementation

In order to reduce the length, only extract the necessary source code.

encapsulation

On the basis of the source code of the dynamic library version, add the encapsulation dynamic library header file C_callso.h:

#ifdef __cplusplus extern "C" { #endif int cso_init(char* soname); int cso_uninit(); Int CSetPointA(Point* Point, Point* point1); //int FooCall(void); #ifdef __cplusplus } #endifCopy the code

The main code of the corresponding implementation file is as follows:

#include <dlfcn.h> void* g_sohandle = NULL; int cso_init(char* soname) { g_sohandle = dlopen(soname, RTLD_LAZY); if (g_sohandle == NULL) return -1; return 0; } int cso_uninit() { if (g_sohandle ! = NULL) dlclose(g_sohandle); return 0; } int CSetPointA(Point* point, Point* point1) { typedef int (*ptr)(Point*, Point*); printf("in c file call so\n"); ptr fptr = (ptr)dlsym(g_sohandle, "FooSetPointA"); return (*fptr)(point, point1); }Copy the code

Among them, CSetPointA function is docking FooSetPointA function, only do simple encapsulation.

call

The complete Golang test code is as follows:

package main /* #cgo LDFLAGS: -ldl #include <stdlib.h> #include "c_callso.h" #include "c_callso.c" */ import "C" import ( "fmt" "unsafe" ) var ( csoname = "./libfoo.so1" //csoname = "./aXi3n0fr1.rd" ) func so_test() { fmt.Println("go c++ so test") soname := C.CString(csoname) ret := C.cso_init(soname) if ret ! = 0 { fmt.Println("cso_init failed ", Ret) return} defer c.foo (unsafe.pointer (soname)) defer c.so_uninit () // var myPoint, myPoint1 C.Point myPoint.x = 100; myPoint.y = 200; Mypoint.pinname = c.string ("Hello ") // The Pointer form defer C.tree (unsafe.pointer (mypoint.pinname)) // the fixed-length array, Arr := [16] c.char {} mystr := "Hell "for I := 0; i < len(mystr) && i < 15; I++ {arr = [I] Arthur c. har (mystr [I])} myPoint. Inname = arr / / array format FMT Println (" Golang | org struct ", myPoint, "single: ", myPoint.x, myPoint.y, myPoint.pinname) // Struct pointer incoming/outgoing ret = c.setpointa (&myPoint, &mypoint1) // C++ uses arrays of strings, Bytes //carr = c.gigabytes (mypoint1.name, 100) for I := range mypoint1.name {if mypoint1.name [I]! = 0 { carr = append(carr, Byte (myPoint1. Name [I]))}} gostr: = string (carr) / / to go string FMT. Println (" Golang | c + + call ret: ", ret, mypoint1. x, gostr, mypoint1. name) // If the pointer does not allocate memory, the return string is null, Return <nil> gostr = c.gostring (mypoint1.pname) defer C.tree (unbroadening.Pointer(mypoint1.pname)) fmt.Println("Golang | out pointer:", gostr, unsafe.Pointer(myPoint1.pname)) } func main() { so_test() }Copy the code

The main difference from the previous article example is that c.so_init is called to initialize the dynamic library, and eventually cSO_uninit is called to release it.

Results analysis

At runtime, you just need to keep the location and name of the dynamic library as specified in Golang, without setting the LD_LIBRARY_PATH environment variable.

go c++ so test
Golang | org struct  {100 200 [72 101 108 108 32 0 0 0 0 0 0 0 0 0 0 0] 0xe2fc10 [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] <nil>} single:  100 200 0xe2fc10
in c file call so
C++ | got buf: Hell 
C++ | pname: Hello 
C++ | ptr: 0xe2fc30
Golang | c++ call ret:  0 101 name in c++ [110 97 109 101 32 105 110 32 99 43 43 0 0 0 0 0]
Golang | out pointer: Hell  | name in c++ malloc 0xe2fc30
Copy the code

practice

The dynamic library initialization function cso_init is reserved. The dynamic library provides as few business interfaces as possible, so as to reduce the number of code interfaces between golang and C++.

conclusion

The method in this paper, however, increases the source-level complexity and may not always meet the requirements, so it is for reference only. Libxxx. so is the name of the dynamic library for Linux, but any name is acceptable.