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

Embarcadero MAKE执行pb_compile报错的原因及修复方案咨询

解决Embarcadero MAKE执行pb_compile目标的语法错误问题

问题背景

使用Embarcadero MAKE Version 5.43运行以下Makefile时,执行make pb_compile出现语法错误:

define HELPBODY
Available commands:

    make help       - this thing.

    make init       - install python dependancies
    make test       - run tests and coverage
    make pylint     - code analysis
    make build      - pylint + test
    make docs       - generate html docs using sphinx

    make dist       - build source distribution
    mage register   - register in pypi
    make upload     - upload to pypi

    make pb_fetch   - fetch protobufs from SteamRE
    make pb_compile - compile with protoc
    make pb_clear   - removes *.proto
    make pb_update  - pb_fetch + pb_compile

endef

export HELPBODY
help:
    @echo "$$HELPBODY"

init:
    pip install -r requirements.txt

test:
    coverage erase
    PYTHONHASHSEED=0 nosetests --verbosity 1 --with-coverage --cover-package=dota2

pylint:
    pylint -r n -f colorized dota2 || true

build: pylint test docs

.FORCE:
docs: .FORCE
    $(MAKE) -C docs html

clean:
    rm -rf dist dota2.egg-info dota2/*.pyc

dist: clean
    python setup.py sdist

register:
    python setup.py register -r pypi

upload: dist register
    twine upload -r pypi dist/*

pb_fetch:
    wget -nv --backups=1 --show-progress -P ./protobufs/ -i protobuf_list.txt
    rm -f ./protobufs/*.1
    sed -i '1s/^/syntax = "proto2"\;\npackage dota\;\n/' protobufs/*.proto
    sed -i 's/\(optional\|repeated\) \.\([A-Z]\)/\1 dota.\2/' protobufs/*.proto
    sed -i 's/cc_generic_services/py_generic_services/' protobufs/*.proto
    sed -i 's/ = 6000/ = 7000/' protobufs/steammessages.proto  # extentions hack

pb_compile:
    for filepath in `ls ./protobufs/*.proto`; do \
        protoc3 --python_out ./dota2/protobufs/ --proto_path=./protobufs "$$filepath"; \
    done;
    sed -i '/^import sys/! s/^import /import dota2.protobufs./' dota2/protobufs/*_pb2.py

pb_clear:
    rm -f ./protobufs/*.proto ./dota2/protobufs/*_pb2.py

gen_enums:
    python gen_enum_from_protos.py > dota2/proto_enums.py

pb_update: pb_fetch pb_compile gen_enums

初次报错

MAKE Version 5.43  Copyright (c) 1987, 2019 Embarcadero Technologies, Inc.
Error makefile 2: Command syntax error
Error makefile 22: Command syntax error
Error makefile 24: Command syntax error
Error makefile 40: Colon expected
*** 4 errors during make ***

简化后仍报错

将pb_compile目标简化为以下内容后:

pb_compile:
    for filepath in `ls ./protobufs/*.proto`; do \
        protoc3 --python_out ./dota2/protobufs/ --proto_path=./protobufs "$$filepath"; \
    done;
    sed -i '/^import sys/! s/^import /import dota2.protobufs./' dota2/protobufs/*_pb2.py

执行时依然报错:

MAKE Version 5.43 Copyright (c) 1987, 2019 Embarcadero Technologies, Inc.
for filepath in `ls ./protobufs/*.proto`; do protoc3 --python_out ./dota2/protobufs/ --proto_path=./protobufs "$filepath"; done;
Unexpected occurrence: filepath.

** error 1 ** deleting pb_compile

问题根源

Embarcadero MAKE(原Borland Make)默认调用Windows的cmd.exe作为执行shell,而编写的循环是Bash/Linux shell语法,两者语法不兼容:

  • cmd.exe不支持for var in ...这种遍历方式
  • cmd.exe不识别反引号`的命令替换语法
  • Makefile中的变量转义规则在不同Make工具中也有差异

修复方案

方案1:改用GNU Make(推荐)

如果环境允许,安装GNU Make(例如通过Chocolatey安装make,或使用MinGW/MSYS2套件中的make),直接运行gmake pb_compile或make pb_compile,原Makefile的Bash语法即可正常工作。

方案2:修改为cmd.exe兼容语法

将pb_compile目标的循环改写为Windows cmd支持的格式:

pb_compile:
    for %%f in (.\protobufs\*.proto) do (
        protoc3 --python_out .\dota2\protobufs\ --proto_path=.\protobufs "%%f"
    )
    sed -i '/^import sys/! s/^import /import dota2.protobufs./' dota2/protobufs/*_pb2.py

注意事项:

  • cmd循环变量需用双百分号%%f(单百分号会被Make解析为通配符)
  • 路径可使用Windows风格反斜杠\,或保持正斜杠(cmd可识别)
  • 直接用通配符匹配文件,替换Bash的ls命令替换

方案3:用Python脚本替代shell循环(跨平台最佳)

利用项目本身的Python环境,编写跨平台脚本处理编译逻辑,彻底避免shell语法差异:

  1. 创建compile_protos.py脚本:
import os
import subprocess

# 配置路径
PROTO_DIR = "./protobufs"
OUT_DIR = "./dota2/protobufs"

# 确保输出目录存在
os.makedirs(OUT_DIR, exist_ok=True)

# 编译所有proto文件
for filename in os.listdir(PROTO_DIR):
    if filename.endswith(".proto"):
        proto_path = os.path.join(PROTO_DIR, filename)
        subprocess.run(
            ["protoc3", "--python_out", OUT_DIR, "--proto_path", PROTO_DIR, proto_path],
            check=True,
            encoding="utf-8"
        )

# 修改生成文件的import语句
for filename in os.listdir(OUT_DIR):
    if filename.endswith("_pb2.py"):
        file_path = os.path.join(OUT_DIR, filename)
        with open(file_path, "r", encoding="utf-8") as f:
            lines = f.readlines()
        with open(file_path, "w", encoding="utf-8") as f:
            for line in lines:
                if line.startswith("import ") and not line.startswith("import sys"):
                    # 替换import为带包路径的形式
                    f.write(f"import dota2.protobufs.{line[7:]}")
                else:
                    f.write(line)
  1. 修改Makefile中的pb_compile目标:
pb_compile:
    python compile_protos.py

这种方式无需依赖特定shell或Make工具,在任何支持Python的平台都能正常执行。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 21:35:09