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语法差异:
- 创建
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)
- 修改Makefile中的pb_compile目标:
pb_compile: python compile_protos.py
这种方式无需依赖特定shell或Make工具,在任何支持Python的平台都能正常执行。
内容的提问来源于stack exchange,提问作者igrik
相关产品推荐
相关产品推荐

