609 lines
27 KiB
Bash
Executable File
609 lines
27 KiB
Bash
Executable File
#!/bin/bash
|
|
# ==============================================================================
|
|
# setup-vscode-macos.sh
|
|
#
|
|
# Rend un projet STM32CubeIDE (genere par STM32CubeMX, toolchain GCC/Makefile)
|
|
# compilable, flashable et debogable depuis VS Code sur macOS.
|
|
#
|
|
# Reutilisable tel quel sur un autre projet STM32CubeIDE : copiez ce script a
|
|
# la racine du projet (a cote du dossier "gcc/") et lancez-le.
|
|
#
|
|
# Ce qu'il fait :
|
|
# 1. Verifie/installe la toolchain (arm-none-eabi-gcc, GNU make 4.x)
|
|
# 2. Localise STM32CubeIDE et ses outils embarques (ST-LINK_gdbserver,
|
|
# STM32CubeProgrammer)
|
|
# 3. Corrige les incompatibilites macOS connues dans les Makefiles/scripts
|
|
# de lien generes par CubeMX (mot-cle READONLY, rmdir BSD, --specs)
|
|
# 4. Si le projet utilise TouchGFX : cree des wrappers Wine (via TouchGFX.app,
|
|
# qui embarque Wine) pour les outils imageconvert/fontconvert, qui n'ont
|
|
# pas de version macOS
|
|
# 5. Signe arm-none-eabi-gdb avec les entitlements necessaires au debogage
|
|
# sur macOS (cree un certificat de signature de code auto-signe si besoin)
|
|
# 6. Genere .vscode/tasks.json, c_cpp_properties.json et launch.json
|
|
# 7. Lance une compilation de test pour valider
|
|
#
|
|
# Ce que ce script NE PEUT PAS deviner de maniere fiable (a vos yeux de
|
|
# verifier si la compilation de test echoue) :
|
|
# - Des fichiers sources ajoutes au projet APRES la derniere generation du
|
|
# Makefile par CubeMX (ex: un driver BSP ajoute a la main) : le Makefile
|
|
# genere peut alors ne pas les lister, meme s'ils apparaissent bien dans
|
|
# le .cproject de STM32CubeIDE. Si la compilation de test echoue avec des
|
|
# "undefined reference" ou "No such file or directory", il faudra ajouter
|
|
# ces fichiers/chemins a la main dans gcc/makefile_<projet> (variables
|
|
# board_c_files += ... et board_include_paths += ...).
|
|
# - Le point d'acces SWD (access port) et la strategie de reset a utiliser
|
|
# pour le debogage : ce script utilise des valeurs par defaut modifiables
|
|
# en tete de script (DEBUG_ACCESS_PORT, DEBUG_RESET_STRATEGY). Pour un
|
|
# projet different, verifiez ces valeurs dans un fichier .launch existant
|
|
# de STM32CubeIDE (dossier STM32CubeIDE/**/*.launch), champs
|
|
# "com.st.stm32cube.ide.mcu.debug.launch.access_port_id" et
|
|
# "com.st.stm32cube.ide.mcu.debug.stlink.reset_strategy".
|
|
#
|
|
# ==============================================================================
|
|
|
|
set -uo pipefail
|
|
|
|
# ------------------------------------------------------------------------------
|
|
# Parametres modifiables
|
|
# ------------------------------------------------------------------------------
|
|
DEBUG_GDB_PORT="61234"
|
|
DEBUG_ACCESS_PORT="0" # "-m <n>" pour ST-LINK_gdbserver. Mettre 1 si le
|
|
# projet a une architecture boot+appli en memoire
|
|
# externe (verifier le .launch existant, voir ci-dessus)
|
|
DEBUG_CONNECT_UNDER_RESET="1" # 1 = ajoute "-k" (connexion sous reset)
|
|
GDB_SIGN_IDENTITY="gdb-cert"
|
|
|
|
# ------------------------------------------------------------------------------
|
|
# Utilitaires
|
|
# ------------------------------------------------------------------------------
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
PROJECT_ROOT="$SCRIPT_DIR"
|
|
STEP=0
|
|
|
|
log() { STEP=$((STEP+1)); echo ""; echo "[$STEP] $*"; }
|
|
info() { echo " $*"; }
|
|
warn() { echo " ATTENTION: $*" >&2; }
|
|
die() { echo "ERREUR: $*" >&2; exit 1; }
|
|
|
|
# ==============================================================================
|
|
log "Verification de la toolchain ARM"
|
|
# ==============================================================================
|
|
if ! command -v arm-none-eabi-gcc >/dev/null 2>&1; then
|
|
info "arm-none-eabi-gcc introuvable, installation via Homebrew..."
|
|
command -v brew >/dev/null 2>&1 || die "Homebrew n'est pas installe (https://brew.sh). Installez-le puis relancez ce script."
|
|
brew install --cask gcc-arm-embedded 2>/dev/null || brew install arm-none-eabi-gcc || die "Echec de l'installation d'arm-none-eabi-gcc"
|
|
fi
|
|
ARM_GCC_PATH="$(command -v arm-none-eabi-gcc)"
|
|
info "arm-none-eabi-gcc : $ARM_GCC_PATH ($(arm-none-eabi-gcc --version | head -1))"
|
|
|
|
ARM_GDB_PATH="$(command -v arm-none-eabi-gdb || true)"
|
|
[ -z "$ARM_GDB_PATH" ] && die "arm-none-eabi-gdb introuvable (devrait etre installe avec arm-none-eabi-gcc)"
|
|
info "arm-none-eabi-gdb : $ARM_GDB_PATH"
|
|
|
|
# ==============================================================================
|
|
log "Verification de GNU Make 4.x (celui d'Apple, 3.81, est trop ancien)"
|
|
# ==============================================================================
|
|
GNU_MAKE=""
|
|
if make --version 2>/dev/null | head -1 | grep -qE "GNU Make (4|5|6|7|8|9)"; then
|
|
GNU_MAKE="$(command -v make)"
|
|
else
|
|
for candidate in /usr/local/opt/make/libexec/gnubin/make /opt/homebrew/opt/make/libexec/gnubin/make; do
|
|
[ -x "$candidate" ] && GNU_MAKE="$candidate" && break
|
|
done
|
|
if [ -z "$GNU_MAKE" ]; then
|
|
info "GNU Make recent introuvable, installation via Homebrew (sera nomme 'gmake')..."
|
|
command -v brew >/dev/null 2>&1 || die "Homebrew n'est pas installe (https://brew.sh)."
|
|
brew install make || die "Echec de l'installation de make"
|
|
for candidate in /usr/local/opt/make/libexec/gnubin/make /opt/homebrew/opt/make/libexec/gnubin/make; do
|
|
[ -x "$candidate" ] && GNU_MAKE="$candidate" && break
|
|
done
|
|
fi
|
|
fi
|
|
[ -z "$GNU_MAKE" ] && die "Impossible de localiser un GNU Make >= 4.0 apres installation"
|
|
info "GNU Make utilise : $GNU_MAKE ($("$GNU_MAKE" --version | head -1))"
|
|
|
|
# ==============================================================================
|
|
log "Localisation du dossier de build GCC du projet"
|
|
# ==============================================================================
|
|
GCC_DIR=""
|
|
for d in "$PROJECT_ROOT/gcc" "$PROJECT_ROOT/GCC" "$PROJECT_ROOT/Gcc"; do
|
|
[ -d "$d" ] && GCC_DIR="$d" && break
|
|
done
|
|
[ -z "$GCC_DIR" ] && die "Dossier 'gcc/' introuvable a la racine du projet ($PROJECT_ROOT). Ce script attend un projet CubeMX genere avec la toolchain 'STM32CubeIDE / Makefile'."
|
|
info "Dossier de build : $GCC_DIR"
|
|
|
|
SUBMAKEFILES=()
|
|
while IFS= read -r line; do
|
|
SUBMAKEFILES+=("$line")
|
|
done < <(find "$GCC_DIR" -maxdepth 1 -type f -iname "makefile_*" | sort)
|
|
TOP_MAKEFILE="$GCC_DIR/Makefile"
|
|
[ -f "$TOP_MAKEFILE" ] || die "Makefile principal introuvable dans $GCC_DIR"
|
|
if [ "${#SUBMAKEFILES[@]}" -eq 0 ]; then
|
|
SUBMAKEFILES=("$TOP_MAKEFILE")
|
|
fi
|
|
info "Makefile(s) detecte(s) : ${SUBMAKEFILES[*]}"
|
|
|
|
# ==============================================================================
|
|
log "Localisation de STM32CubeIDE et de ses outils embarques"
|
|
# ==============================================================================
|
|
CUBEIDE_APP=""
|
|
for d in "/Applications/STMicroelectronics/STM32CubeIDE.app" "/Applications/STM32CubeIDE.app"; do
|
|
[ -d "$d" ] && CUBEIDE_APP="$d" && break
|
|
done
|
|
[ -z "$CUBEIDE_APP" ] && CUBEIDE_APP="$(mdfind "kMDItemFSName == 'STM32CubeIDE.app'" 2>/dev/null | head -1)"
|
|
[ -z "$CUBEIDE_APP" ] && die "STM32CubeIDE.app introuvable dans /Applications. Installez-le depuis st.com (necessaire pour le flash/debug via ST-Link)."
|
|
info "STM32CubeIDE : $CUBEIDE_APP"
|
|
|
|
GDBSERVER_BIN="$(find "$CUBEIDE_APP/Contents/Eclipse/plugins" -maxdepth 1 -iname "*stlink-gdb-server*" -type d 2>/dev/null | sort -V | tail -1)/tools/bin/ST-LINK_gdbserver"
|
|
CUBEPROG_BIN_DIR="$(find "$CUBEIDE_APP/Contents/Eclipse/plugins" -maxdepth 1 -iname "*cubeprogrammer*" -type d 2>/dev/null | sort -V | tail -1)/tools/bin"
|
|
CUBEPROG_CLI="$CUBEPROG_BIN_DIR/STM32_Programmer_CLI"
|
|
|
|
[ -x "$GDBSERVER_BIN" ] || die "ST-LINK_gdbserver introuvable sous $CUBEIDE_APP"
|
|
[ -x "$CUBEPROG_CLI" ] || die "STM32_Programmer_CLI introuvable sous $CUBEIDE_APP"
|
|
info "ST-LINK_gdbserver : $GDBSERVER_BIN"
|
|
info "STM32_Programmer_CLI: $CUBEPROG_CLI"
|
|
|
|
# ==============================================================================
|
|
log "Recherche d'un chargeur de memoire externe (.stldr), si applicable"
|
|
# ==============================================================================
|
|
EXT_LOADER="$(find "$PROJECT_ROOT" -iname "*.stldr" -maxdepth 3 2>/dev/null | head -1)"
|
|
if [ -n "$EXT_LOADER" ]; then
|
|
info "External loader trouve : $EXT_LOADER"
|
|
EXT_LOADER_ARGS_PROG=(-el "$EXT_LOADER")
|
|
EXT_LOADER_ARGS_GDB="-el \${workspaceFolder}/$(python3 -c "import os,sys; print(os.path.relpath(sys.argv[1], sys.argv[2]))" "$EXT_LOADER" "$PROJECT_ROOT" 2>/dev/null || echo "$EXT_LOADER")"
|
|
else
|
|
info "Aucun external loader trouve (normal si le projet n'utilise pas de memoire externe XSPI/QSPI)."
|
|
EXT_LOADER_ARGS_PROG=()
|
|
EXT_LOADER_ARGS_GDB=""
|
|
fi
|
|
|
|
# ==============================================================================
|
|
log "Correction des incompatibilites macOS dans les scripts de lien (.ld)"
|
|
# ==============================================================================
|
|
LD_FILES=$(find "$PROJECT_ROOT" -iname "*.ld" -not -path "*/STM32CubeIDE/*" 2>/dev/null)
|
|
FIXED_LD=0
|
|
for ld in $LD_FILES; do
|
|
if grep -q "(READONLY)" "$ld" 2>/dev/null; then
|
|
sed -i '' 's/ (READONLY)//' "$ld"
|
|
info "Corrige (mot-cle READONLY, GCC11+ uniquement) : $ld"
|
|
FIXED_LD=$((FIXED_LD+1))
|
|
fi
|
|
done
|
|
[ "$FIXED_LD" -eq 0 ] && info "Rien a corriger."
|
|
|
|
# ==============================================================================
|
|
log "Correction des incompatibilites macOS dans les Makefiles"
|
|
# ==============================================================================
|
|
for mk in "${SUBMAKEFILES[@]}" "$TOP_MAKEFILE"; do
|
|
[ -f "$mk" ] || continue
|
|
|
|
# rmdir --ignore-fail-on-non-empty n'existe pas sur macOS (BSD rmdir)
|
|
if grep -q -- "--ignore-fail-on-non-empty" "$mk" 2>/dev/null; then
|
|
sed -i '' -E 's/rmdir --ignore-fail-on-non-empty ([^ ]+)/rmdir \1 2>\/dev\/null || true/' "$mk"
|
|
info "Corrige (rmdir portable) : $mk"
|
|
fi
|
|
|
|
# --specs=nosys.specs sans --specs=nano.specs cause des symboles
|
|
# __sf_fake_stdin/stdout/stderr non resolus avec FreeRTOS
|
|
if grep -q -- "--specs=nosys.specs" "$mk" 2>/dev/null && ! grep -q -- "--specs=nano.specs" "$mk" 2>/dev/null; then
|
|
sed -i '' 's/--specs=nosys.specs/--specs=nosys.specs \\\n\t--specs=nano.specs/' "$mk"
|
|
info "Ajoute --specs=nano.specs au linker : $mk"
|
|
fi
|
|
|
|
# Ajout d'une branche Darwin pour imageconvert/fontconvert si TouchGFX est utilise
|
|
if grep -q "imageconvert_executable" "$mk" 2>/dev/null && ! grep -q "UNAME), Darwin" "$mk" 2>/dev/null; then
|
|
TOUCHGFX_WIN_IMG=$(grep -oE '[A-Za-z0-9_/.-]+/win/imageconvert\.out' "$mk" | head -1)
|
|
TOUCHGFX_WIN_FONT=$(grep -oE '[A-Za-z0-9_/.-]+/win/fontconvert\.out' "$mk" | head -1)
|
|
if [ -n "$TOUCHGFX_WIN_IMG" ]; then
|
|
info "TouchGFX detecte dans $mk - mise en place des wrappers Wine macOS"
|
|
|
|
TOUCHGFX_APP=""
|
|
for d in "/Applications/STMicroelectronics/TouchGFX.app" "/Applications/TouchGFX.app"; do
|
|
[ -d "$d" ] && TOUCHGFX_APP="$d" && break
|
|
done
|
|
[ -z "$TOUCHGFX_APP" ] && TOUCHGFX_APP="$(mdfind "kMDItemFSName == 'TouchGFX.app'" 2>/dev/null | head -1)"
|
|
|
|
if [ -z "$TOUCHGFX_APP" ] || [ ! -x "$TOUCHGFX_APP/Contents/SharedSupport/wine/bin/wine64" ]; then
|
|
warn "TouchGFX.app (Designer) introuvable ou non-Wineskin sous /Applications - impossible de generer les wrappers automatiquement."
|
|
warn "Installez TouchGFX Designer pour macOS depuis st.com, puis relancez ce script."
|
|
else
|
|
WRAP_DIR="$GCC_DIR/macos_wine_wrappers"
|
|
mkdir -p "$WRAP_DIR"
|
|
WINE64="$TOUCHGFX_APP/Contents/SharedSupport/wine/bin/wine64"
|
|
WINE_LIBS="$TOUCHGFX_APP/Contents/Frameworks:$TOUCHGFX_APP/Contents/SharedSupport/wine/lib"
|
|
|
|
for pair in "imageconvert:$TOUCHGFX_WIN_IMG" "fontconvert:$TOUCHGFX_WIN_FONT"; do
|
|
name="${pair%%:*}"; relpath="${pair#*:}"
|
|
[ -z "$relpath" ] && continue
|
|
cat > "$WRAP_DIR/$name.sh" << EOF
|
|
#!/bin/sh
|
|
# Lance $name.out (Windows) via le Wine embarque dans TouchGFX.app
|
|
export DYLD_FALLBACK_LIBRARY_PATH="$WINE_LIBS"
|
|
exec "$WINE64" "$PROJECT_ROOT/$relpath" "\$@" 2>/dev/null
|
|
EOF
|
|
chmod +x "$WRAP_DIR/$name.sh"
|
|
info "Wrapper cree : $WRAP_DIR/$name.sh"
|
|
done
|
|
|
|
# Insere une branche Darwin juste avant le "else" qui gere Windows/Linux
|
|
MK_REL_GCC=$(basename "$mk")
|
|
awk -v wrapdir="$(python3 -c "import os,sys; print(os.path.relpath(sys.argv[1], sys.argv[2]))" "$WRAP_DIR" "$PROJECT_ROOT" 2>/dev/null || echo "gcc/macos_wine_wrappers")" '
|
|
/ifeq \(\$\(UNAME\), Linux\)/ { print; infile=1; next }
|
|
infile && /^else$/ && !inserted {
|
|
print "else ifeq ($(UNAME), Darwin)"
|
|
print "imageconvert_executable := " wrapdir "/imageconvert.sh"
|
|
print "fontconvert_executable := " wrapdir "/fontconvert.sh"
|
|
inserted=1
|
|
}
|
|
{ print }
|
|
' "$mk" > "$mk.tmp" && mv "$mk.tmp" "$mk"
|
|
info "Branche Darwin ajoutee dans $mk"
|
|
fi
|
|
fi
|
|
fi
|
|
done
|
|
|
|
# ==============================================================================
|
|
log "Compilation de test"
|
|
# ==============================================================================
|
|
( cd "$GCC_DIR" && "$GNU_MAKE" -j"$(sysctl -n hw.ncpu)" )
|
|
BUILD_STATUS=$?
|
|
if [ "$BUILD_STATUS" -ne 0 ]; then
|
|
warn "La compilation a echoue. Causes frequentes :"
|
|
warn " - fichiers sources ajoutes au projet apres la derniere generation du"
|
|
warn " Makefile (comparez avec STM32CubeIDE/*/. cproject) -> a ajouter a la main"
|
|
warn " dans gcc/makefile_<projet> (board_c_files += / board_include_paths +=)"
|
|
warn "Les fichiers .vscode/ seront quand meme generes ; relancez juste le build"
|
|
warn "depuis VS Code une fois les corrections faites."
|
|
else
|
|
info "Compilation reussie."
|
|
fi
|
|
|
|
# ==============================================================================
|
|
log "Signature de code pour arm-none-eabi-gdb (necessaire pour deboguer sur macOS)"
|
|
# ==============================================================================
|
|
if codesign -dv "$ARM_GDB_PATH" 2>&1 | grep -q "com.apple.security.cs.debugger" 2>/dev/null; then
|
|
info "Deja signe correctement."
|
|
elif security find-identity -v -p codesigning 2>/dev/null | grep -q "$GDB_SIGN_IDENTITY"; then
|
|
info "Certificat '$GDB_SIGN_IDENTITY' deja present, signature de gdb..."
|
|
cat > /tmp/gdb-entitlement.xml << 'EOF'
|
|
<?xml version="1.0" encoding="UTF-8"?>
|
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
<plist version="1.0">
|
|
<dict>
|
|
<key>com.apple.security.cs.debugger</key>
|
|
<true/>
|
|
<key>com.apple.security.get-task-allow</key>
|
|
<true/>
|
|
</dict>
|
|
</plist>
|
|
EOF
|
|
codesign --entitlements /tmp/gdb-entitlement.xml -fs "$GDB_SIGN_IDENTITY" "$ARM_GDB_PATH"
|
|
else
|
|
info "Creation d'un certificat de signature de code auto-signe '$GDB_SIGN_IDENTITY'..."
|
|
info "(macOS va probablement demander votre mot de passe pour lui faire confiance)"
|
|
KEYCHAIN="$HOME/Library/Keychains/login.keychain-db"
|
|
openssl req -new -newkey rsa:2048 -x509 -days 3650 -nodes \
|
|
-keyout /tmp/gdb-cert.key -out /tmp/gdb-cert.crt \
|
|
-subj "/CN=$GDB_SIGN_IDENTITY" \
|
|
-addext "basicConstraints=critical,CA:true" \
|
|
-addext "keyUsage=critical,digitalSignature,keyCertSign" \
|
|
-addext "extendedKeyUsage=critical,codeSigning" >/dev/null 2>&1
|
|
openssl pkcs12 -export -out /tmp/gdb-cert.p12 -inkey /tmp/gdb-cert.key -in /tmp/gdb-cert.crt \
|
|
-passout pass:temp -legacy >/dev/null 2>&1
|
|
security import /tmp/gdb-cert.p12 -k "$KEYCHAIN" -P temp -T /usr/bin/codesign -T /usr/bin/security
|
|
security add-trusted-cert -p codeSign -k "$KEYCHAIN" /tmp/gdb-cert.crt
|
|
rm -f /tmp/gdb-cert.key /tmp/gdb-cert.crt /tmp/gdb-cert.p12
|
|
|
|
cat > /tmp/gdb-entitlement.xml << 'EOF'
|
|
<?xml version="1.0" encoding="UTF-8"?>
|
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
<plist version="1.0">
|
|
<dict>
|
|
<key>com.apple.security.cs.debugger</key>
|
|
<true/>
|
|
<key>com.apple.security.get-task-allow</key>
|
|
<true/>
|
|
</dict>
|
|
</plist>
|
|
EOF
|
|
codesign --entitlements /tmp/gdb-entitlement.xml -fs "$GDB_SIGN_IDENTITY" "$ARM_GDB_PATH" \
|
|
|| warn "La signature a echoue - relancez ce script apres avoir accepte la demande de confiance macOS."
|
|
fi
|
|
|
|
# ==============================================================================
|
|
log "Extraction des chemins d'include / defines (pour l'auto-completion VS Code)"
|
|
# ==============================================================================
|
|
# On essaie chaque makefile jusqu'a en trouver un qui expose "include_paths :="
|
|
# (le plus complet, generalement celui de l'application principale - "Boot" par
|
|
# exemple n'a souvent qu'une variante simplifiee sans cette variable).
|
|
MAIN_APP_MAKEFILE=""
|
|
INCLUDE_PATHS_RAW=""
|
|
DEFINES_RAW=""
|
|
for candidate in "${SUBMAKEFILES[@]}"; do
|
|
candidate_basename="$(basename "$candidate")"
|
|
candidate_dump=$(cd "$GCC_DIR" && "$GNU_MAKE" -f "$candidate_basename" -p 2>/dev/null)
|
|
candidate_includes=$(echo "$candidate_dump" | grep -m1 "^include_paths :=" | sed 's/^include_paths[[:space:]]*:=[[:space:]]*//')
|
|
if [ -n "$candidate_includes" ]; then
|
|
MAIN_APP_MAKEFILE="$candidate"
|
|
MAKE_DUMP="$candidate_dump"
|
|
INCLUDE_PATHS_RAW="$candidate_includes"
|
|
DEFINES_RAW=$(echo "$candidate_dump" | grep -m1 "^c_compiler_options =" | grep -oE '\-D[A-Za-z0-9_]+' | sed 's/^-D//' | sort -u)
|
|
break
|
|
fi
|
|
done
|
|
if [ -z "$INCLUDE_PATHS_RAW" ]; then
|
|
warn "Extraction des chemins d'include incomplete - c_cpp_properties.json pourra necessiter des ajustements manuels."
|
|
MAIN_APP_MAKEFILE="${SUBMAKEFILES[0]}"
|
|
fi
|
|
info "Makefile utilise pour l'extraction : $(basename "$MAIN_APP_MAKEFILE")"
|
|
|
|
INCLUDE_ITEMS=()
|
|
for p in $INCLUDE_PATHS_RAW; do
|
|
INCLUDE_ITEMS+=(" \"\${workspaceFolder}/$p\"")
|
|
done
|
|
DEFINE_ITEMS=()
|
|
for d in $DEFINES_RAW; do
|
|
DEFINE_ITEMS+=(" \"$d\"")
|
|
done
|
|
join_with_commas() {
|
|
local first=1
|
|
for item in "$@"; do
|
|
[ "$first" -eq 0 ] && printf ",\n"
|
|
printf "%s" "$item"
|
|
first=0
|
|
done
|
|
[ "$#" -gt 0 ] && printf "\n"
|
|
}
|
|
INCLUDE_JSON=""
|
|
[ "${#INCLUDE_ITEMS[@]}" -gt 0 ] && INCLUDE_JSON="$(join_with_commas "${INCLUDE_ITEMS[@]}")"
|
|
DEFINES_JSON=""
|
|
[ "${#DEFINE_ITEMS[@]}" -gt 0 ] && DEFINES_JSON="$(join_with_commas "${DEFINE_ITEMS[@]}")"
|
|
info "${#INCLUDE_ITEMS[@]} chemins d'include et ${#DEFINE_ITEMS[@]} defines extraits."
|
|
|
|
# ==============================================================================
|
|
log "Detection de la structure du projet (mono-projet ou Boot+Appli)"
|
|
# ==============================================================================
|
|
BOOT_ELF=""
|
|
APPLI_ELF=""
|
|
if [ -d "$PROJECT_ROOT/Boot" ] && [ -d "$PROJECT_ROOT/Appli" ]; then
|
|
info "Structure Boot + Appli detectee (architecture avec bootloader externe)."
|
|
BOOT_ELF=$(find "$PROJECT_ROOT/Boot" -iname "target.elf" 2>/dev/null | head -1)
|
|
APPLI_ELF=$(find "$PROJECT_ROOT/Appli" -iname "target.elf" 2>/dev/null | head -1)
|
|
else
|
|
info "Structure mono-projet detectee."
|
|
APPLI_ELF=$(find "$PROJECT_ROOT" -iname "target.elf" -not -path "*/STM32CubeIDE/*" 2>/dev/null | head -1)
|
|
fi
|
|
[ -z "$BOOT_ELF" ] && [ -d "$PROJECT_ROOT/Boot" ] && BOOT_ELF="Boot/TouchGFX/build/bin/target.elf"
|
|
[ -z "$APPLI_ELF" ] && APPLI_ELF="$(find "$GCC_DIR/.." -iname "target.elf" -not -path "*/STM32CubeIDE/*" 2>/dev/null | head -1)"
|
|
BOOT_ELF_REL=${BOOT_ELF#"$PROJECT_ROOT/"}
|
|
APPLI_ELF_REL=${APPLI_ELF#"$PROJECT_ROOT/"}
|
|
|
|
# ==============================================================================
|
|
log "Generation des fichiers .vscode/"
|
|
# ==============================================================================
|
|
mkdir -p "$PROJECT_ROOT/.vscode"
|
|
GCC_DIR_REL=${GCC_DIR#"$PROJECT_ROOT/"}
|
|
|
|
# --- c_cpp_properties.json ---
|
|
{
|
|
echo "{"
|
|
echo " \"version\": 4,"
|
|
echo " \"configurations\": ["
|
|
echo " {"
|
|
echo " \"name\": \"STM32\","
|
|
echo " \"compilerPath\": \"$ARM_GCC_PATH\","
|
|
echo " \"cStandard\": \"gnu11\","
|
|
echo " \"cppStandard\": \"gnu++14\","
|
|
echo " \"intelliSenseMode\": \"linux-gcc-arm\","
|
|
echo " \"defines\": ["
|
|
echo "$DEFINES_JSON"
|
|
echo " ],"
|
|
echo " \"includePath\": ["
|
|
echo "$INCLUDE_JSON"
|
|
echo " ]"
|
|
echo " }"
|
|
echo " ]"
|
|
echo "}"
|
|
} > "$PROJECT_ROOT/.vscode/c_cpp_properties.json"
|
|
info "Genere : .vscode/c_cpp_properties.json"
|
|
|
|
# --- tasks.json ---
|
|
RESET_FLAG=""
|
|
[ "$DEBUG_CONNECT_UNDER_RESET" = "1" ] && RESET_FLAG='"-k",'
|
|
EXT_LOADER_PROG_ARGS=""
|
|
[ -n "$EXT_LOADER" ] && EXT_LOADER_PROG_ARGS="\"-el\", \"\${workspaceFolder}/${EXT_LOADER#"$PROJECT_ROOT/"}\","
|
|
EXT_LOADER_GDB_ARGS=""
|
|
[ -n "$EXT_LOADER" ] && EXT_LOADER_GDB_ARGS="-el \${workspaceFolder}/${EXT_LOADER#"$PROJECT_ROOT/"} "
|
|
|
|
cat > "$PROJECT_ROOT/.vscode/tasks.json" << EOF
|
|
{
|
|
"version": "2.0.0",
|
|
"tasks": [
|
|
{
|
|
"label": "Build",
|
|
"type": "shell",
|
|
"command": "$GNU_MAKE",
|
|
"args": ["-j8"],
|
|
"options": { "cwd": "\${workspaceFolder}/$GCC_DIR_REL" },
|
|
"group": { "kind": "build", "isDefault": true },
|
|
"problemMatcher": ["\$gcc"],
|
|
"presentation": { "reveal": "always", "panel": "shared", "clear": true }
|
|
},
|
|
{
|
|
"label": "Clean",
|
|
"type": "shell",
|
|
"command": "$GNU_MAKE",
|
|
"args": ["clean"],
|
|
"options": { "cwd": "\${workspaceFolder}/$GCC_DIR_REL" },
|
|
"group": "build",
|
|
"problemMatcher": []
|
|
},
|
|
{
|
|
"label": "Flash",
|
|
"type": "shell",
|
|
"command": "$CUBEPROG_CLI",
|
|
"args": [
|
|
"-c", "port=SWD",
|
|
$EXT_LOADER_PROG_ARGS
|
|
"-w", "\${workspaceFolder}/$APPLI_ELF_REL",
|
|
"-v",
|
|
"-rst"
|
|
],
|
|
"group": "none",
|
|
"problemMatcher": []
|
|
},
|
|
{
|
|
"label": "Start ST-LINK GDB Server",
|
|
"type": "shell",
|
|
"command": "$GDBSERVER_BIN",
|
|
"args": [
|
|
"-p", "$DEBUG_GDB_PORT",
|
|
"-l", "1",
|
|
"-d",
|
|
"-cp", "$CUBEPROG_BIN_DIR",
|
|
$EXT_LOADER_PROG_ARGS
|
|
"-m", "$DEBUG_ACCESS_PORT",
|
|
$RESET_FLAG
|
|
"-e"
|
|
],
|
|
"isBackground": true,
|
|
"problemMatcher": {
|
|
"pattern": { "regexp": "^(x)(x)\$" },
|
|
"background": {
|
|
"activeOnStart": true,
|
|
"beginsPattern": "^STMicroelectronics ST-LINK GDB server",
|
|
"endsPattern": "Waiting for debugger connection|Error in initializing ST-LINK device"
|
|
}
|
|
},
|
|
"presentation": { "reveal": "always", "panel": "dedicated" }
|
|
},
|
|
{
|
|
"label": "Stop ST-LINK GDB Server",
|
|
"type": "shell",
|
|
"command": "pkill -f ST-LINK_gdbserver || true",
|
|
"problemMatcher": [],
|
|
"presentation": { "reveal": "silent" }
|
|
}
|
|
]
|
|
}
|
|
EOF
|
|
# Nettoyage des eventuelles virgules trainantes (arguments optionnels vides)
|
|
sed -i '' -E 's/,([[:space:]]*\])/\1/' "$PROJECT_ROOT/.vscode/tasks.json"
|
|
info "Genere : .vscode/tasks.json"
|
|
|
|
if [ -n "$BOOT_ELF_REL" ] && [ -d "$PROJECT_ROOT/Boot" ]; then
|
|
cat >> /dev/null << 'NOTE'
|
|
Structure Boot+Appli : deux tasks de flash separees ajoutees ci-dessous en plus.
|
|
NOTE
|
|
python3 - "$PROJECT_ROOT/.vscode/tasks.json" "$BOOT_ELF_REL" "$APPLI_ELF_REL" "$CUBEPROG_CLI" "$EXT_LOADER" <<'PYEOF'
|
|
import json, sys
|
|
path, boot_elf, appli_elf, cli, extloader = sys.argv[1:6]
|
|
with open(path) as f:
|
|
data = json.load(f)
|
|
extra_args = ["-c", "port=SWD"]
|
|
if extloader:
|
|
extra_args += ["-el", "${workspaceFolder}/" + extloader.split("/", 1)[-1] if "/" in extloader else extloader]
|
|
def flash_task(label, elf_rel):
|
|
hex_rel = elf_rel.rsplit(".elf", 1)[0] + ".hex"
|
|
return {
|
|
"label": label, "type": "shell", "command": cli,
|
|
"args": extra_args + ["-w", "${workspaceFolder}/" + hex_rel, "-v", "-rst"],
|
|
"group": "none", "problemMatcher": []
|
|
}
|
|
data["tasks"] = [t for t in data["tasks"] if t["label"] != "Flash"]
|
|
data["tasks"].insert(2, flash_task("Flash Boot", boot_elf))
|
|
data["tasks"].insert(3, flash_task("Flash Appli", appli_elf))
|
|
data["tasks"].append({"label": "Flash All (Boot + Appli)", "dependsOrder": "sequence", "dependsOn": ["Flash Boot", "Flash Appli"], "problemMatcher": []})
|
|
with open(path, "w") as f:
|
|
json.dump(data, f, indent=2)
|
|
PYEOF
|
|
info "tasks.json adapte pour la structure Boot+Appli (Flash Boot / Flash Appli separes)."
|
|
fi
|
|
|
|
# --- launch.json ---
|
|
LAUNCH_CMDS_APPLI='"monitor halt", "load", "tbreak main"'
|
|
LAUNCH_CMDS_SINGLE='"monitor halt", "load", "tbreak main", "monitor reset"'
|
|
|
|
if [ -n "$BOOT_ELF_REL" ] && [ -d "$PROJECT_ROOT/Boot" ]; then
|
|
cat > "$PROJECT_ROOT/.vscode/launch.json" << EOF
|
|
{
|
|
"version": "0.2.0",
|
|
"configurations": [
|
|
{
|
|
"name": "Debug Boot",
|
|
"type": "cortex-debug",
|
|
"request": "launch",
|
|
"cwd": "\${workspaceFolder}",
|
|
"executable": "\${workspaceFolder}/$BOOT_ELF_REL",
|
|
"servertype": "external",
|
|
"gdbTarget": "localhost:$DEBUG_GDB_PORT",
|
|
"gdbPath": "$ARM_GDB_PATH",
|
|
"overrideLaunchCommands": [$LAUNCH_CMDS_SINGLE],
|
|
"preLaunchTask": "Start ST-LINK GDB Server",
|
|
"postDebugTask": "Stop ST-LINK GDB Server"
|
|
},
|
|
{
|
|
"name": "Debug Appli",
|
|
"type": "cortex-debug",
|
|
"request": "launch",
|
|
"cwd": "\${workspaceFolder}",
|
|
"executable": "\${workspaceFolder}/$APPLI_ELF_REL",
|
|
"servertype": "external",
|
|
"gdbTarget": "localhost:$DEBUG_GDB_PORT",
|
|
"gdbPath": "$ARM_GDB_PATH",
|
|
"overrideLaunchCommands": [$LAUNCH_CMDS_APPLI],
|
|
"preLaunchTask": "Start ST-LINK GDB Server",
|
|
"postDebugTask": "Stop ST-LINK GDB Server"
|
|
}
|
|
]
|
|
}
|
|
EOF
|
|
info "NOTE : structure Boot+Appli detectee. Workflow de debogage :"
|
|
info " 1) Lancer 'Debug Boot', attendre le flash, arreter la session"
|
|
info " 2) Lancer 'Debug Appli', attendre l'arret sur main()"
|
|
info " 3) Appuyer sur le bouton NRST physique de la carte"
|
|
info " 4) Cliquer Continue"
|
|
info " (verifiez ce comportement sur votre projet - certains projets mono-image n'en ont pas besoin)"
|
|
else
|
|
cat > "$PROJECT_ROOT/.vscode/launch.json" << EOF
|
|
{
|
|
"version": "0.2.0",
|
|
"configurations": [
|
|
{
|
|
"name": "Debug",
|
|
"type": "cortex-debug",
|
|
"request": "launch",
|
|
"cwd": "\${workspaceFolder}",
|
|
"executable": "\${workspaceFolder}/$APPLI_ELF_REL",
|
|
"servertype": "external",
|
|
"gdbTarget": "localhost:$DEBUG_GDB_PORT",
|
|
"gdbPath": "$ARM_GDB_PATH",
|
|
"overrideLaunchCommands": [$LAUNCH_CMDS_SINGLE],
|
|
"preLaunchTask": "Start ST-LINK GDB Server",
|
|
"postDebugTask": "Stop ST-LINK GDB Server"
|
|
}
|
|
]
|
|
}
|
|
EOF
|
|
fi
|
|
info "Genere : .vscode/launch.json"
|
|
|
|
# ==============================================================================
|
|
log "Termine"
|
|
# ==============================================================================
|
|
echo ""
|
|
echo "Recapitulatif :"
|
|
echo " - Build : Cmd+Shift+B dans VS Code, ou tache 'Build'"
|
|
echo " - Flash : Terminal > Run Task > Flash (ou 'Flash Boot'/'Flash Appli')"
|
|
echo " - Debug : panneau Run and Debug de VS Code"
|
|
echo ""
|
|
echo "Extensions VS Code requises (a installer manuellement si absentes) :"
|
|
echo " - C/C++ (ms-vscode.cpptools)"
|
|
echo " - Cortex-Debug (marus25.cortex-debug)"
|
|
echo ""
|
|
if [ "$BUILD_STATUS" -ne 0 ]; then
|
|
echo "ATTENTION : la compilation de test a echoue - voir les messages ci-dessus"
|
|
echo "avant de considerer la configuration comme terminee."
|
|
fi
|