emsdk-env 0.8.0 → 0.10.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 +39 -3
- package/dist/{build-DzrgEC4A.js → build-BE9Z95iJ.js} +394 -20
- package/dist/build-BE9Z95iJ.js.map +1 -0
- package/dist/{build-ya4uDvN7.cjs → build-BGtsNe6D.cjs} +392 -18
- package/dist/build-BGtsNe6D.cjs.map +1 -0
- package/dist/index.cjs +3 -3
- package/dist/index.d.ts +46 -9
- package/dist/index.mjs +3 -3
- package/dist/vite.cjs +7 -5
- package/dist/vite.cjs.map +1 -1
- package/dist/vite.d.ts +37 -10
- package/dist/vite.mjs +7 -5
- package/dist/vite.mjs.map +1 -1
- package/package.json +7 -7
- package/dist/build-DzrgEC4A.js.map +0 -1
- package/dist/build-ya4uDvN7.cjs.map +0 -1
package/README.md
CHANGED
|
@@ -28,6 +28,8 @@ export default defineConfig({
|
|
|
28
28
|
plugins: [
|
|
29
29
|
// Add as a plugin
|
|
30
30
|
emsdkEnv({
|
|
31
|
+
// Generate a runtime loader code
|
|
32
|
+
generatedLoader: { enable: true },
|
|
31
33
|
// Build targets
|
|
32
34
|
targets: {
|
|
33
35
|
// Generate "add.wasm"
|
|
@@ -35,7 +37,9 @@ export default defineConfig({
|
|
|
35
37
|
// Compiler options
|
|
36
38
|
options: ['-O3', '-std=c99'],
|
|
37
39
|
// Linker options
|
|
38
|
-
linkOptions: ['
|
|
40
|
+
linkOptions: ['--no-entry'],
|
|
41
|
+
// Linker directives
|
|
42
|
+
linkDirectives: { STANDALONE_WASM: 1 },
|
|
39
43
|
// Exported symbols
|
|
40
44
|
exports: ['_add'],
|
|
41
45
|
},
|
|
@@ -86,12 +90,15 @@ project/
|
|
|
86
90
|
├── package.json
|
|
87
91
|
├── vite.config.ts
|
|
88
92
|
├── src/
|
|
93
|
+
│ ├── generated/
|
|
94
|
+
│ │ └── wasm-loader.ts // (Generate automatically)
|
|
89
95
|
│ └── wasm/
|
|
90
|
-
│ └── add.wasm
|
|
96
|
+
│ └── add.wasm // (Built WASM binary)
|
|
91
97
|
└── wasm/
|
|
92
98
|
└── add.c
|
|
93
99
|
```
|
|
94
100
|
|
|
101
|
+
- `wasm-loader.ts` is helper code that loads and makes WASM binaries usable.
|
|
95
102
|
- In addition to the above, a temporary build directory is created under the OS temp directory.
|
|
96
103
|
The default location is `${TMPDIR}/emsdk-env` (typically `/tmp/emsdk-env` on Unix).
|
|
97
104
|
This directory is used during the build process and is typically deleted after the build completes.
|
|
@@ -99,7 +106,36 @@ project/
|
|
|
99
106
|
|
|
100
107
|
Of course, you can change these. Specify them in the Vite plugin options.
|
|
101
108
|
|
|
102
|
-
You might find it odd that the built binary is placed in `src/wasm/`,
|
|
109
|
+
You might find it odd that the built binary is placed in `src/wasm/`,
|
|
110
|
+
but this is because the Vite server defaults to a path where it can easily access WASM binaries.
|
|
111
|
+
|
|
112
|
+
If `generatedLoader.enable` is set to `true`, emsdk-env also generates a WASM loader helper code by default at `src/generated/wasm-loader.ts`.
|
|
113
|
+
That loader can call the final WASM exports directly:
|
|
114
|
+
|
|
115
|
+
```typescript
|
|
116
|
+
import { loadAddWasm } from './generated/wasm-loader';
|
|
117
|
+
|
|
118
|
+
// WASM exported function declaration (You need to define it)
|
|
119
|
+
interface AddExports {
|
|
120
|
+
add?: (a: number, b: number) => number;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// Load WASM binary and instantiates it
|
|
124
|
+
const wasm = await loadAddWasm<AddExports>();
|
|
125
|
+
|
|
126
|
+
// Get `add()` function entry point
|
|
127
|
+
const add = wasm.exports.add;
|
|
128
|
+
if (typeof add !== 'function') {
|
|
129
|
+
throw new Error('add function not found in wasm exports.');
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// Then use it now
|
|
133
|
+
const result = add(1, 2);
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
- You need to define WASM export functions yourself.
|
|
137
|
+
When doing so, the symbol name for the exported function is the same as the C/C++ function name in TypeScript,
|
|
138
|
+
but the symbol name specified in `exports: [...]` typically requires an underscore prefix (`add()` --> `_add`).
|
|
103
139
|
|
|
104
140
|
If you plan to operate with the default settings, there is essentially no configuration work required.
|
|
105
141
|
|
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
/*!
|
|
2
2
|
* name: emsdk-env
|
|
3
|
-
* version: 0.
|
|
3
|
+
* version: 0.10.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:
|
|
8
|
+
* git.commit.hash: 7ee173408d930a3cc7444806156538a24a617b55
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
|
-
import { mkdir, access, constants, mkdtemp, rename, rm, readFile } from "fs/promises";
|
|
11
|
+
import { mkdir, access, constants, mkdtemp, rename, rm, writeFile, readFile } from "fs/promises";
|
|
12
12
|
import { homedir, tmpdir } from "os";
|
|
13
13
|
import { glob } from "glob";
|
|
14
|
-
import { join, resolve, isAbsolute, dirname,
|
|
14
|
+
import { join, resolve, relative, isAbsolute, dirname, parse } from "path";
|
|
15
15
|
import { spawn } from "child_process";
|
|
16
16
|
const __NOOP_HANDLER = () => {
|
|
17
17
|
};
|
|
@@ -552,6 +552,11 @@ const DEFAULT_IMPORT_LIB_DIR = "lib";
|
|
|
552
552
|
const DEFAULT_WASM_BUILD_DIR = join(tmpdir(), "emsdk-env");
|
|
553
553
|
const DEFAULT_EMSDK_TARGET_VERSION = "latest";
|
|
554
554
|
const DEFAULT_WASM_OPT_ARGS = ["-Oz"];
|
|
555
|
+
const DEFAULT_GENERATED_LOADER_OUT_FILE = join(
|
|
556
|
+
"src",
|
|
557
|
+
"generated",
|
|
558
|
+
"wasm-loader.ts"
|
|
559
|
+
);
|
|
555
560
|
let buildSequence = 0;
|
|
556
561
|
const padNumber = (value, length = 2) => String(value).padStart(length, "0");
|
|
557
562
|
const formatTimestamp = (date) => {
|
|
@@ -578,7 +583,7 @@ const normalizePrepareOptions = (options) => {
|
|
|
578
583
|
...rest
|
|
579
584
|
};
|
|
580
585
|
};
|
|
581
|
-
const
|
|
586
|
+
const parseStringKeyValueInput = (values) => {
|
|
582
587
|
const parsed = {};
|
|
583
588
|
for (const entry of values) {
|
|
584
589
|
const index = entry.indexOf("=");
|
|
@@ -592,24 +597,40 @@ const parseKeyValueInput = (values) => {
|
|
|
592
597
|
}
|
|
593
598
|
return parsed;
|
|
594
599
|
};
|
|
595
|
-
const
|
|
596
|
-
const
|
|
600
|
+
const isDefineMap = (input) => input instanceof Map;
|
|
601
|
+
const normalizeDefineInput = (input) => {
|
|
602
|
+
if (!input) {
|
|
603
|
+
return {};
|
|
604
|
+
}
|
|
605
|
+
if (Array.isArray(input)) {
|
|
606
|
+
return parseStringKeyValueInput(input);
|
|
607
|
+
}
|
|
608
|
+
if (isDefineMap(input)) {
|
|
609
|
+
return Object.fromEntries(input);
|
|
610
|
+
}
|
|
611
|
+
return { ...input };
|
|
612
|
+
};
|
|
613
|
+
const isLinkDirectiveMap = (input) => input instanceof Map;
|
|
614
|
+
const normalizeLinkDirectiveInput = (input) => {
|
|
597
615
|
if (!input) {
|
|
598
616
|
return {};
|
|
599
617
|
}
|
|
600
618
|
if (Array.isArray(input)) {
|
|
601
|
-
return
|
|
619
|
+
return parseStringKeyValueInput(input);
|
|
602
620
|
}
|
|
603
|
-
if (
|
|
621
|
+
if (isLinkDirectiveMap(input)) {
|
|
604
622
|
return Object.fromEntries(input);
|
|
605
623
|
}
|
|
606
624
|
return { ...input };
|
|
607
625
|
};
|
|
608
626
|
const mergeDefines = (common, target) => ({
|
|
609
|
-
...
|
|
610
|
-
...
|
|
627
|
+
...normalizeDefineInput(common),
|
|
628
|
+
...normalizeDefineInput(target)
|
|
629
|
+
});
|
|
630
|
+
const mergeLinkDirectives = (common, target) => ({
|
|
631
|
+
...normalizeLinkDirectiveInput(common),
|
|
632
|
+
...normalizeLinkDirectiveInput(target)
|
|
611
633
|
});
|
|
612
|
-
const mergeLinkDirectives = (common, target) => mergeDefines(common, target);
|
|
613
634
|
const resolveWasmOptEnabled = (common, target) => {
|
|
614
635
|
var _a, _b;
|
|
615
636
|
return (_b = (_a = target == null ? void 0 : target.enable) != null ? _a : common == null ? void 0 : common.enable) != null ? _b : false;
|
|
@@ -693,14 +714,25 @@ const resolveDefines = (defines, env) => {
|
|
|
693
714
|
}
|
|
694
715
|
return resolved;
|
|
695
716
|
};
|
|
717
|
+
const resolveLinkDirectiveValue = (value, env, label) => {
|
|
718
|
+
if (typeof value === "string") {
|
|
719
|
+
return expandPlaceholders(value, env, label);
|
|
720
|
+
}
|
|
721
|
+
if (Array.isArray(value)) {
|
|
722
|
+
return value.map(
|
|
723
|
+
(entry, index) => expandPlaceholders(entry, env, `${label}[${index}]`)
|
|
724
|
+
);
|
|
725
|
+
}
|
|
726
|
+
return value;
|
|
727
|
+
};
|
|
696
728
|
const resolveLinkDirectives = (directives, env) => {
|
|
697
729
|
const resolved = {};
|
|
698
730
|
for (const [key, value] of Object.entries(directives)) {
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
731
|
+
resolved[key] = resolveLinkDirectiveValue(
|
|
732
|
+
value,
|
|
733
|
+
env,
|
|
734
|
+
`linkDirectives.${key}`
|
|
735
|
+
);
|
|
704
736
|
}
|
|
705
737
|
return resolved;
|
|
706
738
|
};
|
|
@@ -725,12 +757,13 @@ const resolveSourcesFromPatterns = async (patterns, env, srcDir, label) => {
|
|
|
725
757
|
const buildDefineFlags = (defines) => Object.entries(defines).flatMap(
|
|
726
758
|
([key, value]) => value === null || value === void 0 ? [`-D${key}`] : [`-D${key}=${String(value)}`]
|
|
727
759
|
);
|
|
760
|
+
const serializeLinkDirectiveValue = (value) => Array.isArray(value) ? JSON.stringify(value) : String(value);
|
|
728
761
|
const buildLinkDirectiveFlags = (directives) => {
|
|
729
762
|
if (Object.keys(directives).length === 0) {
|
|
730
763
|
return [];
|
|
731
764
|
}
|
|
732
765
|
return Object.entries(directives).flatMap(
|
|
733
|
-
([key, value]) => value === null || value === void 0 ? ["-s", key] : ["-s", `${key}=${
|
|
766
|
+
([key, value]) => value === null || value === void 0 ? ["-s", key] : ["-s", `${key}=${serializeLinkDirectiveValue(value)}`]
|
|
734
767
|
);
|
|
735
768
|
};
|
|
736
769
|
const buildExportFlags = (exports$1) => {
|
|
@@ -785,6 +818,256 @@ const dedupeValues = (values) => {
|
|
|
785
818
|
}
|
|
786
819
|
return deduped;
|
|
787
820
|
};
|
|
821
|
+
const isSubPath = (parentDir, targetPath) => {
|
|
822
|
+
const rel = relative(parentDir, targetPath);
|
|
823
|
+
if (rel === "") {
|
|
824
|
+
return true;
|
|
825
|
+
}
|
|
826
|
+
return !rel.startsWith("..") && !isAbsolute(rel);
|
|
827
|
+
};
|
|
828
|
+
const readTextIfExists = async (filePath) => {
|
|
829
|
+
try {
|
|
830
|
+
return await readFile(filePath, "utf8");
|
|
831
|
+
} catch (error) {
|
|
832
|
+
const nodeError = error;
|
|
833
|
+
if (nodeError.code === "ENOENT") {
|
|
834
|
+
return void 0;
|
|
835
|
+
}
|
|
836
|
+
throw error;
|
|
837
|
+
}
|
|
838
|
+
};
|
|
839
|
+
const writeTextIfChanged = async (filePath, content) => {
|
|
840
|
+
const existing = await readTextIfExists(filePath);
|
|
841
|
+
if (existing === content) {
|
|
842
|
+
return false;
|
|
843
|
+
}
|
|
844
|
+
await ensureDirectory(dirname(filePath));
|
|
845
|
+
await writeFile(filePath, content, "utf8");
|
|
846
|
+
return true;
|
|
847
|
+
};
|
|
848
|
+
const toPascalCaseIdentifier = (value) => {
|
|
849
|
+
const tokens = value.split(/[^A-Za-z0-9]+/).map((token) => token.trim()).filter((token) => token.length > 0);
|
|
850
|
+
if (tokens.length === 0) {
|
|
851
|
+
throw new Error(`Cannot derive loader function name from target: ${value}`);
|
|
852
|
+
}
|
|
853
|
+
const pascal = tokens.map((token) => token.charAt(0).toUpperCase() + token.slice(1)).join("");
|
|
854
|
+
return /^[0-9]/.test(pascal) ? `Target${pascal}` : pascal;
|
|
855
|
+
};
|
|
856
|
+
const toRelativeImportSpecifier = (fromFile, toFile) => {
|
|
857
|
+
const rel = relative(dirname(fromFile), toFile).replace(/\\/g, "/");
|
|
858
|
+
return rel.startsWith(".") ? rel : `./${rel}`;
|
|
859
|
+
};
|
|
860
|
+
const buildGeneratedLoaderContent = (generatedLoaderFile, targets) => {
|
|
861
|
+
const targetBlocks = targets.map((target) => {
|
|
862
|
+
const specifier = JSON.stringify(
|
|
863
|
+
toRelativeImportSpecifier(generatedLoaderFile, target.outFile)
|
|
864
|
+
);
|
|
865
|
+
return `export const ${target.functionName} = async <T extends object>(
|
|
866
|
+
options?: TargetWasmLoadOptions
|
|
867
|
+
): Promise<WasmInstance<T>> => {
|
|
868
|
+
const source = options?.url ?? new URL(${specifier}, import.meta.url);
|
|
869
|
+
return await loadWasm<T>(source, createWasmLoadOptions(options?.imports));
|
|
870
|
+
};`;
|
|
871
|
+
}).join("\n\n");
|
|
872
|
+
return `// Generated by emsdk-env. DO NOT EDIT.
|
|
873
|
+
|
|
874
|
+
export type WasmSource =
|
|
875
|
+
| string
|
|
876
|
+
| URL
|
|
877
|
+
| ArrayBuffer
|
|
878
|
+
| ArrayBufferView
|
|
879
|
+
| Response;
|
|
880
|
+
|
|
881
|
+
export interface WasmLoadOptions {
|
|
882
|
+
readonly imports?: WebAssembly.Imports;
|
|
883
|
+
}
|
|
884
|
+
|
|
885
|
+
export interface TargetWasmLoadOptions extends WasmLoadOptions {
|
|
886
|
+
readonly url?: string | URL;
|
|
887
|
+
}
|
|
888
|
+
|
|
889
|
+
const isResponse = (value: WasmSource): value is Response =>
|
|
890
|
+
typeof Response !== 'undefined' && value instanceof Response;
|
|
891
|
+
|
|
892
|
+
const createWasmLoadOptions = (
|
|
893
|
+
imports: WebAssembly.Imports | undefined
|
|
894
|
+
): WasmLoadOptions | undefined => (imports ? { imports } : undefined);
|
|
895
|
+
|
|
896
|
+
export interface WasmInstance<T extends object> {
|
|
897
|
+
readonly exports: T;
|
|
898
|
+
readonly memory: WebAssembly.Memory;
|
|
899
|
+
readonly table: WebAssembly.Table | undefined;
|
|
900
|
+
readonly rawExports: WebAssembly.Exports;
|
|
901
|
+
readonly module: WebAssembly.Module;
|
|
902
|
+
readonly instance: WebAssembly.Instance;
|
|
903
|
+
readonly initialize: (() => unknown) | undefined;
|
|
904
|
+
readonly start: (() => unknown) | undefined;
|
|
905
|
+
}
|
|
906
|
+
|
|
907
|
+
const resolveWasmBytes = async (source: WasmSource): Promise<ArrayBuffer> => {
|
|
908
|
+
if (isResponse(source)) {
|
|
909
|
+
return await source.arrayBuffer();
|
|
910
|
+
}
|
|
911
|
+
if (source instanceof URL || typeof source === 'string') {
|
|
912
|
+
const response = await fetch(source);
|
|
913
|
+
if (!response.ok) {
|
|
914
|
+
throw new Error(\`Failed to fetch wasm: \${response.url}\`);
|
|
915
|
+
}
|
|
916
|
+
return await response.arrayBuffer();
|
|
917
|
+
}
|
|
918
|
+
if (source instanceof ArrayBuffer) {
|
|
919
|
+
return source;
|
|
920
|
+
}
|
|
921
|
+
if (ArrayBuffer.isView(source)) {
|
|
922
|
+
const view = new Uint8Array(
|
|
923
|
+
source.buffer,
|
|
924
|
+
source.byteOffset,
|
|
925
|
+
source.byteLength
|
|
926
|
+
);
|
|
927
|
+
return view.slice().buffer;
|
|
928
|
+
}
|
|
929
|
+
throw new TypeError('Unsupported wasm source.');
|
|
930
|
+
};
|
|
931
|
+
|
|
932
|
+
const getImportValue = (
|
|
933
|
+
imports: WebAssembly.Imports | undefined,
|
|
934
|
+
moduleName: string,
|
|
935
|
+
name: string
|
|
936
|
+
) => {
|
|
937
|
+
const moduleImports = imports?.[moduleName];
|
|
938
|
+
if (!moduleImports || typeof moduleImports !== 'object') {
|
|
939
|
+
return undefined;
|
|
940
|
+
}
|
|
941
|
+
return (moduleImports as Record<string, unknown>)[name];
|
|
942
|
+
};
|
|
943
|
+
|
|
944
|
+
const resolveMemory = (
|
|
945
|
+
module: WebAssembly.Module,
|
|
946
|
+
instance: WebAssembly.Instance,
|
|
947
|
+
imports: WebAssembly.Imports | undefined
|
|
948
|
+
) => {
|
|
949
|
+
let memory: WebAssembly.Memory | undefined;
|
|
950
|
+
for (const entry of WebAssembly.Module.exports(module)) {
|
|
951
|
+
if (entry.kind !== 'memory') {
|
|
952
|
+
continue;
|
|
953
|
+
}
|
|
954
|
+
if (memory) {
|
|
955
|
+
throw new Error('Multiple wasm memories are not supported.');
|
|
956
|
+
}
|
|
957
|
+
const value = instance.exports[entry.name];
|
|
958
|
+
if (!(value instanceof WebAssembly.Memory)) {
|
|
959
|
+
throw new Error(\`Export is not a WebAssembly.Memory: \${entry.name}\`);
|
|
960
|
+
}
|
|
961
|
+
memory = value;
|
|
962
|
+
}
|
|
963
|
+
if (memory) {
|
|
964
|
+
return memory;
|
|
965
|
+
}
|
|
966
|
+
for (const entry of WebAssembly.Module.imports(module)) {
|
|
967
|
+
if (entry.kind !== 'memory') {
|
|
968
|
+
continue;
|
|
969
|
+
}
|
|
970
|
+
if (memory) {
|
|
971
|
+
throw new Error('Multiple wasm memories are not supported.');
|
|
972
|
+
}
|
|
973
|
+
const value = getImportValue(imports, entry.module, entry.name);
|
|
974
|
+
if (!(value instanceof WebAssembly.Memory)) {
|
|
975
|
+
throw new Error(
|
|
976
|
+
\`Imported value is not a WebAssembly.Memory: \${entry.module}.\${entry.name}\`
|
|
977
|
+
);
|
|
978
|
+
}
|
|
979
|
+
memory = value;
|
|
980
|
+
}
|
|
981
|
+
if (!memory) {
|
|
982
|
+
throw new Error('WASM memory export/import was not resolved.');
|
|
983
|
+
}
|
|
984
|
+
return memory;
|
|
985
|
+
};
|
|
986
|
+
|
|
987
|
+
const resolveTable = (
|
|
988
|
+
module: WebAssembly.Module,
|
|
989
|
+
instance: WebAssembly.Instance,
|
|
990
|
+
imports: WebAssembly.Imports | undefined
|
|
991
|
+
) => {
|
|
992
|
+
let table: WebAssembly.Table | undefined;
|
|
993
|
+
for (const entry of WebAssembly.Module.exports(module)) {
|
|
994
|
+
if (entry.kind !== 'table') {
|
|
995
|
+
continue;
|
|
996
|
+
}
|
|
997
|
+
if (table) {
|
|
998
|
+
throw new Error('Multiple wasm tables are not supported.');
|
|
999
|
+
}
|
|
1000
|
+
const value = instance.exports[entry.name];
|
|
1001
|
+
if (!(value instanceof WebAssembly.Table)) {
|
|
1002
|
+
throw new Error(\`Export is not a WebAssembly.Table: \${entry.name}\`);
|
|
1003
|
+
}
|
|
1004
|
+
table = value;
|
|
1005
|
+
}
|
|
1006
|
+
if (table) {
|
|
1007
|
+
return table;
|
|
1008
|
+
}
|
|
1009
|
+
for (const entry of WebAssembly.Module.imports(module)) {
|
|
1010
|
+
if (entry.kind !== 'table') {
|
|
1011
|
+
continue;
|
|
1012
|
+
}
|
|
1013
|
+
if (table) {
|
|
1014
|
+
throw new Error('Multiple wasm tables are not supported.');
|
|
1015
|
+
}
|
|
1016
|
+
const value = getImportValue(imports, entry.module, entry.name);
|
|
1017
|
+
if (!(value instanceof WebAssembly.Table)) {
|
|
1018
|
+
throw new Error(
|
|
1019
|
+
\`Imported value is not a WebAssembly.Table: \${entry.module}.\${entry.name}\`
|
|
1020
|
+
);
|
|
1021
|
+
}
|
|
1022
|
+
table = value;
|
|
1023
|
+
}
|
|
1024
|
+
return table;
|
|
1025
|
+
};
|
|
1026
|
+
|
|
1027
|
+
export const loadWasm = async <T extends object>(
|
|
1028
|
+
source: WasmSource,
|
|
1029
|
+
options?: WasmLoadOptions
|
|
1030
|
+
): Promise<WasmInstance<T>> => {
|
|
1031
|
+
const bytes = await resolveWasmBytes(source);
|
|
1032
|
+
const module = await WebAssembly.compile(bytes);
|
|
1033
|
+
const instance = await WebAssembly.instantiate(module, options?.imports ?? {});
|
|
1034
|
+
|
|
1035
|
+
const functionExports: Record<string, (...args: unknown[]) => unknown> = {};
|
|
1036
|
+
for (const entry of WebAssembly.Module.exports(module)) {
|
|
1037
|
+
if (entry.kind !== 'function') {
|
|
1038
|
+
continue;
|
|
1039
|
+
}
|
|
1040
|
+
const value = instance.exports[entry.name];
|
|
1041
|
+
if (typeof value !== 'function') {
|
|
1042
|
+
throw new Error(\`Export is not a function: \${entry.name}\`);
|
|
1043
|
+
}
|
|
1044
|
+
functionExports[entry.name] = value as (...args: unknown[]) => unknown;
|
|
1045
|
+
}
|
|
1046
|
+
|
|
1047
|
+
const initialize =
|
|
1048
|
+
typeof instance.exports._initialize === 'function'
|
|
1049
|
+
? (instance.exports._initialize as () => unknown)
|
|
1050
|
+
: undefined;
|
|
1051
|
+
const start =
|
|
1052
|
+
typeof instance.exports._start === 'function'
|
|
1053
|
+
? (instance.exports._start as () => unknown)
|
|
1054
|
+
: undefined;
|
|
1055
|
+
|
|
1056
|
+
return {
|
|
1057
|
+
exports: functionExports as T,
|
|
1058
|
+
memory: resolveMemory(module, instance, options?.imports),
|
|
1059
|
+
table: resolveTable(module, instance, options?.imports),
|
|
1060
|
+
rawExports: instance.exports,
|
|
1061
|
+
module,
|
|
1062
|
+
instance,
|
|
1063
|
+
initialize,
|
|
1064
|
+
start,
|
|
1065
|
+
};
|
|
1066
|
+
};
|
|
1067
|
+
|
|
1068
|
+
${targetBlocks}
|
|
1069
|
+
`;
|
|
1070
|
+
};
|
|
788
1071
|
const isRecord = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
|
|
789
1072
|
const resolvePackageJsonPath = async (startPath, packageName) => {
|
|
790
1073
|
let current = dirname(startPath);
|
|
@@ -885,6 +1168,42 @@ const resolveImportDirectories = async (rootDir, imports) => {
|
|
|
885
1168
|
libDirs: dedupeValues(libDirs)
|
|
886
1169
|
};
|
|
887
1170
|
};
|
|
1171
|
+
const resolveGeneratedLoaderOutFile = (rootDir, env, generatedLoader) => {
|
|
1172
|
+
var _a;
|
|
1173
|
+
if (!(generatedLoader == null ? void 0 : generatedLoader.enable)) {
|
|
1174
|
+
return void 0;
|
|
1175
|
+
}
|
|
1176
|
+
const rawOutFile = expandPlaceholders(
|
|
1177
|
+
(_a = generatedLoader.outFile) != null ? _a : DEFAULT_GENERATED_LOADER_OUT_FILE,
|
|
1178
|
+
env,
|
|
1179
|
+
"generatedLoader.outFile"
|
|
1180
|
+
);
|
|
1181
|
+
return resolvePath(rootDir, rawOutFile);
|
|
1182
|
+
};
|
|
1183
|
+
const resolveGeneratedLoaderWatchDirs = (rootDir, srcDir, commonIncludeDirs, env, targetEntries, importIncludeDirs) => {
|
|
1184
|
+
const dirs = [srcDir, ...resolveIncludeDirs(commonIncludeDirs, env, rootDir)];
|
|
1185
|
+
for (const [targetName, target] of targetEntries) {
|
|
1186
|
+
if (!target.includeDirs || target.includeDirs.length === 0) {
|
|
1187
|
+
continue;
|
|
1188
|
+
}
|
|
1189
|
+
const targetEnv = {
|
|
1190
|
+
...env,
|
|
1191
|
+
TARGET_NAME: targetName
|
|
1192
|
+
};
|
|
1193
|
+
dirs.push(...resolveIncludeDirs(target.includeDirs, targetEnv, rootDir));
|
|
1194
|
+
}
|
|
1195
|
+
dirs.push(...importIncludeDirs);
|
|
1196
|
+
return dedupeValues(dirs);
|
|
1197
|
+
};
|
|
1198
|
+
const validateGeneratedLoaderOutFile = (generatedLoaderFile, watchDirs) => {
|
|
1199
|
+
for (const dir of watchDirs) {
|
|
1200
|
+
if (isSubPath(dir, generatedLoaderFile)) {
|
|
1201
|
+
throw new Error(
|
|
1202
|
+
`generatedLoader.outFile must not be placed under watched directory: ${generatedLoaderFile}`
|
|
1203
|
+
);
|
|
1204
|
+
}
|
|
1205
|
+
}
|
|
1206
|
+
};
|
|
888
1207
|
const buildCompileArgs = (options, includeDirs, defines, env, rootDir) => {
|
|
889
1208
|
const resolvedOptions = expandArray(options, env, "options");
|
|
890
1209
|
const includeArgs = resolveIncludeDirs(includeDirs, env, rootDir).map(
|
|
@@ -967,6 +1286,22 @@ const buildWasm = async (options) => {
|
|
|
967
1286
|
const importIncludeDirs = importDirectories.includeDirs;
|
|
968
1287
|
const importLibDirs = importDirectories.libDirs;
|
|
969
1288
|
const linkLibDirs = dedupeValues([libDir, ...importLibDirs]);
|
|
1289
|
+
const generatedLoaderFile = resolveGeneratedLoaderOutFile(
|
|
1290
|
+
rootDir,
|
|
1291
|
+
envWithDirs,
|
|
1292
|
+
options.generatedLoader
|
|
1293
|
+
);
|
|
1294
|
+
if (generatedLoaderFile) {
|
|
1295
|
+
const watchDirs = resolveGeneratedLoaderWatchDirs(
|
|
1296
|
+
rootDir,
|
|
1297
|
+
srcDir,
|
|
1298
|
+
commonIncludeDirs,
|
|
1299
|
+
envWithDirs,
|
|
1300
|
+
targetEntries,
|
|
1301
|
+
importIncludeDirs
|
|
1302
|
+
);
|
|
1303
|
+
validateGeneratedLoaderOutFile(generatedLoaderFile, watchDirs);
|
|
1304
|
+
}
|
|
970
1305
|
logger.debug(`Detected rootDir: '${rootDir}'`);
|
|
971
1306
|
logger.debug(`Detected srcDir: '${srcDir}'`);
|
|
972
1307
|
logger.debug(`Detected outDir: '${outDir}'`);
|
|
@@ -983,6 +1318,9 @@ const buildWasm = async (options) => {
|
|
|
983
1318
|
logger.debug(
|
|
984
1319
|
`Detected importLibDirs: [${importLibDirs.map((p) => `'${p}'`).join(",")}]`
|
|
985
1320
|
);
|
|
1321
|
+
if (generatedLoaderFile) {
|
|
1322
|
+
logger.debug(`Detected generatedLoaderFile: '${generatedLoaderFile}'`);
|
|
1323
|
+
}
|
|
986
1324
|
await ensureDirectory(outDir);
|
|
987
1325
|
await ensureDirectory(libDir);
|
|
988
1326
|
await ensureDirectory(buildDir);
|
|
@@ -1005,6 +1343,7 @@ const buildWasm = async (options) => {
|
|
|
1005
1343
|
return wasmOptCommand;
|
|
1006
1344
|
};
|
|
1007
1345
|
const outFiles = {};
|
|
1346
|
+
let resultGeneratedLoaderFile;
|
|
1008
1347
|
const buildTargets = async (expectedType) => {
|
|
1009
1348
|
var _a2;
|
|
1010
1349
|
for (const [targetName, target] of targetEntries) {
|
|
@@ -1276,6 +1615,40 @@ const buildWasm = async (options) => {
|
|
|
1276
1615
|
try {
|
|
1277
1616
|
await buildTargets("archive");
|
|
1278
1617
|
await buildTargets("wasm");
|
|
1618
|
+
if (generatedLoaderFile) {
|
|
1619
|
+
const generatedTargets = [];
|
|
1620
|
+
const functionNames = /* @__PURE__ */ new Set();
|
|
1621
|
+
for (const [targetName, target] of targetEntries) {
|
|
1622
|
+
if (resolveTargetType(target.type) !== "wasm") {
|
|
1623
|
+
continue;
|
|
1624
|
+
}
|
|
1625
|
+
const outFile = outFiles[targetName];
|
|
1626
|
+
if (!outFile) {
|
|
1627
|
+
continue;
|
|
1628
|
+
}
|
|
1629
|
+
const functionName = `load${toPascalCaseIdentifier(targetName)}Wasm`;
|
|
1630
|
+
if (functionNames.has(functionName)) {
|
|
1631
|
+
throw new Error(
|
|
1632
|
+
`Generated loader function name collision: ${functionName}`
|
|
1633
|
+
);
|
|
1634
|
+
}
|
|
1635
|
+
functionNames.add(functionName);
|
|
1636
|
+
generatedTargets.push({
|
|
1637
|
+
targetName,
|
|
1638
|
+
functionName,
|
|
1639
|
+
outFile
|
|
1640
|
+
});
|
|
1641
|
+
}
|
|
1642
|
+
const content = buildGeneratedLoaderContent(
|
|
1643
|
+
generatedLoaderFile,
|
|
1644
|
+
generatedTargets
|
|
1645
|
+
);
|
|
1646
|
+
const didWrite = await writeTextIfChanged(generatedLoaderFile, content);
|
|
1647
|
+
logger.info(
|
|
1648
|
+
didWrite ? `Generated loader: ${relative(rootDir, generatedLoaderFile)}` : `Generated loader unchanged: ${relative(rootDir, generatedLoaderFile)}`
|
|
1649
|
+
);
|
|
1650
|
+
resultGeneratedLoaderFile = generatedLoaderFile;
|
|
1651
|
+
}
|
|
1279
1652
|
} finally {
|
|
1280
1653
|
if (cleanupBuildDir) {
|
|
1281
1654
|
await rm(buildRunDir, { recursive: true, force: true });
|
|
@@ -1283,7 +1656,8 @@ const buildWasm = async (options) => {
|
|
|
1283
1656
|
}
|
|
1284
1657
|
return {
|
|
1285
1658
|
emsdkRoot,
|
|
1286
|
-
outFiles
|
|
1659
|
+
outFiles,
|
|
1660
|
+
...resultGeneratedLoaderFile ? { generatedLoaderFile: resultGeneratedLoaderFile } : {}
|
|
1287
1661
|
};
|
|
1288
1662
|
};
|
|
1289
1663
|
export {
|
|
@@ -1291,4 +1665,4 @@ export {
|
|
|
1291
1665
|
createConsoleLogger as c,
|
|
1292
1666
|
prepareEmsdk as p
|
|
1293
1667
|
};
|
|
1294
|
-
//# sourceMappingURL=build-
|
|
1668
|
+
//# sourceMappingURL=build-BE9Z95iJ.js.map
|