Multiple Targets
Track memory across different boards, build types, or feature variants. Each target maintains its own independent history in the MemBrowse Portal.
Examples of targets:
- Different boards:
stm32f4,nrf52840,esp32 - Build types:
debug,release - Feature variants:
with-bluetooth,minimal
Targets Configuration
Create .github/membrowse-targets.json to define your build targets:
{
"targets": [
{
"name": "stm32f4",
"elf": "build/stm32f4/firmware.elf",
"ld": "boards/stm32f4/linker.ld",
"build_script": "make TARGET=stm32f4"
},
{
"name": "nrf52840",
"elf": "build/nrf52840/firmware.elf",
"ld": "boards/nrf52840/linker.ld boards/nrf52840/memory.ld",
"build_script": "make TARGET=nrf52840"
}
]
}
Target Properties
| Property | Required | Description |
|---|---|---|
name | Yes | Unique identifier for this target |
elf | Yes | Path to the ELF file after building |
ld | No | Path to linker script(s), space-separated if multiple. If omitted, MemBrowse uses default Code/Data regions based on ELF section flags. |
build_script | Yes | Command to build this target |
def | No | Linker script variable definitions (e.g., "__flash_size__=4096K __ram_size__=256K") |
Multiple Linker Scripts
If your project uses multiple linker scripts, list them space-separated:
{
"name": "my-target",
"elf": "build/firmware.elf",
"ld": "memory.ld sections.ld board.ld"
}
MemBrowse will parse all scripts to understand your complete memory layout.
Linker Variable Definitions
Use the def property to pass variable definitions to the linker script parser. This is useful when your linker scripts use variables for memory sizes:
{
"name": "stm32f4",
"elf": "build/firmware.elf",
"ld": "linker.ld",
"build_script": "make all",
"def": "__flash_size__=512K __ram_size__=128K"
}
In the workflow, pass this to the action:
- name: Analyze memory
uses: membrowse/membrowse-action@v1
with:
elf: ${{ matrix.target.elf }}
ld: ${{ matrix.target.ld }}
target_name: ${{ matrix.target.name }}
api_key: ${{ secrets.MEMBROWSE_API_KEY }}
linker_vars: ${{ matrix.target.def }}
Full Workflow with Matrix Builds
With multiple targets, each target runs as a separate matrix job. Unlike the single-target setup where the comment step runs inline, here the reports from each matrix job need to be collected into one place first. Each analyze job uploads its report as an artifact:
- name: Upload report artifact
if: ${{ steps.analyze.outcome == 'success' }}
uses: actions/upload-artifact@v4
with:
name: membrowse-report-${{ matrix.target.name }}
path: ${{ steps.analyze.outputs.report_path }}
Then a separate comment job downloads all the artifacts and aggregates them into a single PR comment:
comment:
needs: analyze
runs-on: ubuntu-latest
if: github.event_name == 'pull_request'
steps:
- uses: actions/checkout@v5
- name: Download report artifacts
uses: actions/download-artifact@v4
with:
pattern: membrowse-report-*
path: reports
merge-multiple: true
- name: Post PR comment
uses: membrowse/membrowse-action/comment-action@v1
with:
json_files: "reports/*.json"
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
Complete workflow
Here's the full workflow. Create .github/workflows/membrowse.yml:
name: MemBrowse Memory Report
on:
pull_request:
push:
branches:
- main
permissions:
contents: read
pull-requests: write
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
setup:
runs-on: ubuntu-latest
outputs:
targets: ${{ steps.read-targets.outputs.targets }}
steps:
- uses: actions/checkout@v5
- name: Read targets configuration
id: read-targets
run: echo "targets=$(jq -c '.targets' .github/membrowse-targets.json)" >> $GITHUB_OUTPUT
analyze:
needs: setup
runs-on: ubuntu-latest
strategy:
matrix:
target: ${{ fromJson(needs.setup.outputs.targets) }}
steps:
- uses: actions/checkout@v5
with:
fetch-depth: 0
# Add your build tool setup here (e.g., arm-none-eabi-gcc)
- name: Build ${{ matrix.target.name }}
run: ${{ matrix.target.build_script }}
- name: Analyze memory
id: analyze
continue-on-error: true
uses: membrowse/membrowse-action@v1
with:
elf: ${{ matrix.target.elf }}
ld: ${{ matrix.target.ld }}
target_name: ${{ matrix.target.name }}
api_key: ${{ secrets.MEMBROWSE_API_KEY }}
linker_vars: ${{ matrix.target.def }}
- name: Upload report artifact
if: ${{ steps.analyze.outcome == 'success' }}
uses: actions/upload-artifact@v4
with:
name: membrowse-report-${{ matrix.target.name }}
path: ${{ steps.analyze.outputs.report_path }}
comment:
needs: analyze
runs-on: ubuntu-latest
if: github.event_name == 'pull_request'
steps:
- uses: actions/checkout@v5
- name: Download report artifacts
uses: actions/download-artifact@v4
with:
pattern: membrowse-report-*
path: reports
merge-multiple: true
- name: Post PR comment
uses: membrowse/membrowse-action/comment-action@v1
with:
json_files: "reports/*.json"
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
For multiple targets, all results appear in a single PR comment.
Action Reference
Inputs (membrowse/membrowse-action@v1)
| Input | Required | Description |
|---|---|---|
elf | No | Path to ELF file. Not required when identical=true. |
ld | No | Path to linker script(s), space-separated. If omitted, MemBrowse uses default Code/Data regions based on ELF section flags. |
target_name | Yes | Name for this build target |
api_key | No | MemBrowse API key. Not required for tokenless uploads in open-source projects. |
api_url | No | MemBrowse API base URL (default: https://api.membrowse.com) |
linker_vars | No | Linker script variable definitions, space-separated (e.g., __flash_size__=4096K __ram_size__=256K) |
dont_fail_on_alerts | No | Don't exit with failure on budget alerts (default: false) |
verbose | No | Logging level: WARNING, INFO, or DEBUG (default: WARNING) |
pr_author_name | No | PR author name (auto-detected from GitHub event if not provided) |
pr_author_email | No | PR author email (auto-detected from GitHub event if not provided) |
identical | No | Metadata-only upload, skip ELF analysis (default: false) |
Outputs
| Output | Description |
|---|---|
report_path | File path to the generated JSON report file |
Inputs (membrowse/membrowse-action/comment-action@v1)
The comment-action supports two modes: file mode (reads local JSON report files) and summary mode (fetches per-target summaries from the MemBrowse API). Use file mode for standard workflows, and summary mode when report artifacts aren't available (e.g., cross-workflow comments).
| Input | Required | Description |
|---|---|---|
json_files | No | Space-separated list of JSON report file paths or glob pattern (e.g., reports/*.json). Used in file mode. |
api_key | No | MemBrowse API key. When provided with commit, enables summary mode — fetches data from the API instead of reading JSON files. |
commit | No | Commit SHA to fetch summary for. Requires api_key. |
pr_number | No | PR number to post comment on. Auto-detected from GitHub event context or commit SHA if not provided. |
api_url | No | MemBrowse API base URL (default: https://api.membrowse.com) |
comment_template | No | Path to a custom Jinja2 template file for comment formatting |
Either json_files or both api_key + commit must be provided.