面向 汽车 MCU(Infineon AURIX TC3x/TC4x、NXP S32K/S32R、Renesas RH850 等)
BSP / MCAL / 中间件 / 标定 工程师,按"工作场景 → 命令 → 实战片段"组织。
TASKING ctc | 3–5× | |
make -j$(nproc) | ||
objdumpreadelf、nm原生 | ||
core.fsync, partial clone友好) | ||
| iSYSTEM 调试器 | 直接 USB / ETH / TCP, 协议原生 |
一句话:Windows + IDE 给"研发期人肉调试",Linux + 脚本 给"批构建 / 回归 / CI / 自动化调试"。本文按场景归纳命令。
pwd -L/-P | pwd -P真路径,排除软链 | |
lsll、ls -al | ll是 ls -l常用别名) | Build/obj下 ELF 大小 |
cd -pushd/ popd | ||
mkdir -p a/b/c | inc/inc_private目录树 | |
rm -rf build/* | ||
cp -r src dstinstall -m 644 in out | ||
mv | ||
touch | ||
ln -sfn | ~/bin | |
tree -L 2 -I 'build|.git' | ||
realpathreadlink -f | ||
statfile、file -z | ||
fuser filelsof file | ||
inotifywait -m . | ||
watch -n 5 |
# 1) 编译产物单独目录,不在源码里找 ELF
cd ~/work/aurix_tc39x/projectA && ls -lh build/out/*.elf
# 2) 仓库里谁最胖(找出意外提交的大件)
du -sh * .[!.]* | sort -hr | head -20
# 3) 工具链升级,链接只动一处
ln -sfn /opt/tasking_v6.3r1 ~/tools/tasking
# 4) 批量改后缀
for f in *.c; do mv -- "$f" "${f%.c}.cpp"; done
# 5) 工程根目录 template(autogen)
mkdir -p {src,include,test,scripts,tools,docs,ci}
# 6) 同步工具链脚本给同事(用 install,带权限)
install -m 0755 scripts/build.sh /opt/share/build.sh
# 7) 清空构建但保留 git index 目录
find build/ -mindepth 1 -maxdepth 1 -exec rm -rf {} +
# 8) 谁在锁住 ELF,造成下次 gdb 报错
fuser build/out/firmware.elf
# 或更详细
lsof build/out/firmware.elf
# 9) 新人第一件事:开 autocd / dirspell / cdspell
echo "shopt -s autocd dirspell cdspell" >> ~/.bashrc
# 10) 大仓里小心 `rm -rf *`——在脚本里强约束
shopt -s failglob
rm -rf -- "$builddir"/* # 一定要带 --cat | .c / .h直接看 | |
lessmore | .map, .log | |
head -ntail -n、tail -F | tail -F build.log | |
nl | ||
wc -lwc -lcw | ||
diff -ruvimdiff、meld | ||
vimnvim/ nano | ||
batcat) | .map/ .log时体验更好 | |
hexdump -Cxxd、hexyl | ||
jqyq(YAML) |
# 1) 反汇编 + 看 Busy 函数
objdump -dl firmware.elf | less
# 2) tail 复合实战:一边构建一边把 warning/error 拣出来
make -j8 2>&1 | tee build.log | grep -E 'warning:|error:|undefined|multiple def'
# 3) 大 map 文件只看 RAM 段
sed -n '/^Linker script and memory map/,$p; /\(RAM\|RAM_NV\)/,/0x/{p}' project.map | less
# 4) vim:删空行 + 改换行 + 内置 diff
:g/^\s*$/d
:set ff=unix
:diffthis
# 5) bat 取代 cat,看 .map / .ld 滚上下舒服
bat --style=plain build/project.map
# 6) 看 .hex 是否包含某段
xxd firmware.hex | grep -E 'DEADBEEF|12345678'
# 7) vim 中:term 终端 + 跑 make
:term make -j8
# 8) ARXML 里挑所有 5 秒周期的 EcuC 模块
xmllint --xpath '//*[contains(@SHORT-NAME,"EcuC")]/*' Config/Config_EcuC.arxml
# 9) sed 三招,车规代码常备
sed -i 's/Copyright 2022/Copyright 2026/g' $(find . -name '*.[ch]')
sed -i '/^[[:space:]]*\/\/ TODO/d' app.c # 一键删 TODO 注释
sed -i 's/[[:space:]]\+$//' *.c # 去尾空白
# 10) awk 把 .map 里最大的 30 个函数拎出来
awk 'index($0," .text.")>0 {sym=$0} /^ \.text/ {p=1} p && /\.text\./{p=0} p' project.map \
| awk 'NF>=2 && $1 ~ /^[0-9a-f]+$/{print $1,$5,$6,$7,$8}' | sort -k1 | head -30
# 11) 列 git ls-files 出来的文件,grep 不进 .git 目录
git ls-files | xargs -n1 wc -l | sort -nr | headchmod 755 run.shchmod -R u+rwX,g+rwX,o-rwx | |
chown -R user:group dir | |
sudo -Esudo -i | |
umask 022 | |
envprintenv、export VAR=... | |
whichtype/ command -v | |
alias ll='ls -alF' | ~/.bashrc |
mkdir -m 0750 -p | |
xargs -d'\n' |
车规工程里 TASKING / Keil / IAR 的 LIC server 锁 eth0MAC, 写脚本需要把环境拉满:
#!/usr/bin/env bash
# scripts/build.sh —— 车规工程的标准入口脚本
set -euo pipefail
: "${PROJECT_DIR:=$(cd "$(dirname "$0")/.." && pwd)}"
: "${BUILD_DIR:=$PROJECT_DIR/Build}"
: "${TARGET:=tc39x}"
: "${BUILD_TYPE:=release}"
export TASKING_HOME=/opt/tasking_v6.3r1
export LM_LICENSE_FILE=27000@licsrv
export LM_PROJECT=@licsrv:~/.flexlmrc
export PATH="$TASKING_HOME/bin:$PATH"
echo ">>> [$TARGET / $BUILD_TYPE]"
mkdir -p "$BUILD_DIR/$TARGET/$BUILD_TYPE"
cd "$BUILD_DIR/$TARGET/$BUILD_TYPE"
cmake -G Ninja \
-DCMAKE_BUILD_TYPE="$BUILD_TYPE" \
-DCMAKE_TOOLCHAIN_FILE="$PROJECT_DIR/toolchain/${TARGET}.cmake" \
"$PROJECT_DIR"
cmake --build . --target firmware.elf -- -k
size firmware.elf
cp firmware.elf "$PROJECT_DIR/dist/$TARGET-$BUILD_TYPE.elf"# 干净的脚本模板:set -euo pipefail + trap + mktemp + getopts
#!/usr/bin/env bash
set -euo pipefail
trap 'echo "ERROR line $LINENO" >&2; exit 1' ERR
# 临时目录,退出自动清
tmp=$(mktemp -d); trap 'rm -rf "$tmp"' EXIT
while getopts ":c:t:hv" opt; do
case $opt in
c) cfg=$OPTARG ;;
t) target=$OPTARG ;;
v) VERBOSE=1 ;;
h) sed -n '2,/^####/p' "$0"; exit 0 ;;
*) echo "Bad option: -$OPTARG"; exit 2 ;;
esac
done
# 安全拼命令,避免 split
find src -name '*.c' -print0 | xargs -0 -n1 -I{} echo "Compiling: {}"# 系统共享的工具链,放进 /opt 后建群组
sudo groupadd eng
sudo chown -R :eng /opt/tasking_v6.3r1
sudo chmod -R g+rwX /opt/tasking_v6.3r1
sudo usermod -aG eng $USER
newgrp eng # 立即生效uname -acat /etc/os-release | |
nproclscpu | |
free -h/proc/meminfo | |
df -h -Tdu -sh | |
tophtop/ glances/ btop | |
ps auxfpstree -p/ pgrep -f ctc | |
kill -TERM-9 | |
uptimeiostat 1、vmstat 1、mpstat -P ALL 1 | |
lsof -p PIDstrace -p PID、perf top -p PID | |
numactl --cpunodebind=0 --membind=0 ./a.out |
# 1) 编译是不是吃满了
make -j$(nproc) &
sleep 10 && mpstat -P ALL 1 5
# 2) 谁在疯狂写盘
iotop -oP # 抓到 ctc 在烧,判断是缺内存 swap 还是 LTO
# 或
pidstat -dl 1 # 看每个进程的 IO 量
pidstat -w 1 # 看上下文切换
# 3) 构建卡住,怀疑 ctc 在死等文件
pgrep -af ctc
pstree -ap $(pgrep -of 'ctc.*main\.c')
# 4) 看编译进程当前在打开哪个文件
lsof -p $(pgrep -of ctc) | head
# 5) 看是不是锁住了
ls -l /work/.git/index.lock
fuser -v /work/.git/index.lock
# 6) 内存吃紧,swap 高,主动释放 dentry
sync && echo 3 > /proc/sys/vm/drop_caches # 仅 root
# 7) NUMA 系统上,绑核跑 distcc server(避免跨 socket RTT)
numactl --cpunodebind=0 --membind=0 distccd --no-detach --daemon
# 8) perf 抓 ctc 的热点(看哪个 phase 慢)
perf record -F 99 -p $(pgrep -of ctc) -g -- sleep 5
perf script | stackcollapse-perf.pl | flamegraph.pl > flame.svg
# 9) 系统级 sar(需要 sysstat),跑一日次日整改
sudo apt install sysstat
sar -r -n DEV -u 5 60 > /tmp/sar_daily.txt
# 10) "哪些进程用了网络"——车规 OTA 用得上
ss -tunp | head -20
ss -bp '( sport = :443 )'grep -RInrg/ ag | |
findfd | |
sed | |
awk | |
sortuniq -c/ cut/ tr/ xargs | |
fzffpp(路径) | |
agrg(ripgrep) |
# 1) 找工程里所有 TODO
rg -n --colors 'line:yellow' 'TODO|FIXME' .
# 2) 找谁在用未定义的宏 / 老 API
rg -n --no-heading '\bUNUSED\b' src/
# 3) 找 3 万行内超过 250 列的 source(大概率复制粘贴)
rg -n '.{250,}' src/
# 4) 看哪个 .c 包含最多的 #include(代码味道)
rg -n '^#include' src/ --type c | awk -F: '{print $1}' | sort | uniq -c | sort -rn | head
# 5) AUTOSAR 模块版本一致性扫描
rg -n --hidden 'AR-VERSION\s*=' third_party/ | sort -t: -k2 -u
# 6) find 实战:C 文件中超过 100 KB 的,定位异常
find src -name '*.c' -size +100k -printf '%s %p\n' | sort -nr
# 7) find 实战:7 天内修改过的 build.sh
find scripts -name '*.sh' -mtime -7 -print
# 8) sed 一行把 team 旧版权改新版权
find . -type f \( -name '*.c' -o -name '*.h' \) | xargs sed -i 's/Copyright 2022/Copyright 2026/g'
# 9) sed 把所有 K&R 函数定义改成 ANSI
find src -name '*.c' | xargs sed -i 's/^\([A-Za-z_]\w*\)\s*(/&/
# 10) awk: 把 .map 里每个 .text 里函数按 size 排
awk '
/\.text\.[0-9]+/ {block=$1}
/0x[0-9a-f]+/ && $0 ~ /^0x/ {sym[block]++; bytes[block]+=($1+0)}
END { for (b in bytes) printf "%-30s %10d %5d\n", b, bytes[b], sym[b] }
' project.map | sort -k2 -nr | head
# 11) 找 ELF 里包含的字符串 token(避免误删)
strings firmware.elf | rg -i 'CAN_|BSW_|OEM_' | sort -u
# 12) fzf + 工具:交互式跳到工程里的任一 BSP
fd -t d -d 2 . ~/work/bsp | fzf | cd
# 13) GNU parallel(替代 xargs,车规批量跑测试用例用)
fd -e c . test/ | parallel -j8 --bar make test SUITE={/}
# 14) rg 排除 noise:仓库 + 不进 build
rg -n 'TODO' --hidden --glob '!build/**' --glob '!.git/**'
# 15) 找 a2l 里的 calibrated variable 总数
rg -c '<MEASUREMENT>' calibration.a2lssh user@host | |
scpsftp | |
rsync -avzP | |
curl -Owget | |
git clone | |
ping -c 3mtr/ traceroute -T | |
ss -tulpn | gdbserver、licd) |
nc -lvnp 3333 | |
sshfs user@host:/path ~/mnt | |
autossh -M 0 -o "ServerAliveInterval 10" ... | |
mosh user@host |
# 1) rsync 增量同步 BSP,排除 build / .git
rsync -avzP -e ssh \
--exclude '.git/' --exclude 'Build/' --exclude '*.bak' \
/work/aurix_bsp/ user@buildsrv:/srv/bsp/
# 2) --dry-run 先核对不会动什么
rsync -avzPn -e ssh src/ user@host:dst/
# 3) 把 .elf 烧写设备推给小批量车队的 gbox
rsync -avzP build/out/*.elf user@gbox:/srv/ota/staged/
# 4) ssh 配 alias + 自动转发 license 端口
cat >> ~/.ssh/config <<'SSH_EOF'
Host buildsrv
HostName 10.0.5.42
User wang
IdentityFile ~/.ssh/id_ed25519
LocalForward 27000 10.0.5.42:27000 # 转发 Flexlm
ServerAliveInterval 30
Compression yes
Host gbox
HostName 10.0.8.21
User dev
ProxyJump buildsrv # 跳板
SSH_EOF
# 5) autossh 防止 debug 断开
autossh -M 0 -N \
-o "ServerAliveInterval 10" -o "ServerAliveCountMax 3" \
-L 3333:127.0.0.1:3333 user@target # 本地 3333 -> 远端 gdbserver
# 6) 拷贝到多机并行(车规机柜)
parallel -j5 "rsync -azP --delete build/out/ {}:/srv/ota/" \
::: host1:host2:host3:host4:host5
# 7) 拉公司 Nexus 上的 MCAL 包(可能要 token)
curl -L -H "Authorization: Bearer $NEXUS_TOKEN" \
-o mcal-aurix-v6.5.zip https://nexus.example.com/mcal/AURIX/MCAL-6.5.zip
# 8) 局域网发现:License 端口 + iSYSTEM 守护端口
ss -tulpn | grep -E '27000|1234|3333|20000'
# 9) 把远端 PC 目录直接挂进来当本地路径
sshfs user@buildsrv:/work ~/mnt/build
# 10) netcat 写一个临时 HTTP proxy(迫不得已时)
nc -lvnp 8080 -c "echo -e 'HTTP/1.0 200 OK\r\n\r\nOK'; echo"make -j$(nproc) -k | |
cmake -B build -G Ninja | |
scons -j8 | |
ninja -C build -t targets | |
ctc -t TC39XB -D__CPU__=tc39xb | |
nmreadelf、objdump、size | |
compcertkirin | |
cloctokei | |
pycscopegtags、ctags -R | |
bear -- make all |
# 姿态 A:直接 make + TASKING makefile
cd projectA/Build
export TASKING_HOME=/opt/tasking_v6.3r1
export LM_LICENSE_FILE=27000@licsrv
export PATH="$TASKING_HOME/bin:$PATH"
make -f makefile_tc39x BUILD=release all
# 姿态 B:Eclipse headless CDT build
/opt/tasking_v6.3r1/eclipse/eclipse \
-noSplash -application org.eclipse.cdt.managedbuilder.core.buildheadless \
-data ~/workspace -import /work/proj -build tc39x/release -vm /usr/bin/java
# 姿态 C:cmake 加 toolchain 文件
cmake -B build/tc39x -G Ninja \
-DCMAKE_TOOLCHAIN_FILE=toolchain/tasking-tc39x.cmake \
-DBSP_DIR=third_party/bsp \
-DCMAKE_BUILD_TYPE=Release
# 当时编译首次释放脚本
scripts/build.sh -t tc39x -vtoolchain/tasking-tc39x.cmake:
set(CMAKE_SYSTEM_NAME Generic)
set(CMAKE_C_COMPILER ctc)
set(CMAKE_CXX_COMPILER ctc++)
set(CMAKE_C_FLAGS_INIT "-t TC39XB -D__CPU__=tc39xb --iso99 --float-honor-inf")
set(CMAKE_CXX_FLAGS_INIT "-t TC39XB -D__CPU__=tc39xb --iso99 --float-honor-inf")
set(CMAKE_ASM_COMPILER ctc)
set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)
set(CMAKE_SYSTEM_PROCESSOR tricore)# 1) ccache 切到 NVMe 上的大目录
export CCACHE_DIR=/opt/ccache
mkdir -p "$CCACHE_DIR"
ccache --max-size=50G
ccache --set-config compression=1 # 老的吞吐不够, 默认开压缩更划算
CCACHE_PREFIX=distcc ccache ctc -O2 -c core.c
# 2) 跨机 distcc(局域网小机房, 1Gbps)
export DISTCC_HOSTS="build01 build02 build03 build04"
export DISTCC_BACKOFF=1
make -j32 CC='distcc ctc' CXX='distcc ctc++'
# 3) 用 pump 模式(更激进)
export DISTCC_PUMP=1
# 4) 命中率统计
ccache -s
ccache -p --verbose
# 5) sccache(Rust 工具,但也支持 c/c++,s3 后端)
RUSTC_WRAPPER=sccache sccache ctc -O2 -c core.c# 1) 看每个 section 在 Flash 的占用
readelf -S firmware.elf | grep -E 'PROGBITS|NOBITS'
readelf -l firmware.elf | head
# 2) 看链接后函数落在哪
nm --size-sort -r firmware.elf | head -30
# 3) 把内存布局画成 .svg, 评审用
python3 -c '
import re, sys
data = open("project.map").read()
# 简化 parse — 实际写可以调 parseMap()
print("map parsed") '
# 4) 改完 ld 脚本后,看 warning
ld -T tc39x.ld -Map=out.map -no-warn-rwx-segment ./*.o 2>&1 \
| rg -i 'warning|error|leftover'
# 5) 看固件里 RAM 占多少
size -A firmware.elf# Cppcheck(车规项目内网常用)
cppcheck --enable=all --inline-suppr \
--suppress=missingIncludeSystem --platform=tricore \
--suppress=configurationNotChecked \
-i Build -i third_party -j$(nproc) src/
# Cppcheck 生成 sarif, 接 Sarif Viewer / GitHub Code Scanning
cppcheck --enable=all ... --rule-file=mapping.txt --output=sarif --output-file=result.sarif src/
# 商业工具(LDRA / Polyspace / Vector vADASdev / Parasoft / Coverity)
LDRA /path/to/testfile.prj /-batch
polyspace-code-prover -options batch.opt
# clang-tidy 车规 checklist
clang-tidy --checks='bugprone-*,cert-*,misc-*,readability-*' \
-p build/compile_commands.json src/core.c车规嵌入式几乎不用 GDB,iSYSTEM winIDEA覆盖 AURIX、C2000、Cortex-M/R、RH850 等目标;
在 Linux 上能整脚本化,通过.dmm脚本 +Isystem.CLI.Runner接入 CI。
~/work/aurix_proj/
├── workspace.iws
├── proj.iwd
└── scripts/
├── probe.dmm
├── flash.dmm
└── dump_calibration.dmmiSYSTEM 的脚本扩展名是
.dmm(debugger macro memory),语法和别家接近但风格自有特征。
export ISYSTEM_HOME=/opt/isystem
# GUI
$ISYSTEM_HOME/bin/winidea64 workspace.iws &
# Headless:通过 iSYSTEM CommandLineRunner
"$ISYSTEM_HOME/cmdline/Isystem.CLI.Runner.exe" \
--workspace workspace.iws \
--run scripts/probe.dmm
# 批量(d 一组工况)
for f in scripts/auto/*.dmm; do
echo ">>> $f"
"$ISYSTEM_HOME/cmdline/Isystem.CLI.Runner.exe" \
--workspace workspace.iws --run "$f" \
| tee -a auto_$(date +%F).log
done.dmm脚本片段; scripts/probe.dmm —— reset + 跑 main + 显示寄存器
Reset
Go.Main
Break.Set app_main_loop
Go
Wait STATE.PROGRAM()
Register.View
EXIT
; scripts/dump_calibration.dmm —— 标定区 dump
LOCAL &addr &size
&addr = 0x80030000
&size = 0x4000
Memory.Save "out/calib_dump.bin" &addr /Size &size
EXIT
; scripts/flash.dmm —— 烧到内置 Flash
Memory.Load "build/out/firmware.hex" /Verify
EXIT
; scripts/watch_watchdog.dmm —— 看门狗到期前的现场
Break.Set T100ms_Watchdog /Write
Go
Wait STATE.PROGRAM()
Print "Watchdog timeout arrived, captured context"
EXIT
Connect
Reset.Pin
Memory.Load "build/out/firmware.elf" /DEBUG /CODE /RELAX
EXITlsusbVID=0x21bf), sudo icd_usb start | ||
Connect | SetConnect RESET | |
ctc -g3--debug-info | ||
sudo systemctl restart isystem |
调试器负责"把信息捞出来",怎么还原语义留给这层:
# 1) PC → 源码(崩溃栈还原)
addr2line -e firmware.elf -f 0x80001234 0x80001288
# 2) demangle + 谁最大(看哪些 function 撑胖了)
nm --size-sort -r firmware.elf | head -30 | c++filt
# 3) ELF section + Flash 占比
readelf -S firmware.elf | grep -E 'PROGBITS|NOBITS'
size -A firmware.elf
# 4) 反汇编特定函数 + 反注释
objdump -d --disassemble=CanIf_TxConfirmation firmware.elf | less
# 5) 二进制字符串(库名 / OEM 标识 / OTA token)
strings firmware.elf | sort -u > /tmp/strs.txt
# 6) 嵌入签名 / 头信息
binwalk -e firmware.elf -C /tmp/binwalk_out/
readelf -a firmware.elf | head
# 7) 静态分析 / MISRA
cppcheck --enable=all --inline-suppr --platform=tricore \
-i Build -i third_party -j$(nproc) src/
# 8) 地图文件解析:谁占用 Flash 最多
awk '/^\.text/ {p=1} /^\.(\.|rodata|data|bss)/ {p=0} p' project.map \
| awk '$1 ~ /^0x/ {print $1, $5}' | sort -k1 | head
# 9) 反汇编里长 > 200 行的"巨函数"
objdump -d firmware.elf \
| awk '/^[0-9a-f]+ <[^>]+>:/{sym=$0; cnt=0; next} /^[ \t]/{cnt++} /^$/{if(sym && cnt>200){print sym, cnt}; sym=""}'
# 10) 看 ICU 段,把 .text 里的所有函数列出(给覆盖率工具)
nm --defined-only -l firmware.elf \
| rg ' [Tt] ' | awk '{print $3}' \
| xargs -I{} c++filt --no-demangle <<< "{}" > coverage.lst车规项目常常受 ASPICE / ISO 26262 / 功能安全约束,分支策略、追溯、签名都比普通后端严得多。
git config --global init.defaultBranch main
git config --global core.autocrlf input # 提交以 LF, checkout 自动转
git config --global core.filemode false # 容器 / 共享编译机必备
git config --global core.pager 'less -FRX'
git config --global core.fsmonitor true # 把 fsmonitor 套起来
git config --global commit.gpgsign true # 车规要求每个 commit 可追溯
git config --global user.signingkey ABB9C72D... # 团队共享 key
git config --global user.name "Wang XXX"
git config --global user.email "wang@oem.com"
git config --global pull.ff only # 显式拒绝 fast-forward 之外
git config --global push.autoSetupRemote true # push 时自动建同名词
git config --global rebase.autoStash true # 隐藏未提交再 rebase
git config --global rebase.missingCommits warn
# 2.x 系列(≥ 2.32):用 switch / restore 替代 checkout,出厂语义
git switch feature/canif-asr422
git restore --staged file.c# 1) 拉 / 切 / 同步(rebase 防止噪声合井)
git fetch origin
git switch feature/canif-asr422
git pull --rebase --autostash
# 2) 提交流程(车规常要求 review 每个 hunk)
git add -p # s/y/n/q 逐块过
git status
git diff --staged
git commit -m "CANIF-321: fix NM timeout in PNC0 transition"
git push
# 3) 同步 fork / mirror
git remote add upstream git@internal.git:asw/bsp.git
git fetch upstream
git rebase upstream/main
# 4) 仓库 dry-run:提交遗漏大文件?(如 .elf / .a)
git rev-list --objects --all | sort -k2 | uniq | sort -rn | head
# 5) 找谁提交了 MCU-spec 上不允许的字符(CI 也可走这个)
git grep -P "[^\x00-\x7F]" -- '*.c' '*.h'
# 6) 团队要求 DCO / Signed-off-by(很多车厂硬性)
git config alias.commit 'commit -s'
git config alias.amend 'commit -s --amend'# .gitattributes — 仓库根目录下
* text=auto eol=lf
*.c *.h *.md text eol=lf
*.elf *.bin *.hex *.a *.so binary
*.arxml *.dbc text # ARXML diff 友好
*.arxml diff=arxml
*.dbc diff=dbc# 1) Git LFS 装一遍
git lfs install
git lfs track "*.elf" "*.bin" "*.hex" "*.arxml"
git lfs migrate import --everything # 历史一次性迁过去
# 2) 看 LFS 存量
git lfs ls-files
git lfs status
# 3) LFS server 跑不通时,降级到 git-fs 顺序校验
git lfs fsck# 手动 bisect
git bisect start
git bisect bad HEAD
git bisect good v3.4.0
git bisect run sh -c 'make clean >/dev/null && make -j8 all >/dev/null 2>&1 && ./test_runner'
# 全自动 bisect(配合 ccache,只跑必要 TU)
git bisect run sh -c 'ccache -z && make -j8 2>&1 | tail -50 && ./test_runner'# 各自独立 build/ 目录,各跑 make,互不干扰
git worktree add ../feature-A feature/canif
git worktree add ../release release/2025.Q4
git worktree add ../hotfix hotfix/uds-srv-2025-12
# 每个 worktree 都是独立 working dir,但共享 git store# 1) init 全树
git submodule update --init --recursive
git submodule foreach 'git checkout release/2025.Q4'
git config --global submodule.recurse true
# 2) sparse-checkout:只把 MCAL 拉下来给 build 用
git sparse-checkout init --cone
git sparse-checkout set src/mcal/Can third_party/CanIf include/
# 3) partial clone:带宽 / 磁盘都省
git clone --filter=blob:less=10M --sparse https://git.com/bsp.git# pre-commit:本地强制 cppcheck + commit 签名
cat > .git/hooks/pre-commit <<'HOOK_EOF'
#!/usr/bin/env bash
set -euo pipefail
git diff --cached --name-only --diff-filter=ACM \
| grep -E '\.(c|h|cpp|hpp)$' \
| xargs -r cppcheck --quiet --enable=warning --inline-suppr
HOOK_EOF
chmod +x .git/hooks/pre-commit
# commit-msg:必须含 Jira / Traceable ID
cat > .git/hooks/commit-msg <<'HOOK_EOF'
#!/usr/bin/env bash
set -euo pipefail
if ! grep -Eq '(CANIF|COMM|BSP|EASR|MCAL)-[0-9]+' "$1"; then
echo "ERROR: commit message must contain a traceable id"
exit 1
fi
HOOK_EOF
chmod +x .git/hooks/commit-msg
# 团队统一钩子:用 husky / pre-commit 框架维护(而不是直接改 .git/hooks)
pip install pre-commit
cat > .pre-commit-config.yaml <<'YAML_EOF'
repos:
- repo: local
hooks:
- id: cppcheck
name: cppcheck
entry: cppcheck --quiet --enable=warning --inline-suppr
language: system
types: [c, c++]
- id: trailing
name: strip-trailing-whitespace
entry: scripts/strip-trailing
language: system
YAML_EOF
pre-commit install# 1) 签名 tag(车规 release tag 必签)
git tag -s v2025.Q4 -m "Release 2025.Q4 - signed by wang"
git verify-tag v2025.Q4
# 2) 列 release note,从 log 自动产
git log --oneline v2025.Q3..v2025.Q4 --no-merges | tee CHANGELOG.txt
# 3) 找回被 reset 掉的提交
git reflog | head
git checkout -b recover-abc123~/.bashrc节选)# ls 彩蛋
alias ll='ls -alF --time-style=long-iso'
alias la='ls -A'
alias l='ls -CF'
alias duh='du -sh'
alias dfh='df -hT'
alias path='tr ":" "\n" <<< "$PATH"'
# 嵌入式工具链
alias tasking='cd "${TASKING_HOME:-/opt/tasking}" 2>/dev/null && ls bin/ | head'
alias isystem='cd "${ISYSTEM_HOME:-/opt/isystem}" 2>/dev/null && ls bin/'
# 构建快捷
alias b='make -j$(nproc) BUILD=release'
alias bc='make -j$(nproc) clean'
alias cr='cmake -B build -G Ninja && ninja -C build'
alias crelease='cmake -B build -G Ninja -DCMAKE_BUILD_TYPE=Release && ninja -C build'
# Git
alias gs='git status -sb'
alias gd='git diff'
alias gdc='git diff --cached'
alias gpl='git pull --rebase --autostash'
alias gps='git push'
alias gb='git branch -vv'
alias gw='git switch'
alias gco='git checkout'
alias gm='git merge --no-ff'
alias gr='git rebase'
alias glg='git log --oneline --graph --decorate -20'
alias gll='git log --graph --pretty=format:"%h %ad %an %s" --date=short'
alias gfp='git fetch --prune --tags'
alias gclean='git branch --merged | grep -v "^* main" | xargs -n1 git branch -d'
# 安全 rm(防粗心)
alias rm='rm -I --preserve-root'
# 工具栏函数 —— 一个 gdb-less 版调试器
fsize() { du -sh "$@" 2>/dev/null; } # file size
fwatch() { while :; do clear; "$@"; sleep 2; done; } # 自动刷新
fd() { command -v fd >/dev/null 2>&1 && command fd "$@" || find "$@"; } # 默认 fd
wgrep() { rg --color=always -n "$@" | less -R; } # 带色 less
# Car-style 环境显示:打开 shell 时看一眼
bannermsg() {
local d=$(date +'%F %a')
local j=$(jobs | wc -l)
echo "[$d] cores=$(nproc) user=$(whoami) jobs=$j"
}
bannermsg刷新并永久保存:
echo "source ~/.bashrc" >> ~/.bash_profile
source ~/.bashrcpwd -Pcd -lltree -L 2pushdpopd | ||
cp -rmvrm -rfln -stouchinstall | ||
catlessheadtail -Fvimbatxxd | ||
chmodchownsudo -Eset -euo pipefailtrap | ||
ps auxftopkill -TERMnproclsof -pstrace -pperf | ||
df -hTdu -shfree -hiostat 1vmstatmpstat | ||
rg -ngrep -RInfindfdsed -iawkfzf | ||
sshscprsync -avzPcurlncsshfsautossh | ||
make -j$(nproc)cmake -G Ninjaninjactcccache | ||
winidea64 -ws -run script.dmm | ||
addr2linec++filtobjdumpreadelfnmsize | ||
cppcheckclang-tidy、Polyspace、LDRA、Coverity | ||
statusadd -pcommit -sswitchpull --rebasebisect runworktreelfs | ||
pre-commitcommit-msgpre-pushhushprepare-commit-msg | ||
lsusbipssenvwhichtreerealpathfuser |
~/.bashrc改成像 §10那样,source后试 ll、gs、gpl、gclean。rg、fd、bat、htop、tree、ccache、ninja、parallel、pre-commit,apt install/ dnf install一次过。ssh-keygen -t ed25519生成一对密钥,推到代码平台;写一份 ~/.ssh/config。cmake -B build -G Ninja && ninja -C build,落地 firmware.elf。build/下分别跑 size、nm --size-sort、readelf -h,把报告贴到团队 wiki。scripts/build.sh(带 set -euo pipefail、trap、mktemp),接 ctc(并支持切 target)。pre-commit:cppcheck、clang-format、commit-msg三件套。git bisect run回归定位,只看不改。Isystem.CLI.Runner.exe --workspace workspace.iws --run scripts/flash.dmm,记录输出。.dmm脚本写到 scripts/regression/,让 CI 能跑。写在最后:嵌入式 / 车规场景的命令生态,本质上是 「批构建能力 + 可追溯 + 可重复」三件事的工程化。
掌握以上命令,意味着你能从"敲代码的人"扩展为"能交付 release 工程的人"。