Go调用C++静态库

666 阅读3分钟

Go如何调用C++静态库,保姆级别教程来了!!! 最近因为工作需要,需要使用Go程序调用C及C++中一些库,网上的文章比较凌乱,有些已经过时,踩了许多坑,最终完成了集成,这里我写了一个完整的集成示例,方便大家快速集成,也避免踩坑!

1.环境说明

序号项目版本说明
1Go1.19.7
2g++MinGW-W64- 8.1.0
3cmake3.26.4C++编译工具
4ninja1.10.2C++编译工具
5Goland2023.2.4Go开发工具
6CLion2023.2.2C++开发工具
7Windows11开发操作系统

2.流程说明

Go如何调用C++库,主要分为3步:

1)制作C++静态库

2)创建Go程序

3)在Go应用中调用C++静态库

3.制作C++静态库

示例中,我们使用C++编写了一个加法和减法运算的函数,并将其编译成静态库,提供给Go程序调用

3.1文件清单

├── build                     --编译目录
├── CMakeLists.txt            --cmake编译文件
├── cpp_test.h                --头文件
└── cpp_test.cpp              --源文件

3.2文件源码

3.2.1 cpp_test.h

#ifndef FATHER_CPP_TEST_H
#define FATHER_CPP_TEST_H


#ifdef __cplusplus
extern "C" {
#endif


int sub(int a,int b);

int add(int a,int b);

#ifdef __cplusplus
}
#endif

#endif //FATHER_CPP_TEST_H

3.2.2 cpp_test.cpp

#include "cpp_test.h"


int sub(int a,int b){
    return a-b;
}

int add(int a,int b){
    return a+b;
}

3.2.3 CMakeLists.txt

cmake_minimum_required(VERSION 3.22)
project(hello_lib)

set(CMAKE_CXX_STANDARD 11)

add_library(cpp_test STATIC cpp_test.cpp)

3.3 编译过程

编译步骤:

# 1. 如果build目录不存在,自行创建,然后进入build目录
cd build
# 2. 使用cmake编译工具生成文件,cmake
cmake .. -G Ninja
# 3. 使用ninja编译工具进行最终编译
ninja

完成输出:

cd build
cmake .. -G Ninja
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: C:/mingw64/bin/c++.exe - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done (1.3s)
-- Generating done (0.0s)
-- Build files have been written to: x:/cpp_test/build

ninja.exe
[2/2] Linking CXX static library libcpp_test.a

4.编写Go程序

这里使用一个main程序演示调用C++静态库过程

4.1 文件清单

完整的Go程序目录结构:

├── go.mod                --go mod文件
├── include               --头文件目录
│   └── cpp_test.h        --头文件
├── lib                   --静态库文件目录
│   └── libcpp_test.a     --静态库文件
└── main.go               --Go程序
  1. 将C++库中的cpp_test.h头文件,存放至include文件夹中
  2. 将libcpp_test.a库文件,存放至lib文件夹中

4.2文件源码

4.2.1 main.go

package main

/*
#cgo CFLAGS: -I./include
#cgo LDFLAGS: -L./lib -lcpp_test -lstdc++
#include "cpp_test.h"
*/
import "C"
import "fmt"

func main() {
    fmt.Println(C.sub(C.int(5), C.int(1)))
    fmt.Println(C.add(C.int(1), C.int(4)))
}

说明:

1、import "C" 是启用Cgo,以及cgo配置,头文件,C函数

2、需要调用的C语言的内容使用/**/注释起来,放在import "C"之前

3、其中有两个#cgo命令,分别是编译和链接参数

#cgo CFLAGS: -I/user/local/include //库对应头文件所在的目录加入头文件检索路径

#cgo LDFLAGS: -L/user/local/lib -l库 //库所在目录加为链接库检索路径

4.3 执行输出

示例程序中,我们使用分别调用C++库的加法运行和减法运算

~$ ls

Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
d----           2023/11/2    14:30                include
d----           2023/11/2    14:30                lib
-a---           2023/11/2    11:41             22 go.mod
-a---           2023/11/2    14:45            230 main.go

~$ go run .
4
5

5.扩展信息

因Go与C中语言数据类型有差别,我们在调用C函数需要进行类型转换,Golang 和 C 的基本数值类型转换对照表如下:

6.参考资料

  1. cmake保姆级教程
  2. Golang 调用 C/C++,例子式教程
  3. CGO类型定义
  4. golang调用c库
  5. golang调用c++库
  6. cgo介绍