构建导入cgo包的Go程序时如何指定头文件与库路径(需使用CMake)
实现方案
整体思路是通过CMake先完成cgo模块B的编译,自动生成适配本地路径的cgo编译参数,Go程序A编译时直接读取预先生成的参数即可解决非标准路径下的头文件、库文件寻址问题。
步骤1:配置cgo模块B的CMake规则
先确定模块B的目录结构参考如下:
B/ ├── include/ # 存放B对外暴露的头文件 │ └── b.h ├── src/ # 存放B的C/C++实现源码 │ └── b.c ├── cgo_flags.in # cgo参数模板文件 └── CMakeLists.txt
首先编写B目录下的CMakeLists.txt:
cmake_minimum_required(VERSION 3.16) project(B C) # 统一输出路径,避免文件散落 set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) # 声明B的头文件路径 set(B_PUBLIC_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/include) # 编译生成动态库 add_library(B SHARED src/b.c) target_include_directories(B PUBLIC $<BUILD_INTERFACE:${B_PUBLIC_INCLUDE_DIR}> $<INSTALL_INTERFACE:include> ) # 自动填充路径生成cgo参数文件 configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/cgo_flags.in ${CMAKE_BINARY_DIR}/cgo_flags @ONLY )
然后编写同目录下的cgo_flags.in模板文件:
CGO_CFLAGS=-I@B_PUBLIC_INCLUDE_DIR@ CGO_LDFLAGS=-L@CMAKE_LIBRARY_OUTPUT_DIRECTORY@ -lB
步骤2:编译cgo模块B
执行标准CMake编译流程生成动态库和参数文件:
# 在B的源码目录下执行 mkdir -p build && cd build cmake .. make
编译完成后,B的build目录下会生成lib/libB.so动态库,以及填充好实际路径的cgo_flags参数文件。
步骤3:编译Go程序A
在A的源码目录执行编译前,先导入B生成的cgo参数和运行时库路径:
# 导入编译所需的头文件、库路径参数 export $(cat /path/to/B/build/cgo_flags) # 导入运行时动态库搜索路径,避免执行二进制时找不到.so export LD_LIBRARY_PATH=/path/to/B/build/lib:$LD_LIBRARY_PATH # 正常执行go build即可 go build
可选:一键编译整合方案
如果需要同时管理B和A的编译,可以在顶层目录新增总CMakeLists.txt,实现一键编译整个项目:
cmake_minimum_required(VERSION 3.16) project(MyProject C Go) # 先编译cgo模块B add_subdirectory(B) # 定义Go程序A的编译目标 add_custom_target(A ALL COMMAND ${CMAKE_COMMAND} -E env CGO_CFLAGS=-I${CMAKE_CURRENT_SOURCE_DIR}/B/include CGO_LDFLAGS=-L${CMAKE_BINARY_DIR}/B/lib -lB LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/B/lib go build WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/A DEPENDS B )
配置完成后在顶层目录执行cmake . && make即可自动完成B的编译、A的编译全流程,不需要手动导出环境变量。
内容的提问来源于stack exchange,提问作者Shuduo
相关产品推荐
相关产品推荐

