Extensions
- I'm using the rust-analyzer extension for code analysis. It is better than the Rust extension.
- CodeLLDB extension to enable debugging of a Rust program, using lldb.
Cross-compiling
The target board has a 64-bit ARM processor, so I want to use Rust to cross-compile for target aarch64-unknown-linux-gnu.
I'm using Ubuntu 18.04 LTS (it is old, but I have to use it to support an old project built with an old Yocto version). I used apt to install Ubuntu package gcc-8-aarch64-linux-gnu. On a more recent Ubuntu perhaps I could install a more modern package such as gcc-11-aarch64-linux-gnu.
In my ~/.cargo/config:
[target.aarch64-unknown-linux-gnu]
linker = "aarch64-linux-gnu-gcc-8"
Then, I can manually use cargo to cross-compile using the command:
cargo build --target=aarch64-unknown-linux-gnu
Then to cross-compile within VS Code — In my VS Code workspace for myapp, in .vscode/tasks.json:
{
...
"tasks": [
...
{
"label": "rust: cargo build ARM"
"type": "cargo",
"command": "build",
"args": ["--target=aarch64-unknown-linux-gnu"],
"problemMatcher": [
"$rustc"
],
"group": "build",
},
]
}
Then I just do Shift-Ctrl-B, and select the "rust: cargo build ARM" build task.
Remote debugging
The goal is to run myapp on targetboard.local as low-privileges user targetuser (rather than root).
In VS Code, the CodeLLDB extension uses lldb to debug Rust programs. But, lldb is a large compilation in Yocto for the target hardware. But, it works fine to connect to gdbserver running on the target board. The embedded Linux image running on the target board just needs to have gdbserver on it.
The target board also needs to have an SSH server running on it, with support for either rsync or plain SSH copy. rsync is good because it can be faster to do the copy of the executable to the target.
In my VS Code workspace for myapp, in .vscode/launch.json:
{
...
"configurations": [
...
{
"type": "lldb",
"request": "custom",
"name": "Remote executable 'myapp'",
"preLaunchTask": "rust: remote ARM debug setup",
"targetCreateCommands": ["target create ${workspaceFolder}/target/aarch64-unknown-linux-gnu/debug/myapp"],
"processCreateCommands": ["gdb-remote targetboard.local:17777"]
}
]
}
In my VS Code workspace for myapp, in .vscode/tasks.json:
{
...
"tasks": [
...
{
"label": "rust: remote ARM debug setup",
"type": "shell",
"command": "${workspaceFolder}/scripts/remote_debug.sh",
"args": [ "${workspaceFolder}", "targetboard.local", "17777" ],
"group": "none",
"dependsOn": [
"rust: cargo build ARM",
],
},
]
}
In my VS Code workspace for myapp, I created the script scripts/remote_debug.sh:
#!/bin/bash
VSCODE_WS="$1"
SSH_REMOTE="$2"
GDBPORT="$3"
APP="myapp"
TARGET_ARCH="aarch64-unknown-linux-gnu"
BUILD_BIN_FILE="${VSCODE_WS}/target/${TARGET_ARCH}/debug/${APP}"
TARGET_USER="targetuser"
TARGET_BIN_FILE="/home/targetuser/${APP}"
TARGET_CWD="/var/lib/myapp"
ssh "${TARGET_USER}@${SSH_REMOTE}" "killall gdbserver ${APP}"
if ! rsync -avz "${BUILD_BIN_FILE}" "${TARGET_USER}@${SSH_REMOTE}:${TARGET_BIN_FILE}"; then
# If rsync doesn't work, it may not be available on target. Fallback to trying SSH copy.
if ! scp "${BUILD_BIN_FILE}" "${TARGET_USER}@${SSH_REMOTE}:${TARGET_BIN_FILE}"; then
exit 2
fi
fi
ssh -f "${TARGET_USER}@${SSH_REMOTE}" "sh -c 'cd ${TARGET_CWD}; nohup gdbserver *:${GDBPORT} ${TARGET_BIN_FILE} > /dev/null 2>&1 &'"
The target CWD /var/lib/myapp needs to exist with the right user permissions for targetuser. I could just specify /home/targetuser instead.
With that set up, I can just press F5 in VS Code, and it will compile, copy the file to the target board, and start remote-debugging it through gdbserver.