1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
|
# External Library Size Measurement (Task #76)
## Goal
Measure the true binary size of demo code vs external library overhead by stubbing out all system dependencies with minimal implementations.
**Motivation:** Current STRIP_ALL builds include wgpu_native (~3-4MB), GLFW, and system libraries. We need to isolate core demo size to:
- Track size budget accurately
- Identify optimization targets
- Measure progress toward 64KB goal
## Problem Statement
Current size breakdown is opaque:
```
STRIP_ALL build: ~5.1MB total
├── wgpu_native: ~3-4MB (estimate)
├── GLFW: ~500KB (estimate)
├── System libs: ~500KB (estimate)
└── Demo code: ??? KB (unknown)
```
**Goal:** Measure demo code size precisely by replacing external dependencies with stubs.
## Approach
Create `STRIP_EXTERNAL_LIBS` build mode:
- Replaces real libraries with minimal stub implementations
- Functions compile but do nothing (return nullptr, no-ops)
- Binary compiles successfully but **does not run**
- Purpose: Size measurement only
## Architecture
### Stub Implementations
#### 1. wgpu_native Stubs (`third_party/stubs/wgpu_native.c`)
Minimal WebGPU API implementation:
```c
// All functions return nullptr or void
WGPUInstance wgpuCreateInstance(const WGPUInstanceDescriptor* desc) {
(void)desc;
return (WGPUInstance)0;
}
WGPUAdapter wgpuInstanceRequestAdapter(...) {
return (WGPUAdapter)0;
}
// ~200 functions to stub
```
**Strategy:**
- Parse `webgpu.h` to generate stubs automatically
- All pointers return nullptr
- All numeric returns = 0
- All void functions are empty
#### 2. GLFW Stubs (`third_party/stubs/glfw3.c`)
Window/input API stubs:
```c
int glfwInit(void) { return 1; }
void glfwTerminate(void) {}
GLFWwindow* glfwCreateWindow(...) { return (GLFWwindow*)0; }
void glfwPollEvents(void) {}
int glfwWindowShouldClose(GLFWwindow* w) { (void)w; return 0; }
// ~100 functions
```
#### 3. miniaudio Stubs (`third_party/stubs/miniaudio.c`)
Audio backend stubs:
```c
ma_result ma_context_init(...) { return MA_SUCCESS; }
ma_result ma_device_init(...) { return MA_SUCCESS; }
ma_result ma_device_start(...) { return MA_SUCCESS; }
void ma_device_stop(...) {}
void ma_device_uninit(...) {}
// ~50 functions used by demo
```
#### 4. System Library Stubs
**pthread:**
```c
int pthread_create(...) { return 0; }
int pthread_join(...) { return 0; }
int pthread_mutex_init(...) { return 0; }
// ~20 functions
```
**Math (libm):**
```c
double sin(double x) { (void)x; return 0.0; }
double cos(double x) { (void)x; return 0.0; }
float sinf(float x) { (void)x; return 0.0f; }
// ~30 functions
```
**Platform-specific (macOS):**
```c
// Stub Metal/Foundation/Cocoa frameworks
// Minimal Objective-C stubs if needed
```
### Build System Integration
**CMakeLists.txt:**
```cmake
if(DEMO_STRIP_EXTERNAL_LIBS)
# Build stub libraries
add_library(wgpu_stub STATIC third_party/stubs/wgpu_native.c)
add_library(glfw_stub STATIC third_party/stubs/glfw3.c)
add_library(miniaudio_stub STATIC third_party/stubs/miniaudio.c)
add_library(system_stub STATIC third_party/stubs/system.c)
# Override library targets
set(DEMO_LIBS wgpu_stub glfw_stub miniaudio_stub system_stub)
# Minimal flags (no LTO to see unoptimized size)
set(CMAKE_C_FLAGS "-Os")
set(CMAKE_CXX_FLAGS "-Os")
endif()
```
**Build command:**
```bash
cmake -S . -B build_size -DDEMO_STRIP_EXTERNAL_LIBS=ON
cmake --build build_size -j4
ls -lh build_size/demo64k # True demo size
```
## Implementation Plan
### Phase 1: Stub Generation Tool
**Script: `scripts/generate_stubs.py`**
Parses header files and generates stub implementations:
```python
# Parse webgpu.h, glfw3.h, miniaudio.h
# Extract function signatures
# Generate minimal implementations
# Output to third_party/stubs/
```
**Input:** Header files with annotations
**Output:** Complete stub .c files
**Heuristics:**
- Pointer returns → nullptr
- Numeric returns → 0
- Boolean returns → true/1
- Void functions → empty body
- Enum returns → first enum value
### Phase 2: Build System Integration
1. Add `DEMO_STRIP_EXTERNAL_LIBS` option
2. Create stub library targets
3. Override `DEMO_LIBS` when flag enabled
4. Disable features requiring runtime (audio playback, window creation)
### Phase 3: Compatibility Layer
Some demo code expects valid objects. Add thin shims:
**`src/platform/stub_platform.cc`:**
```cpp
#if defined(STRIP_EXTERNAL_LIBS)
// Override platform_init to skip GLFW
PlatformState platform_init(bool, int, int) {
PlatformState state = {};
state.width = 1280;
state.height = 720;
return state;
}
#endif
```
**`src/audio/stub_audio.cc`:**
```cpp
#if defined(STRIP_EXTERNAL_LIBS)
// Override audio_init to skip miniaudio
void audio_init() {}
void audio_start() {}
#endif
```
### Phase 4: Validation
Ensure binary compiles and links:
```bash
# Should compile successfully
cmake -S . -B build_size -DDEMO_STRIP_EXTERNAL_LIBS=ON
cmake --build build_size -j4
# Size measurement
ls -lh build_size/demo64k
# Strip debug symbols
strip build_size/demo64k
ls -lh build_size/demo64k
# Compare with real build
ls -lh build_strip/demo64k
```
## Expected Results
**Size Breakdown (Projected):**
```
Real STRIP_ALL build: 5.1 MB
├── wgpu_native: 3.5 MB (68%)
├── GLFW: 0.5 MB (10%)
├── System libs: 0.6 MB (12%)
└── Demo code: 0.5 MB (10%)
STRIP_EXTERNAL_LIBS build: 0.5 MB
└── Demo code only: 0.5 MB (100%)
```
**Validation:**
- Binary compiles without errors
- All symbols resolve
- Size is significantly smaller (< 1MB)
- Binary does NOT run (expected)
## Use Cases
### 1. Size Budget Tracking
```bash
# Weekly measurement
./scripts/measure_size.sh
# Outputs: Demo=512KB, External=4.5MB
```
### 2. Optimization Targeting
Identify which subsystems contribute most to demo size:
- GPU effects: 150KB
- 3D rendering: 120KB
- Audio synthesis: 100KB
- Asset system: 80KB
### 3. CI Integration
Track size growth over time:
```yaml
# .github/workflows/size_check.yml
- name: Measure demo size
run: |
cmake -B build_size -DDEMO_STRIP_EXTERNAL_LIBS=ON
size=$(stat -f%z build_size/demo64k)
echo "Demo size: $size bytes"
```
## Trade-offs
### Pros
- Accurate size measurement
- Identifies optimization targets
- Simple implementation (stubs)
- No runtime required
### Cons
- Maintenance burden (stubs must match real APIs)
- Binary doesn't run (testing impossible)
- Platform-specific stubbing (macOS frameworks complex)
- Stub generation tool needs maintenance
### Alternative Approaches
**1. Link-time size analysis:**
```bash
# Use linker map to attribute size
-Wl,-map,output.map
# Parse map file to see per-symbol sizes
```
**Pro:** No stubs needed
**Con:** Complex parsing, less accurate
**2. Binary diff analysis:**
```bash
# Build with/without each library
# Diff binary sizes
```
**Pro:** Simpler
**Con:** Doesn't isolate demo code cleanly
**3. Compiler size reports:**
```bash
-ffunction-sections -fdata-sections
-Wl,--print-gc-sections
```
**Pro:** Built-in tooling
**Con:** Still includes external library overhead
**Chosen:** Stub approach (most accurate, clear results)
## Implementation Effort
**Estimated time: 8-12 hours**
- Phase 1: Stub generation (3-4 hours)
- Phase 2: Build integration (2-3 hours)
- Phase 3: Compatibility layer (2-3 hours)
- Phase 4: Validation & documentation (1-2 hours)
**Priority:** Low (measurement tool, not critical for demo)
## Success Criteria
1. Binary compiles successfully with `STRIP_EXTERNAL_LIBS=ON`
2. Size < 1MB (proves external lib overhead is measured)
3. Repeatable builds produce consistent sizes
4. Can track size changes over time
5. Documentation clear for future use
## Related Files
**New files:**
- `third_party/stubs/wgpu_native.c` - WebGPU stubs (~200 functions)
- `third_party/stubs/glfw3.c` - GLFW stubs (~100 functions)
- `third_party/stubs/miniaudio.c` - Audio stubs (~50 functions)
- `third_party/stubs/system.c` - System library stubs (pthread, math)
- `scripts/generate_stubs.py` - Stub generation tool
- `scripts/measure_size.sh` - Size measurement script
**Modified files:**
- `CMakeLists.txt` - Add STRIP_EXTERNAL_LIBS mode
- `src/platform/platform.cc` - Conditional stub overrides
- `src/audio/audio.cc` - Conditional stub overrides
## Notes
- This is a **measurement tool**, not a runtime mode
- Binary will not execute (all APIs stubbed)
- Useful for tracking optimization progress
- Can reveal surprising size contributors
- Platform-specific (stubs may differ on Windows/Linux/macOS)
|