You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让setuptools记录文件修改时间以避免重复编译Go共享库?

如何让setuptools的自定义构建命令基于文件修改时间跳过重复编译?

我想给setuptools添加一个自定义构建命令,用来编译Go共享库。这个编译过程耗时不短,但Go源码很少改动。所以我想知道:能不能让setuptools记录上次运行时文件的最后修改时间,以此判断是否需要重新编译?还是说必须用SCons这类更专业的构建工具?我不介意用时间戳或者其他简单策略来判断文件更新情况。

我已经写了部分代码,如下:

class BuildGo(build_py):
    ''' Build Go bindings before building Python extension '''
    def run(self):
        # What should go into go_sources_modified?
        if self.go_sources_modified():
            self.compile_go()
        build_py.run(self)

    def compile_go(self):
        version = None
        refusal = 'Will not compile Go bindings'
        try:
            version = subprocess.check_output(['go', 'version'])
        except subprocess.CalledProcessError:
            print('Didn\'t find Go compiler.')
            print(refusal)
            return
        match = re.search(br'go(\d+)\.(\d+)\.(\d+)', version)
        if match:
            version = tuple(map(int, match.group(1, 2, 3)))
        else:
            print('Unrecognized version of Go compiler: {}'.format(version))
            print(refusal)
            return
        req_version = 1, 9, 1
        if version < req_version:
            print('You need Go compiler version higher than: {}'.format(
                req_version,
            ))
            print(refusal)
            return
        try:
            result = subprocess.check_output([
                'go', 'build', '-v', '-buildmode=c-shared',
                '-o', SHLIB_LOCATION, SHLIB_PACKAGE,
            ])
            print(result)
        except subprocess.CalledProcessError as e:
            print(e.stderr)
            raise

不需要用SCons,自己实现时间戳判断完全可行

你完全不需要依赖SCons这类工具,用简单的文件修改时间对比就能实现需求。下面给你两种实用的方案:

方案1:对比源文件和目标库的修改时间

这是最直接的方法——检查所有Go源文件的最后修改时间,只要有任何一个比生成的共享库新,就触发重新编译。

把go_sources_modified方法实现如下:

import os
from pathlib import Path

def go_sources_modified(self):
    # 替换成你实际的Go源码目录和目标共享库路径
    go_source_dir = Path("go")
    target_lib = Path(SHLIB_LOCATION)

    # 如果目标库还不存在,必须编译
    if not target_lib.exists():
        return True

    # 获取目标库的最后修改时间
    target_mtime = target_lib.stat().st_mtime

    # 遍历所有.go源文件,检查是否有更新的文件
    for go_file in go_source_dir.rglob("*.go"):
        # 别忘了把go.mod、go.sum也加入检查,这些文件变化也需要重新编译
        if go_file.name in ("go.mod", "go.sum") or go_file.suffix == ".go":
            if go_file.stat().st_mtime > target_mtime:
                return True

    # 所有源文件都比目标库旧,不需要编译
    return False

方案2:用状态文件记录编译快照

如果你的场景更复杂(比如依赖其他非Go文件),可以创建一个状态文件,记录上次编译时所有源文件的修改时间哈希,下次编译前对比快照判断是否需要更新。

实现示例:

import os
import json
from pathlib import Path

def go_sources_modified(self):
    state_file = Path(".go_build_state")
    go_source_dir = Path("go")
    target_lib = Path(SHLIB_LOCATION)

    # 目标库不存在则直接编译
    if not target_lib.exists():
        return True

    # 收集当前所有相关文件的修改时间
    current_state = {}
    for file_path in go_source_dir.rglob("*"):
        if file_path.name in ("go.mod", "go.sum") or file_path.suffix == ".go":
            current_state[str(file_path)] = file_path.stat().st_mtime

    # 对比保存的状态
    if state_file.exists():
        with open(state_file, "r") as f:
            saved_state = json.load(f)
        if saved_state == current_state:
            return False

    # 状态不匹配,需要编译
    return True

# 记得在compile_go方法最后添加更新状态的代码
def compile_go(self):
    # ... 原有编译代码 ...
    
    # 编译成功后,更新状态文件
    state_file = Path(".go_build_state")
    go_source_dir = Path("go")
    current_state = {}
    for file_path in go_source_dir.rglob("*"):
        if file_path.name in ("go.mod", "go.sum") or file_path.suffix == ".go":
            current_state[str(file_path)] = file_path.stat().st_mtime
    with open(state_file, "w") as f:
        json.dump(current_state, f)

额外小提示

  • 把状态文件.go_build_state加入到.gitignore里,避免提交到版本控制。
  • 如果你的Go源码分散在多个目录,调整go_source_dir的路径或者添加多个目录遍历即可。

这样你就能在setuptools里实现轻量的增量编译,完全不需要引入复杂的第三方构建工具。

内容的提问来源于stack exchange,提问作者wvxvw

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 04:45:51