emsdk-env 0.6.0 → 0.8.0

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,17 +1,17 @@
1
1
  /*!
2
2
  * name: emsdk-env
3
- * version: 0.6.0
3
+ * version: 0.8.0
4
4
  * description: Emscripten environment builder
5
5
  * author: Kouji Matsui (@kekyo@mi.kekyo.net)
6
6
  * license: MIT
7
7
  * repository.url: https://github.com/kekyo/emsdk-env
8
- * git.commit.hash: b3d95605029bb48999dacbfe7f264f960144b13d
8
+ * git.commit.hash: 8c3f97866a85cc6c99383eff3526c04077032eac
9
9
  */
10
10
 
11
11
  import { mkdir, access, constants, mkdtemp, rename, rm, readFile } from "fs/promises";
12
12
  import { homedir, tmpdir } from "os";
13
13
  import { glob } from "glob";
14
- import { join, resolve, isAbsolute, dirname, relative } from "path";
14
+ import { join, resolve, isAbsolute, dirname, relative, parse } from "path";
15
15
  import { spawn } from "child_process";
16
16
  const __NOOP_HANDLER = () => {
17
17
  };
@@ -517,6 +517,24 @@ const resolveEmarCommand = async (env, emsdkRoot) => {
517
517
  }
518
518
  return "emar";
519
519
  };
520
+ const resolveWasmOptCommand = async (env, emsdkRoot) => {
521
+ var _a;
522
+ if (env.WASM_OPT) {
523
+ return env.WASM_OPT;
524
+ }
525
+ const binaryenRoot = (_a = env.BINARYEN_ROOT) != null ? _a : env.BINARYEN;
526
+ if (binaryenRoot) {
527
+ const candidate = join(binaryenRoot, "bin", "wasm-opt");
528
+ if (await pathExists(candidate)) {
529
+ return candidate;
530
+ }
531
+ }
532
+ const fallback = join(emsdkRoot, "upstream", "bin", "wasm-opt");
533
+ if (await pathExists(fallback)) {
534
+ return fallback;
535
+ }
536
+ return "wasm-opt";
537
+ };
520
538
  const createConsoleLogger = (prefix) => {
521
539
  return {
522
540
  debug: (msg) => console.debug(`[${prefix}]: ${msg}`),
@@ -533,6 +551,7 @@ const DEFAULT_IMPORT_INCLUDE_DIR = "include";
533
551
  const DEFAULT_IMPORT_LIB_DIR = "lib";
534
552
  const DEFAULT_WASM_BUILD_DIR = join(tmpdir(), "emsdk-env");
535
553
  const DEFAULT_EMSDK_TARGET_VERSION = "latest";
554
+ const DEFAULT_WASM_OPT_ARGS = ["-Oz"];
536
555
  let buildSequence = 0;
537
556
  const padNumber = (value, length = 2) => String(value).padStart(length, "0");
538
557
  const formatTimestamp = (date) => {
@@ -559,10 +578,101 @@ const normalizePrepareOptions = (options) => {
559
578
  ...rest
560
579
  };
561
580
  };
581
+ const parseKeyValueInput = (values) => {
582
+ const parsed = {};
583
+ for (const entry of values) {
584
+ const index = entry.indexOf("=");
585
+ if (index === -1) {
586
+ parsed[entry] = void 0;
587
+ continue;
588
+ }
589
+ const key = entry.slice(0, index);
590
+ const value = entry.slice(index + 1);
591
+ parsed[key] = value;
592
+ }
593
+ return parsed;
594
+ };
595
+ const isKeyValueMap = (value) => value instanceof Map;
596
+ const normalizeKeyValueInput = (input) => {
597
+ if (!input) {
598
+ return {};
599
+ }
600
+ if (Array.isArray(input)) {
601
+ return parseKeyValueInput(input);
602
+ }
603
+ if (isKeyValueMap(input)) {
604
+ return Object.fromEntries(input);
605
+ }
606
+ return { ...input };
607
+ };
562
608
  const mergeDefines = (common, target) => ({
563
- ...common != null ? common : {},
564
- ...target != null ? target : {}
609
+ ...normalizeKeyValueInput(common),
610
+ ...normalizeKeyValueInput(target)
565
611
  });
612
+ const mergeLinkDirectives = (common, target) => mergeDefines(common, target);
613
+ const resolveWasmOptEnabled = (common, target) => {
614
+ var _a, _b;
615
+ return (_b = (_a = target == null ? void 0 : target.enable) != null ? _a : common == null ? void 0 : common.enable) != null ? _b : false;
616
+ };
617
+ const resolveWasmOptArgs = (common, target, env) => {
618
+ var _a, _b;
619
+ const commonArgs = (_a = common == null ? void 0 : common.options) != null ? _a : DEFAULT_WASM_OPT_ARGS;
620
+ const targetArgs = (_b = target == null ? void 0 : target.options) != null ? _b : [];
621
+ const mergedArgs = [...commonArgs, ...targetArgs];
622
+ return expandArray(mergedArgs, env, "wasmOpt.options");
623
+ };
624
+ const stripOuterQuotes = (value) => {
625
+ const trimmed = value.trim();
626
+ if (trimmed.startsWith('"') && trimmed.endsWith('"') || trimmed.startsWith("'") && trimmed.endsWith("'")) {
627
+ return trimmed.slice(1, -1);
628
+ }
629
+ return trimmed;
630
+ };
631
+ const extractWasmBinaryFile = (value) => {
632
+ if (value.startsWith("WASM_BINARY_FILE=")) {
633
+ return value.slice("WASM_BINARY_FILE=".length);
634
+ }
635
+ const match = value.match(/^(?:-s|--settings)(?:=)?WASM_BINARY_FILE=(.+)$/);
636
+ if (match) {
637
+ return match[1];
638
+ }
639
+ return void 0;
640
+ };
641
+ const resolveWasmBinaryFileFromLinkOptions = (linkOptions) => {
642
+ for (let index = 0; index < linkOptions.length; index += 1) {
643
+ const option = linkOptions[index];
644
+ if (!option) {
645
+ continue;
646
+ }
647
+ if (option === "-s" || option === "--settings") {
648
+ const next = linkOptions[index + 1];
649
+ if (!next) {
650
+ continue;
651
+ }
652
+ const extracted2 = extractWasmBinaryFile(next);
653
+ if (extracted2) {
654
+ return stripOuterQuotes(extracted2);
655
+ }
656
+ }
657
+ const extracted = extractWasmBinaryFile(option);
658
+ if (extracted) {
659
+ return stripOuterQuotes(extracted);
660
+ }
661
+ }
662
+ return void 0;
663
+ };
664
+ const resolveWasmOptInputFile = (resolvedOutFile, resolvedLinkOptions) => {
665
+ const wasmBinaryFile = resolveWasmBinaryFileFromLinkOptions(resolvedLinkOptions);
666
+ if (wasmBinaryFile) {
667
+ return isAbsolute(wasmBinaryFile) ? wasmBinaryFile : resolve(dirname(resolvedOutFile), wasmBinaryFile);
668
+ }
669
+ const parsed = parse(resolvedOutFile);
670
+ if (parsed.ext.toLowerCase() === ".wasm") {
671
+ return resolvedOutFile;
672
+ }
673
+ const baseName = parsed.name.toLowerCase().endsWith(".wasm") ? parsed.name : `${parsed.name}.wasm`;
674
+ return join(parsed.dir, baseName);
675
+ };
566
676
  const resolvePath = (rootDir, value) => isAbsolute(value) ? value : resolve(rootDir, value);
567
677
  const expandPlaceholders = (value, env, label) => value.replace(/\{([A-Z0-9_]+)\}/g, (_match, key) => {
568
678
  const replacement = env[key];
@@ -583,6 +693,17 @@ const resolveDefines = (defines, env) => {
583
693
  }
584
694
  return resolved;
585
695
  };
696
+ const resolveLinkDirectives = (directives, env) => {
697
+ const resolved = {};
698
+ for (const [key, value] of Object.entries(directives)) {
699
+ if (typeof value === "string") {
700
+ resolved[key] = expandPlaceholders(value, env, `linkDirectives.${key}`);
701
+ } else {
702
+ resolved[key] = value;
703
+ }
704
+ }
705
+ return resolved;
706
+ };
586
707
  const resolveIncludeDirs = (includeDirs, env, rootDir) => {
587
708
  const expanded = expandArray(includeDirs, env, "includeDirs");
588
709
  return expanded.map((value) => resolvePath(rootDir, value));
@@ -601,7 +722,17 @@ const resolveSourcesFromPatterns = async (patterns, env, srcDir, label) => {
601
722
  sources.sort();
602
723
  return sources;
603
724
  };
604
- const buildDefineFlags = (defines) => Object.entries(defines).map(([key, value]) => `-D${key}=${String(value)}`);
725
+ const buildDefineFlags = (defines) => Object.entries(defines).flatMap(
726
+ ([key, value]) => value === null || value === void 0 ? [`-D${key}`] : [`-D${key}=${String(value)}`]
727
+ );
728
+ const buildLinkDirectiveFlags = (directives) => {
729
+ if (Object.keys(directives).length === 0) {
730
+ return [];
731
+ }
732
+ return Object.entries(directives).flatMap(
733
+ ([key, value]) => value === null || value === void 0 ? ["-s", key] : ["-s", `${key}=${String(value)}`]
734
+ );
735
+ };
605
736
  const buildExportFlags = (exports$1) => {
606
737
  if (exports$1.length === 0) {
607
738
  return [];
@@ -864,6 +995,15 @@ const buildWasm = async (options) => {
864
995
  if (emarCommand) {
865
996
  logger.debug(`Detected emarCommand: '${emarCommand}'`);
866
997
  }
998
+ let wasmOptCommand;
999
+ const getWasmOptCommand = async () => {
1000
+ if (wasmOptCommand) {
1001
+ return wasmOptCommand;
1002
+ }
1003
+ wasmOptCommand = await resolveWasmOptCommand(envWithDirs, emsdkRoot);
1004
+ logger.debug(`Detected wasmOptCommand: '${wasmOptCommand}'`);
1005
+ return wasmOptCommand;
1006
+ };
867
1007
  const outFiles = {};
868
1008
  const buildTargets = async (expectedType) => {
869
1009
  var _a2;
@@ -878,17 +1018,29 @@ const buildWasm = async (options) => {
878
1018
  `linkOptions is not supported for archive target: ${targetName}`
879
1019
  );
880
1020
  }
1021
+ if (target.linkDirectives !== void 0) {
1022
+ throw new Error(
1023
+ `linkDirectives is not supported for archive target: ${targetName}`
1024
+ );
1025
+ }
881
1026
  if (target.exports !== void 0) {
882
1027
  throw new Error(
883
1028
  `exports is not supported for archive target: ${targetName}`
884
1029
  );
885
1030
  }
1031
+ if (target.wasmOpt !== void 0) {
1032
+ throw new Error(
1033
+ `wasmOpt is not supported for archive target: ${targetName}`
1034
+ );
1035
+ }
886
1036
  }
887
1037
  const mergedLinkOptions = targetType === "archive" ? [] : [
888
1038
  ...ensureArray(common.linkOptions),
889
1039
  ...ensureArray(target.linkOptions)
890
1040
  ];
1041
+ const mergedLinkDirectives = targetType === "archive" ? {} : mergeLinkDirectives(common.linkDirectives, target.linkDirectives);
891
1042
  const mergedExports = targetType === "archive" ? [] : [...ensureArray(common.exports), ...ensureArray(target.exports)];
1043
+ const wasmOptEnabled = targetType === "archive" ? false : resolveWasmOptEnabled(common.wasmOpt, target.wasmOpt);
892
1044
  const baseCompileOptions = [
893
1045
  ...ensureArray(common.options),
894
1046
  ...ensureArray(target.options)
@@ -946,9 +1098,15 @@ const buildWasm = async (options) => {
946
1098
  const targetBuildDir = resolve(buildRunDir, targetName);
947
1099
  await rm(targetBuildDir, { recursive: true, force: true });
948
1100
  await ensureDirectory(targetBuildDir);
949
- const resolvedLinkOptions = targetType === "archive" ? [] : expandArray(mergedLinkOptions, targetEnv, "linkOptions");
1101
+ const resolvedLinkDirectives = targetType === "archive" ? {} : resolveLinkDirectives(mergedLinkDirectives, targetEnv);
1102
+ const linkDirectiveArgs = buildLinkDirectiveFlags(resolvedLinkDirectives);
1103
+ const resolvedLinkOptions = targetType === "archive" ? [] : [
1104
+ ...linkDirectiveArgs,
1105
+ ...expandArray(mergedLinkOptions, targetEnv, "linkOptions")
1106
+ ];
950
1107
  const resolvedExports = targetType === "archive" ? [] : expandArray(mergedExports, targetEnv, "exports");
951
1108
  const exportArgs = buildExportFlags(resolvedExports);
1109
+ const resolvedWasmOptArgs = wasmOptEnabled ? resolveWasmOptArgs(common.wasmOpt, target.wasmOpt, targetEnv) : [];
952
1110
  const baseCompileArgs = buildCompileArgs(
953
1111
  baseCompileOptions,
954
1112
  baseIncludeDirs,
@@ -957,7 +1115,6 @@ const buildWasm = async (options) => {
957
1115
  rootDir
958
1116
  );
959
1117
  const groupCompileArgs = sourceGroups.map((group) => {
960
- var _a3;
961
1118
  const groupOptions = [
962
1119
  ...baseCompileOptions,
963
1120
  ...ensureArray(group == null ? void 0 : group.options)
@@ -966,7 +1123,7 @@ const buildWasm = async (options) => {
966
1123
  ...baseIncludeDirs,
967
1124
  ...ensureArray(group == null ? void 0 : group.includeDirs)
968
1125
  ];
969
- const groupDefines = mergeDefines(baseDefines, (_a3 = group == null ? void 0 : group.defines) != null ? _a3 : {});
1126
+ const groupDefines = mergeDefines(baseDefines, group == null ? void 0 : group.defines);
970
1127
  return buildCompileArgs(
971
1128
  groupOptions,
972
1129
  groupIncludeDirs,
@@ -1082,6 +1239,36 @@ const buildWasm = async (options) => {
1082
1239
  buildEnv,
1083
1240
  emsdkOptions.signal
1084
1241
  );
1242
+ if (wasmOptEnabled) {
1243
+ const wasmOptInput = resolveWasmOptInputFile(
1244
+ resolvedOutFile,
1245
+ resolvedLinkOptions
1246
+ );
1247
+ if (!await pathExists(wasmOptInput)) {
1248
+ throw new Error(
1249
+ `wasm-opt enabled but wasm binary not found: ${wasmOptInput}`
1250
+ );
1251
+ }
1252
+ const tempOutFile = `${wasmOptInput}.opt`;
1253
+ const wasmOptArgs = [
1254
+ wasmOptInput,
1255
+ "-o",
1256
+ tempOutFile,
1257
+ ...resolvedWasmOptArgs
1258
+ ];
1259
+ const wasmOptCommand2 = await getWasmOptCommand();
1260
+ logger.info(`Optimizing target: ${targetName}.wasm`);
1261
+ logger.debug(`wasm-opt ${wasmOptArgs.join(" ")}`);
1262
+ await runCommandWithEnv(
1263
+ wasmOptCommand2,
1264
+ wasmOptArgs,
1265
+ rootDir,
1266
+ buildEnv,
1267
+ emsdkOptions.signal
1268
+ );
1269
+ await rm(wasmOptInput, { force: true });
1270
+ await rename(tempOutFile, wasmOptInput);
1271
+ }
1085
1272
  }
1086
1273
  outFiles[targetName] = resolvedOutFile;
1087
1274
  }
@@ -1104,4 +1291,4 @@ export {
1104
1291
  createConsoleLogger as c,
1105
1292
  prepareEmsdk as p
1106
1293
  };
1107
- //# sourceMappingURL=build-B0LjpT0A.js.map
1294
+ //# sourceMappingURL=build-DzrgEC4A.js.map