How to compile and link Go code into c++ with CMake

Viewed 786

I am trying to compile Go code to library and then link c++ and lib with CMake.
I've already tried make shared lib with gcc like this https://medium.com/swlh/build-and-use-go-packages-as-c-libraries-889eb0c19838.

go build -o cas.so -buildmode=c-shared cmd/c-mock-server/main.go
gcc -o main main.c ./cas.so

So now I need create shared library and link that with c++ code using CMake, but I really dont know how to do this

1 Answers

Build your project structure before using cmake:

# tree .
.
├── CMakeLists.txt
├── go
│   ├── CMakeLists.txt
│   ├── go.mod
│   └── module.go
└── test.cpp

Files

./CMakeLists.txt

cmake_minimum_required(VERSION 3.0)
project(test)

add_subdirectory(go)

set(TARGET test)
set(SRCS test.cpp)

add_executable(${TARGET} ${SRCS})
target_link_libraries(${TARGET} goshim pthread)

./test.cpp

#include <iostream>
#include <string>
#include "go/module.h"

int main() {
    int res = Add(1, 2);
    std::cout << res << std::endl;

    GoString str;
    str.p = "Hello World";
    str.n = strlen(str.p);
    Print(str);

    std::string s = "Go-Module";
    char *cstr = new char[s.length()+1];
    std::strcpy (cstr, s.c_str());

    cstr = StrFxn(cstr);
    std::cout << cstr << std::endl;
    delete[] cstr;

    return 0;
}

./go/CMakeLists.txt

cmake_minimum_required(VERSION 3.0)
project(test_go)

set(TARGET shim_go)

set(SRCS module.go)
set(LIB module.so)

add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${LIB}
  DEPENDS ${SRCS}
  WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
  COMMAND env GOPATH=${GOPATH} go build -buildmode=c-archive
  -o "${CMAKE_CURRENT_BINARY_DIR}/${LIB}"
  ${CMAKE_GO_FLAGS} ./...
  COMMENT "Building Go library")

add_custom_target(${TARGET} DEPENDS ${LIB} ${HEADER})
add_library(goshim STATIC IMPORTED GLOBAL)
add_dependencies(goshim ${TARGET})
set_target_properties(goshim
  PROPERTIES
  IMPORTED_LOCATION ${CMAKE_CURRENT_BINARY_DIR}/${LIB}
  INTERFACE_INCLUDE_DIRECTORIES ${CMAKE_CURRENT_BINARY_DIR})

./go/module.go

package main

import "C"

import (
    "sort"
    "fmt"
)

//export Add
func Add(a, b int) int {
    return a + b
}

//export Sub
func Sub(a, b int) int {
    return a - b
}

//export Print
func Print(str string) {
    fmt.Printf("Go prints: %s\n", str)
}

func strFxn(input string) string {
    return "Hello " + input + " World"
}

//export StrFxn
func StrFxn(cinput *C.char) *C.char {
    // C data needs to be manually managed in memory.
    // But we will do it from C++.
    input := C.GoString(cinput)
    return C.CString(strFxn(input))
}

//export Sort
func Sort(vals []int) {
    sort.Ints(vals)
}

func main() {
    // We need the main function to make possible
    // CGO compiler to compile the package as C shared library
}

./go/go.mod

total 16
module demo/module

go 1.16

Run

# cmake .
-- The C compiler identification is AppleClang 12.0.0.12000032
-- The CXX compiler identification is AppleClang 12.0.0.12000032
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: /Library/Developer/CommandLineTools/usr/bin/cc - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: /Library/Developer/CommandLineTools/usr/bin/c++ - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: /tmp/demo

#  make
[ 33%] Building Go library
[ 33%] Built target shim_go
[ 66%] Building CXX object CMakeFiles/test.dir/test.cpp.o
[100%] Linking CXX executable test
[100%] Built target test

# ./test
3
Go prints: Hello World
Hello Go-Module World
Related