R核的Linux环境和Windows环境切换
背景说明:
客户发过来的MCU的R核编译环境是基于Linux设置的,目前私人电脑没有安装Linux环境,所以针对客户的工程我们面临一个问题:仅仅为了编译是否一定需要安装Linux环境?是否可以在windows环境下直接编译?
分析说明:
Step1:
使用gfile.exe查看已经编译的o文件,输出:ARM little endian relocatable (ELF)
1.ARM:指令集架构为标准 ARM;
2.little endian:小端字节序(ARM常用字节序,低位在前);
3.relocatable:可重定位目标文件(即尚未进行绝对地址绑定的中间.o,可供链接器任意布局);
4.ELF:遵循国际标准的可执行与可链接格式(Executable and Linking Format)。

Step2:
使用gnm.exe查看内部的函数符号

Step3:
查看makefile等文件中的编译设置
PLATFORM = ArmCommon
CPU_CORE = CORTEX_R52
INSTRUCTION_SET= THUMB
以上都证明这些.o文件与Windows下的GHS ARM工具链完全兼容,完全无需依赖Linux虚拟机即可在Windows下实现100%原生构建。
动作实施:
Step1:
解析原Linux下的脚本
#!/usr/bin/env bash
# Linux (Ubuntu) build entry for the B2 board, mirroring the Windows flow of
# build.bat -> build_b2.bat 1:1 (single-variant B2 build, secure image, size
# report, version extraction, artifact copy and MAP analysis).
#
# Usage: ./build_ubuntu.sh [options] [-- extra-make-arguments]
set -euo pipefail
SCRIPT_DIR=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)
REPO_ROOT=$(cd -- "$SCRIPT_DIR/../.." && pwd)
LINUX_BUILD_DIR="$REPO_ROOT/MakeSupport/platform/J6P/linux_build"
PROJECT_MAKEFILE="$REPO_ROOT/MakeSupport/project/J6P/Makefile.project"
BUILD_WORK_DIR="$REPO_ROOT/MakeSupport/build/J6P"
IMAGE_DIR="$REPO_ROOT/MakeSupport/image/J6P"
FLASH_DIR="$REPO_ROOT/MakeSupport/flash/J6P"
MAP_DIR="$REPO_ROOT/MakeSupport/quality/J6P/map_report"
DEBUG_SCRIPT_DIR="$REPO_ROOT/MakeSupport/debug/J6P"
OUTPUT_DIR="$REPO_ROOT/output"
LOG_DIR="$BUILD_WORK_DIR/log"
LOG_FILE="$LOG_DIR/build_b2.log"
source "$LINUX_BUILD_DIR/ghs_env.sh"
GHS_PATH=$(find_ghs_path)
GHS_LICENSE_CHECK_SCRIPT=${GHS_LICENSE_CHECK_SCRIPT:-$LINUX_BUILD_DIR/check_ghs_license.sh}
if [[ -z ${JOBS:-} ]]; then
if command -v nproc >/dev/null 2>&1; then
JOBS=$(nproc)
else
JOBS=3
fi
fi
# Mirrors the first-argument switches of build_b2.bat; anything after `--` (or
# any non-switch argument) is forwarded to make, like %* in the batch file.
BUILD_MODE=default
EXTRA_MAKE_ARGS=()
FAST=0
ORIG_ARGS=("$@")
usage() {
cat <<'EOF'
Usage: ./build_ubuntu.sh [options] [-- extra-make-arguments]
Options:
-r Rebuild (make target `rebuild`)
-rel Release environment build (deletes generated .c/.asm/.s and
links from objects only, like build_b2.bat -rel)
-i Rebuild ELF and BIN, then generate the signed image
clean Clean intermediate files (no artifacts are produced)
-j, --jobs N Parallel job count (default: detected logical CPU count)
--libobj L3 platform object-tree build: compile platform sources
only (application directories excluded) and publish the
objects as a directory tree + customer kit tarball
--app [plat_tree] [app_tree]
L3 application build: compile application sources and
pure-link them with the platform object tree. plat_tree
defaults to ../../platform_objtree (the unpacked-kit
layout), so `build_ubuntu.sh --app` is enough there.
Later, when the application ships as a library, pass
its prebuilt object tree as [app_tree] (same entry)
-fast Accelerated build: rsync the working tree to a fast disk
(/dev/shm, falls back to /tmp), build there, copy artifacts
back. Combine with other options, e.g. `./build_ubuntu.sh -fast -r`.
NAS repo is never modified; the fast work area is rebuilt on
every run and does not survive a reboot (by design).
-h, --help Show this help
Environment overrides:
GHS_PATH Linux GHS compiler directory
GHS_LICENSE_CHECK_SCRIPT
License status script
JOBS Default parallel job count
EOF
}
fast_flow() {
# Accelerated build: copy the working tree to a fast disk, build there,
# copy artifacts back. The NAS repo itself is never modified.
local fast_root candidate avail work lock t0 t1 rc real_commit
fast_root=""
for candidate in /dev/shm /tmp; do
[[ -d $candidate && -w $candidate ]] || continue
avail=$(df -B1G --output=avail "$candidate" 2>/dev/null | tail -1 | tr -d ' ')
[[ -n $avail && $avail -ge 8 ]] && fast_root=$candidate && break
done
if [[ -z $fast_root ]]; then
echo "[fast] no fast disk with >=8G free (/dev/shm or /tmp); run without -fast" >&2
exit 1
fi
work=$fast_root/fb_$(basename "$REPO_ROOT")
lock=$fast_root/.fb_$(basename "$REPO_ROOT").lock
if ! mkdir "$lock" 2>/dev/null; then
# stale-lock recovery: a killed build cannot run its EXIT trap
if [[ -f "$lock/pid" ]] && ! kill -0 "$(cat "$lock/pid")" 2>/dev/null; then
echo "[fast] removing stale lock (pid $(cat "$lock/pid") not running)"
rm -rf "$lock"
mkdir "$lock" || { echo "[fast] cannot acquire $lock" >&2; exit 1; }
else
echo "[fast] another build holds $lock" >&2
exit 1
fi
fi
printf '%s\n' $$ > "$lock/pid"
trap 'rm -rf "$work" 2>/dev/null; rm -rf "$lock" 2>/dev/null' EXIT
echo "[fast] $REPO_ROOT -> $work ($fast_root)"
mkdir -p "$work"
rsync_progress=()
if [[ -t 1 ]]; then
rsync_progress=(--info=progress2)
fi
rsync -a -L "${rsync_progress[@]}" --delete \
--exclude=.git --exclude=output --exclude='MakeSupport/build' \
"$REPO_ROOT/" "$work/repo/"
# Fallback sweep: backslash includes are silently swallowed on Linux
# (fixed upstream for ThirdParty; older branches still need this). The
# sweep only touches the fast-disk copy, never the NAS repo.
python3 - "$work/repo" <<'PYSWEEP'
import glob, io, os, re, sys
repo = sys.argv[1]
BS = chr(92)
pat = re.compile('^[ \t]*-?include[ \t]+.*' + re.escape(BS), re.M)
for p in [os.path.join(repo, 'App/Appl/Makefile.project.part.defines')] + \
glob.glob(os.path.join(repo, 'App/Appl', '**', '*.mak'), recursive=True):
try:
t = io.open(p, newline='', encoding='utf-8', errors='replace').read()
except OSError:
continue
new = pat.sub(lambda m: m.group(0).replace(BS, '/'), t)
if new != t:
io.open(p, 'w', newline='', encoding='utf-8').write(new)
PYSWEEP
rm -rf "$work/build"
mkdir -p "$work/build"
ln -sfn "$work/build" "$work/repo/MakeSupport/build"
# The fast-disk copy has no .git; hand the real commit id to the child so
# git_version.h keeps the true revision instead of the fallback '0'.
real_commit=$(git -C "$REPO_ROOT" rev-parse --short HEAD 2>/dev/null || printf '0')
t0=$(date +%s)
rc=0
( cd "$work/repo/App/Appl" && \
FASTBUILD_CHILD=1 GIT_COMMIT_OVERRIDE=$real_commit ./build_ubuntu.sh "$@" ) || rc=$?
t1=$(date +%s)
echo "[fast] build took $(( (t1-t0)/60 )) min $(( (t1-t0)%60 )) sec (rc=$rc)"
echo "[fast] copying artifacts back to NAS..."
mkdir -p "$REPO_ROOT/output" "$REPO_ROOT/MakeSupport/build/J6P/output"
[[ -d "$work/repo/output" ]] && rsync -a "${rsync_progress[@]}" --delete "$work/repo/output/" "$REPO_ROOT/output/"
rsync -a "$work/build/J6P/output/" "$REPO_ROOT/MakeSupport/build/J6P/output/" 2>/dev/null || true
[[ -d "$work/build/J6P/log" ]] && rsync -a "$work/build/J6P/log/" "$REPO_ROOT/MakeSupport/build/J6P/log/" 2>/dev/null || true
rm -rf $work
echo "[fast] work area cleared"
echo "[fast] done. artifacts: $REPO_ROOT/output/"
exit "$rc"
}
while (($#)); do
case "$1" in
-r)
BUILD_MODE=rebuild
;;
-rel)
BUILD_MODE=rel
;;
-i)
BUILD_MODE=image
;;
clean)
BUILD_MODE=clean
;;
--libobj)
BUILD_MODE=libobj
;;
--app)
shift
# both value slots are optional: '-'-prefixed tokens (e.g. -fast)
# never occupy a slot, so option order is free; the unpacked-kit
# layout has the platform tree at a fixed place and covers the
# no-argument case
L3_PLAT_TREE_ARG=; L3_APP_TREE_ARG=
if [[ $# -gt 0 && ! "$1" =~ ^- ]]; then
L3_PLAT_TREE_ARG=$1
shift || true
if [[ $# -gt 0 && ! "$1" =~ ^- ]]; then
L3_APP_TREE_ARG=$1
shift || true
fi
fi
: "${L3_PLAT_TREE_ARG:=../../platform_objtree}"
BUILD_MODE=app
;;
-fast)
FAST=1
;;
-h|-usage|--help)
BUILD_MODE=help
;;
-j|--jobs)
shift
[[ $# -gt 0 ]] || { echo "Missing job count" >&2; exit 2; }
JOBS=$1
;;
--)
shift
EXTRA_MAKE_ARGS+=("$@")
break
;;
*)
EXTRA_MAKE_ARGS+=("$1")
;;
esac
(($#)) && shift || true
done
[[ "$JOBS" =~ ^[1-9][0-9]*$ ]] || {
echo "Invalid job count: $JOBS" >&2
exit 2
}
if (( FAST )) && [[ "${FASTBUILD_CHILD:-0}" != "1" && "$BUILD_MODE" != "help" ]]; then
child_args=()
for _a in "${ORIG_ARGS[@]}"; do
if [[ "$_a" != "-fast" ]]; then
child_args+=("$_a")
fi
done
fast_flow "${child_args[@]}"
fi
export PATH="$LINUX_BUILD_DIR:$PATH"
require_file() {
[[ -e "$1" ]] || { echo "Required file not found: $1" >&2; exit 1; }
}
command -v make >/dev/null || { echo "GNU make is required" >&2; exit 1; }
command -v python3 >/dev/null || { echo "python3 is required" >&2; exit 1; }
require_file "$GHS_PATH/ccarm"
require_file "$GHS_PATH/gsize"
require_file "$SCRIPT_DIR/Makefile"
require_file "$LINUX_BUILD_DIR/cygpath"
# Board names come from the same config build_b2.bat reads.
MCU_OUTPUT_AB=
MCUEXT_OUTPUT_AB=
MCU_OUTPUT_B2=
MCUEXT_OUTPUT_B2=
while IFS='=' read -r key value; do
[[ -n "$key" && "$key" != \#* ]] || continue
value=${value%$'\r'}
case "$key" in
MCU_OUTPUT_AB) MCU_OUTPUT_AB=$value ;;
MCUEXT_OUTPUT_AB) MCUEXT_OUTPUT_AB=$value ;;
MCU_OUTPUT_B2) MCU_OUTPUT_B2=$value ;;
MCUEXT_OUTPUT_B2) MCUEXT_OUTPUT_B2=$value ;;
esac
done <"$SCRIPT_DIR/makeconfig_mcu_names.mak"
[[ -n "$MCU_OUTPUT_B2" ]] || { echo "MCU_OUTPUT_B2 not found in makeconfig_mcu_names.mak" >&2; exit 1; }
run_license_check() {
echo "[INFO] Checking GHS license status..."
if ! GHS_PATH="$GHS_PATH" GHS_LICENSE_MAKEFILE="$PROJECT_MAKEFILE" bash "$GHS_LICENSE_CHECK_SCRIPT"; then
echo "[ERROR] GHS license check failed; build will not start." >&2
return 1
fi
}
write_git_version() {
local commit_id build_date build_time build_host build_user
commit_id=${GIT_COMMIT_OVERRIDE:-$(git rev-parse --short HEAD 2>/dev/null || printf '0')}
build_date=$(date '+%Y-%m-%d')
build_time=$(date '+%H:%M:%S')
# McuVersionBinInfo embeds the host name in a char[32] field; long cloud
# host names must be truncated to keep the initializer valid.
build_host=$(hostname | cut -c1-31)
build_user=${USER:-$(id -un)}
{
printf '#define GIT_VER_SHORT_COMMIT_ID "%s"\n' "$commit_id"
printf '#define GIT_VER_SHORT_COMMIT_ID_U64 0x%sULL\n' "$commit_id"
printf '#define BUILD_COMPUTER_NAME "%s"\n' "$build_host"
printf '#define BUILD_USER_NAME "%s"\n' "$build_user"
printf '#define BUILD_DATE "%s"\n' "$build_date"
printf '#define BUILD_TIME "%s"\n' "$build_time"
} >"$SCRIPT_DIR/git_version.h"
}
format_duration() {
local elapsed=$1
printf '%d min %d sec' "$((elapsed / 60))" "$((elapsed % 60))"
}
run_size_report() {
echo "CODE SIZE:"
"$GHS_PATH/gsize" -nobss "$OUTPUT_DIR/$MCU_OUTPUT_B2.elf"
echo "-------------------------------------------------------------------------------"
echo "DATA SIZE:"
"$GHS_PATH/gsize" -notext -nodata "$OUTPUT_DIR/$MCU_OUTPUT_B2.elf"
echo "Make Bin Success."
}
run_extract_version() {
local extract_ver_script="$SCRIPT_DIR/tools/inject_version/extract_version.py"
if [[ -f "$extract_ver_script" ]]; then
python3 "$extract_ver_script" "$OUTPUT_DIR/$MCU_OUTPUT_B2.bin" "$OUTPUT_DIR/$MCU_OUTPUT_B2.dnm" 2>&1
fi
}
make_release_env() {
local objdir="$BUILD_WORK_DIR/obj/b2"
local projectdir="$REPO_ROOT"
echo "********************************************************************************"
echo "Preparing release environment..."
echo "[WARNING] This deletes generated .c/.asm/.s sources and links from objects only,"
echo " exactly like build_b2.bat -rel. Recover sources with 'git checkout'."
# delete generated source files (mirrors: for /r ..\..\ (*.c *.asm *.s))
find "$REPO_ROOT/App" -type f \( -name '*.c' -o -name '*.asm' -o -name '*.s' \) -delete
# delete object side files (mirrors: for /r obj (*.dbo *.d *.dirstamp))
find "$objdir" -type f \( -name '*.dbo' -o -name '*.d' -o -name '*.dirstamp' \) -delete 2>/dev/null || true
# copy object tree to the repository root so linking works without sources
if [[ -d "$objdir" ]]; then
cp -rf "$BUILD_WORK_DIR/obj/." "$projectdir/"
fi
rm -rf "$BUILD_WORK_DIR/err/b2" "$BUILD_WORK_DIR/lst/b2" "$objdir"
rm -f "$OUTPUT_DIR/$MCU_OUTPUT_B2".*
run_make default
rm -rf "$BUILD_WORK_DIR/err/b2" "$BUILD_WORK_DIR/lst/b2" "$objdir"
rm -f "$OUTPUT_DIR/$MCU_OUTPUT_B2".*
echo "Binary Environment Compile Success."
}
run_make() {
local target=$1
# OBJ/LST/ERR/LOG_PATH come from J6P_BUILD_DIR in Makefile.project.part.defines
# (shared with the Windows .bat flow); no need to pass them here.
make -f Makefile -Otarget -j"$JOBS" \
MAKESUPPORT_DIR=../../MakeSupport \
GHS_PATH="$GHS_PATH" \
BUILD_OUTPUT_DIR=../../output \
build_b2=1 \
"$target" \
"${EXTRA_MAKE_ARGS[@]}"
}
make_secure_image() {
echo "********************************************************************************"
echo "make secure image bin..."
local secure_image_script="$IMAGE_DIR/seucre_img/bin2image/FreeRtos/run_hbbin2img.py"
local secure_private_key="$IMAGE_DIR/seucre_img/bin2image/FreeRtos/ia_p256_private.pem"
rm -f "$OUTPUT_DIR/$MCU_OUTPUT_B2.img" "$OUTPUT_DIR/$MCUEXT_OUTPUT_B2.img" "$OUTPUT_DIR/$MCUEXT_OUTPUT_B2.bin"
echo "Processing bin files..."
# --mcu-sram-8m-layout matches build_b2.bat: repack the two SRAM ranges into
# one MCU image; the legacy dual-image split (MCUExt) is not used anymore.
if ! python3 "$secure_image_script" \
"$OUTPUT_DIR/$MCU_OUTPUT_B2.bin" \
"$OUTPUT_DIR/$MCU_OUTPUT_B2.img" \
"$secure_private_key" \
--mcu-sram-8m-layout; then
echo "Python script failed" >&2
return 1
fi
if [[ -f "$OUTPUT_DIR/$MCU_OUTPUT_B2.img" ]]; then
echo "Main image file generated successfully"
[[ -f "$OUTPUT_DIR/$MCUEXT_OUTPUT_B2.img" ]] && echo "Extended image file generated successfully"
[[ -f "$OUTPUT_DIR/$MCUEXT_OUTPUT_B2.bin" ]] && echo "Extended bin file generated successfully"
echo "Make Image Success."
else
echo "Make Image Failed - $MCU_OUTPUT_B2.img not generated." >&2
return 1
fi
}
archive_debug_sidecars() {
local sidecar_dir="$REPO_ROOT/MakeSupport/build/J6P/output"
mkdir -p "$sidecar_dir"
local moved=0 ext f
for ext in dla dle; do
for f in "$SCRIPT_DIR"/*."$ext"; do
[[ -f "$f" ]] || continue
mv -f "$f" "$sidecar_dir/"
moved=$((moved + 1))
done
done
for ext in dla dle dnm elf.rsp; do
for f in "$OUTPUT_DIR"/*."$ext"; do
[[ -f "$f" ]] || continue
mv -f "$f" "$sidecar_dir/"
moved=$((moved + 1))
done
done
((moved)) && echo "[INFO] Debug sidecars archived in $sidecar_dir ($moved files)"
}
copy_artifacts_to_output() {
local artifact
mkdir -p "$OUTPUT_DIR"
echo "[INFO] Copying Board B2 artifacts to output/ ..."
# linker artifacts are emitted directly to OUTPUT_DIR (BUILD_OUTPUT_DIR);
# never source them from App/Appl, stale leftovers must not leak into output
# fastboot script lives in App/Appl with ..\..\output-relative img paths;
# the output copy is rewritten to bare img names (img sits next to it).
local fastboot_script="$SCRIPT_DIR/fastboot_flash_$MCU_OUTPUT_B2.bat"
if [[ -f "$fastboot_script" ]]; then
local fb_content
fb_content="$(<"$fastboot_script")"
fb_content="${fb_content//..\\..\\output\\/}"
printf '%s\n' "$fb_content" >"$OUTPUT_DIR/fastboot_flash_$MCU_OUTPUT_B2.bat"
fi
if [[ -f "$SCRIPT_DIR/ASW/VOYAH_Version.h" ]]; then
cp -f "$SCRIPT_DIR/ASW/VOYAH_Version.h" "$OUTPUT_DIR/VOYAH_Version.h"
fi
# Debug sidecars: allow Trace32 attach directly from output/ (L2.9 scheme)
local debug_script
for debug_script in Lauterbach.bat Lauterbach.cmm breaks.cmm; do
[[ -f "$DEBUG_SCRIPT_DIR/$debug_script" ]] && cp -f "$DEBUG_SCRIPT_DIR/$debug_script" "$OUTPUT_DIR/$debug_script"
done
printf 'ready_for_ci_packaging\n' >"$OUTPUT_DIR/ready_for_ci_packaging"
echo "[INFO] Artifacts copied to output/"
}
run_map_analyzer() {
local map_script="$MAP_DIR/map_analyzer.py"
if [[ ! -f "$map_script" ]]; then
echo "[INFO] MAP analyzer script not found, skipping..."
return 0
fi
# Match build.bat selection priority: AB map first, then B2.
local map_file=
[[ -f "$OUTPUT_DIR/$MCU_OUTPUT_AB.map" ]] && map_file="$OUTPUT_DIR/$MCU_OUTPUT_AB.map"
[[ -z "$map_file" && -f "$OUTPUT_DIR/$MCU_OUTPUT_B2.map" ]] && map_file="$OUTPUT_DIR/$MCU_OUTPUT_B2.map"
if [[ -z "$map_file" ]]; then
echo "[WARN] MAP file not found, skipping analyzer..."
return 0
fi
local ld_file="$SCRIPT_DIR/GenData/Stub/vLinkGen_Template.ld"
echo "[INFO] Running MAP analyzer..."
if ! python3 "$map_script" "$map_file" "$ld_file" --output all --out-dir "$MAP_DIR"; then
echo "[WARN] MAP analyzer failed, skipping..."
return 0
fi
if [[ -f "$MAP_DIR/Vexus_memory_report.html" ]]; then
cp -f "$MAP_DIR/Vexus_memory_report.html" "$OUTPUT_DIR/"
echo "[INFO] MAP report copied to output/"
fi
}
# L3: unpack application prebuilt libraries (.a) declared in App.mak
# (APP_USER_LIBS += ...) into appusrobj/, one subdir per library, duplicate
# member names into dupN/ (base names preserved for .ld object placement).
extract_app_usrlibs() {
local appmak="$SCRIPT_DIR/ASW/App.mak"
[[ -f "$appmak" ]] || return 0
local libs
libs=$(grep -E "^[[:space:]]*APP_USER_LIBS[[:space:]]*\+=" "$appmak" \
| grep -v "^[[:space:]]*#" | sed "s/.*+=[[:space:]]*//" | sed "s/#.*//" | tr "\\\\" "/")
[[ -z "$libs" ]] && return 0
local out="$BUILD_WORK_DIR/appusrobj"
rm -rf "$out"
mkdir -p "$out"
local lib libname ex
for lib in $libs; do
if [[ ! -f "$SCRIPT_DIR/$lib" && ! -f "$lib" ]]; then
echo "[ERROR] APP_USER_LIBS entry not found: $lib" >&2
return 1
fi
[[ -f "$lib" ]] || lib="$SCRIPT_DIR/$lib"
libname=$(basename "$lib" .a)
ex="$out/$libname"
mkdir -p "$ex"
local members=() m
mapfile -t members < <(ar t "$lib")
(( ${#members[@]} )) || { echo "[ERROR] empty archive: $lib" >&2; return 1; }
local -A cnt=()
local singles=()
for m in "${members[@]}"; do cnt[$m]=$(( ${cnt[$m]:-0} + 1 )); done
for m in "${members[@]}"; do
if [[ ${cnt[$m]} -eq 1 ]]; then singles+=("$m"); fi
done
local -A used=()
for m in "${members[@]}"; do
if [[ ${cnt[$m]} -le 1 ]]; then continue; fi
used[$m]=$(( ${used[$m]:-0} + 1 ))
mkdir -p "$ex/dup${used[$m]}"
(cd "$ex/dup${used[$m]}" && ar x -N "${used[$m]}" "$lib" "$m")
done
if [[ ${#singles[@]} -gt 0 ]]; then
(cd "$ex" && ar x "$lib" "${singles[@]}")
fi
echo "[L3] unpacked app library $lib -> $ex"
done
}
build_impl() {
cd "$SCRIPT_DIR"
# Defensive sweep: stale artifacts left by the old App/Appl layout
# must never leak into output (they are gitignored build outputs).
rm -f "$SCRIPT_DIR"/MCU_*.{bin,elf,img,map,hex,dla,dle,dnm,rsp} \
"$SCRIPT_DIR"/MCUExt_*.{bin,elf,img,map,hex,dla,dle,dnm,rsp}
if [[ "$BUILD_MODE" != clean && "$BUILD_MODE" != help ]]; then
# Mirror build.bat: start every publishing build with an empty output folder.
mkdir -p "$OUTPUT_DIR"
find "$OUTPUT_DIR" -mindepth 1 -delete
run_license_check || return $?
fi
write_git_version
# Mirror build_b2.bat: response file and debug sidecar are always regenerated.
rm -f "$OUTPUT_DIR/$MCU_OUTPUT_B2.dnm" "$OUTPUT_DIR/$MCU_OUTPUT_B2.elf.rsp"
case "$BUILD_MODE" in
help)
run_make help
return $?
;;
clean)
run_make clean
return $?
;;
rebuild)
echo "rebuild starting......"
rm -f "$OUTPUT_DIR/$MCU_OUTPUT_B2.bin" "$OUTPUT_DIR/$MCUEXT_OUTPUT_B2.bin"
run_make rebuild || return $?
;;
rel)
rm -f "$OUTPUT_DIR/$MCU_OUTPUT_B2.bin" "$OUTPUT_DIR/$MCUEXT_OUTPUT_B2.bin"
run_make default || return $?
;;
image)
rm -f "$OUTPUT_DIR/$MCU_OUTPUT_B2.elf" "$OUTPUT_DIR/$MCU_OUTPUT_B2.bin" "$OUTPUT_DIR/$MCUEXT_OUTPUT_B2.bin"
run_make default || return $?
;;
libobj)
EXTRA_MAKE_ARGS+=("L3_BUILD_MODE=libobj")
run_make libobjtree || return $?
local tree="$REPO_ROOT/MakeSupport/delivery/platobjtree"
echo "[L3] platform object tree published: $(find "$tree" -name '*.o' | wc -l) objects -> $tree"
# Package the customer kit (object tree + build framework, no source mutation)
local pack_script="$SCRIPT_DIR/tools/dfzy/package_objtree.py"
if [[ -f "$pack_script" ]]; then
python3 "$pack_script" "$REPO_ROOT" "$OUTPUT_DIR/DFRD_objkit_$(date '+%Y%m%d').tar.gz" || return $?
else
echo "[WARN] packaging script not found: $pack_script (skipped)" >&2
fi
return 0
;;
app)
if [[ -z "${L3_PLAT_TREE_ARG:-}" ]]; then
echo "[ERROR] --app requires the platform object tree path" >&2
return 1
fi
# L3_TREE_IN_PLACE: tree dirs must be RELATIVE to App/Appl (absolute
# paths overflow the shell in make $(shell find ...) consumers); the
# trees are consumed in place through stable symlinks, never moved
[[ -d "$L3_PLAT_TREE_ARG" ]] || { echo "[ERROR] platform tree not found: $L3_PLAT_TREE_ARG (default ../../platform_objtree = unpacked-kit layout; pass <plat_tree> explicitly otherwise)" >&2; return 1; }
local plat_abs app_abs
plat_abs=$(cd "$L3_PLAT_TREE_ARG" && pwd)
ln -sfn "$plat_abs" "$BUILD_WORK_DIR/platobjtree"
local app_args=("L3_BUILD_MODE=app" "L3_PLAT_OBJ_DIR=../../MakeSupport/build/J6P/platobjtree")
if [[ -n "${L3_APP_TREE_ARG:-}" ]]; then
# later phase: application ships as a prebuilt object tree
[[ -d "$L3_APP_TREE_ARG" ]] || { echo "[ERROR] app tree not found: $L3_APP_TREE_ARG" >&2; return 1; }
app_abs=$(cd "$L3_APP_TREE_ARG" && pwd)
ln -sfn "$app_abs" "$BUILD_WORK_DIR/appobjtree"
app_args+=("L3_APP_OBJ_DIR=../../MakeSupport/build/J6P/appobjtree")
fi
extract_app_usrlibs || return $?
EXTRA_MAKE_ARGS+=("${app_args[@]}")
rm -f "$OUTPUT_DIR/$MCU_OUTPUT_B2.bin" "$OUTPUT_DIR/$MCUEXT_OUTPUT_B2.bin"
run_make default || return $?
;;
default)
rm -f "$OUTPUT_DIR/$MCU_OUTPUT_B2.bin" "$OUTPUT_DIR/$MCUEXT_OUTPUT_B2.bin"
run_make default || return $?
;;
esac
if [[ ! -f "$OUTPUT_DIR/$MCU_OUTPUT_B2.bin" ]]; then
echo "Make Bin Failed." >&2
return 1
fi
run_size_report || return $?
run_extract_version
if [[ "$BUILD_MODE" == rel ]]; then
make_release_env || return $?
fi
# build_b2.bat keeps image generation enabled for every producing mode.
make_secure_image || return $?
archive_debug_sidecars
copy_artifacts_to_output || return $?
run_map_analyzer
}
mkdir -p "$LOG_DIR"
: >"$LOG_FILE"
START_EPOCH=$(date +%s)
printf '[B2] Build started at %s\n' "$(date '+%Y-%m-%d %H:%M:%S')" | tee -a "$LOG_FILE"
set +e
(set -euo pipefail; build_impl) 2>&1 | tee -a "$LOG_FILE"
BUILD_RESULT=${PIPESTATUS[0]}
set -e
END_EPOCH=$(date +%s)
printf '[B2] Build finished at %s\n' "$(date '+%Y-%m-%d %H:%M:%S')" | tee -a "$LOG_FILE"
printf '[B2] Build duration: %s\n' \
"$(format_duration "$((END_EPOCH - START_EPOCH))")" | tee -a "$LOG_FILE"
if ((BUILD_RESULT != 0)); then
echo "[ERROR] Board B2 build failed! Error code: $BUILD_RESULT" | tee -a "$LOG_FILE" >&2
exit "$BUILD_RESULT"
fi
echo "[INFO] Board B2 build completed successfully"
Step2:
构建纯Windows环境下的编译脚本
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
================================================================================
DFRD_objkit Windows One-Click Build Runner
Platform: Horizon Journey 6P (J6P) B2 Board
Compiler: Green Hills MULTI ARM Compiler (ccarm.exe / comp_202114)
================================================================================
"""
import os
import sys
import glob
import subprocess
import time
def find_ghs_dir():
candidates = [
r"D:\ghs\comp_202114",
r"C:\ghs\comp_202114",
r"D:\ghs\comp_202214",
r"C:\ghs\comp_202214",
]
if "GHS_PATH" in os.environ and os.path.exists(os.environ["GHS_PATH"]):
return os.environ["GHS_PATH"]
for c in candidates:
if os.path.exists(os.path.join(c, "ccarm.exe")):
return c
return None
def parse_app_mak(appl_dir):
app_mak = os.path.join(appl_dir, "ASW", "App.mak")
sources = []
includes = []
if not os.path.exists(app_mak):
return sources, includes
with open(app_mak, "r", encoding="utf-8", errors="ignore") as f:
for line in f:
line = line.strip()
if line.startswith("#"):
continue
if "APP_USER_SOURCES" in line and "+=" in line:
val = line.split("+=")[-1].strip().replace("/", os.sep).replace("\\", os.sep)
if val:
full_p = os.path.join(appl_dir, val)
if os.path.exists(full_p):
sources.append(full_p)
elif "ADDITIONAL_INCLUDES" in line and "+=" in line:
val = line.split("+=")[-1].strip().replace("/", os.sep).replace("\\", os.sep)
if val:
full_p = os.path.join(appl_dir, val)
if os.path.exists(full_p):
includes.append(full_p)
return sources, includes
def build_windows():
print("="*80)
print(" [J6P B2] DFRD_objkit Windows One-Click Build System")
print("="*80)
script_dir = os.path.abspath(os.path.dirname(__file__))
# If placed in App/Appl or in root
if os.path.exists(os.path.join(script_dir, "ASW")):
appl_dir = script_dir
repo_root = os.path.abspath(os.path.join(appl_dir, "..", ".."))
else:
repo_root = script_dir
appl_dir = os.path.join(repo_root, "App", "Appl")
ghs_dir = find_ghs_dir()
if not ghs_dir:
print("[ERROR] Could not find GHS compiler installation (ccarm.exe)!")
print(" Please set GHS_PATH=D:\\ghs\\comp_xxxxxx or ensure D:\\ghs\\comp_202114 exists.")
return False
cc_exe = os.path.join(ghs_dir, "ccarm.exe")
gsize_exe = os.path.join(ghs_dir, "gsize.exe")
print(f"[ENV] Repo Root: {repo_root}")
print(f"[ENV] App Directory:{appl_dir}")
print(f"[ENV] GHS Toolchain:{ghs_dir}")
out_dir = os.path.join(repo_root, "output")
os.makedirs(out_dir, exist_ok=True)
build_work_dir = os.path.join(repo_root, "MakeSupport", "build", "J6P")
obj_b2_dir = os.path.join(build_work_dir, "obj", "b2")
os.makedirs(obj_b2_dir, exist_ok=True)
# 1. Generate git_version.h
git_ver_h = os.path.join(appl_dir, "git_version.h")
commit_id = "0000000"
try:
git_res = subprocess.run(["git", "rev-parse", "--short", "HEAD"], capture_output=True, text=True, cwd=repo_root)
if git_res.returncode == 0 and git_res.stdout.strip():
commit_id = git_res.stdout.strip()
except Exception:
pass
date_str = time.strftime("%Y-%m-%d")
time_str = time.strftime("%H:%M:%S")
with open(git_ver_h, "w", encoding="utf-8") as f:
f.write(f'#define GIT_VER_SHORT_COMMIT_ID "{commit_id}"\n')
f.write(f'#define GIT_VER_SHORT_COMMIT_ID_U64 0x{commit_id}ULL\n')
f.write(f'#define BUILD_COMPUTER_NAME "{os.environ.get("COMPUTERNAME", "WIN-BUILD")}"\n')
f.write(f'#define BUILD_USER_NAME "{os.environ.get("USERNAME", "builder")}"\n')
f.write(f'#define BUILD_DATE "{date_str}"\n')
f.write(f'#define BUILD_TIME "{time_str}"\n')
print(f"\n[Step 1/5] Generated build info header: git_version.h")
# 2. Collect include paths
inc_dirs = [
os.path.join(ghs_dir, "include", "arm"),
os.path.join(ghs_dir, "ansi"),
]
for root, dirs, files in os.walk(repo_root):
if any(f.endswith('.h') for f in files):
if 'MakeSupport' not in root and 'output' not in root and 'platform_objtree' not in root:
inc_dirs.append(root)
# Extra includes from App.mak
asw_srcs_from_mak, asw_incs_from_mak = parse_app_mak(appl_dir)
for d in asw_incs_from_mak:
if d not in inc_dirs:
inc_dirs.append(d)
inc_flags = [f"-I{d}" for d in inc_dirs if os.path.exists(d)]
# Common CFLAGS for Horizon J6P ARM Cortex-R52
cflags = [
"-cpu=cortexr52",
"-c99",
"-noobj",
"--long_long",
"-G",
"-dual_debug",
"-farcalls",
"-dwarf2",
"-no_misalign_pack",
"-pragma_asm_inline",
"--gnu_asm",
"-align8",
"-Osize",
"--diag_suppress=1",
"-DDISABLE_MCAL_INTERMODULE_ASR_CHECK",
"-DMCU_SRAM_8M_LAYOUT",
"-DBRS_PLATFORM_ArmCommon",
"-DBRS_COMP_GreenHills",
"-DMATRIX6P_A_ADAPTATION",
] + inc_flags
# 3. Compile ASW sources
if not asw_srcs_from_mak:
# Default fallback
asw_srcs_from_mak = [
os.path.join(appl_dir, "ASW", "DfzyDemo", "DfzyDemo.c"),
os.path.join(appl_dir, "ASW", "EthProxy", "STA_Someip_Com.c"),
os.path.join(appl_dir, "ASW", "EthProxy", "EthProxy_SWC.c"),
]
asw_objs = []
print(f"[Step 2/5] Compiling {len(asw_srcs_from_mak)} ASW application sources...")
for src in asw_srcs_from_mak:
if not os.path.exists(src):
continue
rel_src = os.path.relpath(src, appl_dir)
obj_name = os.path.splitext(os.path.basename(src))[0] + ".o"
out_obj = os.path.join(obj_b2_dir, "ASW", os.path.dirname(rel_src), obj_name)
os.makedirs(os.path.dirname(out_obj), exist_ok=True)
cmd = [cc_exe, "-c", src, "-o", out_obj] + cflags
res = subprocess.run(cmd, capture_output=True, text=True, cwd=appl_dir)
if res.returncode != 0:
print(f"\n[ERROR] Compilation failed for {rel_src}:")
print(res.stderr)
return False
asw_objs.append(out_obj)
print(f" [CC OK] {rel_src} -> {os.path.basename(out_obj)}")
# 4. Collect precompiled platform objects & SafetyLib
plat_tree = os.path.join(repo_root, "platform_objtree")
print(f"[Step 3/5] Loading precompiled platform object tree...")
plat_objs = []
if os.path.exists(plat_tree):
for root, dirs, files in os.walk(plat_tree):
for f in files:
if f.endswith(".o"):
plat_objs.append(os.path.join(root, f))
print(f" Loaded {len(plat_objs)} platform object files from platform_objtree.")
extra_libs = []
safety_lib = os.path.join(appl_dir, "SafetyLib", "SafetyLib.a")
if os.path.exists(safety_lib):
print(f" Loaded Safety Library: SafetyLib.a")
extra_libs.append(safety_lib)
# 5. Link Target ELF / BIN / HEX / MAP
target_name = "MCU_L4_H56E_V1.0"
target_base = os.path.join(out_dir, target_name)
target_elf = target_base + ".elf"
target_map = target_base + ".map"
target_hex = target_base + ".hex"
target_bin = target_base + ".bin"
target_img = target_base + ".img"
linker_script = os.path.join(appl_dir, "GenData", "Stub", "vLinkGen_Template.ld")
rsp_file = target_elf + ".rsp"
all_objs = asw_objs + plat_objs + extra_libs
with open(rsp_file, "w", encoding="utf-8") as f:
for obj in all_objs:
f.write(f'"{obj.replace(os.sep, "/")}"\n')
print(f"[Step 4/5] Generated linker response file ({len(all_objs)} objects): {os.path.basename(rsp_file)}")
ldflags = [
"--preprocess_linker_directive_full",
"-nostartfiles",
"-e=intvect_CoreExceptions",
linker_script.replace(os.sep, "/"),
"-o", target_elf.replace(os.sep, "/"),
"-cpu=cortexr52",
"-pragma_asm_inline",
"-g",
"-keepmap",
"-dual_debug",
f"-map={target_map.replace(os.sep, '/')}",
f"-hex={target_hex.replace(os.sep, '/')}",
f"-memory={target_bin.replace(os.sep, '/')}",
"-thumb",
"-thumb_lib",
"-dwarf2",
"-Ogeneral",
"-Omax",
"-Xgvared",
"--no_vla",
"--gnu_asm",
"--no_commons",
"-no_discard_zero_initializers",
"-preprocess_assembly_files",
"-split_data_sections_by_alignment",
"-individual_data_sections",
"-individual_pragma_data_sections",
"-individual_function_sections",
"-individual_pragma_function_sections",
"-individual_attribute_data_sections",
"-individual_attribute_function_sections",
"-individual_section_name_extra_dot",
"-align8",
"--unknown_pragma_errors",
"--incorrect_pragma_errors",
"-passsource",
"-globalcheck=normal",
"-mapfile_type=2",
"-Man", "-Ml", "-Mx", "-Mu",
"-ignore_debug_references",
"-delete",
"-data_delete",
"-retainlocals",
f"@{rsp_file.replace(os.sep, '/')}"
]
print(f"[Step 5/5] Linking final firmware: {os.path.basename(target_elf)} ...")
t0 = time.time()
res = subprocess.run([cc_exe] + ldflags, capture_output=True, text=True, cwd=appl_dir)
t1 = time.time()
if res.returncode != 0:
print(f"\n[ERROR] Link failed (Return Code: {res.returncode}):")
print(res.stderr)
return False
# Generate signed image (.img)
sign_script = os.path.join(repo_root, "MakeSupport", "image", "J6P", "seucre_img", "bin2image", "FreeRtos", "run_hbbin2img.py")
sign_key = os.path.join(repo_root, "MakeSupport", "image", "J6P", "seucre_img", "bin2image", "FreeRtos", "ia_p256_private.pem")
if os.path.exists(sign_script) and os.path.exists(sign_key) and os.path.exists(target_bin):
print(f"\n[Pack] Packaging signed boot image (.img)...")
sign_cmd = [sys.executable, sign_script, target_bin, target_img, sign_key, "--mcu-sram-8m-layout"]
subprocess.run(sign_cmd, capture_output=True, text=True, cwd=appl_dir)
print("\n" + "="*80)
print(f" [SUCCESS] Build completed successfully in {t1-t0:.2f} seconds!")
print("="*80)
print(f"Firmware output artifacts located in: {out_dir}")
for ext, path in [("ELF", target_elf), ("BIN", target_bin), ("HEX", target_hex), ("IMG", target_img), ("MAP", target_map)]:
if os.path.exists(path):
print(f" * [{ext:<3}] {os.path.basename(path):<28} ({os.path.getsize(path)/1024/1024:.2f} MB / {os.path.getsize(path):,} bytes)")
# Print size summary
if os.path.exists(gsize_exe) and os.path.exists(target_elf):
print("\n=== FIRMWARE MEMORY LAYOUT SUMMARY ===")
res_size = subprocess.run([gsize_exe, target_elf], capture_output=True, text=True)
lines = res_size.stdout.strip().split("\n")
# print header and total
for line in lines[:5]:
print(line)
if len(lines) > 10:
print(" ...")
for line in lines[-5:]:
print(line)
return True
if __name__ == "__main__":
success = build_windows()
sys.exit(0 if success else 1)
最后:
1.脚本之间的转换现在用AI十分的快捷,能极大的提高开发效率。但是特么的现在极高的开发效率被极多的开发任务又抹平了。
2.用点好的AI,别被垃圾的费钱的AI道德绑架了。

浙公网安备 33010602011771号