Golang中C语言包含库出现的奇怪行为
Golang中C语言包含库出现的奇怪行为 好的,这是更简洁的版本……甚至不需要容器就能复现这个行为。 已在 Mac(和一个 Ubuntu 容器中)测试过。
Darwin desktop-gv38ou7.uniserv.de 19.5.0 Darwin Kernel Version 19.5.0: Tue May 26 20:41:44 PDT 2020; root:xnu-6153.121.2~2/RELEASE_X86_64 x86_64
go version go1.14.4 darwin/amd64
我们需要两个文件。
文件 demo.go
package main
// #include <stdio.h>
// #include "demo.h"
// void answer(){
// fprintf(stderr,"the answer to life universe and everything is: %d\n",ANSWER);
// }
import "C"
func main() {
C.answer();
}
以及文件 demo.h
#define ANSWER 43
现在使用 go run demo.go 运行程序,会得到输出:
the answer to life universe and everything is: 43
将 demo.h 中的值 ANSWER 改为 42,再次使用 go run demo.go 运行,却没有返回 42 这个值,它仍然返回:
the answer to life universe and everything is: 43
但应该是“42”……我甚至可以把文件改成无效的 C 代码,我仍然会得到这个值:
the answer to life universe and everything is: 43
我是不是哪里搞错了?
更多关于Golang中C语言包含库出现的奇怪行为的实战教程也可以访问 https://www.itying.com/category-94-b0.html
啊,看来我必须使用以下命令清理缓存:
go clean -cache
谢谢
更多关于Golang中C语言包含库出现的奇怪行为的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
由于您没有说明实际如何构建容器,因此主机上的更改不会以任何方式影响容器,这似乎是正确的。
我使用 -v /Users/graf/DEV/:/root/develop 挂载了文件系统,并在容器中处理了这些文件……但我能够在没有使用容器的情况下复现此行为……(见上文)
这是一个典型的CGo缓存问题。当使用go run时,CGo会缓存编译结果,即使头文件已修改也不会重新编译C代码部分。
问题分析
CGo在编译时会缓存中间文件,包括预处理后的C代码。修改头文件后,Go工具链可能没有检测到变化,导致继续使用缓存的版本。
解决方案
1. 清理缓存后重新运行
// 清理所有缓存
go clean -cache
go clean -testcache
// 或者清理特定包的缓存
go clean -i .
// 然后重新运行
go run demo.go
2. 使用-a标志强制重新编译
go run -a demo.go
3. 使用go build替代go run
// 先清理
go clean
// 重新构建
go build demo.go
// 运行生成的可执行文件
./demo
4. 使用-x标志查看编译过程
go run -x demo.go
这会显示详细的编译步骤,可以看到CGo是否重新编译了C代码。
示例验证
创建测试文件验证:
demo.go
package main
// #include <stdio.h>
// #include "demo.h"
// void answer(){
// fprintf(stderr,"the answer to life universe and everything is: %d\n",ANSWER);
// }
import "C"
func main() {
C.answer()
}
demo.h
#define ANSWER 42
执行:
# 清理缓存
go clean -cache
# 强制重新编译
go run -a demo.go
输出应该是:
the answer to life universe and everything is: 42
根本原因
CGo的缓存机制基于文件的时间戳和内容哈希。在某些情况下,特别是快速连续修改文件时,文件系统的时间戳可能没有足够精度,或者Go的缓存检测逻辑没有正确识别到头文件的变更。
这是CGo的一个已知行为,特别是在开发过程中频繁修改C/C++头文件时容易出现。建议在修改C/C++代码后总是执行清理操作。

