node-av 5.1.0 → 5.2.0-beta.2

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.
@@ -1,405 +0,0 @@
1
- /* eslint-disable @stylistic/max-len */
2
- /**
3
- * Markdown Report Generator
4
- *
5
- * Generates a formatted BENCHMARK.md report from benchmark results.
6
- */
7
-
8
- import { execSync } from 'node:child_process';
9
- import { readFileSync, writeFileSync } from 'node:fs';
10
- import { arch, cpus, platform, release, totalmem } from 'node:os';
11
- import { basename, dirname, resolve } from 'node:path';
12
- import { fileURLToPath } from 'node:url';
13
-
14
- import { getFFmpegVersion, probeMediaFile } from './ffmpeg-cli.js';
15
- import { formatBytes, formatPercentDiff } from './measure.js';
16
-
17
- import type { LatencyMetrics } from '../cases/latency.js';
18
- import type { BenchmarkComparison } from '../runner.js';
19
-
20
- const __filename = fileURLToPath(import.meta.url);
21
- const __dirname = dirname(__filename);
22
- const rootDir = resolve(__dirname, '../..');
23
-
24
- /**
25
- * System information for the report
26
- */
27
- export interface SystemInfo {
28
- os: string;
29
- osVersion: string;
30
- arch: string;
31
- cpu: string;
32
- cpuCores: number;
33
- ram: string;
34
- gpu?: string;
35
- ffmpegVersion: string;
36
- nodeAVVersion: string;
37
- nodeVersion: string;
38
- }
39
-
40
- /**
41
- * Input file information
42
- */
43
- export interface InputFileInfo {
44
- path: string;
45
- duration: number;
46
- resolution?: string;
47
- codec?: string;
48
- fps?: number;
49
- }
50
-
51
- /**
52
- * Complete benchmark report data
53
- */
54
- export interface BenchmarkReport {
55
- systemInfo: SystemInfo;
56
- /** @deprecated Use inputFileInfos instead */
57
- inputFileInfo?: InputFileInfo;
58
- inputFileInfos?: InputFileInfo[];
59
- transcodeResults: BenchmarkComparison[];
60
- memoryResults: BenchmarkComparison[];
61
- latencyMetrics?: LatencyMetrics;
62
- timestamp: string;
63
- }
64
-
65
- /**
66
- * Gather system information
67
- */
68
- export async function getSystemInfo(): Promise<SystemInfo> {
69
- const cpuInfo = cpus();
70
- const cpu = cpuInfo[0]?.model ?? 'Unknown';
71
-
72
- // Try to detect GPU
73
- let gpu: string | undefined;
74
- try {
75
- if (platform() === 'darwin') {
76
- gpu = execSync('system_profiler SPDisplaysDataType 2>/dev/null | grep "Chipset Model" | head -1 | cut -d: -f2', {
77
- encoding: 'utf-8',
78
- }).trim();
79
- } else if (platform() === 'linux') {
80
- gpu = execSync("lspci 2>/dev/null | grep -i 'vga\\|3d\\|display' | head -1 | cut -d: -f3", { encoding: 'utf-8' }).trim();
81
- } else if (platform() === 'win32') {
82
- gpu = execSync('wmic path win32_VideoController get name 2>nul | findstr /v "Name"', { encoding: 'utf-8' }).trim();
83
- }
84
- } catch {
85
- // GPU detection failed, continue without it
86
- }
87
-
88
- // Get FFmpeg version
89
- let ffmpegVersion = 'Unknown';
90
- try {
91
- ffmpegVersion = await getFFmpegVersion();
92
- } catch {
93
- // Continue without version
94
- }
95
-
96
- // Get node-av version from package.json
97
- let nodeAVVersion = 'Unknown';
98
- try {
99
- const pkgPath = resolve(rootDir, 'package.json');
100
- const pkgContent = readFileSync(pkgPath, 'utf-8');
101
- const pkg = JSON.parse(pkgContent);
102
- nodeAVVersion = pkg.version;
103
- } catch {
104
- // Continue without version
105
- }
106
-
107
- return {
108
- os: platform(),
109
- osVersion: release(),
110
- arch: arch(),
111
- cpu,
112
- cpuCores: cpuInfo.length,
113
- ram: formatBytes(totalmem()),
114
- gpu: gpu ?? undefined,
115
- ffmpegVersion,
116
- nodeAVVersion,
117
- nodeVersion: process.version,
118
- };
119
- }
120
-
121
- /**
122
- * Format system info section for markdown
123
- */
124
- function formatSystemInfoSection(info: SystemInfo): string {
125
- let section = `## System Information
126
-
127
- | Property | Value |
128
- |----------|-------|
129
- | **OS** | ${info.os} ${info.osVersion} |
130
- | **Architecture** | ${info.arch} |
131
- | **CPU** | ${info.cpu} |
132
- | **CPU Cores** | ${info.cpuCores} |
133
- | **RAM** | ${info.ram} |`;
134
-
135
- if (info.gpu) {
136
- section += `\n| **GPU** | ${info.gpu} |`;
137
- }
138
-
139
- section += `
140
- | **Node.js** | ${info.nodeVersion} |
141
- | **FFmpeg** | ${info.ffmpegVersion} |
142
- | **node-av** | ${info.nodeAVVersion} |
143
- `;
144
-
145
- return section;
146
- }
147
-
148
- /**
149
- * Format input file info section (single file - legacy)
150
- */
151
- function formatInputFileSection(info: InputFileInfo | undefined): string {
152
- if (!info) return '';
153
-
154
- return `## Test Input
155
-
156
- | Property | Value |
157
- |----------|-------|
158
- | **File** | \`${info.path}\` |
159
- | **Duration** | ${info.duration.toFixed(1)}s |
160
- | **Resolution** | ${info.resolution ?? 'N/A'} |
161
- | **Codec** | ${info.codec ?? 'N/A'} |
162
- | **FPS** | ${info.fps?.toFixed(1) ?? 'N/A'} |
163
- `;
164
- }
165
-
166
- /**
167
- * Format input files info section (multiple files)
168
- */
169
- function formatInputFilesSection(infos: InputFileInfo[] | undefined): string {
170
- if (!infos || infos.length === 0) return '';
171
-
172
- let section = `## Test Inputs
173
-
174
- | File | Codec | Resolution | FPS | Duration |
175
- |------|-------|------------|-----|----------|
176
- `;
177
-
178
- for (const info of infos) {
179
- const filename = basename(info.path);
180
- section += `| ${filename} | ${info.codec ?? 'N/A'} | ${info.resolution ?? 'N/A'} | ${info.fps?.toFixed(0) ?? 'N/A'} | ${info.duration.toFixed(1)}s |\n`;
181
- }
182
-
183
- return section;
184
- }
185
-
186
- /**
187
- * Format transcode results table
188
- */
189
- function formatTranscodeSection(results: BenchmarkComparison[]): string {
190
- if (results.length === 0) return '';
191
-
192
- // Group results by input file
193
- const grouped = new Map<string, BenchmarkComparison[]>();
194
- for (const result of results) {
195
- const inputFile = basename(result.config.inputFile);
196
- if (!grouped.has(inputFile)) {
197
- grouped.set(inputFile, []);
198
- }
199
- grouped.get(inputFile)!.push(result);
200
- }
201
-
202
- let section = '## Transcode Speed\n';
203
-
204
- // If only one input file, don't show grouping
205
- if (grouped.size === 1) {
206
- const results = [...grouped.values()][0];
207
- section += formatTranscodeTable(results);
208
- } else {
209
- // Multiple input files - show grouped
210
- for (const [inputFile, groupResults] of grouped) {
211
- section += '\n### Input: ' + inputFile + '\n';
212
- section += formatTranscodeTable(groupResults);
213
- }
214
- }
215
-
216
- return section;
217
- }
218
-
219
- /**
220
- * Format a single transcode results table
221
- */
222
- function formatTranscodeTable(results: BenchmarkComparison[]): string {
223
- let section = `
224
- | Test | FFmpeg CLI (FPS) | node-av (FPS) | FFmpeg CLI (Time) | node-av (Time) | Diff |
225
- |------|------------------|---------------|-------------------|----------------|------|
226
- `;
227
-
228
- for (const result of results) {
229
- const ffmpegFps = result.ffmpegCLI.fps?.mean.toFixed(1) ?? 'N/A';
230
- const nodeAVFps = result.nodeAV.fps?.mean.toFixed(1) ?? 'N/A';
231
- const ffmpegDuration = formatDuration(result.ffmpegCLI.durationMs.mean);
232
- const nodeAVDuration = formatDuration(result.nodeAV.durationMs.mean);
233
- const diff = result.comparison.fpsDiffPercent;
234
- const diffStr = diff !== undefined ? formatPercentDiff(diff) : 'N/A';
235
-
236
- section += `| ${result.config.name} | ${ffmpegFps} fps | ${nodeAVFps} fps | ${ffmpegDuration} | ${nodeAVDuration} | ${diffStr} |\n`;
237
- }
238
-
239
- return section;
240
- }
241
-
242
- /**
243
- * Format memory results table
244
- */
245
- function formatMemorySection(results: BenchmarkComparison[]): string {
246
- if (results.length === 0) return '';
247
-
248
- // Group results by input file
249
- const grouped = new Map<string, BenchmarkComparison[]>();
250
- for (const result of results) {
251
- const inputFile = basename(result.config.inputFile);
252
- if (!grouped.has(inputFile)) {
253
- grouped.set(inputFile, []);
254
- }
255
- grouped.get(inputFile)!.push(result);
256
- }
257
-
258
- let section = '## Memory Usage\n';
259
-
260
- // If only one input file, don't show grouping
261
- if (grouped.size === 1) {
262
- const results = [...grouped.values()][0];
263
- section += formatMemoryTable(results);
264
- } else {
265
- // Multiple input files - show grouped
266
- for (const [inputFile, groupResults] of grouped) {
267
- section += '\n### Input: ' + inputFile + '\n';
268
- section += formatMemoryTable(groupResults);
269
- }
270
- }
271
-
272
- section += `
273
- *Note: FFmpeg CLI memory is measured via \`/usr/bin/time\` (macOS: \`-l\`, Linux: \`-v\`).
274
- `;
275
-
276
- return section;
277
- }
278
-
279
- /**
280
- * Format a single memory results table
281
- */
282
- function formatMemoryTable(results: BenchmarkComparison[]): string {
283
- let section = `
284
- | Test | FFmpeg CLI Peak | node-av Peak | Difference |
285
- |------|----------------|--------------|------------|
286
- `;
287
-
288
- for (const result of results) {
289
- // Note: FFmpeg CLI memory is estimated and may not be accurate
290
- const ffmpegMem = result.ffmpegCLI.peakMemoryBytes.mean > 0 ? formatBytes(result.ffmpegCLI.peakMemoryBytes.mean) : 'N/A*';
291
- const nodeAVMem = formatBytes(result.nodeAV.peakMemoryBytes.mean);
292
- const diffStr = result.ffmpegCLI.peakMemoryBytes.mean > 0 ? formatPercentDiff(result.comparison.memoryDiffPercent) : 'N/A';
293
-
294
- section += `| ${result.config.name} | ${ffmpegMem} | ${nodeAVMem} | ${diffStr} |\n`;
295
- }
296
-
297
- return section;
298
- }
299
-
300
- /**
301
- * Format latency section
302
- */
303
- function formatLatencySection(metrics: LatencyMetrics | undefined): string {
304
- if (!metrics) return '';
305
-
306
- return `## Latency
307
-
308
- | Metric | Mean | Min | Max | StdDev |
309
- |--------|------|-----|-----|--------|
310
- | Demuxer Open | ${formatMs(metrics.demuxerOpen.stats.mean)} | ${formatMs(metrics.demuxerOpen.stats.min)} | ${formatMs(metrics.demuxerOpen.stats.max)} | ${formatMs(metrics.demuxerOpen.stats.stdDev)} |
311
- | First Packet | ${formatMs(metrics.firstPacket.stats.mean)} | ${formatMs(metrics.firstPacket.stats.min)} | ${formatMs(metrics.firstPacket.stats.max)} | ${formatMs(metrics.firstPacket.stats.stdDev)} |
312
- | First Frame | ${formatMs(metrics.firstFrame.stats.mean)} | ${formatMs(metrics.firstFrame.stats.min)} | ${formatMs(metrics.firstFrame.stats.max)} | ${formatMs(metrics.firstFrame.stats.stdDev)} |
313
- | First Encoded Packet | ${formatMs(metrics.firstEncodedPacket.stats.mean)} | ${formatMs(metrics.firstEncodedPacket.stats.min)} | ${formatMs(metrics.firstEncodedPacket.stats.max)} | ${formatMs(metrics.firstEncodedPacket.stats.stdDev)} |
314
- | Pipeline Total | ${formatMs(metrics.pipelineTotal.stats.mean)} | ${formatMs(metrics.pipelineTotal.stats.min)} | ${formatMs(metrics.pipelineTotal.stats.max)} | ${formatMs(metrics.pipelineTotal.stats.stdDev)} |
315
-
316
- *Note: Each metric is measured independently. "First Encoded Packet" uses default encoder settings while "Pipeline Total" uses \`tune=zerolatency\` for low-latency output.*
317
- `;
318
- }
319
-
320
- /**
321
- * Format milliseconds
322
- */
323
- function formatMs(ms: number): string {
324
- if (ms < 1) {
325
- return `${(ms * 1000).toFixed(0)}µs`;
326
- }
327
- return `${ms.toFixed(1)}ms`;
328
- }
329
-
330
- /**
331
- * Format duration in milliseconds
332
- */
333
- function formatDuration(ms: number): string {
334
- if (ms < 1000) {
335
- return `${ms.toFixed(0)}ms`;
336
- }
337
- return `${(ms / 1000).toFixed(2)}s`;
338
- }
339
-
340
- /**
341
- * Generate the complete BENCHMARK.md report
342
- */
343
- export async function generateReport(report: BenchmarkReport): Promise<string> {
344
- const systemSection = formatSystemInfoSection(report.systemInfo);
345
- // Support both single file (legacy) and multiple files
346
- const inputSection =
347
- report.inputFileInfos && report.inputFileInfos.length > 0 ? formatInputFilesSection(report.inputFileInfos) : formatInputFileSection(report.inputFileInfo);
348
- const transcodeSection = formatTranscodeSection(report.transcodeResults);
349
- const memorySection = formatMemorySection(report.memoryResults);
350
- const latencySection = formatLatencySection(report.latencyMetrics);
351
-
352
- const markdown = `# node-av Benchmark Results
353
-
354
- > Generated: ${report.timestamp}
355
-
356
- ${systemSection}
357
-
358
- ${inputSection}
359
-
360
- ${transcodeSection}
361
-
362
- ${memorySection}
363
-
364
- ${latencySection}
365
- `;
366
-
367
- return markdown;
368
- }
369
-
370
- /**
371
- * Write the benchmark report to BENCHMARK.md
372
- */
373
- export async function writeReport(report: BenchmarkReport): Promise<void> {
374
- const markdown = await generateReport(report);
375
- const outputPath = resolve(rootDir, 'BENCHMARK.md');
376
- writeFileSync(outputPath, markdown, 'utf-8');
377
- console.log(`\n📄 Report written to: ${outputPath}`);
378
- }
379
-
380
- /**
381
- * Save raw results to JSON for later analysis
382
- */
383
- export function saveResultsJSON(report: BenchmarkReport): void {
384
- const outputPath = resolve(__dirname, '../results/benchmark-results.json');
385
- writeFileSync(outputPath, JSON.stringify(report, null, 2), 'utf-8');
386
- console.log(`📊 Raw results saved to: ${outputPath}`);
387
- }
388
-
389
- /**
390
- * Create input file info from probing
391
- */
392
- export async function createInputFileInfo(filePath: string): Promise<InputFileInfo> {
393
- try {
394
- const info = await probeMediaFile(filePath);
395
- return {
396
- path: filePath,
397
- duration: info.duration,
398
- resolution: info.width && info.height ? `${info.width}x${info.height}` : undefined,
399
- codec: info.videoCodec,
400
- fps: info.fps,
401
- };
402
- } catch {
403
- return { path: filePath, duration: 0 };
404
- }
405
- }
package/binding.gyp DELETED
@@ -1,166 +0,0 @@
1
- {
2
- "targets": [
3
- {
4
- "target_name": "node-av",
5
- "sources": [
6
- "src/bindings/index.cc",
7
- "src/bindings/packet.cc",
8
- "src/bindings/frame.cc",
9
- "src/bindings/frame_async.cc",
10
- "src/bindings/frame_sync.cc",
11
- "src/bindings/codec.cc",
12
- "src/bindings/codec_context.cc",
13
- "src/bindings/codec_context_async.cc",
14
- "src/bindings/codec_context_sync.cc",
15
- "src/bindings/codec_parameters.cc",
16
- "src/bindings/codec_parser.cc",
17
- "src/bindings/format_context.cc",
18
- "src/bindings/format_context_async.cc",
19
- "src/bindings/format_context_sync.cc",
20
- "src/bindings/stream.cc",
21
- "src/bindings/dictionary.cc",
22
- "src/bindings/input_format.cc",
23
- "src/bindings/input_format_async.cc",
24
- "src/bindings/input_format_sync.cc",
25
- "src/bindings/output_format.cc",
26
- "src/bindings/io_context.cc",
27
- "src/bindings/io_context_async.cc",
28
- "src/bindings/io_context_sync.cc",
29
- "src/bindings/error.cc",
30
- "src/bindings/software_scale_context.cc",
31
- "src/bindings/software_scale_context_async.cc",
32
- "src/bindings/software_scale_context_sync.cc",
33
- "src/bindings/software_resample_context.cc",
34
- "src/bindings/software_resample_context_async.cc",
35
- "src/bindings/software_resample_context_sync.cc",
36
- "src/bindings/filter.cc",
37
- "src/bindings/filter_context.cc",
38
- "src/bindings/filter_context_async.cc",
39
- "src/bindings/filter_context_sync.cc",
40
- "src/bindings/filter_graph.cc",
41
- "src/bindings/filter_graph_async.cc",
42
- "src/bindings/filter_graph_sync.cc",
43
- "src/bindings/filter_graph_segment.cc",
44
- "src/bindings/filter_inout.cc",
45
- "src/bindings/hardware_device_context.cc",
46
- "src/bindings/hardware_frames_context.cc",
47
- "src/bindings/hardware_frames_context_async.cc",
48
- "src/bindings/hardware_frames_context_sync.cc",
49
- "src/bindings/log.cc",
50
- "src/bindings/utilities.cc",
51
- "src/bindings/audio_fifo.cc",
52
- "src/bindings/audio_fifo_async.cc",
53
- "src/bindings/audio_fifo_sync.cc",
54
- "src/bindings/fifo.cc",
55
- "src/bindings/fifo_async.cc",
56
- "src/bindings/fifo_sync.cc",
57
- "src/bindings/frame_utils.cc",
58
- "src/bindings/bitstream_filter.cc",
59
- "src/bindings/bitstream_filter_context.cc",
60
- "src/bindings/bitstream_filter_context_async.cc",
61
- "src/bindings/bitstream_filter_context_sync.cc",
62
- "src/bindings/option.cc",
63
- "src/bindings/sync_queue.cc",
64
- "externals/jellyfin-ffmpeg/fftools/sync_queue.c",
65
- ],
66
- "include_dirs": [
67
- "<!@(node -p \"require('node-addon-api').include\")",
68
- "/opt/ffbuild/prefix/include",
69
- "<(module_root_dir)/externals/jellyfin-ffmpeg",
70
- "<(module_root_dir)/externals/jellyfin-ffmpeg/libavcodec",
71
- ],
72
- "library_dirs": ["/opt/ffbuild/prefix/lib"],
73
- "dependencies": ["<!(node -p \"require('node-addon-api').gyp\")"],
74
- "cflags!": ["-fno-exceptions"],
75
- "cflags_cc!": ["-fno-exceptions"],
76
- "defines": ["NAPI_DISABLE_CPP_EXCEPTIONS"],
77
- "libraries": [
78
- "-Wl,-force_load,/opt/ffbuild/prefix/lib/libavformat.a",
79
- "-Wl,-force_load,/opt/ffbuild/prefix/lib/libavcodec.a",
80
- "-Wl,-force_load,/opt/ffbuild/prefix/lib/libavfilter.a",
81
- "-Wl,-force_load,/opt/ffbuild/prefix/lib/libavutil.a",
82
- "-Wl,-force_load,/opt/ffbuild/prefix/lib/libswscale.a",
83
- "-Wl,-force_load,/opt/ffbuild/prefix/lib/libswresample.a",
84
- "-Wl,-force_load,/opt/ffbuild/prefix/lib/libavdevice.a",
85
- "-L/opt/ffbuild/prefix/lib",
86
- "/opt/ffbuild/prefix/lib/libx264.a",
87
- "/opt/ffbuild/prefix/lib/libx265.a",
88
- "/opt/ffbuild/prefix/lib/libvpx.a",
89
- "/opt/ffbuild/prefix/lib/libopus.a",
90
- "/opt/ffbuild/prefix/lib/libmp3lame.a",
91
- "/opt/ffbuild/prefix/lib/libdav1d.a",
92
- "/opt/ffbuild/prefix/lib/libSvtAv1Enc.a",
93
- "/opt/ffbuild/prefix/lib/libogg.a",
94
- "/opt/ffbuild/prefix/lib/libvorbis.a",
95
- "/opt/ffbuild/prefix/lib/libvorbisenc.a",
96
- "/opt/ffbuild/prefix/lib/libtheora.a",
97
- "/opt/ffbuild/prefix/lib/libtheoraenc.a",
98
- "/opt/ffbuild/prefix/lib/libtheoradec.a",
99
- "/opt/ffbuild/prefix/lib/libwebp.a",
100
- "/opt/ffbuild/prefix/lib/libwebpmux.a",
101
- "/opt/ffbuild/prefix/lib/libsrt.a",
102
- "/opt/ffbuild/prefix/lib/libass.a",
103
- "/opt/ffbuild/prefix/lib/libharfbuzz.a",
104
- "/opt/ffbuild/prefix/lib/libfontconfig.a",
105
- "/opt/ffbuild/prefix/lib/libfreetype.a",
106
- "/opt/ffbuild/prefix/lib/libfribidi.a",
107
- "/opt/ffbuild/prefix/lib/libbluray.a",
108
- "/opt/ffbuild/prefix/lib/libudfread.a",
109
- "/opt/ffbuild/prefix/lib/libz.a",
110
- "/opt/ffbuild/prefix/lib/liblzma.a",
111
- "/opt/ffbuild/prefix/lib/libfdk-aac.a",
112
- "/opt/ffbuild/prefix/lib/libNE10.a",
113
- "/opt/ffbuild/prefix/lib/libchromaprint.a",
114
- "/opt/ffbuild/prefix/lib/libopenmpt.a",
115
- "/opt/ffbuild/prefix/lib/libzvbi.a",
116
- "/opt/ffbuild/prefix/lib/libzimg.a",
117
- "/opt/ffbuild/prefix/lib/libgmp.a",
118
- "/opt/ffbuild/prefix/lib/libssl.a",
119
- "/opt/ffbuild/prefix/lib/libcrypto.a",
120
- "/opt/ffbuild/prefix/lib/libwhisper.a",
121
- "/opt/ffbuild/prefix/lib/libggml.a",
122
- "/opt/ffbuild/prefix/lib/libggml-base.a",
123
- "/opt/ffbuild/prefix/lib/libggml-cpu.a",
124
- "/opt/ffbuild/prefix/lib/libggml-blas.a",
125
- "/opt/ffbuild/prefix/lib/libggml-metal.a",
126
- "-liconv",
127
- "-lxml2",
128
- "-lbz2",
129
- "-framework CoreFoundation",
130
- "-framework CoreVideo",
131
- "-framework CoreMedia",
132
- "-framework CoreServices",
133
- "-framework AudioToolbox",
134
- "-framework VideoToolbox",
135
- "-framework AVFoundation",
136
- "-framework AppKit",
137
- "-framework Accelerate",
138
- "-framework Security",
139
- "-framework IOKit",
140
- "-framework OpenGL",
141
- "-framework Metal",
142
- "-framework MetalKit",
143
- "-framework Foundation",
144
- "-framework OpenCL",
145
- ],
146
- "xcode_settings": {
147
- "GCC_ENABLE_CPP_EXCEPTIONS": "YES",
148
- "CLANG_CXX_LIBRARY": "libc++",
149
- "CLANG_CXX_LANGUAGE_STANDARD": "c++17",
150
- "MACOSX_DEPLOYMENT_TARGET": "12.0",
151
- "OTHER_CPLUSPLUSFLAGS": [
152
- "-fexceptions",
153
- "-O3",
154
- ],
155
- "OTHER_LDFLAGS": [
156
- "-Wl,-dead_strip",
157
- "-Wl,-no_warn_duplicate_libraries",
158
- ],
159
- "CONDITIONS": [
160
- ["target_arch=='x64'", {"ARCHS": ["x86_64"]}],
161
- ["target_arch=='arm64'", {"ARCHS": ["arm64"]}],
162
- ],
163
- },
164
- }
165
- ]
166
- }