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,11 +1,11 @@
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
  "use strict";
@@ -540,6 +540,24 @@ const resolveEmarCommand = async (env, emsdkRoot) => {
540
540
  }
541
541
  return "emar";
542
542
  };
543
+ const resolveWasmOptCommand = async (env, emsdkRoot) => {
544
+ var _a;
545
+ if (env.WASM_OPT) {
546
+ return env.WASM_OPT;
547
+ }
548
+ const binaryenRoot = (_a = env.BINARYEN_ROOT) != null ? _a : env.BINARYEN;
549
+ if (binaryenRoot) {
550
+ const candidate = path.join(binaryenRoot, "bin", "wasm-opt");
551
+ if (await pathExists(candidate)) {
552
+ return candidate;
553
+ }
554
+ }
555
+ const fallback = path.join(emsdkRoot, "upstream", "bin", "wasm-opt");
556
+ if (await pathExists(fallback)) {
557
+ return fallback;
558
+ }
559
+ return "wasm-opt";
560
+ };
543
561
  const createConsoleLogger = (prefix) => {
544
562
  return {
545
563
  debug: (msg) => console.debug(`[${prefix}]: ${msg}`),
@@ -556,6 +574,7 @@ const DEFAULT_IMPORT_INCLUDE_DIR = "include";
556
574
  const DEFAULT_IMPORT_LIB_DIR = "lib";
557
575
  const DEFAULT_WASM_BUILD_DIR = path.join(os.tmpdir(), "emsdk-env");
558
576
  const DEFAULT_EMSDK_TARGET_VERSION = "latest";
577
+ const DEFAULT_WASM_OPT_ARGS = ["-Oz"];
559
578
  let buildSequence = 0;
560
579
  const padNumber = (value, length = 2) => String(value).padStart(length, "0");
561
580
  const formatTimestamp = (date) => {
@@ -582,10 +601,101 @@ const normalizePrepareOptions = (options) => {
582
601
  ...rest
583
602
  };
584
603
  };
604
+ const parseKeyValueInput = (values) => {
605
+ const parsed = {};
606
+ for (const entry of values) {
607
+ const index = entry.indexOf("=");
608
+ if (index === -1) {
609
+ parsed[entry] = void 0;
610
+ continue;
611
+ }
612
+ const key = entry.slice(0, index);
613
+ const value = entry.slice(index + 1);
614
+ parsed[key] = value;
615
+ }
616
+ return parsed;
617
+ };
618
+ const isKeyValueMap = (value) => value instanceof Map;
619
+ const normalizeKeyValueInput = (input) => {
620
+ if (!input) {
621
+ return {};
622
+ }
623
+ if (Array.isArray(input)) {
624
+ return parseKeyValueInput(input);
625
+ }
626
+ if (isKeyValueMap(input)) {
627
+ return Object.fromEntries(input);
628
+ }
629
+ return { ...input };
630
+ };
585
631
  const mergeDefines = (common, target) => ({
586
- ...common != null ? common : {},
587
- ...target != null ? target : {}
632
+ ...normalizeKeyValueInput(common),
633
+ ...normalizeKeyValueInput(target)
588
634
  });
635
+ const mergeLinkDirectives = (common, target) => mergeDefines(common, target);
636
+ const resolveWasmOptEnabled = (common, target) => {
637
+ var _a, _b;
638
+ return (_b = (_a = target == null ? void 0 : target.enable) != null ? _a : common == null ? void 0 : common.enable) != null ? _b : false;
639
+ };
640
+ const resolveWasmOptArgs = (common, target, env) => {
641
+ var _a, _b;
642
+ const commonArgs = (_a = common == null ? void 0 : common.options) != null ? _a : DEFAULT_WASM_OPT_ARGS;
643
+ const targetArgs = (_b = target == null ? void 0 : target.options) != null ? _b : [];
644
+ const mergedArgs = [...commonArgs, ...targetArgs];
645
+ return expandArray(mergedArgs, env, "wasmOpt.options");
646
+ };
647
+ const stripOuterQuotes = (value) => {
648
+ const trimmed = value.trim();
649
+ if (trimmed.startsWith('"') && trimmed.endsWith('"') || trimmed.startsWith("'") && trimmed.endsWith("'")) {
650
+ return trimmed.slice(1, -1);
651
+ }
652
+ return trimmed;
653
+ };
654
+ const extractWasmBinaryFile = (value) => {
655
+ if (value.startsWith("WASM_BINARY_FILE=")) {
656
+ return value.slice("WASM_BINARY_FILE=".length);
657
+ }
658
+ const match = value.match(/^(?:-s|--settings)(?:=)?WASM_BINARY_FILE=(.+)$/);
659
+ if (match) {
660
+ return match[1];
661
+ }
662
+ return void 0;
663
+ };
664
+ const resolveWasmBinaryFileFromLinkOptions = (linkOptions) => {
665
+ for (let index = 0; index < linkOptions.length; index += 1) {
666
+ const option = linkOptions[index];
667
+ if (!option) {
668
+ continue;
669
+ }
670
+ if (option === "-s" || option === "--settings") {
671
+ const next = linkOptions[index + 1];
672
+ if (!next) {
673
+ continue;
674
+ }
675
+ const extracted2 = extractWasmBinaryFile(next);
676
+ if (extracted2) {
677
+ return stripOuterQuotes(extracted2);
678
+ }
679
+ }
680
+ const extracted = extractWasmBinaryFile(option);
681
+ if (extracted) {
682
+ return stripOuterQuotes(extracted);
683
+ }
684
+ }
685
+ return void 0;
686
+ };
687
+ const resolveWasmOptInputFile = (resolvedOutFile, resolvedLinkOptions) => {
688
+ const wasmBinaryFile = resolveWasmBinaryFileFromLinkOptions(resolvedLinkOptions);
689
+ if (wasmBinaryFile) {
690
+ return path.isAbsolute(wasmBinaryFile) ? wasmBinaryFile : path.resolve(path.dirname(resolvedOutFile), wasmBinaryFile);
691
+ }
692
+ const parsed = path.parse(resolvedOutFile);
693
+ if (parsed.ext.toLowerCase() === ".wasm") {
694
+ return resolvedOutFile;
695
+ }
696
+ const baseName = parsed.name.toLowerCase().endsWith(".wasm") ? parsed.name : `${parsed.name}.wasm`;
697
+ return path.join(parsed.dir, baseName);
698
+ };
589
699
  const resolvePath = (rootDir, value) => path.isAbsolute(value) ? value : path.resolve(rootDir, value);
590
700
  const expandPlaceholders = (value, env, label) => value.replace(/\{([A-Z0-9_]+)\}/g, (_match, key) => {
591
701
  const replacement = env[key];
@@ -606,6 +716,17 @@ const resolveDefines = (defines, env) => {
606
716
  }
607
717
  return resolved;
608
718
  };
719
+ const resolveLinkDirectives = (directives, env) => {
720
+ const resolved = {};
721
+ for (const [key, value] of Object.entries(directives)) {
722
+ if (typeof value === "string") {
723
+ resolved[key] = expandPlaceholders(value, env, `linkDirectives.${key}`);
724
+ } else {
725
+ resolved[key] = value;
726
+ }
727
+ }
728
+ return resolved;
729
+ };
609
730
  const resolveIncludeDirs = (includeDirs, env, rootDir) => {
610
731
  const expanded = expandArray(includeDirs, env, "includeDirs");
611
732
  return expanded.map((value) => resolvePath(rootDir, value));
@@ -624,7 +745,17 @@ const resolveSourcesFromPatterns = async (patterns, env, srcDir, label) => {
624
745
  sources.sort();
625
746
  return sources;
626
747
  };
627
- const buildDefineFlags = (defines) => Object.entries(defines).map(([key, value]) => `-D${key}=${String(value)}`);
748
+ const buildDefineFlags = (defines) => Object.entries(defines).flatMap(
749
+ ([key, value]) => value === null || value === void 0 ? [`-D${key}`] : [`-D${key}=${String(value)}`]
750
+ );
751
+ const buildLinkDirectiveFlags = (directives) => {
752
+ if (Object.keys(directives).length === 0) {
753
+ return [];
754
+ }
755
+ return Object.entries(directives).flatMap(
756
+ ([key, value]) => value === null || value === void 0 ? ["-s", key] : ["-s", `${key}=${String(value)}`]
757
+ );
758
+ };
628
759
  const buildExportFlags = (exports$1) => {
629
760
  if (exports$1.length === 0) {
630
761
  return [];
@@ -887,6 +1018,15 @@ const buildWasm = async (options) => {
887
1018
  if (emarCommand) {
888
1019
  logger.debug(`Detected emarCommand: '${emarCommand}'`);
889
1020
  }
1021
+ let wasmOptCommand;
1022
+ const getWasmOptCommand = async () => {
1023
+ if (wasmOptCommand) {
1024
+ return wasmOptCommand;
1025
+ }
1026
+ wasmOptCommand = await resolveWasmOptCommand(envWithDirs, emsdkRoot);
1027
+ logger.debug(`Detected wasmOptCommand: '${wasmOptCommand}'`);
1028
+ return wasmOptCommand;
1029
+ };
890
1030
  const outFiles = {};
891
1031
  const buildTargets = async (expectedType) => {
892
1032
  var _a2;
@@ -901,17 +1041,29 @@ const buildWasm = async (options) => {
901
1041
  `linkOptions is not supported for archive target: ${targetName}`
902
1042
  );
903
1043
  }
1044
+ if (target.linkDirectives !== void 0) {
1045
+ throw new Error(
1046
+ `linkDirectives is not supported for archive target: ${targetName}`
1047
+ );
1048
+ }
904
1049
  if (target.exports !== void 0) {
905
1050
  throw new Error(
906
1051
  `exports is not supported for archive target: ${targetName}`
907
1052
  );
908
1053
  }
1054
+ if (target.wasmOpt !== void 0) {
1055
+ throw new Error(
1056
+ `wasmOpt is not supported for archive target: ${targetName}`
1057
+ );
1058
+ }
909
1059
  }
910
1060
  const mergedLinkOptions = targetType === "archive" ? [] : [
911
1061
  ...ensureArray(common.linkOptions),
912
1062
  ...ensureArray(target.linkOptions)
913
1063
  ];
1064
+ const mergedLinkDirectives = targetType === "archive" ? {} : mergeLinkDirectives(common.linkDirectives, target.linkDirectives);
914
1065
  const mergedExports = targetType === "archive" ? [] : [...ensureArray(common.exports), ...ensureArray(target.exports)];
1066
+ const wasmOptEnabled = targetType === "archive" ? false : resolveWasmOptEnabled(common.wasmOpt, target.wasmOpt);
915
1067
  const baseCompileOptions = [
916
1068
  ...ensureArray(common.options),
917
1069
  ...ensureArray(target.options)
@@ -969,9 +1121,15 @@ const buildWasm = async (options) => {
969
1121
  const targetBuildDir = path.resolve(buildRunDir, targetName);
970
1122
  await promises.rm(targetBuildDir, { recursive: true, force: true });
971
1123
  await ensureDirectory(targetBuildDir);
972
- const resolvedLinkOptions = targetType === "archive" ? [] : expandArray(mergedLinkOptions, targetEnv, "linkOptions");
1124
+ const resolvedLinkDirectives = targetType === "archive" ? {} : resolveLinkDirectives(mergedLinkDirectives, targetEnv);
1125
+ const linkDirectiveArgs = buildLinkDirectiveFlags(resolvedLinkDirectives);
1126
+ const resolvedLinkOptions = targetType === "archive" ? [] : [
1127
+ ...linkDirectiveArgs,
1128
+ ...expandArray(mergedLinkOptions, targetEnv, "linkOptions")
1129
+ ];
973
1130
  const resolvedExports = targetType === "archive" ? [] : expandArray(mergedExports, targetEnv, "exports");
974
1131
  const exportArgs = buildExportFlags(resolvedExports);
1132
+ const resolvedWasmOptArgs = wasmOptEnabled ? resolveWasmOptArgs(common.wasmOpt, target.wasmOpt, targetEnv) : [];
975
1133
  const baseCompileArgs = buildCompileArgs(
976
1134
  baseCompileOptions,
977
1135
  baseIncludeDirs,
@@ -980,7 +1138,6 @@ const buildWasm = async (options) => {
980
1138
  rootDir
981
1139
  );
982
1140
  const groupCompileArgs = sourceGroups.map((group) => {
983
- var _a3;
984
1141
  const groupOptions = [
985
1142
  ...baseCompileOptions,
986
1143
  ...ensureArray(group == null ? void 0 : group.options)
@@ -989,7 +1146,7 @@ const buildWasm = async (options) => {
989
1146
  ...baseIncludeDirs,
990
1147
  ...ensureArray(group == null ? void 0 : group.includeDirs)
991
1148
  ];
992
- const groupDefines = mergeDefines(baseDefines, (_a3 = group == null ? void 0 : group.defines) != null ? _a3 : {});
1149
+ const groupDefines = mergeDefines(baseDefines, group == null ? void 0 : group.defines);
993
1150
  return buildCompileArgs(
994
1151
  groupOptions,
995
1152
  groupIncludeDirs,
@@ -1105,6 +1262,36 @@ const buildWasm = async (options) => {
1105
1262
  buildEnv,
1106
1263
  emsdkOptions.signal
1107
1264
  );
1265
+ if (wasmOptEnabled) {
1266
+ const wasmOptInput = resolveWasmOptInputFile(
1267
+ resolvedOutFile,
1268
+ resolvedLinkOptions
1269
+ );
1270
+ if (!await pathExists(wasmOptInput)) {
1271
+ throw new Error(
1272
+ `wasm-opt enabled but wasm binary not found: ${wasmOptInput}`
1273
+ );
1274
+ }
1275
+ const tempOutFile = `${wasmOptInput}.opt`;
1276
+ const wasmOptArgs = [
1277
+ wasmOptInput,
1278
+ "-o",
1279
+ tempOutFile,
1280
+ ...resolvedWasmOptArgs
1281
+ ];
1282
+ const wasmOptCommand2 = await getWasmOptCommand();
1283
+ logger.info(`Optimizing target: ${targetName}.wasm`);
1284
+ logger.debug(`wasm-opt ${wasmOptArgs.join(" ")}`);
1285
+ await runCommandWithEnv(
1286
+ wasmOptCommand2,
1287
+ wasmOptArgs,
1288
+ rootDir,
1289
+ buildEnv,
1290
+ emsdkOptions.signal
1291
+ );
1292
+ await promises.rm(wasmOptInput, { force: true });
1293
+ await promises.rename(tempOutFile, wasmOptInput);
1294
+ }
1108
1295
  }
1109
1296
  outFiles[targetName] = resolvedOutFile;
1110
1297
  }
@@ -1125,4 +1312,4 @@ const buildWasm = async (options) => {
1125
1312
  exports.buildWasm = buildWasm;
1126
1313
  exports.createConsoleLogger = createConsoleLogger;
1127
1314
  exports.prepareEmsdk = prepareEmsdk;
1128
- //# sourceMappingURL=build-C7VNCGou.cjs.map
1315
+ //# sourceMappingURL=build-ya4uDvN7.cjs.map