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

4 回复

啊,看来我必须使用以下命令清理缓存:

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++代码后总是执行清理操作。

回到顶部