go 的 `cgo` 机制默认仅自动编译包根目录下的 c/c++ 源文件,不支持通过 `//go:cgo_` 伪指令直接递归或显式引入子目录中的 c 文件;若需组织 c 代码到子目录,必须借助外部构建流程或重构为独立包并导出 go 接口。
Go 工具链对 C 代码的集成是轻量级且有明确边界的:cgo 仅扫描当前 Go 包根目录(即包含 .go 文件的目录)下后缀为 .c、.cpp、

因此,若你希望将 C 代码逻辑性地组织在子目录(如 ./csrc/ 或 ./internal/c/)中,有且仅有两种可行路径:
拆分为独立 Go 包(推荐用于模块化 C 封装)
将子目录设为一个独立的 Go 包(含 csrc/ 下的 .c 和 csrc/_cgo_export.h 等),并在其中编写 export 函数供 Go 调用:
myproject/
├── main.go
└── cwrapper/
├── cwrapper.go // 含 //export my_c_func,及 build constraints
└── csrc/
├── impl.c
└── impl.h在 cwrapper.go 中需启用 cgo 并声明:
//go:build cgo
// +build cgo
package cwrapper
/*
#include "impl.h"
*/
import "C"
//export my_c_func
func my_c_func() {
// ...
}然后在 main.go 中导入 "myproject/cwrapper" 即可调用。注意:该子包必须能被 go build 直接发现(即非 _ 或 . 开头目录),且其 C 文件仍须位于该子包自身根目录下(即 cwrapper/csrc/ 本身不能直接放 C 文件——除非你把 cwrapper/csrc/ 改名为 cwrapper/ 并移入 .c 文件)。
完全脱离 go build 的 C 构建流程(推荐用于复杂 C 项目)
对于大型 C 库、多层目录结构或需自定义编译选项(如 -O3、-I/path/to/headers、静态链接等),应放弃依赖 cgo 的自动编译,转而:
/* #cgo CFLAGS: -I./csrc/include #cgo LDFLAGS: -L./csrc/lib -lmycore -lm #include "mycore.h" */ import "C"
此方式赋予你完整控制权,也符合 Go 设计哲学:cgo 是桥梁,而非替代 make 的通用构建系统。
⚠️ 注意事项:
总结:Go 的 cgo 是“够用就好”的集成方案,而非万能构建引擎。合理划分职责——C 代码用专业 C 构建工具管理,Go 代码用 go build 管理,二者通过清晰的 ABI 边界(头文件 + #cgo 声明)协作——这才是长期可维护的实践。