@typecad/framework-zephyr 1.0.0-alpha.16 → 1.0.0-alpha.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +202 -21
- package/README.md +49 -87
- package/dist/as-built.d.ts +2 -2
- package/dist/as-built.js +2 -2
- package/dist/audit.d.ts +111 -0
- package/dist/audit.js +416 -0
- package/dist/boardgen.d.ts +1 -9
- package/dist/boardgen.js +288 -47
- package/dist/chips/resolve.js +20 -0
- package/dist/chips/types.d.ts +22 -1
- package/dist/debug-codegen.js +1 -1
- package/dist/display/bindings.d.ts +55 -0
- package/dist/display/bindings.js +316 -0
- package/dist/display/gfx.d.ts +2 -3
- package/dist/display/gfx.js +166 -154
- package/dist/display/index.js +20 -1
- package/dist/display/mipi-dbi-host.d.ts +9 -0
- package/dist/display/mipi-dbi-host.js +174 -0
- package/dist/display/profiles.d.ts +109 -4
- package/dist/display/profiles.js +270 -7
- package/dist/display/touch-adapter.js +119 -49
- package/dist/display/ui-adapter-eink.d.ts +2 -0
- package/dist/display/ui-adapter-eink.js +4 -0
- package/dist/display/ui-adapter-gray.d.ts +8 -0
- package/dist/display/ui-adapter-gray.js +170 -0
- package/dist/display/ui-adapter-mono.d.ts +13 -0
- package/dist/display/ui-adapter-mono.js +230 -0
- package/dist/display/ui-adapter-native.d.ts +10 -0
- package/dist/display/ui-adapter-native.js +295 -0
- package/dist/display/ui-adapter-shared.d.ts +11 -0
- package/dist/display/ui-adapter-shared.js +122 -0
- package/dist/display/ui-adapter.js +510 -558
- package/dist/doctor.js +4 -4
- package/dist/dt-config/custom-board.js +2 -2
- package/dist/dt-config/kconfig.d.ts +62 -1
- package/dist/dt-config/kconfig.js +141 -38
- package/dist/dt-config/overlay.d.ts +15 -2
- package/dist/dt-config/overlay.js +433 -18
- package/dist/framework.manifest.d.ts +10 -4
- package/dist/framework.manifest.js +133 -17
- package/dist/index.d.ts +2 -0
- package/dist/index.js +14 -6
- package/dist/licenses.d.ts +2 -2
- package/dist/licenses.js +13 -92
- package/dist/lowering/can.d.ts +25 -0
- package/dist/lowering/can.js +97 -0
- package/dist/lowering/clock.d.ts +17 -0
- package/dist/lowering/clock.js +58 -0
- package/dist/lowering/fs.js +1 -1
- package/dist/lowering/gpio.js +0 -32
- package/dist/lowering/hid.d.ts +27 -0
- package/dist/lowering/hid.js +244 -0
- package/dist/lowering/http.js +264 -32
- package/dist/lowering/i2c.d.ts +8 -0
- package/dist/lowering/i2c.js +137 -5
- package/dist/lowering/i2s.d.ts +27 -0
- package/dist/lowering/i2s.js +98 -0
- package/dist/lowering/index.d.ts +9 -1
- package/dist/lowering/index.js +25 -1
- package/dist/lowering/interrupts.js +6 -0
- package/dist/lowering/matrix.d.ts +15 -0
- package/dist/lowering/matrix.js +63 -0
- package/dist/lowering/mqtt.js +110 -8
- package/dist/lowering/power.d.ts +3 -2
- package/dist/lowering/power.js +20 -45
- package/dist/lowering/pwm.js +25 -0
- package/dist/lowering/sensor.d.ts +2 -2
- package/dist/lowering/sensor.js +8 -4
- package/dist/lowering/strip.d.ts +16 -0
- package/dist/lowering/strip.js +70 -0
- package/dist/lowering/thread.js +5 -1
- package/dist/lowering/trace.d.ts +44 -0
- package/dist/lowering/trace.js +239 -0
- package/dist/lowering/uart.js +6 -1
- package/dist/lowering/usb.d.ts +3 -1
- package/dist/lowering/usb.js +16 -13
- package/dist/lowering/wdt.js +2 -29
- package/dist/sbom.d.ts +181 -0
- package/dist/sbom.js +901 -0
- package/dist/sdk/board-catalog-sync.d.ts +1 -3
- package/dist/sdk/board-catalog-sync.js +4 -10
- package/dist/strategy.d.ts +82 -46
- package/dist/strategy.js +639 -182
- package/dist/tmp-probe.d.ts +2 -0
- package/dist/tmp-probe.js +9 -0
- package/dist/toolchain/debug-config.d.ts +50 -90
- package/dist/toolchain/debug-config.js +239 -510
- package/dist/toolchain/env-check.d.ts +1 -3
- package/dist/toolchain/env-check.js +2 -7
- package/dist/toolchain/index.d.ts +28 -3
- package/dist/toolchain/index.js +498 -62
- package/dist/toolchain/runners.d.ts +16 -0
- package/dist/toolchain/runners.js +75 -0
- package/dist/toolchain/scaffold.d.ts +5 -2
- package/dist/toolchain/scaffold.js +79 -15
- package/dist/toolchain/west-discover.d.ts +6 -0
- package/dist/toolchain/west-discover.js +36 -13
- package/dist/toolchain/west-spawn.js +8 -2
- package/dist/west-inventory.d.ts +25 -0
- package/dist/west-inventory.js +97 -0
- package/installer/README.md +328 -328
- package/installer/install.sh +2 -2
- package/installer/templates/project/.typecad/activate-zephyr.ps1 +1 -1
- package/installer/templates/project/.typecad/activate-zephyr.sh +1 -1
- package/installer/templates/project/.vscode/settings.json +1 -1
- package/installer/templates/project/README.md +2 -2
- package/package.json +5 -5
- package/src/as-built.ts +206 -206
- package/src/audit.ts +529 -0
- package/src/boardgen.ts +265 -50
- package/src/chips/resolve.ts +21 -0
- package/src/chips/types.ts +10 -1
- package/src/display/bindings.ts +347 -0
- package/src/display/gfx.ts +318 -306
- package/src/display/index.ts +87 -70
- package/src/display/mipi-dbi-host.ts +183 -0
- package/src/display/profiles.ts +458 -139
- package/src/display/touch-adapter.ts +119 -49
- package/src/display/ui-adapter-eink.ts +13 -0
- package/src/display/ui-adapter-gray.ts +178 -0
- package/src/display/ui-adapter-mono.ts +238 -0
- package/src/display/ui-adapter-native.ts +304 -0
- package/src/display/ui-adapter-shared.ts +125 -0
- package/src/display/ui-adapter.ts +732 -781
- package/src/doctor.ts +4 -4
- package/src/dt-config/custom-board.ts +2 -2
- package/src/dt-config/kconfig.ts +647 -505
- package/src/dt-config/overlay.ts +1475 -1058
- package/src/framework.manifest.ts +659 -535
- package/src/index.ts +16 -6
- package/src/licenses.ts +346 -425
- package/src/lowering/can.ts +140 -0
- package/src/lowering/clock.ts +91 -0
- package/src/lowering/fs.ts +135 -135
- package/src/lowering/gpio.ts +0 -33
- package/src/lowering/hid.ts +261 -0
- package/src/lowering/http.ts +264 -32
- package/src/lowering/i2c.ts +142 -5
- package/src/lowering/i2s.ts +143 -0
- package/src/lowering/index.ts +18 -1
- package/src/lowering/interrupts.ts +6 -0
- package/src/lowering/matrix.ts +70 -0
- package/src/lowering/mqtt.ts +109 -8
- package/src/lowering/power.ts +41 -0
- package/src/lowering/pwm.ts +192 -167
- package/src/lowering/sensor.ts +159 -155
- package/src/lowering/strip.ts +81 -0
- package/src/lowering/thread.ts +5 -1
- package/src/lowering/trace.ts +270 -0
- package/src/lowering/uart.ts +6 -1
- package/src/lowering/usb.ts +16 -13
- package/src/lowering/wdt.ts +2 -25
- package/src/sbom.ts +1117 -0
- package/src/sdk/board-catalog-sync.ts +4 -25
- package/src/strategy.ts +2680 -2309
- package/src/toolchain/debug-config.ts +262 -522
- package/src/toolchain/env-check.ts +279 -285
- package/src/toolchain/index.ts +1792 -1359
- package/src/toolchain/runners.ts +80 -0
- package/src/toolchain/scaffold.ts +355 -296
- package/src/toolchain/west-discover.ts +35 -13
- package/src/toolchain/west-spawn.ts +174 -168
- package/src/west-inventory.ts +102 -0
- package/dist/async/timer-polyfill.d.ts +0 -10
- package/dist/async/timer-polyfill.js +0 -95
- package/dist/chips/board-overrides.d.ts +0 -7
- package/dist/chips/board-overrides.js +0 -11
- package/dist/chips/esp32.d.ts +0 -2
- package/dist/chips/esp32.js +0 -71
- package/dist/chips/esp32s3.d.ts +0 -2
- package/dist/chips/esp32s3.js +0 -103
- package/dist/chips/soc/.d.ts +0 -2
- package/dist/chips/soc/.js +0 -129
- package/dist/chips/soc/esp32.d.ts +0 -2
- package/dist/chips/soc/esp32.js +0 -120
- package/dist/chips/soc/esp32c3.d.ts +0 -2
- package/dist/chips/soc/esp32c3.js +0 -90
- package/dist/chips/soc/esp32c6.d.ts +0 -2
- package/dist/chips/soc/esp32c6.js +0 -109
- package/dist/chips/soc/esp32s3.d.ts +0 -2
- package/dist/chips/soc/esp32s3.js +0 -189
- package/dist/chips/soc/index.d.ts +0 -2
- package/dist/chips/soc/index.js +0 -23
- package/dist/chips/soc/nrf52840.d.ts +0 -2
- package/dist/chips/soc/nrf52840.js +0 -130
- package/dist/chips/soc/rp2040.d.ts +0 -2
- package/dist/chips/soc/rp2040.js +0 -141
- package/dist/chips/soc/rp2350a.d.ts +0 -2
- package/dist/chips/soc/rp2350a.js +0 -145
- package/dist/chips/soc/samd21g18a.d.ts +0 -2
- package/dist/chips/soc/samd21g18a.js +0 -143
- package/dist/chips/soc/stm32f411xe.d.ts +0 -2
- package/dist/chips/soc/stm32f411xe.js +0 -251
- package/dist/chips/xiao-ble.d.ts +0 -2
- package/dist/chips/xiao-ble.js +0 -100
- package/dist/lowering/pulse.d.ts +0 -7
- package/dist/lowering/pulse.js +0 -51
- package/dist/lowering/tone.d.ts +0 -10
- package/dist/lowering/tone.js +0 -63
- package/dist/lowering/worker-backing.d.ts +0 -14
- package/dist/lowering/worker-backing.js +0 -79
- package/dist/lowering/worker.d.ts +0 -6
- package/dist/lowering/worker.js +0 -14
- package/dist/sdk/board-data.generated.d.ts +0 -2
- package/dist/sdk/board-data.generated.js +0 -4
- package/dist/sdk/catalog-walker.d.ts +0 -90
- package/dist/sdk/catalog-walker.js +0 -682
- package/dist/sdk/dts-reader.d.ts +0 -83
- package/dist/sdk/dts-reader.js +0 -596
- package/src/debug-codegen.ts +0 -207
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export interface RunnersFacts {
|
|
2
|
+
/** The board's declared default debug runner (e.g. 'openocd', 'jlink'). */
|
|
3
|
+
readonly debugRunner?: string;
|
|
4
|
+
/** Absolute path to the arch gdb binary (config.gdb). */
|
|
5
|
+
readonly gdb?: string;
|
|
6
|
+
/** All runners the board configured. */
|
|
7
|
+
readonly runners: readonly string[];
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Parse the subset of runners.yaml cuttlefish consumes. Exported for tests.
|
|
11
|
+
* Returns undefined on shapes it does not understand (callers treat as
|
|
12
|
+
* "no facts" — never crash a build over diagnostics data).
|
|
13
|
+
*/
|
|
14
|
+
export declare function parseRunnersYaml(text: string): RunnersFacts | undefined;
|
|
15
|
+
/** Read the resolved runner facts for a build dir. undefined when absent/unparseable. */
|
|
16
|
+
export declare function readRunnersFacts(buildDir: string): RunnersFacts | undefined;
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
// ---------------------------------------------------------------------------
|
|
2
|
+
// runners.ts — read west's resolved runner facts from a built Zephyr tree.
|
|
3
|
+
//
|
|
4
|
+
// After any successful `west build`, Zephyr writes build/zephyr/runners.yaml —
|
|
5
|
+
// the FULLY RESOLVED debug/flash configuration for the board: the arch gdb
|
|
6
|
+
// binary, the openocd binary + its script search dirs, the jlink device name,
|
|
7
|
+
// the board's declared default debug runner. It is the single source of debug
|
|
8
|
+
// truth west itself uses (`west debug` / `west debugserver` read the same
|
|
9
|
+
// file), so cuttlefish reads it instead of reconstructing any of this.
|
|
10
|
+
//
|
|
11
|
+
// The parser below is deliberately minimal: it understands exactly the shape
|
|
12
|
+
// west's run_common.py emits — top-level scalars, a list section whose items
|
|
13
|
+
// sit at column 0, and a nested config map — and ignores everything else
|
|
14
|
+
// (e.g. the args section). A general YAML dependency is not worth it for one
|
|
15
|
+
// machine-generated file.
|
|
16
|
+
// ---------------------------------------------------------------------------
|
|
17
|
+
import fs from 'node:fs';
|
|
18
|
+
import { join } from 'node:path';
|
|
19
|
+
/**
|
|
20
|
+
* Parse the subset of runners.yaml cuttlefish consumes. Exported for tests.
|
|
21
|
+
* Returns undefined on shapes it does not understand (callers treat as
|
|
22
|
+
* "no facts" — never crash a build over diagnostics data).
|
|
23
|
+
*/
|
|
24
|
+
export function parseRunnersYaml(text) {
|
|
25
|
+
const runners = [];
|
|
26
|
+
let debugRunner;
|
|
27
|
+
let gdb;
|
|
28
|
+
// Section state: '' = top level, 'runners' = the list, 'config' = the map.
|
|
29
|
+
let section = '';
|
|
30
|
+
for (const rawLine of text.split(/\r?\n/)) {
|
|
31
|
+
const trimmed = rawLine.trim();
|
|
32
|
+
if (trimmed.startsWith('#') || trimmed === '')
|
|
33
|
+
continue;
|
|
34
|
+
// List items — west writes the runners list at column 0 and
|
|
35
|
+
// openocd_search indented; both belong to the last-opened section.
|
|
36
|
+
if (trimmed.startsWith('- ')) {
|
|
37
|
+
const item = trimmed.slice(2).trim();
|
|
38
|
+
if (section === 'runners')
|
|
39
|
+
runners.push(item);
|
|
40
|
+
continue; // other sections' lists (openocd_search, args) are unused
|
|
41
|
+
}
|
|
42
|
+
const indent = rawLine.length - rawLine.trimStart().length;
|
|
43
|
+
const m = trimmed.match(/^([A-Za-z0-9_.-]+):\s*(.*)$/);
|
|
44
|
+
if (!m)
|
|
45
|
+
continue; // e.g. west's empty-list `[]` lines — skip, don't bail
|
|
46
|
+
const [, key, value] = m;
|
|
47
|
+
if (indent === 0) {
|
|
48
|
+
if (key === 'runners') {
|
|
49
|
+
section = 'runners';
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
if (key === 'config') {
|
|
53
|
+
section = 'config';
|
|
54
|
+
continue;
|
|
55
|
+
}
|
|
56
|
+
section = '';
|
|
57
|
+
if (key === 'debug-runner' && value)
|
|
58
|
+
debugRunner = value.trim();
|
|
59
|
+
continue;
|
|
60
|
+
}
|
|
61
|
+
if (section === 'config' && key === 'gdb' && value) {
|
|
62
|
+
gdb = value.trim().replace(/^['"]|['"]$/g, '');
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
return { runners, ...(debugRunner ? { debugRunner } : {}), ...(gdb ? { gdb } : {}) };
|
|
66
|
+
}
|
|
67
|
+
/** Read the resolved runner facts for a build dir. undefined when absent/unparseable. */
|
|
68
|
+
export function readRunnersFacts(buildDir) {
|
|
69
|
+
try {
|
|
70
|
+
return parseRunnersYaml(fs.readFileSync(join(buildDir, 'zephyr', 'runners.yaml'), 'utf-8'));
|
|
71
|
+
}
|
|
72
|
+
catch {
|
|
73
|
+
return undefined;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Returns true when the file was written (content changed or file was new). */
|
|
3
3
|
export declare function writeIfChanged(filePath: string, content: string): boolean;
|
|
4
4
|
/**
|
|
5
|
-
* Append
|
|
5
|
+
* Append typecad-hal library packages' devicetree overlay fragments to the
|
|
6
6
|
* generated overlay. Library entries come from the transpiler's libraries.json
|
|
7
7
|
* sidecar (next to the emitted sources) and are already gated on the
|
|
8
8
|
* library's include token appearing in the emitted sources — no re-detection.
|
|
@@ -21,4 +21,7 @@ export declare function appendLibraryOverlayFragments(overlay: string, projectRo
|
|
|
21
21
|
*
|
|
22
22
|
* Idempotent. Mirrors scaffoldEspIdfProject's writeIfChanged discipline.
|
|
23
23
|
*/
|
|
24
|
-
export declare function scaffoldZephyrProject(projectRoot: string, debug?: boolean, userKconfig?: Record<string, string>, psram?: 'opi' | 'quad'
|
|
24
|
+
export declare function scaffoldZephyrProject(projectRoot: string, debug?: boolean, userKconfig?: Record<string, string>, psram?: 'opi' | 'quad', trace?: {
|
|
25
|
+
enabled?: boolean;
|
|
26
|
+
intervalMs?: number;
|
|
27
|
+
}): boolean;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// ---------------------------------------------------------------------------
|
|
2
2
|
// Zephyr project scaffolding
|
|
3
3
|
//
|
|
4
|
-
// Writes the CMakeLists.txt + prj.conf around the
|
|
4
|
+
// Writes the CMakeLists.txt + prj.conf around the typecad-hal-emitted src/main.cpp
|
|
5
5
|
// so `west build` has a valid Zephyr application. Idempotent: overwrites the
|
|
6
6
|
// generated files only when their content changes (avoids invalidating the
|
|
7
7
|
// Ninja incremental build's mtime-based dependency tracking).
|
|
@@ -9,7 +9,9 @@
|
|
|
9
9
|
import { writeFileSync, existsSync, mkdirSync, readFileSync, readdirSync } from 'node:fs';
|
|
10
10
|
import { join } from 'node:path';
|
|
11
11
|
import { resolveKconfigFragments } from '../dt-config/kconfig.js';
|
|
12
|
-
import { scanSensorParts } from './index.js';
|
|
12
|
+
import { scanSensorParts, scanStrips, scanHid, scanMatrix } from './index.js';
|
|
13
|
+
import { profileFromEmittedSource, transportFor, panelControllerFor } from '../display/profiles.js';
|
|
14
|
+
import { readDisplayBinding } from '../display/bindings.js';
|
|
13
15
|
import { readCuttlefishLibrarySidecar } from '@typecad/cuttlefish/library-packages';
|
|
14
16
|
import { SENSOR_PART_INFO } from '@typecad/hal';
|
|
15
17
|
/** Write a file only if the content differs from the existing file.
|
|
@@ -28,7 +30,7 @@ export function writeIfChanged(filePath, content) {
|
|
|
28
30
|
return true;
|
|
29
31
|
}
|
|
30
32
|
/**
|
|
31
|
-
* Names of the
|
|
33
|
+
* Names of the typecad-hal-emitted C/C++ sources under src/ (top level only,
|
|
32
34
|
* matching the old `src/*.cpp src/*.c` glob; sorted so the generated
|
|
33
35
|
* CMakeLists.txt is stable across readdir orderings). Empty when no sources
|
|
34
36
|
* exist yet (first prepare call).
|
|
@@ -61,7 +63,7 @@ function readEmittedSources(srcDir) {
|
|
|
61
63
|
return out;
|
|
62
64
|
}
|
|
63
65
|
/**
|
|
64
|
-
* Append
|
|
66
|
+
* Append typecad-hal library packages' devicetree overlay fragments to the
|
|
65
67
|
* generated overlay. Library entries come from the transpiler's libraries.json
|
|
66
68
|
* sidecar (next to the emitted sources) and are already gated on the
|
|
67
69
|
* library's include token appearing in the emitted sources — no re-detection.
|
|
@@ -96,7 +98,7 @@ export function appendLibraryOverlayFragments(overlay, projectRoot) {
|
|
|
96
98
|
*
|
|
97
99
|
* Idempotent. Mirrors scaffoldEspIdfProject's writeIfChanged discipline.
|
|
98
100
|
*/
|
|
99
|
-
export function scaffoldZephyrProject(projectRoot, debug = false, userKconfig, psram) {
|
|
101
|
+
export function scaffoldZephyrProject(projectRoot, debug = false, userKconfig, psram, trace) {
|
|
100
102
|
const srcDir = join(projectRoot, 'src');
|
|
101
103
|
if (!existsSync(srcDir))
|
|
102
104
|
mkdirSync(srcDir, { recursive: true });
|
|
@@ -122,6 +124,22 @@ export function scaffoldZephyrProject(projectRoot, debug = false, userKconfig, p
|
|
|
122
124
|
const usage = {
|
|
123
125
|
usesAdc: uses('adc_'),
|
|
124
126
|
usesPwm: uses('pwm_'),
|
|
127
|
+
usesStrip: uses('led_strip'),
|
|
128
|
+
strips: scanStrips(src),
|
|
129
|
+
// Sensor parts drive CONFIG_W1 (1-Wire masters) and the exception
|
|
130
|
+
// lines; the same scan the exception block below re-runs.
|
|
131
|
+
sensorParts: scanSensorParts(src),
|
|
132
|
+
usesHid: uses('__tc_hid_'),
|
|
133
|
+
hidProtocol: scanHid(src),
|
|
134
|
+
usesMatrix: uses('__tc_matrix'),
|
|
135
|
+
matrix: scanMatrix(src),
|
|
136
|
+
usesPower: uses('sys_poweroff'),
|
|
137
|
+
usesClock: uses('__tc_rtc'),
|
|
138
|
+
usesCan: uses('can_'),
|
|
139
|
+
canLoopback: uses('CAN_MODE_LOOPBACK'),
|
|
140
|
+
usesI2s: uses('i2s_'),
|
|
141
|
+
// No chip facts at scaffold time — the prepare overlay omits the shim;
|
|
142
|
+
// the chip-aware build path synthesizes it.
|
|
125
143
|
usesDac: uses('dac_') || uses('__tc_dac'),
|
|
126
144
|
usesFS: uses('__tc_fs'),
|
|
127
145
|
usesHwtimer: uses('counter_') || uses('__tc_hw'),
|
|
@@ -130,6 +148,9 @@ export function scaffoldZephyrProject(projectRoot, debug = false, userKconfig, p
|
|
|
130
148
|
// call yet), but the shim still declared DEVICE_DT_GET(DT_NODELABEL(...))
|
|
131
149
|
// so the overlay must enable the node or the device symbol is missing.
|
|
132
150
|
usesI2c: uses('i2c_') || uses('__tc_i2c'),
|
|
151
|
+
// I2C target mode: every i2c.resp_* lowering calls i2c_target_register
|
|
152
|
+
// (and the shim's state carries the i2c_target_* vocabulary).
|
|
153
|
+
usesI2cTarget: uses('i2c_target_'),
|
|
133
154
|
// DT-bound sensor parts: the __tc_sensor_* state references and the
|
|
134
155
|
// sensor_sample_fetch/sensor_channel_get calls both carry the token.
|
|
135
156
|
usesSensor: uses('sensor_') || uses('__tc_sensor'),
|
|
@@ -138,12 +159,32 @@ export function scaffoldZephyrProject(projectRoot, debug = false, userKconfig, p
|
|
|
138
159
|
usesUart: uses('uart_') || uses('__tc_uart'),
|
|
139
160
|
// USB CDC serial: every usb.* lowering calls into the __tc_usb<N>_* shim
|
|
140
161
|
// (device + init helper emitted under usesUsb).
|
|
141
|
-
usesUsb: uses('
|
|
162
|
+
usesUsb: uses('__tc_usb0'),
|
|
142
163
|
// STM32F4 DBGMCU keep-SWD-alive init present (emitted for stm32f4 socs).
|
|
143
164
|
usesStm32DebugSleep: uses('__tc_stm32_dbgmcu'),
|
|
144
165
|
usesWdt: uses('wdt_'),
|
|
145
166
|
usesBle: uses('bt_') || uses('bt_gatt') || uses('bt_le_'),
|
|
146
167
|
usesDisplay: uses('display_write') || uses('display_init') || uses('display_fill_rect') || uses('__tc_display_dev') || uses('CuttlefishDisplayTarget'),
|
|
168
|
+
// Display transport + controller: recovered from the profile marker the
|
|
169
|
+
// display adapters stamp into the emitted source (the profile registry is
|
|
170
|
+
// the single source of truth — no geometry re-derivation here).
|
|
171
|
+
...(() => {
|
|
172
|
+
const profile = profileFromEmittedSource(src);
|
|
173
|
+
if (!profile)
|
|
174
|
+
return {};
|
|
175
|
+
// Registry profiles name a DT compatible via dtCompatible (the driver
|
|
176
|
+
// id itself isn't one); drop-in profiles use the driver string directly.
|
|
177
|
+
const bus = readDisplayBinding(profile.dtCompatible ?? profile.driver)?.busFamily;
|
|
178
|
+
if (bus === 'i2c')
|
|
179
|
+
return { displayBus: 'i2c' };
|
|
180
|
+
// Board-provided panels (native_sim's sdl_dc) carry their own fragments
|
|
181
|
+
// and no bus at all.
|
|
182
|
+
if (profile.boardProvidesDisplay)
|
|
183
|
+
return { displayKconfigExtra: profile.kconfig };
|
|
184
|
+
if (transportFor(profile) !== 'zephyr-display')
|
|
185
|
+
return {};
|
|
186
|
+
return { displayTransport: 'zephyr-display', displayController: panelControllerFor(profile) };
|
|
187
|
+
})(),
|
|
147
188
|
usesTouch: uses('ft6336u') || uses('touch_'),
|
|
148
189
|
// (The power HAL is removed; its former pm_/k_sleep token scan is gone —
|
|
149
190
|
// nothing here must match tx_power_dbm's `power` substring.)
|
|
@@ -174,7 +215,7 @@ export function scaffoldZephyrProject(projectRoot, debug = false, userKconfig, p
|
|
|
174
215
|
// configChanged and reconfigures with the new list baked in.
|
|
175
216
|
const sourceFiles = listEmittedSources(srcDir);
|
|
176
217
|
const cmakeLists = [
|
|
177
|
-
'# Auto-generated by @typecad/framework-zephyr from
|
|
218
|
+
'# Auto-generated by @typecad/framework-zephyr from typecad-hal.config.ts.',
|
|
178
219
|
'cmake_minimum_required(VERSION 3.20.0)',
|
|
179
220
|
'',
|
|
180
221
|
'# The app is its own board root: MCU-only targets generate an out-of-tree',
|
|
@@ -189,7 +230,7 @@ export function scaffoldZephyrProject(projectRoot, debug = false, userKconfig, p
|
|
|
189
230
|
'',
|
|
190
231
|
...(sourceFiles.length > 0
|
|
191
232
|
? [
|
|
192
|
-
'#
|
|
233
|
+
'# TypeCAD-emitted sources. This list is regenerated whenever the',
|
|
193
234
|
'# emitted file set changes (the scaffold rewrites CMakeLists.txt).',
|
|
194
235
|
'target_sources(app PRIVATE',
|
|
195
236
|
...sourceFiles.map((name) => ` src/${name}`),
|
|
@@ -217,12 +258,12 @@ export function scaffoldZephyrProject(projectRoot, debug = false, userKconfig, p
|
|
|
217
258
|
// delegated to resolveKconfigFragments (unit-tested in dt-config/kconfig).
|
|
218
259
|
const symbols = resolveKconfigFragments(usage, debug);
|
|
219
260
|
const prjConf = [
|
|
220
|
-
'# Auto-generated by @typecad/framework-zephyr from
|
|
221
|
-
'# Edit in
|
|
261
|
+
'# Auto-generated by @typecad/framework-zephyr from typecad-hal.config.ts.',
|
|
262
|
+
'# Edit in typecad-hal.config.ts (frameworkData), not here.',
|
|
222
263
|
'# Driver symbols are usage-gated on the emitted source — only peripherals',
|
|
223
264
|
'# the program references are enabled.',
|
|
224
265
|
'',
|
|
225
|
-
'# Route printf/stdout to the console UART (needed by the
|
|
266
|
+
'# Route printf/stdout to the console UART (needed by the typecad-hal',
|
|
226
267
|
'# test runner protocol, which uses printf via __tc_print/__tc_println).',
|
|
227
268
|
'CONFIG_STDOUT_CONSOLE=y',
|
|
228
269
|
'CONFIG_PRINTK=y',
|
|
@@ -241,7 +282,7 @@ export function scaffoldZephyrProject(projectRoot, debug = false, userKconfig, p
|
|
|
241
282
|
wifiHeaderEmitted = true;
|
|
242
283
|
}
|
|
243
284
|
// Skip auto-detected symbols that the user explicitly overrides
|
|
244
|
-
// in
|
|
285
|
+
// in typecad-hal.config.ts zephyr.kconfig — the user value is
|
|
245
286
|
// emitted in the User Kconfig section below and takes precedence.
|
|
246
287
|
if (userKconfig && userKconfig.hasOwnProperty(sym))
|
|
247
288
|
continue;
|
|
@@ -256,7 +297,7 @@ export function scaffoldZephyrProject(projectRoot, debug = false, userKconfig, p
|
|
|
256
297
|
// zephyr.kconfig overrides still win.
|
|
257
298
|
const libraryEntries = readCuttlefishLibrarySidecar(srcDir);
|
|
258
299
|
if (libraryEntries.length > 0) {
|
|
259
|
-
prjConf.push('', '# Library packages (
|
|
300
|
+
prjConf.push('', '# Library packages (typecad-hal.library.json contributions).');
|
|
260
301
|
for (const entry of libraryEntries) {
|
|
261
302
|
for (const line of entry.kconfig) {
|
|
262
303
|
const sym = line.split('=')[0];
|
|
@@ -266,6 +307,29 @@ export function scaffoldZephyrProject(projectRoot, debug = false, userKconfig, p
|
|
|
266
307
|
}
|
|
267
308
|
}
|
|
268
309
|
}
|
|
310
|
+
// ── Trace heartbeat Kconfig ────────────────────────────────────────────────
|
|
311
|
+
// zephyr.trace.enabled in typecad-hal.config.ts turns on the [TR: sampler
|
|
312
|
+
// (emitted by the strategy at transpile time from the same config record).
|
|
313
|
+
// The symbol set is exactly what the sampler calls: runtime stats
|
|
314
|
+
// (k_thread_runtime_stats_*), the monitor list (k_thread_foreach —
|
|
315
|
+
// kernel/thread_monitor.c only links under THREAD_MONITOR), thread names
|
|
316
|
+
// (k_thread_name_get/set), and stack inspection (0xAA fill +
|
|
317
|
+
// stack_info.size). User zephyr.kconfig overrides still win.
|
|
318
|
+
if (trace?.enabled === true) {
|
|
319
|
+
const traceSymbols = [
|
|
320
|
+
['CONFIG_THREAD_RUNTIME_STATS', 'y'],
|
|
321
|
+
['CONFIG_THREAD_MONITOR', 'y'],
|
|
322
|
+
['CONFIG_THREAD_NAME', 'y'],
|
|
323
|
+
['CONFIG_INIT_STACKS', 'y'],
|
|
324
|
+
['CONFIG_THREAD_STACK_INFO', 'y'],
|
|
325
|
+
];
|
|
326
|
+
prjConf.push('', '# Trace heartbeat (typecad-hal.config.ts → zephyr.trace).');
|
|
327
|
+
for (const [sym, val] of traceSymbols) {
|
|
328
|
+
if (userKconfig && userKconfig.hasOwnProperty(sym))
|
|
329
|
+
continue;
|
|
330
|
+
prjConf.push(`${sym}=${val}`);
|
|
331
|
+
}
|
|
332
|
+
}
|
|
269
333
|
// Per-part Kconfig exceptions: catalog parts whose driver is NOT default-y
|
|
270
334
|
// on its DT node carry extra lines here (empty today — every in-tree sensor
|
|
271
335
|
// driver lights up from the node; the path exists so the first exception
|
|
@@ -279,10 +343,10 @@ export function scaffoldZephyrProject(projectRoot, debug = false, userKconfig, p
|
|
|
279
343
|
prjConf.push(line);
|
|
280
344
|
}
|
|
281
345
|
}
|
|
282
|
-
// Emit user-specified Kconfig from
|
|
346
|
+
// Emit user-specified Kconfig from typecad-hal.config.ts zephyr.kconfig.
|
|
283
347
|
// These override any matching auto-detected symbol (skipped above).
|
|
284
348
|
if (userKconfig) {
|
|
285
|
-
prjConf.push('', '# User Kconfig (
|
|
349
|
+
prjConf.push('', '# User Kconfig (typecad-hal.config.ts → zephyr.kconfig).');
|
|
286
350
|
for (const [sym, val] of Object.entries(userKconfig)) {
|
|
287
351
|
prjConf.push(`${sym}=${val}`);
|
|
288
352
|
}
|
|
@@ -30,6 +30,12 @@ export declare function discoverFromPath(): WestInstall | null;
|
|
|
30
30
|
/** The canonical Zephyr workspace layout puts the venv beside the SDK:
|
|
31
31
|
* <workspace>/{.venv, zephyr}. So ${ZEPHYR_BASE}/../.venv is the venv. */
|
|
32
32
|
export declare function discoverFromZephyrBase(): WestInstall | null;
|
|
33
|
+
/** The installer-written SDK dir for the default micromamba env, when the
|
|
34
|
+
* installer has run on this machine. Read WITHOUT requiring micromamba
|
|
35
|
+
* mode — a PATH/venv west install is enriched with it so builds spawned
|
|
36
|
+
* through it still pin the installer's SDK (otherwise Zephyr's CMake
|
|
37
|
+
* searches $HOME and can pick up a stray, older SDK). */
|
|
38
|
+
export declare function installerSdkDir(): string | undefined;
|
|
33
39
|
/** The installer-written ZEPHYR_BASE of the micromamba env, fs-only (no
|
|
34
40
|
* spawn) — the cheap probe shared by board-catalog overlay discovery.
|
|
35
41
|
* Undefined when the installer env or its env-vars file is absent. */
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
// 1. `west` already on PATH (env already activated / global install).
|
|
12
12
|
// 2. $ZEPHYR_BASE venv: ${ZEPHYR_BASE}/../.venv/<python> -m west.
|
|
13
13
|
// 3. micromamba env from @typecad/zephyr-installer (invoked via `micromamba run`,
|
|
14
|
-
// so
|
|
14
|
+
// so typecad-hal builds work with NO manual activation).
|
|
15
15
|
// 4. Well-known workspace layouts: ~/zephyrproject/.venv, /opt/zephyrproject/.
|
|
16
16
|
// venv, etc.
|
|
17
17
|
// 5. System pythons (`python`, `python3`, `py`) via `-m west`.
|
|
@@ -111,6 +111,34 @@ export function discoverFromZephyrBase() {
|
|
|
111
111
|
source: 'zephyr-base-venv',
|
|
112
112
|
};
|
|
113
113
|
}
|
|
114
|
+
/** The installer-written SDK dir for the default micromamba env, when the
|
|
115
|
+
* installer has run on this machine. Read WITHOUT requiring micromamba
|
|
116
|
+
* mode — a PATH/venv west install is enriched with it so builds spawned
|
|
117
|
+
* through it still pin the installer's SDK (otherwise Zephyr's CMake
|
|
118
|
+
* searches $HOME and can pick up a stray, older SDK). */
|
|
119
|
+
export function installerSdkDir() {
|
|
120
|
+
const mm = findMicromamba();
|
|
121
|
+
if (!mm)
|
|
122
|
+
return undefined;
|
|
123
|
+
const envName = process.env.TYPECAD_ZEPHYR_ENV || 'zephyr';
|
|
124
|
+
const envDir = join(mm.rootPrefix, 'envs', envName);
|
|
125
|
+
if (!existsSync(envDir))
|
|
126
|
+
return undefined;
|
|
127
|
+
const sdk = readMicromambaEnvVar(envDir, 'TYPECAD_ZEPHYR_SDK_INSTALL_DIR');
|
|
128
|
+
return sdk && existsSync(sdk) ? sdk : undefined;
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* The micromamba env created by `@typecad/zephyr-installer`. The env's west
|
|
132
|
+
* lives at envs/<name>/bin/west (POSIX) or Scripts/west.exe (Windows). Found
|
|
133
|
+
* installs are invoked via `micromamba run -n <name> west …` (see
|
|
134
|
+
* west-spawn.ts), which sets up the env's full PATH (cmake/ninja/dtc) AND runs
|
|
135
|
+
* the activation hook (ZEPHYR_BASE / ZEPHYR_SDK_INSTALL_DIR) — so builds work
|
|
136
|
+
* with NO manual `micromamba activate`. This is what makes a fresh
|
|
137
|
+
* `typecad-hal build` succeed in any project without the user activating.
|
|
138
|
+
*
|
|
139
|
+
* Env name defaults to "zephyr"; override via TYPECAD_ZEPHYR_ENV. File-check
|
|
140
|
+
* based (no spawn) so it's cheap to run on every invocation.
|
|
141
|
+
*/
|
|
114
142
|
// ── Strategy 3: micromamba env (the @typecad/zephyr-installer install) ─────
|
|
115
143
|
// Locate the micromamba binary + root prefix. The installer downloads
|
|
116
144
|
// micromamba to $MAMBA_ROOT_PREFIX/bin (POSIX) or Library/bin (Windows); the
|
|
@@ -123,18 +151,6 @@ function findMicromamba() {
|
|
|
123
151
|
: join(root, 'bin', 'micromamba');
|
|
124
152
|
return existsSync(exe) ? { exe, rootPrefix: root } : null;
|
|
125
153
|
}
|
|
126
|
-
/**
|
|
127
|
-
* The micromamba env created by `@typecad/zephyr-installer`. The env's west
|
|
128
|
-
* lives at envs/<name>/bin/west (POSIX) or Scripts/west.exe (Windows). Found
|
|
129
|
-
* installs are invoked via `micromamba run -n <name> west …` (see
|
|
130
|
-
* west-spawn.ts), which sets up the env's full PATH (cmake/ninja/dtc) AND runs
|
|
131
|
-
* the activation hook (ZEPHYR_BASE / ZEPHYR_SDK_INSTALL_DIR) — so cuttlefish
|
|
132
|
-
* builds work with NO manual `micromamba activate`. This is what makes a fresh
|
|
133
|
-
* `cuttlefish build` succeed in any project without the user activating.
|
|
134
|
-
*
|
|
135
|
-
* Env name defaults to "zephyr"; override via TYPECAD_ZEPHYR_ENV. File-check
|
|
136
|
-
* based (no spawn) so it's cheap to run on every cuttlefish invocation.
|
|
137
|
-
*/
|
|
138
154
|
/** Read a TYPECAD_ZEPHYR_* value from the installer-written env-vars file in
|
|
139
155
|
* a micromamba env. Handles .sh (export VAR="val"), .bat (set "VAR=val"),
|
|
140
156
|
* and .ps1 ($env:VAR = "val"). Returns undefined if absent/unreadable. */
|
|
@@ -284,6 +300,13 @@ export function discoverWest() {
|
|
|
284
300
|
install = null;
|
|
285
301
|
}
|
|
286
302
|
if (install) {
|
|
303
|
+
// A PATH/venv west install knows nothing about the installer's SDK.
|
|
304
|
+
// Enrich it: west-spawn pins the child's ZEPHYR_SDK_INSTALL_DIR to the
|
|
305
|
+
// installer dir, so Zephyr's CMake cannot pick up a stray SDK from
|
|
306
|
+
// $HOME (a version mismatch that only surfaces at configure time).
|
|
307
|
+
if (!install.sdkInstallDir) {
|
|
308
|
+
install.sdkInstallDir = installerSdkDir();
|
|
309
|
+
}
|
|
287
310
|
cachedDiscover = install;
|
|
288
311
|
return install;
|
|
289
312
|
}
|
|
@@ -49,6 +49,12 @@ export function buildEnv(install) {
|
|
|
49
49
|
// flashing works without activation. $ZEPHYR_SDK_INSTALL_DIR (set by an
|
|
50
50
|
// activated env) wins over the discovered install dir.
|
|
51
51
|
const sdkRoot = env.ZEPHYR_SDK_INSTALL_DIR || install.sdkInstallDir;
|
|
52
|
+
// Pin the west/cmake child to the discovered SDK: without this, Zephyr's
|
|
53
|
+
// FindZephyr-sdk searches $HOME and can latch onto a stray, older SDK —
|
|
54
|
+
// a configure-time version failure that only surfaces in the build log.
|
|
55
|
+
if (!env.ZEPHYR_SDK_INSTALL_DIR && install.sdkInstallDir) {
|
|
56
|
+
env.ZEPHYR_SDK_INSTALL_DIR = install.sdkInstallDir;
|
|
57
|
+
}
|
|
52
58
|
const openocdBin = sdkRoot ? join(sdkRoot, 'hosttools', 'openocd', 'bin') : undefined;
|
|
53
59
|
const prepend = [
|
|
54
60
|
openocdBin !== undefined && existsSync(openocdBin) ? openocdBin : undefined,
|
|
@@ -92,7 +98,7 @@ export function westSpawn(westArgs, baseOptions) {
|
|
|
92
98
|
throw new Error([
|
|
93
99
|
'west (the Zephyr build tool) was not found.',
|
|
94
100
|
'',
|
|
95
|
-
'
|
|
101
|
+
'typecad-hal looked for it on PATH, in $ZEPHYR_BASE/.venv, in common',
|
|
96
102
|
'Zephyr workspace dirs (~/zephyrproject/.venv), and as a system',
|
|
97
103
|
"Python module (`python -m west`). To fix:",
|
|
98
104
|
'',
|
|
@@ -113,7 +119,7 @@ export function westSpawn(westArgs, baseOptions) {
|
|
|
113
119
|
if (install.mode === 'micromamba' && install.micromambaExe) {
|
|
114
120
|
// `micromamba run -n <env> west …` sets up the env's full PATH
|
|
115
121
|
// (cmake/ninja/dtc) and runs the activation hook (ZEPHYR_BASE /
|
|
116
|
-
// ZEPHYR_SDK_INSTALL_DIR), so
|
|
122
|
+
// ZEPHYR_SDK_INSTALL_DIR), so typecad-hal builds work WITHOUT the user
|
|
117
123
|
// activating the env. Inject MAMBA_ROOT_PREFIX so micromamba finds envs.
|
|
118
124
|
const mmEnv = { ...env };
|
|
119
125
|
if (install.mambaRootPrefix)
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { ReadDir, ReadFile } from '@typecad/cuttlefish/api/shared';
|
|
2
|
+
/** Normalize a path for case-insensitive, separator-agnostic comparison. */
|
|
3
|
+
export declare function norm(p: string): string;
|
|
4
|
+
/**
|
|
5
|
+
* Filter the west manifest to the modules whose sources were compiled in the
|
|
6
|
+
* last build. A module is "linked" iff some compiled translation unit lives
|
|
7
|
+
* under its abspath. If the build data is unparseable, no filtering is applied
|
|
8
|
+
* (degrade to listing all modules rather than reporting nothing).
|
|
9
|
+
*/
|
|
10
|
+
export declare function filterLinkedModules(ccText: string, modules: {
|
|
11
|
+
name: string;
|
|
12
|
+
abspath: string;
|
|
13
|
+
}[]): {
|
|
14
|
+
name: string;
|
|
15
|
+
abspath: string;
|
|
16
|
+
}[];
|
|
17
|
+
/**
|
|
18
|
+
* Find the build's compile_commands.json path under `cwd`. Cuttlefish's Zephyr
|
|
19
|
+
* project root is the transpile output dir (e.g. `<cwd>/src/out`), so the
|
|
20
|
+
* build dir is `<root>/build` — not necessarily `<cwd>/build`. Check the
|
|
21
|
+
* common layouts, then fall back to a bounded search (skipping
|
|
22
|
+
* node_modules/.git/dist and dot-directories). Returns the PATH (the caller
|
|
23
|
+
* decides whether to read it); undefined when no build exists.
|
|
24
|
+
*/
|
|
25
|
+
export declare function findCompileCommandsPath(readFile: ReadFile, readdir: ReadDir, cwd?: string): string | undefined;
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
// ---------------------------------------------------------------------------
|
|
2
|
+
// @typecad/framework-zephyr — shared west workspace ground truth
|
|
3
|
+
//
|
|
4
|
+
// The as-built inventory both `typecad-hal licenses` and `typecad-hal sbom`
|
|
5
|
+
// report from: which west manifest modules the last build ACTUALLY compiled
|
|
6
|
+
// (linked-module filtering via the build's compile_commands.json), plus the
|
|
7
|
+
// build-directory discovery that locates it. A west manifest carries every
|
|
8
|
+
// vendor HAL/library; almost none are linked by a single project — both the
|
|
9
|
+
// license table and the SBOM scope to the linked set by default, so they stay
|
|
10
|
+
// honest about what is actually inside the firmware.
|
|
11
|
+
//
|
|
12
|
+
// Moved out of licenses.ts when the sbom command grew a second consumer; the
|
|
13
|
+
// behavior (case-insensitive, separator-agnostic path matching; degrade to
|
|
14
|
+
// "no filtering" on unparseable build data) is unchanged.
|
|
15
|
+
// ---------------------------------------------------------------------------
|
|
16
|
+
import * as path from 'node:path';
|
|
17
|
+
/** Normalize a path for case-insensitive, separator-agnostic comparison. */
|
|
18
|
+
export function norm(p) {
|
|
19
|
+
return p.split('\\').join('/').toLowerCase();
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Filter the west manifest to the modules whose sources were compiled in the
|
|
23
|
+
* last build. A module is "linked" iff some compiled translation unit lives
|
|
24
|
+
* under its abspath. If the build data is unparseable, no filtering is applied
|
|
25
|
+
* (degrade to listing all modules rather than reporting nothing).
|
|
26
|
+
*/
|
|
27
|
+
export function filterLinkedModules(ccText, modules) {
|
|
28
|
+
let arr;
|
|
29
|
+
try {
|
|
30
|
+
arr = JSON.parse(ccText);
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
return modules;
|
|
34
|
+
}
|
|
35
|
+
if (!Array.isArray(arr))
|
|
36
|
+
return modules;
|
|
37
|
+
// One normalized blob of every compiled source path; membership is then a
|
|
38
|
+
// substring check per module (O(modules) after an O(TUs) join).
|
|
39
|
+
const blob = arr
|
|
40
|
+
.map((e) => norm(typeof e?.file === 'string' ? e.file : ''))
|
|
41
|
+
.join('\n');
|
|
42
|
+
return modules.filter((m) => blob.includes(norm(m.abspath) + '/'));
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Find the build's compile_commands.json path under `cwd`. Cuttlefish's Zephyr
|
|
46
|
+
* project root is the transpile output dir (e.g. `<cwd>/src/out`), so the
|
|
47
|
+
* build dir is `<root>/build` — not necessarily `<cwd>/build`. Check the
|
|
48
|
+
* common layouts, then fall back to a bounded search (skipping
|
|
49
|
+
* node_modules/.git/dist and dot-directories). Returns the PATH (the caller
|
|
50
|
+
* decides whether to read it); undefined when no build exists.
|
|
51
|
+
*/
|
|
52
|
+
export function findCompileCommandsPath(readFile, readdir, cwd = process.cwd()) {
|
|
53
|
+
const direct = [
|
|
54
|
+
path.join(cwd, 'build', 'compile_commands.json'),
|
|
55
|
+
path.join(cwd, 'out', 'build', 'compile_commands.json'),
|
|
56
|
+
path.join(cwd, 'src', 'out', 'build', 'compile_commands.json'),
|
|
57
|
+
];
|
|
58
|
+
for (const c of direct) {
|
|
59
|
+
if (readFile(c))
|
|
60
|
+
return c;
|
|
61
|
+
}
|
|
62
|
+
// Bounded recursive search for a build/compile_commands.json.
|
|
63
|
+
const isCc = (p) => {
|
|
64
|
+
const n = norm(p);
|
|
65
|
+
return n.endsWith('/build/compile_commands.json') || n.endsWith('\\build\\compile_commands.json');
|
|
66
|
+
};
|
|
67
|
+
let found;
|
|
68
|
+
const seen = new Set();
|
|
69
|
+
const walk = (dir, depth) => {
|
|
70
|
+
if (found || depth > 4 || seen.has(dir))
|
|
71
|
+
return;
|
|
72
|
+
seen.add(dir);
|
|
73
|
+
let entries;
|
|
74
|
+
try {
|
|
75
|
+
entries = readdir(dir);
|
|
76
|
+
}
|
|
77
|
+
catch {
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
for (const e of entries) {
|
|
81
|
+
const full = path.join(dir, e);
|
|
82
|
+
if (e === 'compile_commands.json' && isCc(full)) {
|
|
83
|
+
found = full;
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
for (const e of entries) {
|
|
88
|
+
if (found)
|
|
89
|
+
return;
|
|
90
|
+
if (e === 'node_modules' || e === '.git' || e === 'dist' || e.startsWith('.'))
|
|
91
|
+
continue;
|
|
92
|
+
walk(path.join(dir, e), depth + 1);
|
|
93
|
+
}
|
|
94
|
+
};
|
|
95
|
+
walk(cwd, 0);
|
|
96
|
+
return found;
|
|
97
|
+
}
|