Add script to generate compiler_commands.json for all projects

We can then use this script in the dev container create command and in
the clang-tidy CI job. This ensures clang-tidy can find all the
correct imports.
diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json
index 00039a7..71defea 100644
--- a/.devcontainer/devcontainer.json
+++ b/.devcontainer/devcontainer.json
@@ -2,7 +2,7 @@
   "image": "ghcr.io/cheriot-platform/devcontainer:latest",
   "remoteUser": "cheriot",
   "containerUser": "cheriot",
-  "onCreateCommand": "git config --global --add safe.directory /workspaces/cheriot-rtos && git submodule update --init --recursive && for dir in tests tests.extra/*/ ex*/[[:digit:]]* ; do (echo Generating compile_commands.json for $dir; cd $dir && xmake f --sdk=/cheriot-tools/ && xmake project -k compile_commands); done",
+  "onCreateCommand": "git config --global --add safe.directory /workspaces/cheriot-rtos && git submodule update --init --recursive && ./scripts/generate_compile_commands.sh",
   "customizations": {
     "vscode": {
       "extensions": [
diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index 833a291..a4bf284 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -83,6 +83,8 @@
       uses: actions/checkout@v4
       with:
         submodules: recursive
+    - name: Generate compiler_commands.json files
+      run: ./scripts/generate_compiler_commands.sh
     - name: Run clang-format and clang-tidy
       run: ./scripts/run_clang_tidy_format.sh /cheriot-tools/bin
 
diff --git a/scripts/common.sh b/scripts/common.sh
new file mode 100644
index 0000000..4026df4
--- /dev/null
+++ b/scripts/common.sh
@@ -0,0 +1,20 @@
+# Common functions to include in multiple scripts
+
+function error() {
+    echo "Error: $1"
+    exit 1
+}
+
+function ensure_cheriot_rtos_root () {
+    [ -d sdk ] || error "Please run this script from the root of the cheriot-rtos repository."
+}
+
+function find_sdk () {
+    if [ -n "$1" ]; then
+        SDK="$(readlink -f $1)"
+    elif [ -d "/cheriot-tools/bin" ]; then
+        SDK=/cheriot-tools
+    else
+        error "No SDK found, please provide as first argument."
+    fi
+}
diff --git a/scripts/generate_compiler_commands.sh b/scripts/generate_compiler_commands.sh
new file mode 100755
index 0000000..cc75a0b
--- /dev/null
+++ b/scripts/generate_compiler_commands.sh
@@ -0,0 +1,17 @@
+#!/bin/env bash
+
+# Generate compile commands files for all known projects in this repo
+
+
+. "$(dirname $0)"/common.sh
+
+ensure_cheriot_rtos_root
+
+find_sdk $1
+
+echo "Using SDK=$SDK"
+
+for dir in tests tests.extra/*/ ex*/[[:digit:]]* ; do 
+    echo Generating compile_commands.json for $dir
+    (cd $dir && xmake f --sdk="${SDK}" && xmake project -k compile_commands)
+done