Why I Started Using This Tool

Here's the routine I was doing every time I changed one line of C. Switch to the terminal and run make. Type an scp command to copy the binary to the board. ssh into the board, run chmod +x, and start gdbserver. Then switch back to VS Code and start the debugger. That's four steps and three windows, and there was always a moment where I wasn't sure if the board was running the new binary or the one from ten minutes ago.

In the last post I put the board's details (IP address, user, port) into settings.json. Now I'm using them. Over the next three posts I build a .vscode/tasks.json that turns the whole routine into a chain VS Code runs for me. This post covers the first link: the build.

What It Does

The finished tasks.json defines three tasks:

  1. build: compiles the program on the PC with the Makefile from #2.
  2. deploy: copies the compiled binary to the DE10-Nano over the network (#5).
  3. gdbserver: logs into the board and starts the program under gdbserver, waiting for the debugger to connect (#6).

They're linked with dependsOn. When you run gdbserver, VS Code sees it depends on deploy, and deploy depends on build. So it runs build → deploy → gdbserver, and if any step fails, the chain stops. You can't reach the debug step without building and copying first, so you never debug a stale binary.

The file starts with a few comments:

{
  // Deploy + on-board debug pipeline for the DE10-Nano.
  // All board/host values come from .vscode/settings.json (${config:xxx}).
  // launch.json's preLaunchTask is "gdbserver", which chains: build -> deploy -> gdbserver.
  "version": "2.0.0",

Normal JSON doesn't allow comments, but VS Code's own config files (tasks.json, settings.json, launch.json) use a looser format called JSON with Comments (JSONC), so // comments are fine. I use them as a mini README at the top of the file.

Here's the build task:

{
  "label": "build",
  "type": "shell",
  "command": "C:/msys64/mingw64/bin/mingw32-make.exe",
  "group": { "kind": "build", "isDefault": true },
  "problemMatcher": ["$gcc"]
}
  • command runs make. Windows doesn't include make, so I use the one from MSYS2, a free package that brings GNU tools to Windows. The MinGW build is named mingw32-make.exe, and I give its full path so it works even if it isn't on my PATH. It reads the Makefile from #2, which calls the ARM cross-compiler.
  • group marks this as the default build task, so Ctrl+Shift+B runs it straight away, without a menu.
  • "problemMatcher": ["$gcc"]: last time I used an empty problem matcher. This time it's a real one. $gcc is built into VS Code. It reads the compiler output, finds lines like src/main.c:12:5: error: ..., and lists them in the Problems panel as clickable links to the exact line. Much easier than scrolling through terminal text.

One thing to check now, before the deploy task needs it: the bin setting (main) has to match the name your Makefile actually produces. My Makefile in #2 used BIN := ytdemo, so update one or the other so they agree.

Final Verdict

On its own, this task is small: Ctrl+Shift+B builds, and compile errors show up as clickable entries in the Problems panel. But it's the base the rest of the chain stands on. Next up is the deploy task, which depends on build and copies the fresh binary to the board every time.