Skip to content

Commit 0132fd7

Browse files
committed
better build splitting
1 parent e97c609 commit 0132fd7

8 files changed

+72
-157
lines changed

.gitattributes

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# Don't diff generated .emscripten-module files
2+
*.emscripten-module.js -diff

.prettierignore

+1-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
ts/ffi.ts
22
ts/ffi-asyncify.ts
3-
ts/quickjs-emscripten-module-asyncify.js
4-
ts/quickjs-emscripten-module.js
3+
*.emscripten-module.js
54
dist/*

Makefile

+23-11
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ QUICKJS_DEFINES:=-D_GNU_SOURCE -DCONFIG_VERSION=\"$(QUICKJS_CONFIG_VERSION)\"
2020

2121
# quickjs-emscripten
2222
EMCC_EXPORTED_FUNCS+=-s EXPORTED_FUNCTIONS=$(shell cat $(BUILD_WRAPPER)/symbols.json)
23+
EMCC_EXPORTED_FUNCS_ASYNCIFY+=-s EXPORTED_FUNCTIONS=$(shell cat $(BUILD_WRAPPER)/symbols.asyncify.json)
2324

2425
# Emscripten options
2526
CFLAGS_EMCC+=-s WASM=1
@@ -60,8 +61,9 @@ endif
6061

6162
default: wasm wasm-asyncify
6263
all: wasm wasm-asyncify native
63-
wasm: $(BUILD_DIR) ts/quickjs-emscripten-module.js ts/ffi.ts
64-
wasm-asyncify: $(BUILD_DIR) ts/quickjs-emscripten-module-asyncify.js ts/ffi-asyncify.ts
64+
generate: ts/ffi.ts ts/ffi-asyncify.ts
65+
wasm: $(BUILD_DIR) ts/quickjs.emscripten-module.js ts/ffi.ts
66+
wasm-asyncify: $(BUILD_DIR) ts/quickjs-asyncify.emscripten-module.js ts/ffi-asyncify.ts
6567
native: $(BUILD_WRAPPER)/native/test.exe
6668

6769
emcc:
@@ -83,6 +85,9 @@ $(WRAPPER_ROOT)/interface.h: $(WRAPPER_ROOT)/interface.c $(BUILD_ROOT)
8385
$(BUILD_WRAPPER)/symbols.json: $(WRAPPER_ROOT)/interface.c $(BUILD_ROOT)
8486
ts-node generate.ts symbols $@
8587

88+
$(BUILD_WRAPPER)/symbols.asyncify.json: $(WRAPPER_ROOT)/interface.c $(BUILD_ROOT)
89+
ts-node generate.ts symbols $@
90+
8691
ts/ffi.ts: $(WRAPPER_ROOT)/interface.c ts/ffi-types.ts generate.ts
8792
$(GENERATE_TS_ENV) ts-node generate.ts ffi $@
8893
prettier --write $@
@@ -93,11 +98,11 @@ ts/ffi-asyncify.ts: $(WRAPPER_ROOT)/interface.c ts/ffi-types.ts generate.ts
9398

9499
### Executables
95100
# The WASM module we'll link to typescript
96-
ts/quickjs-emscripten-module.js: $(BUILD_WRAPPER)/wasm/interface.o $(QUICKJS_OBJS_WASM)
101+
ts/quickjs.emscripten-module.js: $(BUILD_WRAPPER)/wasm/interface.o $(QUICKJS_OBJS_WASM)
97102
$(EMCC) $(CFLAGS) $(CFLAGS_EMCC) $(EMCC_EXPORTED_FUNCS) -o $@ $< $(QUICKJS_OBJS_WASM)
98103

99-
ts/quickjs-emscripten-module-asyncify.js: $(BUILD_WRAPPER)/wasm-asyncify/interface.o $(QUICKJS_OBJS_WASM_ASYNCIFY)
100-
$(EMCC) $(CFLAGS) $(CFLAGS_EMCC) $(CFLAGS_EMCC_ASYNCIFY) $(EMCC_EXPORTED_FUNCS) -o $@ $< $(QUICKJS_OBJS_WASM_ASYNCIFY)
104+
ts/quickjs-asyncify.emscripten-module.js: $(BUILD_WRAPPER)/wasm-asyncify/interface.o $(QUICKJS_OBJS_WASM_ASYNCIFY)
105+
$(EMCC) $(CFLAGS) $(CFLAGS_EMCC) $(CFLAGS_EMCC_ASYNCIFY) $(EMCC_EXPORTED_FUNCS_ASYNCIFY) -o $@ $< $(QUICKJS_OBJS_WASM_ASYNCIFY)
101106

102107
# Trying to debug C...
103108
$(BUILD_WRAPPER)/native/test.exe: $(BUILD_WRAPPER)/native/test.o $(BUILD_WRAPPER)/native/interface.o $(WRAPPER_ROOT) $(QUICKJS_OBJS_NATIVE)
@@ -108,7 +113,7 @@ $(BUILD_WRAPPER)/native/test.exe: $(BUILD_WRAPPER)/native/test.o $(BUILD_WRAPPER
108113
$(BUILD_WRAPPER)/wasm/%.o: $(WRAPPER_ROOT)/%.c $(BUILD_WRAPPER)/symbols.json $(BUILD_ROOT)
109114
$(EMCC) $(CFLAGS) $(CFLAGS_EMCC) $(EMCC_EXPORTED_FUNCS) -c -o $@ $<
110115

111-
$(BUILD_WRAPPER)/wasm-asyncify/%.o: $(WRAPPER_ROOT)/%.c $(BUILD_WRAPPER)/symbols.json $(BUILD_ROOT)
116+
$(BUILD_WRAPPER)/wasm-asyncify/%.o: $(WRAPPER_ROOT)/%.c $(BUILD_WRAPPER)/symbols.asyncify.json $(BUILD_ROOT)
112117
$(EMCC) $(CFLAGS) $(CFLAGS_EMCC) $(CFLAGS_EMCC_ASYNCIFY) $(EMCC_EXPORTED_FUNCS) -c -o $@ $<
113118

114119
$(BUILD_WRAPPER)/native/test.o: $(WRAPPER_ROOT)/test.c $(WRAPPER_ROOT)/interface.h
@@ -129,9 +134,16 @@ $(BUILD_QUICKJS)/native/%.o: $(QUICKJS_ROOT)/%.c | $(BUILD_ROOT)
129134

130135
clean:
131136
rm -rfv ./ts/ffi.ts
132-
rm -rfv ./ts/quickjs-emscripten-module.js
133-
rm -rf ./ts/quickjs-emscripten-module.map
134-
rm -rf ./ts/quickjs-emscripten-module.wasm
135-
rm -rf ./ts/quickjs-emscripten-module.wasm.map
137+
rm -rfv ./ts/quickjs.emscripten-module.js
138+
rm -rf ./ts/quickjs.emscripten-module.map
139+
rm -rf ./ts/quickjs.emscripten-module.wasm
140+
rm -rf ./ts/quickjs.emscripten-module.wasm.map
141+
142+
rm -rfv ./ts/ffi-asyncify.ts
143+
rm -rfv ./ts/quickjs-asyncify.emscripten-module.js
144+
rm -rf ./ts/quickjs-asyncify.emscripten-module.map
145+
rm -rf ./ts/quickjs-asyncify.emscripten-module.wasm
146+
rm -rf ./ts/quickjs-asyncify.emscripten-module.wasm.map
147+
136148
rm -rfv $(BUILD_ROOT)
137-
rm -rf $(WRAPPER_ROOT)/interface.h
149+
rm -rf $(WRAPPER_ROOT)/interface.h

generate.ts

+46-23
Original file line numberDiff line numberDiff line change
@@ -37,12 +37,7 @@ function main() {
3737
const typedefMatches = matchAll(TYPEDEF_RE, interfaceFile)
3838

3939
if (command === 'symbols') {
40-
const symbols = matches
41-
.map(match => {
42-
const name = match[2]
43-
return `_${name}`
44-
})
45-
.concat('_malloc', '_free')
40+
const symbols = buildSymbols(matches)
4641
writeFile(destination, JSON.stringify(symbols))
4742
return
4843
}
@@ -70,32 +65,46 @@ function main() {
7065
throw new Error(`Bad command "${command}". ${USAGE}`)
7166
}
7267

73-
const MaybeAsync = 'MaybeAsync('
68+
// $1: attribute name
69+
// $2: inner type
70+
const ATTRIBUTE_REGEX = /^(\w+)\((.+)\)$/
71+
type Attribute = 'MaybeAsync' | 'AsyncifyOnly'
72+
73+
function parseAttributes(type: string) {
74+
let text = type
75+
let match: RegExpExecArray | null = null
76+
const attributes = new Set<Attribute>()
77+
while ((match = ATTRIBUTE_REGEX.exec(text.trim())) !== null) {
78+
attributes.add(match[1] as Attribute)
79+
text = match[2]
80+
}
81+
82+
if (text.includes(')')) {
83+
throw new Error(`parseAttributes should consume all attributes, but did not: ${text}`)
84+
}
85+
86+
return { type: text, attributes }
87+
}
7488

7589
interface ParsedType {
7690
typescript: string
7791
ffi: string | null
7892
ctype: string
79-
async: boolean
93+
attributes: Set<Attribute>
8094
}
8195

8296
function cTypeToTypescriptType(ctype: string): ParsedType {
97+
let { type, attributes } = parseAttributes(ctype)
98+
8399
// simplify
84-
let type = ctype
85100
// remove const: ignored in JS
86-
type = ctype.replace(/\bconst\b/, '').trim()
101+
type = type.replace(/\bconst\b/, '').trim()
87102
// collapse spaces (around a *, maybe)
88103
type = type.split(' ').join('')
89104

90-
let async = false
91-
if (type.startsWith(MaybeAsync) && type.endsWith(')')) {
92-
async = true
93-
type = type.slice(MaybeAsync.length, -1)
94-
}
95-
96105
// mapping
97106
if (type.includes('char*')) {
98-
return { ffi: 'string', typescript: 'string', ctype, async }
107+
return { ffi: 'string', typescript: 'string', ctype, attributes }
99108
}
100109

101110
let typescript = type.replace(/\*/g, 'Pointer')
@@ -116,7 +125,7 @@ function cTypeToTypescriptType(ctype: string): ParsedType {
116125
ffi = 'number'
117126
}
118127

119-
return { typescript: typescript, ffi, ctype, async }
128+
return { typescript, ffi, ctype, attributes }
120129
}
121130

122131
function renderFunction(args: {
@@ -137,16 +146,16 @@ function renderFunction(args: {
137146
})
138147
.join(', ')
139148

140-
const forceSync = ASYNCIFY && !async && returnType.async
141-
const markAsync = async && returnType.async
149+
const forceSync = ASYNCIFY && !async && returnType.attributes.has('MaybeAsync')
150+
const markAsync = async && returnType.attributes.has('MaybeAsync')
142151

143152
let typescriptFunctionName = functionName
144153
if (markAsync) {
145154
typescriptFunctionName += '_MaybeAsync'
146155
}
147156

148157
const typescriptReturnType =
149-
async && returnType.async
158+
async && returnType.attributes.has('MaybeAsync')
150159
? `${returnType.typescript} | Promise<${returnType.typescript}>`
151160
: returnType.typescript
152161
const typescriptFunctionType = `(${typescriptParams}) => ${typescriptReturnType}`
@@ -179,6 +188,17 @@ function renderFunction(args: {
179188
return ` ${typescriptFunctionName}: ${typescriptFunctionType} =\n ${cwrap}`
180189
}
181190

191+
function buildSymbols(matches: RegExpMatchArray[]) {
192+
const parsed = matches.map(match => {
193+
const [, returnType, functionName, , rawParams] = match
194+
const params = parseParams(rawParams)
195+
return { functionName, returnType: cTypeToTypescriptType(returnType.trim()), params }
196+
})
197+
const filtered = parsed.filter(fn => !fn.returnType.attributes.has('AsyncifyOnly') || ASYNCIFY)
198+
const names = filtered.map(fn => '_' + fn.functionName)
199+
return names.concat('_malloc', '_free')
200+
}
201+
182202
function buildFFI(matches: RegExpExecArray[]) {
183203
const parsed = matches.map(match => {
184204
const [, returnType, functionName, , rawParams] = match
@@ -187,8 +207,11 @@ function buildFFI(matches: RegExpExecArray[]) {
187207
})
188208
const decls: string[] = []
189209
parsed.forEach(fn => {
190-
decls.push(renderFunction({ ...fn, async: false }))
191-
if (fn.returnType.async && ASYNCIFY) {
210+
if (!fn.returnType.attributes.has('AsyncifyOnly') || ASYNCIFY) {
211+
decls.push(renderFunction({ ...fn, async: false }))
212+
}
213+
214+
if (fn.returnType.attributes.has('MaybeAsync') && ASYNCIFY) {
192215
decls.push(renderFunction({ ...fn, async: true }))
193216
}
194217
})

ts/quickjs-emscripten-module-asyncify.js

-62
This file was deleted.

ts/quickjs-emscripten-module.js

-59
This file was deleted.
File renamed without changes.

0 commit comments

Comments
 (0)