emsdk-env 0.3.0 → 0.5.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.
package/README.md CHANGED
@@ -9,14 +9,13 @@ A Vite plugin that automatically builds WASM C/C++ source code using the Emscrip
9
9
 
10
10
  ---
11
11
 
12
- WIP:
13
-
14
12
  ## What is this?
15
13
 
16
- This is a Vite plugin that automatically downloads and manages the Emscripten SDK, and makes it possible to automatically build WASM C/C++ code in your project.
14
+ This is a Vite plugin that automatically downloads and manages the [Emscripten SDK](https://github.com/emscripten-core/emsdk),
15
+ and makes it possible to automatically build WASM C/C++ code in your project.
17
16
  With this plugin, you can easily set up a WASM C/C++ development environment in your Vite project.
18
17
 
19
- Usage is simple. Just add this Vite plugin package to your project and initialize the plugin in `vite.config.ts` like this:
18
+ Usage is simple. Just add this Vite plugin package to your project and initialize the plugin in `vite.config` like this:
20
19
 
21
20
  ```typescript
22
21
  // `vite.config.ts`
@@ -57,6 +56,8 @@ You can focus on writing C/C++ code just like you would TypeScript/JavaScript co
57
56
  - Simplified specification of export symbols
58
57
  - Ability to generate multiple target WASM binaries
59
58
  - Customizable directory paths, compile options, and linker options
59
+ - Archive libraries (`*.a`) can be built and referenced
60
+ - WASM libraries can be distributed and referenced via NPM packages
60
61
 
61
62
  ---
62
63
 
@@ -70,6 +71,9 @@ Add to `devDependencies` (emsdk-env itself does not require runtime code):
70
71
  $ npm install -D emsdk-env
71
72
  ```
72
73
 
74
+ - emsdk-env automatically downloads and caches the Emscripten SDK (located under `~/.cache/emsdk-env/`).
75
+ Therefore, you do not need to manually set up the Emscripten SDK.
76
+
73
77
  ### C/C++ Source Code and Binary Placement
74
78
 
75
79
  By default, C/C++ source code is placed in the `wasm/` directory under your project,
@@ -88,6 +92,19 @@ project/
88
92
  └── add.c
89
93
  ```
90
94
 
95
+ - In addition to the above, a temporary build directory is created under the OS temp directory.
96
+ The default location is `${TMPDIR}/emsdk-env` (typically `/tmp/emsdk-env` on Unix).
97
+ This directory is used during the build process and is typically deleted after the build completes.
98
+ If you override `buildDir` to point inside the project, add it to `.gitignore`.
99
+
100
+ Of course, you can change these. Specify them in the Vite plugin options.
101
+
102
+ You might find it odd that the built binary is placed in `src/wasm/`, but this is because the Vite server defaults to a path where it can easily access WASM binaries.
103
+
104
+ If you plan to operate with the default settings, there is essentially no configuration work required.
105
+
106
+ Other topics include features such as explicitly specifying source files, applying multiple compile options separately, handling multiple target outputs, generating and referencing archive library files, and compilation and referencing NPM packages.
107
+
91
108
  ### Documents
92
109
 
93
110
  For more information, please visit repository and refer README: [emsdk-env](https://github.com/kekyo/emsdk-env)
@@ -1,14 +1,36 @@
1
1
  /*!
2
2
  * name: emsdk-env
3
- * version: 0.3.0
3
+ * version: 0.5.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: 4a03739b8c88111950fa216a7c10c7bfd65ea239
8
+ * git.commit.hash: f54983861d59656c8f39fd46d984c1b373100dde
9
9
  */
10
10
 
11
11
  "use strict";
12
+ var __create = Object.create;
13
+ var __defProp = Object.defineProperty;
14
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
15
+ var __getOwnPropNames = Object.getOwnPropertyNames;
16
+ var __getProtoOf = Object.getPrototypeOf;
17
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
18
+ var __copyProps = (to, from, except, desc) => {
19
+ if (from && typeof from === "object" || typeof from === "function") {
20
+ for (let key of __getOwnPropNames(from))
21
+ if (!__hasOwnProp.call(to, key) && key !== except)
22
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
23
+ }
24
+ return to;
25
+ };
26
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
27
+ // If the importer is in node compatibility mode or this is not an ESM
28
+ // file that has been converted to a CommonJS file using a Babel-
29
+ // compatible transform (i.e. "__esModule" has not been set), then set
30
+ // "default" to the CommonJS "module.exports" for node compatibility.
31
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
32
+ mod
33
+ ));
12
34
  const promises = require("fs/promises");
13
35
  const os = require("os");
14
36
  const glob = require("glob");
@@ -502,6 +524,22 @@ const resolveEmccCommand = async (env, emsdkRoot) => {
502
524
  }
503
525
  return "emcc";
504
526
  };
527
+ const resolveEmarCommand = async (env, emsdkRoot) => {
528
+ if (env.EMAR) {
529
+ return env.EMAR;
530
+ }
531
+ if (env.EMSCRIPTEN) {
532
+ const candidate = path.join(env.EMSCRIPTEN, "emar");
533
+ if (await pathExists(candidate)) {
534
+ return candidate;
535
+ }
536
+ }
537
+ const fallback = path.join(emsdkRoot, "upstream", "emscripten", "emar");
538
+ if (await pathExists(fallback)) {
539
+ return fallback;
540
+ }
541
+ return "emar";
542
+ };
505
543
  const createConsoleLogger = (prefix) => {
506
544
  return {
507
545
  debug: (msg) => console.debug(`[${prefix}]: ${msg}`),
@@ -511,7 +549,11 @@ const createConsoleLogger = (prefix) => {
511
549
  };
512
550
  };
513
551
  const DEFAULT_WASM_SRC_DIR = "wasm";
552
+ const DEFAULT_WASM_INCLUDE_DIR = "include";
514
553
  const DEFAULT_WASM_OUT_DIR = path.join("src", "wasm");
554
+ const DEFAULT_WASM_LIB_DIR = "lib";
555
+ const DEFAULT_IMPORT_INCLUDE_DIR = "include";
556
+ const DEFAULT_IMPORT_LIB_DIR = "lib";
515
557
  const DEFAULT_WASM_BUILD_DIR = path.join(os.tmpdir(), "emsdk-env");
516
558
  const DEFAULT_EMSDK_TARGET_VERSION = "latest";
517
559
  let buildSequence = 0;
@@ -532,6 +574,7 @@ const createBuildId = () => {
532
574
  return `${timestamp}_${seq}_${process.pid}`;
533
575
  };
534
576
  const ensureArray = (value) => value != null ? value : [];
577
+ const resolveTargetType = (value) => value != null ? value : "wasm";
535
578
  const normalizePrepareOptions = (options) => {
536
579
  const { targetVersion, ...rest } = options != null ? options : {};
537
580
  return {
@@ -593,11 +636,11 @@ const createEnvForBuild = (baseEnv, overrides) => ({
593
636
  ...baseEnv,
594
637
  ...overrides
595
638
  });
596
- const resolveTargetOutFile = (targetName, targetOutFile, env, outDir) => {
639
+ const resolveTargetOutFile = (targetName, targetOutFile, env, baseDir, extension) => {
597
640
  if (targetOutFile) {
598
- return resolveOutFile(targetOutFile, env, outDir);
641
+ return resolveOutFile(targetOutFile, env, baseDir);
599
642
  }
600
- return path.resolve(outDir, `${targetName}.wasm`);
643
+ return path.resolve(baseDir, `${targetName}.${extension}`);
601
644
  };
602
645
  const resolveTargetSources = async (targetSources, env, srcDir) => {
603
646
  const patterns = targetSources && targetSources.length > 0 ? targetSources : [path.join(srcDir, "**", "*.c"), path.join(srcDir, "**", "*.cpp")];
@@ -622,6 +665,118 @@ const dedupeSources = (sources) => {
622
665
  }
623
666
  return deduped;
624
667
  };
668
+ const dedupeValues = (values) => {
669
+ const seen = /* @__PURE__ */ new Set();
670
+ const deduped = [];
671
+ for (const value of values) {
672
+ if (seen.has(value)) {
673
+ continue;
674
+ }
675
+ seen.add(value);
676
+ deduped.push(value);
677
+ }
678
+ return deduped;
679
+ };
680
+ const isRecord = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
681
+ const resolvePackageJsonPath = async (startPath, packageName) => {
682
+ let current = path.dirname(startPath);
683
+ for (; ; ) {
684
+ const candidate = path.join(current, "package.json");
685
+ if (await pathExists(candidate)) {
686
+ return candidate;
687
+ }
688
+ const parent = path.dirname(current);
689
+ if (parent === current) {
690
+ throw new Error(`package.json not found for import: ${packageName}`);
691
+ }
692
+ current = parent;
693
+ }
694
+ };
695
+ const loadPackageJson = async (packageJsonPath, packageName) => {
696
+ try {
697
+ const raw = await promises.readFile(packageJsonPath, "utf8");
698
+ const parsed = JSON.parse(raw);
699
+ if (!isRecord(parsed)) {
700
+ throw new Error("package.json must be an object.");
701
+ }
702
+ return parsed;
703
+ } catch (error) {
704
+ const message = error instanceof Error ? error.message : String(error);
705
+ throw new Error(
706
+ `Failed to read package.json for import ${packageName}: ${message}`
707
+ );
708
+ }
709
+ };
710
+ const resolveImportPaths = async (resolver, packageName) => {
711
+ let resolvedEntry;
712
+ try {
713
+ resolvedEntry = resolver.resolve(packageName);
714
+ } catch (error) {
715
+ const message = error instanceof Error ? error.message : String(error);
716
+ throw new Error(`Failed to resolve import ${packageName}: ${message}`);
717
+ }
718
+ const packageJsonPath = await resolvePackageJsonPath(
719
+ resolvedEntry,
720
+ packageName
721
+ );
722
+ const packageRoot = path.dirname(packageJsonPath);
723
+ const packageJson = await loadPackageJson(packageJsonPath, packageName);
724
+ const emsdkConfigRaw = packageJson["emsdk-env"];
725
+ if (emsdkConfigRaw !== void 0 && !isRecord(emsdkConfigRaw)) {
726
+ throw new Error(
727
+ `Invalid emsdk-env config for import ${packageName}: expected an object.`
728
+ );
729
+ }
730
+ const includeRaw = isRecord(emsdkConfigRaw) ? emsdkConfigRaw.include : void 0;
731
+ if (includeRaw !== void 0 && typeof includeRaw !== "string") {
732
+ throw new Error(
733
+ `Invalid emsdk-env include for import ${packageName}: expected a string.`
734
+ );
735
+ }
736
+ const libRaw = isRecord(emsdkConfigRaw) ? emsdkConfigRaw.lib : void 0;
737
+ if (libRaw !== void 0 && typeof libRaw !== "string") {
738
+ throw new Error(
739
+ `Invalid emsdk-env lib for import ${packageName}: expected a string.`
740
+ );
741
+ }
742
+ const includeRel = includeRaw != null ? includeRaw : DEFAULT_IMPORT_INCLUDE_DIR;
743
+ const libRel = libRaw != null ? libRaw : DEFAULT_IMPORT_LIB_DIR;
744
+ const includeDir = path.resolve(packageRoot, includeRel);
745
+ const libDir = path.resolve(packageRoot, libRel);
746
+ const includeExists = await pathExists(includeDir);
747
+ const libExists = await pathExists(libDir);
748
+ if (!includeExists && !libExists) {
749
+ throw new Error(
750
+ `Import ${packageName} does not provide include or lib directories.`
751
+ );
752
+ }
753
+ return {
754
+ includeDir: includeExists ? includeDir : void 0,
755
+ libDir: libExists ? libDir : void 0
756
+ };
757
+ };
758
+ const resolveImportDirectories = async (rootDir, imports) => {
759
+ if (imports.length === 0) {
760
+ return { includeDirs: [], libDirs: [] };
761
+ }
762
+ const moduleApi = await import("node:module");
763
+ const resolver = moduleApi.createRequire(path.resolve(rootDir, "package.json"));
764
+ const includeDirs = [];
765
+ const libDirs = [];
766
+ for (const packageName of imports) {
767
+ const resolved = await resolveImportPaths(resolver, packageName);
768
+ if (resolved.includeDir) {
769
+ includeDirs.push(resolved.includeDir);
770
+ }
771
+ if (resolved.libDir) {
772
+ libDirs.push(resolved.libDir);
773
+ }
774
+ }
775
+ return {
776
+ includeDirs: dedupeValues(includeDirs),
777
+ libDirs: dedupeValues(libDirs)
778
+ };
779
+ };
625
780
  const buildCompileArgs = (options, includeDirs, defines, env, rootDir) => {
626
781
  const resolvedOptions = expandArray(options, env, "options");
627
782
  const includeArgs = resolveIncludeDirs(includeDirs, env, rootDir).map(
@@ -631,15 +786,15 @@ const buildCompileArgs = (options, includeDirs, defines, env, rootDir) => {
631
786
  return { resolvedOptions, includeArgs, defineArgs };
632
787
  };
633
788
  const buildWasm = async (options) => {
634
- var _a, _b, _c, _d, _e, _f, _g, _h, _i;
789
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
635
790
  if (!options) {
636
791
  throw new TypeError("options must be provided.");
637
792
  }
638
793
  if (!options.rule || !options.rule.targets) {
639
794
  throw new TypeError("rule targets must be provided.");
640
795
  }
641
- const targets = Object.entries(options.rule.targets);
642
- if (targets.length === 0) {
796
+ const targetEntries = Object.entries(options.rule.targets);
797
+ if (targetEntries.length === 0) {
643
798
  throw new TypeError("rule targets must not be empty.");
644
799
  }
645
800
  const logger = (_a = options.logger) != null ? _a : createConsoleLogger("emsdk-env");
@@ -656,57 +811,118 @@ const buildWasm = async (options) => {
656
811
  baseEnv,
657
812
  "srcDir"
658
813
  );
814
+ const rawIncludeDir = expandPlaceholders(
815
+ (_d = options.includeDir) != null ? _d : DEFAULT_WASM_INCLUDE_DIR,
816
+ baseEnv,
817
+ "includeDir"
818
+ );
659
819
  const rawOutDir = expandPlaceholders(
660
- (_d = options.outDir) != null ? _d : DEFAULT_WASM_OUT_DIR,
820
+ (_e = options.outDir) != null ? _e : DEFAULT_WASM_OUT_DIR,
661
821
  baseEnv,
662
822
  "outDir"
663
823
  );
824
+ const rawLibDir = expandPlaceholders(
825
+ (_f = options.libDir) != null ? _f : DEFAULT_WASM_LIB_DIR,
826
+ baseEnv,
827
+ "libDir"
828
+ );
664
829
  const rawBuildDir = expandPlaceholders(
665
- (_e = options.buildDir) != null ? _e : DEFAULT_WASM_BUILD_DIR,
830
+ (_g = options.buildDir) != null ? _g : DEFAULT_WASM_BUILD_DIR,
666
831
  baseEnv,
667
832
  "buildDir"
668
833
  );
669
834
  const srcDir = resolvePath(rootDir, rawSrcDir);
835
+ const includeDir = resolvePath(rootDir, rawIncludeDir);
670
836
  const outDir = resolvePath(rootDir, rawOutDir);
837
+ const libDir = resolvePath(rootDir, rawLibDir);
671
838
  const buildDir = resolvePath(rootDir, rawBuildDir);
672
839
  const buildId = createBuildId();
673
840
  const buildRunDir = path.resolve(buildDir, buildId);
674
- const cleanupBuildDir = (_f = options.cleanupBuildDir) != null ? _f : true;
675
- const parallel = (_g = options.parallel) != null ? _g : true;
841
+ const cleanupBuildDir = (_h = options.cleanupBuildDir) != null ? _h : true;
842
+ const parallel = (_i = options.parallel) != null ? _i : true;
676
843
  const envWithDirs = {
677
844
  ...emsdkEnv,
678
845
  ROOT: rootDir,
679
846
  SRC_DIR: srcDir,
847
+ INCLUDE_DIR: includeDir,
680
848
  OUT_DIR: outDir,
849
+ LIB_DIR: libDir,
681
850
  BUILD_DIR: buildDir
682
851
  };
683
852
  const emccCommand = await resolveEmccCommand(envWithDirs, emsdkRoot);
684
- const common = (_h = options.rule.common) != null ? _h : {};
853
+ const common = (_j = options.rule.common) != null ? _j : {};
854
+ const commonIncludeDirs = common.includeDirs === void 0 ? [includeDir] : common.includeDirs;
855
+ const importDirectories = await resolveImportDirectories(
856
+ rootDir,
857
+ ensureArray(options.imports)
858
+ );
859
+ const importIncludeDirs = importDirectories.includeDirs;
860
+ const importLibDirs = importDirectories.libDirs;
861
+ const linkLibDirs = dedupeValues([libDir, ...importLibDirs]);
862
+ logger.debug(`Detected rootDir: '${rootDir}'`);
863
+ logger.debug(`Detected srcDir: '${srcDir}'`);
864
+ logger.debug(`Detected outDir: '${outDir}'`);
865
+ logger.debug(`Detected libDir: '${libDir}'`);
866
+ logger.debug(`Detected buildDir: '${buildDir}'`);
867
+ logger.debug(`Detected buildId: '${buildId}'`);
868
+ logger.debug(`Detected buildRunDir: '${buildRunDir}'`);
869
+ logger.debug(`Detected cleanupBuildDir: ${cleanupBuildDir}`);
870
+ logger.debug(`Detected parallel: ${parallel}`);
871
+ logger.debug(`Detected emccCommand: '${emccCommand}'`);
872
+ logger.debug(
873
+ `Detected importIncludeDirs: [${importIncludeDirs.map((p) => `'${p}'`).join(",")}]`
874
+ );
875
+ logger.debug(
876
+ `Detected importLibDirs: [${importLibDirs.map((p) => `'${p}'`).join(",")}]`
877
+ );
685
878
  await ensureDirectory(outDir);
879
+ await ensureDirectory(libDir);
686
880
  await ensureDirectory(buildDir);
687
881
  await promises.rm(buildRunDir, { recursive: true, force: true });
688
882
  await ensureDirectory(buildRunDir);
883
+ const hasArchiveTargets = targetEntries.some(
884
+ ([, target]) => resolveTargetType(target.type) === "archive"
885
+ );
886
+ const emarCommand = hasArchiveTargets ? await resolveEmarCommand(envWithDirs, emsdkRoot) : void 0;
887
+ if (emarCommand) {
888
+ logger.debug(`Detected emarCommand: '${emarCommand}'`);
889
+ }
689
890
  const outFiles = {};
690
- try {
691
- for (const [targetName, target] of targets) {
692
- const mergedLinkOptions = [
891
+ const buildTargets = async (expectedType) => {
892
+ var _a2;
893
+ for (const [targetName, target] of targetEntries) {
894
+ const targetType = resolveTargetType(target.type);
895
+ if (targetType !== expectedType) {
896
+ continue;
897
+ }
898
+ if (targetType === "archive") {
899
+ if (target.linkOptions !== void 0) {
900
+ throw new Error(
901
+ `linkOptions is not supported for archive target: ${targetName}`
902
+ );
903
+ }
904
+ if (target.exports !== void 0) {
905
+ throw new Error(
906
+ `exports is not supported for archive target: ${targetName}`
907
+ );
908
+ }
909
+ }
910
+ const mergedLinkOptions = targetType === "archive" ? [] : [
693
911
  ...ensureArray(common.linkOptions),
694
912
  ...ensureArray(target.linkOptions)
695
913
  ];
696
- const mergedExports = [
697
- ...ensureArray(common.exports),
698
- ...ensureArray(target.exports)
699
- ];
914
+ const mergedExports = targetType === "archive" ? [] : [...ensureArray(common.exports), ...ensureArray(target.exports)];
700
915
  const baseCompileOptions = [
701
916
  ...ensureArray(common.options),
702
917
  ...ensureArray(target.options)
703
918
  ];
704
919
  const baseIncludeDirs = [
705
- ...ensureArray(common.includeDirs),
706
- ...ensureArray(target.includeDirs)
920
+ ...ensureArray(commonIncludeDirs),
921
+ ...ensureArray(target.includeDirs),
922
+ ...importIncludeDirs
707
923
  ];
708
924
  const baseDefines = mergeDefines(common.defines, target.defines);
709
- const sourceGroups = (_i = target.sourceGroups) != null ? _i : [];
925
+ const sourceGroups = (_a2 = target.sourceGroups) != null ? _a2 : [];
710
926
  const targetEnv = {
711
927
  ...envWithDirs,
712
928
  TARGET_NAME: targetName
@@ -716,7 +932,8 @@ const buildWasm = async (options) => {
716
932
  targetName,
717
933
  target.outFile,
718
934
  targetEnv,
719
- outDir
935
+ targetType === "archive" ? libDir : outDir,
936
+ targetType === "archive" ? "a" : "wasm"
720
937
  );
721
938
  const sources = await resolveTargetSources(
722
939
  target.sources,
@@ -752,12 +969,8 @@ const buildWasm = async (options) => {
752
969
  const targetBuildDir = path.resolve(buildRunDir, targetName);
753
970
  await promises.rm(targetBuildDir, { recursive: true, force: true });
754
971
  await ensureDirectory(targetBuildDir);
755
- const resolvedLinkOptions = expandArray(
756
- mergedLinkOptions,
757
- targetEnv,
758
- "linkOptions"
759
- );
760
- const resolvedExports = expandArray(mergedExports, targetEnv, "exports");
972
+ const resolvedLinkOptions = targetType === "archive" ? [] : expandArray(mergedLinkOptions, targetEnv, "linkOptions");
973
+ const resolvedExports = targetType === "archive" ? [] : expandArray(mergedExports, targetEnv, "exports");
761
974
  const exportArgs = buildExportFlags(resolvedExports);
762
975
  const baseCompileArgs = buildCompileArgs(
763
976
  baseCompileOptions,
@@ -767,7 +980,7 @@ const buildWasm = async (options) => {
767
980
  rootDir
768
981
  );
769
982
  const groupCompileArgs = sourceGroups.map((group) => {
770
- var _a2;
983
+ var _a3;
771
984
  const groupOptions = [
772
985
  ...baseCompileOptions,
773
986
  ...ensureArray(group == null ? void 0 : group.options)
@@ -776,7 +989,7 @@ const buildWasm = async (options) => {
776
989
  ...baseIncludeDirs,
777
990
  ...ensureArray(group == null ? void 0 : group.includeDirs)
778
991
  ];
779
- const groupDefines = mergeDefines(baseDefines, (_a2 = group == null ? void 0 : group.defines) != null ? _a2 : {});
992
+ const groupDefines = mergeDefines(baseDefines, (_a3 = group == null ? void 0 : group.defines) != null ? _a3 : {});
780
993
  return buildCompileArgs(
781
994
  groupOptions,
782
995
  groupIncludeDirs,
@@ -785,7 +998,6 @@ const buildWasm = async (options) => {
785
998
  rootDir
786
999
  );
787
1000
  });
788
- logger.info(`Compiling target: ${targetName}`);
789
1001
  const compileSource = async (source, args, groupIndex) => {
790
1002
  const objectName = toSafeObjectName(rootDir, source, groupIndex);
791
1003
  const outputObject = path.resolve(targetBuildDir, `${objectName}.o`);
@@ -798,6 +1010,8 @@ const buildWasm = async (options) => {
798
1010
  ...args.includeArgs,
799
1011
  ...args.defineArgs
800
1012
  ];
1013
+ const sourcePath = path.relative(rootDir, source);
1014
+ logger.info(`Compiling source: ${sourcePath} --> $tmp/${objectName}.o`);
801
1015
  logger.debug(`emcc ${compileArgs.join(" ")}`);
802
1016
  await runCommandWithEnv(
803
1017
  emccCommand,
@@ -838,6 +1052,9 @@ const buildWasm = async (options) => {
838
1052
  groupIndex: void 0
839
1053
  });
840
1054
  }
1055
+ logger.info(
1056
+ parallel ? `Building target: '${targetName}' [${compileJobs.length} files, in parallel]` : `Building target: '${targetName}' [${compileJobs.length} files]`
1057
+ );
841
1058
  for (let index = 0; index < groupSources.length; index += 1) {
842
1059
  const sourcesInGroup = groupSources[index];
843
1060
  if (!sourcesInGroup) {
@@ -856,24 +1073,45 @@ const buildWasm = async (options) => {
856
1073
  (job) => compileSource(job.source, job.args, job.groupIndex)
857
1074
  )
858
1075
  ) : await buildObjectsSequential();
859
- logger.info(`Linking target: ${targetName}`);
860
- const linkArgs = [
861
- ...objectFiles,
862
- "-o",
863
- resolvedOutFile,
864
- ...resolvedLinkOptions,
865
- ...exportArgs
866
- ];
867
- logger.debug(`emcc ${linkArgs.join(" ")}`);
868
- await runCommandWithEnv(
869
- emccCommand,
870
- linkArgs,
871
- rootDir,
872
- buildEnv,
873
- emsdkOptions.signal
874
- );
1076
+ if (targetType === "archive") {
1077
+ if (!emarCommand) {
1078
+ throw new Error("emar command is required for archive targets.");
1079
+ }
1080
+ logger.info(`Archiving target: ${targetName}.a`);
1081
+ const archiveArgs = ["rcs", resolvedOutFile, ...objectFiles];
1082
+ logger.debug(`emar ${archiveArgs.join(" ")}`);
1083
+ await runCommandWithEnv(
1084
+ emarCommand,
1085
+ archiveArgs,
1086
+ rootDir,
1087
+ buildEnv,
1088
+ emsdkOptions.signal
1089
+ );
1090
+ } else {
1091
+ logger.info(`Linking target: ${targetName}.wasm`);
1092
+ const linkArgs = [
1093
+ ...objectFiles,
1094
+ "-o",
1095
+ resolvedOutFile,
1096
+ ...linkLibDirs.map((dir) => `-L${dir}`),
1097
+ ...resolvedLinkOptions,
1098
+ ...exportArgs
1099
+ ];
1100
+ logger.debug(`emcc ${linkArgs.join(" ")}`);
1101
+ await runCommandWithEnv(
1102
+ emccCommand,
1103
+ linkArgs,
1104
+ rootDir,
1105
+ buildEnv,
1106
+ emsdkOptions.signal
1107
+ );
1108
+ }
875
1109
  outFiles[targetName] = resolvedOutFile;
876
1110
  }
1111
+ };
1112
+ try {
1113
+ await buildTargets("archive");
1114
+ await buildTargets("wasm");
877
1115
  } finally {
878
1116
  if (cleanupBuildDir) {
879
1117
  await promises.rm(buildRunDir, { recursive: true, force: true });
@@ -885,5 +1123,6 @@ const buildWasm = async (options) => {
885
1123
  };
886
1124
  };
887
1125
  exports.buildWasm = buildWasm;
1126
+ exports.createConsoleLogger = createConsoleLogger;
888
1127
  exports.prepareEmsdk = prepareEmsdk;
889
- //# sourceMappingURL=build-DdEthYh8.cjs.map
1128
+ //# sourceMappingURL=build-Djw1ummW.cjs.map