clean: private_clean common_clean
-
+COMSPEC:=$(shell echo %COMSPEC%)
#################################################################
# #
# Else, in BASH environment
else
-
-# Get helios version
-ifeq ($(shell type -P helios),)
- HELIOS_VERSION :=
-else
- HELIOS_VERSION := $(shell helios --version | grep -Po 'Helios \(released by Quectel\) \K[^\s]+')
-endif
+# Get helios version (reuse the existing Windows batch for consistent parsing)
+HELIOS_VERSION := $(shell cmd /c get_helios_version.bat)
# Define a macro to check if a string represents a number
define is_number
$(shell echo "$1" | grep -q '^[0-9]\+$' && echo "true" || echo "false")
else ifeq ($(HELIOS_VERSION),1.4.1)
IS_NEWER_THAN_1_4_1 := true
else
- # Split the version into parts
- HELIOS_VERSION_PARTS := $(subst ., ,$(HELIOS_VERSION))
- # Check if major, minor, and patch are numbers
- IS_MAJOR_NUMBER := $(call is_number,$(word 1,$(HELIOS_VERSION_PARTS)))
- IS_MINOR_NUMBER := $(call is_number,$(word 2,$(HELIOS_VERSION_PARTS)))
- IS_PATCH_NUMBER := $(call is_number,$(word 3,$(HELIOS_VERSION_PARTS)))
-
- # If any part is not a number, report an error
- ifneq ($(IS_MAJOR_NUMBER)$(IS_MINOR_NUMBER)$(IS_PATCH_NUMBER),truetruetrue)
+ # Parse and compare semantic version in one step (avoid shell quoting issues).
+ IS_NEWER_THAN_1_4_1 := $(shell $(PY) -c "import sys; v=sys.argv[1].strip(); parts=v.split('.'); ok=(len(parts)==3 and all(p.isdigit() for p in parts)); print('invalid' if not ok else ('true' if tuple(map(int,parts)) >= (1,4,1) else 'false'))" "$(HELIOS_VERSION)")
+ ifeq ($(IS_NEWER_THAN_1_4_1),invalid)
$(error "Unexpected version format: $(HELIOS_VERSION)")
- else
- # Compare the version with 1.4.1
- IS_NEWER_THAN_1_4_1 := $(shell echo "$(HELIOS_VERSION)" | awk -F. '{if ($$1 > 1 || ($$1 == 1 && $$2 >= 4 && $$3 >= 1)) print "true"; else print "false"}')
endif
endif
# See the License for the specific language governing permissions and
# limitations under the License.
-import json, os, re, sys
+import json, os, re, sys, shutil, subprocess
dep_dict = {}
+SYSTEMROOT = os.environ.get('SystemRoot', r'C:\Windows')
+# 不信任 COMSPEC/ComSpec(批处理/工具链可能把它设成相对路径 cmd.exe),直接固定用系统 cmd.exe 绝对路径
+CMD_EXE = os.path.join(SYSTEMROOT, 'System32', 'cmd.exe')
+
+def _inject_make_abs_path(cmd: str) -> str:
+ """把命令开头的 make 替换成绝对路径,避免 PATH/编码导致找不到可执行文件。"""
+ make_exe = shutil.which('make')
+ if make_exe and cmd.lstrip().startswith('make '):
+ # 只替换开头的 'make ',保留后续参数原样
+ prefix_len = len(cmd) - len(cmd.lstrip())
+ return cmd[:prefix_len] + make_exe + cmd[prefix_len + 4:]
+ return cmd
+
+def run_cmd_capture(cmd: str) -> bytes:
+ """
+ 显式用 cmd.exe 执行(不要依赖 COMSPEC/默认 shell),并捕获 stdout+stderr。
+ """
+ cmd = _inject_make_abs_path(cmd)
+ p = subprocess.Popen(
+ [CMD_EXE, '/d', '/s', '/c', cmd],
+ shell=False,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.STDOUT,
+ )
+ out, _ = p.communicate()
+ return out or b''
+
+def system_cmd(cmd: str) -> int:
+ """用 subprocess.call 显式 cmd.exe 执行。"""
+ cmd = _inject_make_abs_path(cmd)
+ return subprocess.call([CMD_EXE, '/d', '/s', '/c', cmd], shell=False)
def not_empty(s):
if not s == '':
comp_mk = comp_path + '/' + comp_path.split('/')[-1] + '.mk'
cmd = 'make --no-print-directory -f comp_info_tell.mk' + ' COMP_MK=' + comp_mk
- res = os.popen(cmd)
- ret = res.buffer.read().decode(encoding='utf-8')
- res.close()
+ ret = run_cmd_capture(cmd).decode(encoding='utf-8', errors='ignore')
if not ret:
raise RuntimeError('cmd [%s] execution error' % cmd)
regex = re.compile(r'NAME: (.*)\nGLOBAL_INCS: (.*)\nGLOBAL_DEFINE: (.*)\nLOCAL_CFLAGS: (.*)\nLOCAL_ARCHIVES: (.*)\nLOCAL_SRCS: (.*)\nLOCAL_SRCS_2: (.*)\nLOCAL_SRCS_3: (.*)\nLOCAL_INCS: (.*)\nLOCAL_DEFINE: (.*)\nCOMP_DEPS: (.*)\n')
if 'DEF_COLLECT' in v and v['DEF_COLLECT']:
comp_dflags = ' '.join(v['DEF_COLLECT'])
os.environ['COMP_DFLAGS'] = comp_dflags
- if os.system(cmd):
+ if system_cmd(cmd):
raise RuntimeError('cmd [%s] execution error' % cmd)
if 'LOCAL_ARCHIVES' in v and v['LOCAL_ARCHIVES']:
user_archive_list.extend(list(map(lambda x : k + '/' + x, v['LOCAL_ARCHIVES'])))
target_bin = os.environ['TARGET_BIN']
- cmd = 'make --no-print-directory -f link.mk ' + target_bin + ' COMP_ARCHIVES="' + ' '.join(comp_archive_list) + '"' + ' USER_ARCHIVES="' + ' '.join(user_archive_list) + '"'
- if os.system(cmd):
- raise RuntimeError('cmd [%s] execution error' % cmd)
+ make_exe = shutil.which('make') or 'make'
+ env = os.environ.copy()
+ env['COMP_ARCHIVES'] = ' '.join(comp_archive_list)
+ env['USER_ARCHIVES'] = ' '.join(user_archive_list)
+ if subprocess.call([make_exe, '--no-print-directory', '-f', 'link.mk', target_bin], env=env):
+ raise RuntimeError('cmd [make -f link.mk] execution error')
if os.environ['PLAT'] != 'RDA' and os.environ['PLAT'] != 'Qualcomm':
target_hex = os.environ['TARGET_HEX']
- cmd = 'make --no-print-directory -f link.mk ' + target_hex + ' COMP_ARCHIVES="' + ' '.join(comp_archive_list) + '"' + ' USER_ARCHIVES="' + ' '.join(user_archive_list) + '"'
- if os.system(cmd):
- raise RuntimeError('cmd [%s] execution error' % cmd)
+ env = os.environ.copy()
+ env['COMP_ARCHIVES'] = ' '.join(comp_archive_list)
+ env['USER_ARCHIVES'] = ' '.join(user_archive_list)
+ if subprocess.call([make_exe, '--no-print-directory', '-f', 'link.mk', target_hex], env=env):
+ raise RuntimeError('cmd [make -f link.mk] execution error')
def build_proc(app):
print('\n[searching for all components ...] ', end = '', flush=True)
# See the License for the specific language governing permissions and
# limitations under the License.
+USE_WHOLE_ARCHIVE ?= y
+
$(TARGET_BIN): $(TARGET_ELF)
ifeq ($(strip $(PLAT)),Qualcomm)
$(Q)$(OBJCOPY_PY) --bin $^ --output $@
$(TARGET_ELF): $(OUTPUT_LD_FILE) $(COMP_ARCHIVES) $(USER_ARCHIVES) $(STD_LIBS)
@echo
ifeq ($(strip $(PLAT)),ECR6600)
+ifeq ($(strip $(USE_WHOLE_ARCHIVE)),n)
+ # ROM overflow 时,保留 microPython 与 USER_ARCHIVES 的 whole-archive,
+ # 其余 COMP_ARCHIVES 走普通按需拉取,避免输出空壳。
+ $(Q)$(CC) -Wl,--whole-archive \
+ $(filter %/services/microPython/libmicroPython.a,$(COMP_ARCHIVES)) $(USER_ARCHIVES) \
+ -Wl,--no-whole-archive $(filter-out %/services/microPython/libmicroPython.a,$(COMP_ARCHIVES)) $(STD_LIBS) \
+ -o $@ $(LDFLAGS)
+else
$(Q)$(CC) -Wl,--whole-archive \
- $(COMP_ARCHIVES) $(USER_ARCHIVES) -Wl,--no-whole-archive $(STD_LIBS) \
- -o $@ $(LDFLAGS)
+ $(COMP_ARCHIVES) $(USER_ARCHIVES) -Wl,--no-whole-archive $(STD_LIBS) \
+ -o $@ $(LDFLAGS)
+endif
else
+ifeq ($(strip $(USE_WHOLE_ARCHIVE)),n)
+ # 同上:只对 microPython 与 USER_ARCHIVES 使用 whole-archive
$(LD) --whole-archive \
- $(COMP_ARCHIVES) $(USER_ARCHIVES) --no-whole-archive $(STD_LIBS) \
- -o $@ $(LDFLAGS)
+ $(filter %/services/microPython/libmicroPython.a,$(COMP_ARCHIVES)) $(USER_ARCHIVES) \
+ --no-whole-archive $(filter-out %/services/microPython/libmicroPython.a,$(COMP_ARCHIVES)) $(STD_LIBS) \
+ -o $@ $(LDFLAGS)
+else
+ $(LD) --whole-archive \
+ $(COMP_ARCHIVES) $(USER_ARCHIVES) --no-whole-archive $(STD_LIBS) \
+ -o $@ $(LDFLAGS)
+endif
endif
@echo ----- $@ updated
@echo off
+set PATH=D:\helios\bin;%PATH%
+@REM set COMSPEC=cmd.exe
+set "COMSPEC=%SystemRoot%\System32\cmd.exe"
cd Helios_SDK
helios make services/microPython @EG810MCN_GA_ALIPAY EG810MCN_GA_ALIPAY
cd ..
@echo off
-
+set PATH=D:\helios\bin;%PATH%
+@REM set COMSPEC=cmd.exe
+set "COMSPEC=%SystemRoot%\System32\cmd.exe"
cd Helios_SDK
helios clean
cd ..
@echo off
-
+set PATH=D:\helios\bin;%PATH%
+set "COMSPEC=%SystemRoot%\System32\cmd.exe"
cd Helios_SDK
helios clean
cd ..
@GOTO :STEP1
..\..\Helios_SDK\tools\ASR_1606\win32\mklfs.exe -c ext -b 4096 -r 4096 -p 4096 -s 1048576 -i .\images\ext_fs.bin
if errorlevel 1 (
- echo "ext_fs.binÉú³Éʧ°Ü !!!!!!!!!!!!!!! "
+ echo "ext_fs.bin����ʧ�� !!!!!!!!!!!!!!! "
goto exit
)
if errorlevel 0 (
- echo "ext_fs.binÉú³É³É¹¦ !!!!!!!!!!!!!!! "
+ echo "ext_fs.bin���ɳɹ� !!!!!!!!!!!!!!! "
)
:STEP1
..\..\Helios_SDK\tools\ASR_1606\win32\mklfs.exe -c usr -b 4096 -r 4096 -p 4096 -s 1376256 -i .\images\customer_fs.bin
if errorlevel 1 (
- echo "customer_fs.binÉú³Éʧ°Ü Çë¼ì²éusrĿ¼ÊÇ·ñ´óÓÚ316K!!!!!!!!!!!!!!!"
+ echo "customer_fs.bin����ʧ�� ����usrĿ¼�Ƿ����316K!!!!!!!!!!!!!!!"
goto exit
)
if errorlevel 0 (
- echo "customer_fs.binÉú³É³É¹¦ !!!!!!!!!!!!!!! "
+ echo "customer_fs.bin���ɳɹ� !!!!!!!!!!!!!!! "
)
%copy font\ext_font.bin images\ext_font.bin%
..\..\Helios_SDK\tools\common\win32\7z\7z a sdk\system\platform\ASR_1606\boards\EG810MCN_GA_VOLTE\images\firmware_base_release_pack.zip .\images\
if errorlevel 0 (
- echo imagesѹËõ³É¹¦!!!!!!!!!!!!!!
+ echo imagesѹ���ɹ�!!!!!!!!!!!!!!
)
if errorlevel 1 (
- echo imagesѹËõʧ°Ü!!!!!!!!!!!!!!!!!!
+ echo imagesѹ��ʧ��!!!!!!!!!!!!!!!!!!
goto exit
)
xcopy sdk\ ..\..\Helios_SDK\ /e/h/y
@echo off\r
-\r
md images\r
del images /q\r
@GOTO :STEP1\r
..\..\Helios_SDK\tools\ASR_1606\win32\mklfs.exe -c ext -b 4096 -r 4096 -p 4096 -s 1048576 -i .\images\ext_fs.bin\r
if errorlevel 1 (\r
- echo "ext_fs.binÉú³Éʧ°Ü !!!!!!!!!!!!!!! "\r
+ echo "ext_fs.bin生成失败 !!!!!!!!!!!!!!! "\r
goto exit\r
)\r
if errorlevel 0 (\r
- echo "ext_fs.binÉú³É³É¹¦ !!!!!!!!!!!!!!! "\r
+ echo "ext_fs.bin生成成功 !!!!!!!!!!!!!!! "\r
)\r
:STEP1\r
\r
..\..\Helios_SDK\tools\ASR_1606\win32\mklfs.exe -c usr -b 4096 -r 4096 -p 4096 -s 1376256 -i .\images\customer_fs.bin\r
if errorlevel 1 (\r
- echo "customer_fs.binÉú³Éʧ°Ü Çë¼ì²éusrĿ¼ÊÇ·ñ´óÓÚ316K!!!!!!!!!!!!!!!"\r
+ echo "customer_fs.bin生成失败 请检查usr目录是否大于316K!!!!!!!!!!!!!!!"\r
goto exit\r
)\r
if errorlevel 0 (\r
- echo "customer_fs.binÉú³É³É¹¦ !!!!!!!!!!!!!!! "\r
+ echo "customer_fs.bin生成成功 !!!!!!!!!!!!!!! "\r
)\r
\r
%copy font\ext_font.bin images\ext_font.bin%\r
\r
..\..\Helios_SDK\tools\common\win32\7z\7z a sdk\system\platform\ASR_1606\boards\EG810MCN_GA_VOLTE\images\firmware_base_release_pack.zip .\images\\r
if errorlevel 0 (\r
- echo imagesѹËõ³É¹¦!!!!!!!!!!!!!!\r
+ echo images压缩成功!!!!!!!!!!!!!!\r
)\r
if errorlevel 1 (\r
- echo imagesѹËõʧ°Ü!!!!!!!!!!!!!!!!!!\r
+ echo images压缩失败!!!!!!!!!!!!!!!!!!\r
goto exit\r
)\r
xcopy sdk\ ..\..\Helios_SDK\ /e/h/y\r
cd ..\..\Helios_SDK\r
-helios make services/microPython @EG810MCN_GA_VOLTE EG810MCN_GA_VOLTE\r
+helios.exe make services/microPython @EG810MCN_GA_VOLTE EG810MCN_GA_VOLTE\r
cd ..\r
:exit
\ No newline at end of file
--- /dev/null
+import os
+import subprocess
+import datetime
+import sys
+from pathlib import Path
+
+def run_git_command(command):
+ try:
+ # 设置环境变量以正确处理中文文件名
+ env = os.environ.copy()
+ env['LC_ALL'] = 'C.UTF-8'
+ env['LANG'] = 'C.UTF-8'
+
+ result = subprocess.run(
+ command,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE,
+ encoding='utf-8',
+ errors='replace',
+ check=True,
+ env=env
+ )
+ return result.stdout.strip()
+ except subprocess.CalledProcessError as e:
+ print(f"Error executing git command: {e.stderr}")
+ # 不要立即退出,让调用者处理错误
+ raise
+ except UnicodeDecodeError as e:
+ print(f"Encoding error: {e}")
+ raise
+
+def main():
+ if len(sys.argv) > 3:
+ print("Usage: python git_changes_extractor.py [commit1 [commit2]]")
+ print(" If no arguments are provided, uncommitted changes will be extracted")
+ print(" If only commit1 is provided, it defaults to comparing with HEAD")
+ sys.exit(1)
+
+ # 处理不同参数情况
+ if len(sys.argv) == 1:
+ commit1 = None
+ commit2 = None
+ mode = "uncommitted"
+ elif len(sys.argv) == 2:
+ commit1 = sys.argv[1]
+ commit2 = "HEAD"
+ mode = "commits"
+ else:
+ commit1 = sys.argv[1]
+ commit2 = sys.argv[2]
+ mode = "commits"
+
+ # 获取当前仓库路径和名称
+ repo_path = Path(os.getcwd())
+ repo_name = repo_path.name
+
+ # 创建输出目录 (格式: 仓库名_时间戳)
+ timestamp = datetime.datetime.now().strftime("%y%m%d%H%M%S")
+ output_dir_name = f"{repo_name}_{timestamp}"
+ patches_dir = repo_path.parent / "PATCHES"
+ output_dir = patches_dir / output_dir_name
+ output_dir.mkdir(parents=True, exist_ok=True)
+
+ # 创建diff子目录
+ diff_dir = output_dir / "diff"
+ diff_dir.mkdir(exist_ok=True)
+
+ # 获取变更文件列表
+ if mode == "uncommitted":
+ # 获取暂存区变更
+ staged_changes = run_git_command(
+ ["git", "diff", "--name-status", "--cached", "--diff-filter=ACDMRTUXB"]
+ ).splitlines()
+
+ # 获取工作区变更
+ unstaged_changes = run_git_command(
+ ["git", "diff", "--name-status", "--diff-filter=ACDMRTUXB"]
+ ).splitlines()
+
+ # 获取未跟踪文件 (新增但未git add的文件)
+ untracked_files = run_git_command(
+ ["git", "ls-files", "--others", "--exclude-standard"]
+ ).splitlines()
+ untracked_changes = [f"A\t{file}" for file in untracked_files]
+
+ # 合并变更 (暂存区优先,然后工作区,最后未跟踪)
+ change_list = staged_changes.copy()
+
+ # 添加工作区变更中不在暂存区的文件
+ staged_files = {line.split('\t', 1)[1] for line in staged_changes}
+ for line in unstaged_changes:
+ file_path = line.split('\t', 1)[1]
+ if file_path not in staged_files:
+ change_list.append(line)
+
+ # 添加未跟踪文件
+ all_existing_files = {line.split('\t', 1)[1] for line in change_list}
+ for line in untracked_changes:
+ file_path = line.split('\t', 1)[1]
+ if file_path not in all_existing_files:
+ change_list.append(line)
+
+ # 生成完整的未提交变更diff
+ full_diff = run_git_command(
+ ["git", "diff", "--patch", "--cached"]
+ )
+ with open(diff_dir / "uncommitted_changes.diff", "w", encoding='utf-8') as f:
+ f.write(full_diff)
+
+ # 生成工作区与暂存区差异
+ unstaged_diff = run_git_command(
+ ["git", "diff", "--patch"]
+ )
+ with open(diff_dir / "unstaged_changes.diff", "w", encoding='utf-8') as f:
+ f.write(unstaged_diff)
+ else:
+ # 获取两个提交之间的变更
+ change_list = run_git_command(
+ ["git", "diff", "--name-status", commit1, commit2]
+ ).splitlines()
+
+ # 生成每个commit的详细diff
+ commit_hashes = run_git_command(
+ ["git", "rev-list", "--reverse", f"{commit1}..{commit2}"]
+ ).splitlines()
+
+ if not commit_hashes:
+ commit_diff = run_git_command(
+ ["git", "diff", "--patch", commit1, commit2]
+ )
+ diff_file = diff_dir / f"{commit1[:8]}_{commit2[:8]}.diff"
+ with open(diff_file, "w", encoding='utf-8') as f:
+ f.write(commit_diff)
+ else:
+ all_commits = [commit1] + commit_hashes
+ for i in range(len(all_commits) - 1):
+ parent = all_commits[i]
+ child = all_commits[i + 1]
+
+ commit_diff = run_git_command(
+ ["git", "diff", "--patch", parent, child]
+ )
+ diff_file = diff_dir / f"{parent[:8]}_{child[:8]}.diff"
+ with open(diff_file, "w", encoding='utf-8') as f:
+ f.write(commit_diff)
+
+ # 分类变更文件
+ added_files = []
+ modified_files = []
+ deleted_files = []
+
+ for line in change_list:
+ parts = line.split('\t')
+ if len(parts) < 2:
+ continue
+ status, file_path = parts[0], '\t'.join(parts[1:])
+
+ if status == 'A':
+ added_files.append(file_path)
+ elif status == 'M':
+ modified_files.append(file_path)
+ elif status == 'D':
+ deleted_files.append(file_path)
+
+ # 写入变更列表文件
+ with open(output_dir / "gitchangelist.txt", "w", encoding='utf-8') as f:
+ f.write("Added Files:\n")
+ for file in added_files:
+ f.write(f" {file}\n")
+
+ f.write("\nModified Files:\n")
+ for file in modified_files:
+ f.write(f" {file}\n")
+
+ f.write("\nDeleted Files:\n")
+ for file in deleted_files:
+ f.write(f" {file}\n")
+
+ # 写入git log(如果有提交范围)
+ if mode == "commits":
+ git_log = run_git_command(
+ ["git", "log", "--name-status", f"{commit1}..{commit2}"]
+ )
+ with open(output_dir / "gitlog.txt", "w", encoding='utf-8') as f:
+ f.write(git_log)
+ else:
+ # 未提交变更的简短信息
+ with open(output_dir / "gitlog.txt", "w", encoding='utf-8') as f:
+ f.write("Summary of uncommitted changes\n")
+ f.write("================================\n\n")
+ f.write("Changes are relative to HEAD:\n")
+ f.write(run_git_command(["git", "status", "--short"]))
+
+ # 复制变更文件(不包括已删除的)
+ for file_path in added_files + modified_files:
+ source_file = repo_path / file_path
+ target_file = output_dir / file_path
+
+ target_file.parent.mkdir(parents=True, exist_ok=True)
+
+ try:
+ # 直接从工作区复制,因为未跟踪文件在工作区中存在
+ if os.path.exists(source_file):
+ with open(source_file, "rb") as src, open(target_file, "wb") as dst:
+ dst.write(src.read())
+ else:
+ # 从暂存区提取文件内容
+ # 对于包含特殊字符的文件名,使用更安全的方式
+ try:
+ blob_content = run_git_command(
+ ["git", "show", f":{file_path}"]
+ )
+ except:
+ # 如果pathspec失败,尝试使用git cat-file
+ try:
+ # 获取文件的blob hash
+ blob_hash = run_git_command(
+ ["git", "ls-files", "--stage", file_path]
+ ).split()[1]
+ blob_content = run_git_command(
+ ["git", "cat-file", "blob", blob_hash]
+ )
+ except:
+ print(f"Warning: Could not extract staged content for {file_path}")
+ continue
+ with open(target_file, "w", encoding='utf-8') as dst:
+ dst.write(blob_content)
+ except Exception as e:
+ print(f"Error copying file {file_path}: {e}")
+
+ print(f"Changes saved to: {output_dir}")
+
+if __name__ == "__main__":
+ main()
\ No newline at end of file