├── Audio
├── Makefile
├── loader.html
├── loader.js
├── main.cpp
└── output.wasm
├── Basic
├── Makefile
├── loader.html
├── loader.js
├── main.c
└── output.wasm
├── Cpp
├── Makefile
├── loader.html
├── loader.js
├── main.cpp
└── output.wasm
├── Embed
├── Makefile
├── loader.html
├── loader.js
├── loader.minified.js
├── main.cpp
└── output.html
├── GenJS
├── Makefile
├── loader.html
├── loader.js
├── main.c
└── output.wasm
├── LibC
├── Makefile
├── loader.html
├── loader.js
├── main.c
└── output.wasm
├── LoadUrl
├── Makefile
├── loader.html
├── loader.js
├── main.cpp
└── output.wasm
├── README.md
├── UNLICENSE
├── WebGL
├── Makefile
├── loader.html
├── loader.js
├── main.cpp
└── output.wasm
└── showsource.js
/Audio/Makefile:
--------------------------------------------------------------------------------
1 | #
2 | # This is free and unencumbered software released into the public domain.
3 | #
4 | # Anyone is free to copy, modify, publish, use, compile, sell, or
5 | # distribute this software, either in source code form or as a compiled
6 | # binary, for any purpose, commercial or non-commercial, and by any
7 | # means.
8 | #
9 | # In jurisdictions that recognize copyright laws, the author or authors
10 | # of this software dedicate any and all copyright interest in the
11 | # software to the public domain. We make this dedication for the benefit
12 | # of the public at large and to the detriment of our heirs and
13 | # successors. We intend this dedication to be an overt act of
14 | # relinquishment in perpetuity of all present and future rights to this
15 | # software under copyright law.
16 | #
17 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 | # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 | # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20 | # IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
21 | # OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
22 | # ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23 | # OTHER DEALINGS IN THE SOFTWARE.
24 | #
25 | # For more information, please refer to
26 | #
27 |
28 | LLVM_ROOT = D:/dev/wasm/llvm
29 | SYSTEM_ROOT = D:/dev/wasm/system
30 | WASMOPT = D:/dev/wasm/wasm-opt.exe
31 |
32 | EXPORTS = WAFNAudio
33 | SOURCES = main.cpp
34 | BUILD = RELEASE
35 |
36 | #------------------------------------------------------------------------------------------------------
37 |
38 | ifeq ($(BUILD),RELEASE)
39 | OUTDIR := Release-wasm
40 | DBGCFLAGS := -DNDEBUG
41 | LDFLAGS := -strip-all -gc-sections
42 | WOPTFLAGS := -O3
43 | else
44 | OUTDIR := Debug-wasm
45 | DBGCFLAGS := -DDEBUG -D_DEBUG
46 | LDFLAGS :=
47 | WOPTFLAGS := -g -O0
48 | endif
49 |
50 | # Global compiler flags
51 | CXXFLAGS := $(DBGCFLAGS) -Ofast -std=c++11 -fno-rtti -Wno-writable-strings -Wno-unknown-pragmas
52 | CCFLAGS := $(DBGCFLAGS) -Ofast -std=c99
53 |
54 | # Global compiler flags for Wasm targeting
55 | CLANGFLAGS := -target wasm32 -nostdinc
56 | CLANGFLAGS += -D__EMSCRIPTEN__ -D_LIBCPP_ABI_VERSION=2
57 | CLANGFLAGS += -fvisibility=hidden -fno-builtin -fno-exceptions -fno-threadsafe-statics
58 | CLANGFLAGS += -isystem$(SYSTEM_ROOT)/include/libcxx
59 | CLANGFLAGS += -isystem$(SYSTEM_ROOT)/include/compat
60 | CLANGFLAGS += -isystem$(SYSTEM_ROOT)/include
61 | CLANGFLAGS += -isystem$(SYSTEM_ROOT)/include/libc
62 | CLANGFLAGS += -isystem$(SYSTEM_ROOT)/lib/libc/musl/arch/emscripten
63 |
64 | # Flags for wasm-ld
65 | LDFLAGS += -no-entry -allow-undefined -import-memory
66 | LDFLAGS += -export=__wasm_call_ctors -export=malloc -export=free -export=main
67 | LDFLAGS += $(addprefix -export=,$(patsubst _%,%,$(strip $(EXPORTS))))
68 |
69 | # Project Build flags, add defines from the make command line (e.g. D=MACRO=VALUE)
70 | FLAGS := $(subst \\\, ,$(foreach F,$(subst \ ,\\\,$(D)),"-D$(F)"))
71 |
72 | # Check if there are any source files
73 | ifeq ($(SOURCES),)
74 | $(error No source files found for build)
75 | endif
76 |
77 | # Compute tool paths
78 | ISWIN := $(findstring :,$(firstword $(subst \, ,$(subst /, ,$(abspath .)))))
79 | PIPETONULL := $(if $(ISWIN),>nul 2>nul,>/dev/null 2>/dev/null)
80 | ifeq ($(wildcard $(subst $(strip ) ,\ ,$(LLVM_ROOT))/clang*),)
81 | $(error clang executables not found in set LLVM_ROOT path ($(LLVM_ROOT)). Set custom path in this makefile with LLVM_ROOT = $(if $(ISWIN),d:)/path/to/clang)
82 | endif
83 | ifeq ($(wildcard $(subst $(strip ) ,\ ,$(WASMOPT))),)
84 | $(error wasm-opt executable not found in set WASMOPT path ($(WASMOPT)). Fix path in this makefile with WASMOPT = $(if $(ISWIN),d:)/path/to/wasm-opt$(if $(ISWIN),.exe))
85 | endif
86 |
87 | # Surround used commands with double quotes
88 | CC := "$(LLVM_ROOT)/clang"
89 | CXX := "$(LLVM_ROOT)/clang" -x c++
90 | LD := "$(LLVM_ROOT)/wasm-ld"
91 |
92 | all: $(OUTDIR)/loader.js $(OUTDIR)/loader.html $(OUTDIR)/output.wasm
93 | .PHONY: clean cleanall run analyze
94 |
95 | clean:
96 | $(info Removing all build files ...)
97 | @$(if $(wildcard $(OUTDIR)),$(if $(ISWIN),rmdir /S /Q,rm -rf) "$(OUTDIR)" $(PIPETONULL))
98 |
99 | # Generate a list of .o files to build, include dependency rules for source files, then compile files
100 | OBJS := $(addprefix $(OUTDIR)/,$(notdir $(patsubst %.c,%.o,$(patsubst %.cpp,%.o,$(SOURCES)))))
101 | -include $(OBJS:%.o=%.d)
102 | MAKEOBJ = $(OUTDIR)/$(basename $(notdir $(1))).o: $(1) ; $$(call COMPILE,$$@,$$<,$(2),$(3) $$(FLAGS))
103 | $(foreach F,$(filter %.cpp,$(SOURCES)),$(eval $(call MAKEOBJ,$(F),$$(CXX),$$(CXXFLAGS))))
104 | $(foreach F,$(filter %.c ,$(SOURCES)),$(eval $(call MAKEOBJ,$(F),$$(CC),$$(CCFLAGS))))
105 |
106 | $(OUTDIR)/output.wasm : Makefile $(OBJS) System.bc
107 | $(info Linking $@ ...)
108 | @$(LD) $(LDFLAGS) -o $@ $(OBJS) System.bc
109 | @"$(WASMOPT)" --legalize-js-interface $(WOPTFLAGS) $@ -o $@
110 |
111 | $(OUTDIR)/loader.js : loader.js
112 | $(info Copying $^ to $@ ...)
113 | @$(if $(wildcard $(OUTDIR)),,$(shell mkdir "$(OUTDIR)"))
114 | @$(if $(ISWIN),copy,cp) "$^" "$@" $(PIPETONULL)
115 |
116 | $(OUTDIR)/loader.html : loader.html
117 | $(if $(wildcard $(OUTDIR)),,$(shell mkdir "$(OUTDIR)"))
118 | @$(if $(ISWIN),copy,cp) "$^" "$@" $(PIPETONULL)
119 |
120 | define COMPILE
121 | $(info $2)
122 | @$(if $(wildcard $(dir $1)),,$(shell mkdir "$(dir $1)"))
123 | @$3 $4 $(CLANGFLAGS) -MMD -MP -MF $(patsubst %.o,%.d,$1) -o $1 -c $2
124 | endef
125 |
126 | #------------------------------------------------------------------------------------------------------
127 | #if System.bc exists, don't even bother checking sources, build once and forget for now
128 | ifeq ($(if $(wildcard System.bc),1,0),0)
129 | SYS_ADDS := emmalloc.cpp libcxx/*.cpp libcxxabi/src/cxa_guard.cpp compiler-rt/lib/builtins/*.c libc/wasi-helpers.c
130 | SYS_MUSL := complex crypt ctype dirent errno fcntl fenv internal locale math misc mman multibyte prng regex select stat stdio stdlib string termios unistd
131 |
132 | # C++ streams and locale are not included on purpose because it can increase the output up to 500kb
133 | SYS_IGNORE := iostream.cpp strstream.cpp locale.cpp thread.cpp exception.cpp
134 | SYS_IGNORE += abs.c acos.c acosf.c acosl.c asin.c asinf.c asinl.c atan.c atan2.c atan2f.c atan2l.c atanf.c atanl.c ceil.c ceilf.c ceill.c cos.c cosf.c cosl.c exp.c expf.c expl.c
135 | SYS_IGNORE += fabs.c fabsf.c fabsl.c floor.c floorf.c floorl.c log.c logf.c logl.c pow.c powf.c powl.c rintf.c round.c roundf.c sin.c sinf.c sinl.c sqrt.c sqrtf.c sqrtl.c tan.c tanf.c tanl.c
136 | SYS_IGNORE += syscall.c wordexp.c initgroups.c getgrouplist.c popen.c _exit.c alarm.c usleep.c faccessat.c iconv.c
137 |
138 | SYS_SOURCES := $(filter-out $(SYS_IGNORE:%=\%/%),$(wildcard $(addprefix $(SYSTEM_ROOT)/lib/,$(SYS_ADDS) $(SYS_MUSL:%=libc/musl/src/%/*.c))))
139 | SYS_SOURCES := $(subst $(SYSTEM_ROOT)/lib/,,$(SYS_SOURCES))
140 |
141 | ifeq ($(findstring !,$(SYS_SOURCES)),!)
142 | $(error SYS_SOURCES contains a filename with a ! character in it - Unable to continue)
143 | endif
144 |
145 | SYS_MISSING := $(filter-out $(SYS_SOURCES) $(dir $(SYS_SOURCES)),$(subst *.c,,$(subst *.cpp,,$(SYS_ADDS))) $(SYS_MUSL:%=libc/musl/src/%/))
146 | ifeq ($(if $(SYS_MISSING),1,0),1)
147 | $(error SYS_SOURCES missing the following files in $(SYSTEM_ROOT)/lib: $(SYS_MISSING))
148 | endif
149 |
150 | SYS_OLDFILES := $(filter-out $(subst /,!,$(patsubst %.c,%.o,$(patsubst %.cpp,%.o,$(SYS_SOURCES)))),$(notdir $(wildcard temp/*.o)))
151 | $(foreach F,$(SYS_OLDFILES),$(shell $(if $(ISWIN),del "temp\,rm "temp/)$(F)" $(PIPETONULL)))
152 |
153 | SYS_CXXFLAGS := -Ofast -std=c++11 -fno-threadsafe-statics -fno-rtti -I$(SYSTEM_ROOT)/lib/libcxxabi/include
154 | SYS_CXXFLAGS += -DNDEBUG -D_LIBCPP_BUILDING_LIBRARY -D_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS
155 |
156 | SYS_CCFLAGS := -Ofast -std=gnu99 -fno-threadsafe-statics
157 | SYS_CCFLAGS += -DNDEBUG -Dunix -D__unix -D__unix__
158 | SYS_CCFLAGS += -isystem$(SYSTEM_ROOT)/lib/libc/musl/src/internal
159 | SYS_CCFLAGS += -Wno-dangling-else -Wno-ignored-attributes -Wno-bitwise-op-parentheses -Wno-logical-op-parentheses -Wno-shift-op-parentheses -Wno-string-plus-int
160 | SYS_CCFLAGS += -Wno-unknown-pragmas -Wno-shift-count-overflow -Wno-return-type -Wno-macro-redefined -Wno-unused-result -Wno-pointer-sign
161 |
162 | SYS_CPP_OBJS := $(addprefix temp/,$(subst /,!,$(patsubst %.cpp,%.o,$(filter %.cpp,$(SYS_SOURCES)))))
163 | SYS_CC_OBJS := $(addprefix temp/,$(subst /,!,$(patsubst %.c,%.o,$(filter %.c,$(SYS_SOURCES)))))
164 | $(SYS_CPP_OBJS) : ; $(call SYS_COMPILE,$@,$(subst !,/,$(patsubst temp/%.o,$(SYSTEM_ROOT)/lib/%.cpp,$@)),$(CXX),$(SYS_CXXFLAGS))
165 | $(SYS_CC_OBJS) : ; $(call SYS_COMPILE,$@,$(subst !,/,$(patsubst temp/%.o,$(SYSTEM_ROOT)/lib/%.c,$@)),$(CC),$(SYS_CCFLAGS))
166 |
167 | define SYS_COMPILE
168 | $(info $2)
169 | @$(if $(wildcard $(dir $1)),,$(shell mkdir "$(dir $1)"))
170 | @$3 $4 $(CLANGFLAGS) -o $1 -c $2
171 | endef
172 |
173 | System.bc : $(SYS_CPP_OBJS) $(SYS_CC_OBJS)
174 | $(info Creating archive $@ ...)
175 | @$(LD) $(if $(ISWIN),"temp/*.o",temp/*.o) -r -o $@
176 | @$(if $(ISWIN),rmdir /S /Q,rm -rf) "temp"
177 | endif #need System.bc
178 | #------------------------------------------------------------------------------------------------------
179 |
--------------------------------------------------------------------------------
/Audio/loader.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | WebAssembly Sample: Audio
7 |
8 |
9 |
WebAssembly Sample: Audio
10 |
11 |
Loading...
12 |
35 |
36 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/Audio/loader.js:
--------------------------------------------------------------------------------
1 | /*
2 | This is free and unencumbered software released into the public domain.
3 |
4 | Anyone is free to copy, modify, publish, use, compile, sell, or
5 | distribute this software, either in source code form or as a compiled
6 | binary, for any purpose, commercial or non-commercial, and by any
7 | means.
8 |
9 | In jurisdictions that recognize copyright laws, the author or authors
10 | of this software dedicate any and all copyright interest in the
11 | software to the public domain. We make this dedication for the benefit
12 | of the public at large and to the detriment of our heirs and
13 | successors. We intend this dedication to be an overt act of
14 | relinquishment in perpetuity of all present and future rights to this
15 | software under copyright law.
16 |
17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
21 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
22 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23 | OTHER DEALINGS IN THE SOFTWARE.
24 |
25 | For more information, please refer to
26 | */
27 |
28 | // Fetch the .wasm file and store its bytes into the byte array wasmBytes
29 | fetch(WA.module).then(res => res.arrayBuffer()).then(function(wasmBytes){'use strict';wasmBytes = new Uint8Array(wasmBytes);
30 |
31 | // Some global state variables and max heap definition
32 | var HEAP32, HEAPU8, HEAPU16, HEAPU32, HEAPF32;
33 | var WASM_MEMORY, WASM_HEAP, WASM_HEAP_MAX = 256*1024*1024; //max 256MB
34 |
35 | // Define print and error functions if not yet defined by the outer html file
36 | WA.print = WA.print || function (msg) { console.log(msg); };
37 | WA.error = WA.error || function (code, msg) { WA.print('[ERROR] ' + code + ': ' + msg + '\n'); };
38 |
39 | // A generic abort function that if called stops the execution of the program and shows an error
40 | function abort(code, msg)
41 | {
42 | WA.error(code, msg);
43 | throw 'abort';
44 | }
45 |
46 | // Puts a string from javascript onto the wasm memory heap (encoded as UTF8) (max_length is optional)
47 | function WriteHeapString(str, ptr, max_length)
48 | {
49 | for (var e=str,r=HEAPU8,f=ptr,i=(max_length?max_length:HEAPU8.length),a=f,t=f+i-1,b=0;b>6,r[f++]=128|63&k;}
54 | else if(k<=65535){if(t<=f+2)break;r[f++]=224|k>>12,r[f++]=128|k>>6&63,r[f++]=128|63&k;}
55 | else if(k<=2097151){if(t<=f+3)break;r[f++]=240|k>>18,r[f++]=128|k>>12&63,r[f++]=128|k>>6&63,r[f++]=128|63&k;}
56 | else if(k<=67108863){if(t<=f+4)break;r[f++]=248|k>>24,r[f++]=128|k>>18&63,r[f++]=128|k>>12&63,r[f++]=128|k>>6&63,r[f++]=128|63&k;}
57 | else{if(t<=f+5)break;r[f++]=252|k>>30,r[f++]=128|k>>24&63,r[f++]=128|k>>18&63,r[f++]=128|k>>12&63,r[f++]=128|k>>6&63,r[f++]=128|63&k;}
58 | }
59 | return r[f]=0,f-a;
60 | }
61 |
62 | // Reads a string from the wasm memory heap to javascript (decoded as UTF8)
63 | function ReadHeapString(ptr, length)
64 | {
65 | if (length === 0 || !ptr) return '';
66 | for (var hasUtf = 0, t, i = 0; !length || i != length; i++)
67 | {
68 | t = HEAPU8[((ptr)+(i))>>0];
69 | if (t == 0 && !length) break;
70 | hasUtf |= t;
71 | }
72 | if (!length) length = i;
73 | if (hasUtf & 128)
74 | {
75 | for(var r=HEAPU8,o=ptr,p=ptr+length,F=String.fromCharCode,e,f,i,n,C,t,a,g='';;)
76 | {
77 | if(o==p||(e=r[o++],!e)) return g;
78 | 128&e?(f=63&r[o++],192!=(224&e)?(i=63&r[o++],224==(240&e)?e=(15&e)<<12|f<<6|i:(n=63&r[o++],240==(248&e)?e=(7&e)<<18|f<<12|i<<6|n:(C=63&r[o++],248==(252&e)?e=(3&e)<<24|f<<18|i<<12|n<<6|C:(t=63&r[o++],e=(1&e)<<30|f<<24|i<<18|n<<12|C<<6|t))),65536>e?g+=F(e):(a=e-65536,g+=F(55296|a>>10,56320|1023&a))):g+=F((31&e)<<6|f)):g+=F(e);
79 | }
80 | }
81 | // split up into chunks, because .apply on a huge string can overflow the stack
82 | for (var ret = '', curr; length > 0; ptr += 1024, length -= 1024)
83 | ret += String.fromCharCode.apply(String, HEAPU8.subarray(ptr, ptr + Math.min(length, 1024)));
84 | return ret;
85 | }
86 |
87 | // Defines our custom functions in the env object that get passed to the wasm module
88 | function WAJS_WASM_IMPORTS(env)
89 | {
90 | // Function that starts the audio output
91 | env.WAJS_StartAudio = function()
92 | {
93 | // Try to initialize WebAudio context with stereo channels and 44100 hz frequency
94 | var audioCtx;
95 | function findAlias(el, a, b, c) { return el[a+c] || el['moz'+b+c] || el['webkit'+b+c] || el['ms'+b+c]; }
96 | try { audioCtx = new (findAlias(window,'','','AudioContext'))(); } catch (e) { }
97 | if (!audioCtx) { WA.print('Warning: WebAudio not supported\n'); return; }
98 | var encTime = 0, audioSamples = 882, audioSecs = audioSamples/44100;
99 | var ptrTempBuf = 0, f32TempBuf = 0, audioBufs = [{'length':0}], audioBufIdx = 0;
100 |
101 | // Call a function every few milliseconds to fill the audio buffer if required
102 | setInterval(function()
103 | {
104 | // Try to start the audio playback if suspended/blocked by the browser
105 | if (audioCtx.state == 'suspended') { audioCtx.resume(); if (audioCtx.state == 'suspended') return; }
106 |
107 | // Check if enough time has passed for the next audio block to be generated (or return if not)
108 | var ctxTime = audioCtx.currentTime;
109 | if (ctxTime == 0) encTime = 0;
110 | if (encTime - ctxTime > audioSecs) return;
111 |
112 | // Check if the audio buffer size was increased (due to starvation) or if this is the first call
113 | if (audioBufs[0].length != audioSamples)
114 | {
115 | // Allocate memory on the wasm heap where it will place the float encoded stereo audio data
116 | WA.asm.free(ptrTempBuf);
117 | f32TempBuf = ((ptrTempBuf = WA.asm.malloc(audioSamples<<3))>>2); //2 channels, 4 byte per float sized sample
118 |
119 | // Prepare 4 matching audio buffers that get cycled through
120 | for (var i = 0; i != 4; i++) audioBufs[i] = audioCtx.createBuffer(2, audioSamples, 44100);
121 | }
122 |
123 | // Call the wasm module function WAFNAudio to generate audio data
124 | if (WA.asm.WAFNAudio(ptrTempBuf, audioSamples))
125 | {
126 | // Copy the generated data for both channels into the next cycled audio buffer
127 | var soundBuffer = audioBufs[audioBufIdx = ((audioBufIdx + 1) % 4)];
128 | soundBuffer.getChannelData(0).set(HEAPF32.subarray(f32TempBuf, f32TempBuf + audioSamples));
129 | soundBuffer.getChannelData(1).set(HEAPF32.subarray(f32TempBuf + audioSamples, f32TempBuf + (audioSamples<<1)));
130 |
131 | // Send the buffer off to be played back
132 | var source = audioCtx.createBufferSource();
133 | source.connect(audioCtx.destination);
134 | source.buffer = soundBuffer;
135 | source[source.start ? 'start' : 'noteOn'](0.005+encTime);
136 | }
137 |
138 | // Check if this call is too late (and audio data generation is behind audio playback)
139 | if (ctxTime > encTime && ctxTime > .5)
140 | {
141 | // Depending on if the site/tab is focused extend the audio buffer length (up to a maximum of .25 second duration)
142 | if (ctxTime - encTime < audioSecs * 10 && audioSamples < 11025 && document.hasFocus())
143 | {
144 | //only increase buffer when at least some time has passed (not directly after loading) and it's not a giant hickup
145 | audioSecs = (audioSamples += 441)/44100;
146 | WA.print('Warning: Audio callback had starved sending audio by ' + (ctxTime - encTime) + ' seconds. (extending samples to: ' + audioSamples + ')\n');
147 | }
148 | // Reset the encode time cursor (if the site/tab is not focused intentionally delay the playback to be more relaxed)
149 | encTime = ctxTime + (document.hasFocus() ? 0 : 1.5);
150 | }
151 |
152 | // Advance the encode time cursor by the amount played back
153 | encTime += audioSecs;
154 | }, 10);
155 | };
156 | }
157 |
158 | // Set the array views of various data types used to read/write to the wasm memory from JavaScript
159 | function MemorySetBufferViews()
160 | {
161 | var buf = WASM_MEMORY.buffer;
162 | HEAP32 = new Int32Array(buf);
163 | HEAPU8 = new Uint8Array(buf);
164 | HEAPU16 = new Uint16Array(buf);
165 | HEAPU32 = new Uint32Array(buf);
166 | HEAPF32 = new Float32Array(buf);
167 | }
168 |
169 | // Set up the env and wasi objects that contains the functions passed to the wasm module
170 | var env =
171 | {
172 | // sbrk gets called to increase the size of the memory heap by an increment
173 | sbrk: function(increment)
174 | {
175 | var heapOld = WASM_HEAP, heapNew = heapOld + increment, heapGrow = heapNew - WASM_MEMORY.buffer.byteLength;
176 | //console.log('[SBRK] Increment: ' + increment + ' - HEAP: ' + heapOld + ' -> ' + heapNew + (heapGrow > 0 ? ' - GROW BY ' + heapGrow + ' (' + (heapGrow>>16) + ' pages)' : ''));
177 | if (heapNew > WASM_HEAP_MAX) abort('MEM', 'Out of memory');
178 | if (heapGrow > 0) { WASM_MEMORY.grow((heapGrow+65535)>>16); MemorySetBufferViews(); }
179 | WASM_HEAP = heapNew;
180 | return heapOld|0;
181 | },
182 |
183 | // Functions querying the system time
184 | time: function(ptr) { var ret = (Date.now()/1000)|0; if (ptr) HEAPU32[ptr>>2] = ret; return ret; },
185 | gettimeofday: function(ptr) { var now = Date.now(); HEAPU32[ptr>>2]=(now/1000)|0; HEAPU32[(ptr+4)>>2]=((now % 1000)*1000)|0; },
186 |
187 | // Various functions thet can be called from wasm that abort the program
188 | __assert_fail: function(condition, filename, line, func) { abort('CRASH', 'Assert ' + ReadHeapString(condition) + ', at: ' + (filename ? ReadHeapString(filename) : 'unknown filename'), line, (func ? ReadHeapString(func) : 'unknown function')); },
189 | __cxa_uncaught_exception: function() { abort('CRASH', 'Uncaught exception!'); },
190 | __cxa_pure_virtual: function() { abort('CRASH', 'pure virtual'); },
191 | abort: function() { abort('CRASH', 'Abort called'); },
192 | longjmp: function() { abort('CRASH', 'Unsupported longjmp called'); },
193 | };
194 |
195 | // Functions that do nothing in this wasm context
196 | env.setjmp = env.__cxa_atexit = env.__lock = env.__unlock = function() {};
197 |
198 | // Math functions
199 | env.ceil = env.ceilf = Math.ceil;
200 | env.exp = env.expf = Math.exp;
201 | env.floor = env.floorf = Math.floor;
202 | env.log = env.logf = Math.log;
203 | env.pow = env.powf = Math.pow;
204 | env.cos = env.cosf = Math.cos;
205 | env.sin = env.sinf = Math.sin;
206 | env.tan = env.tanf = Math.tan;
207 | env.acos = env.acosf = Math.acos;
208 | env.asin = env.asinf = Math.asin;
209 | env.sqrt = env.sqrtf = Math.sqrt;
210 | env.atan = env.atanf = Math.atan;
211 | env.atan2 = env.atan2f = Math.atan2;
212 | env.fabs = env.fabsf = env.abs = Math.abs;
213 | env.round = env.roundf = env.rint = env.rintf = Math.round;
214 |
215 | // Extend the env object with our custom functions
216 | WAJS_WASM_IMPORTS(env);
217 |
218 | // Find the start point of the stack and the heap to calculate the initial memory requirements
219 | var wasmDataEnd = 64, wasmStackTop = 4096, wasmHeapBase = 65536;
220 | // This code goes through the wasm file sections according the binary encoding description
221 | // https://webassembly.org/docs/binary-encoding/
222 | for (let i = 8, sectionEnd, type, length; i < wasmBytes.length; i = sectionEnd)
223 | {
224 | // Get() gets the next single byte, GetLEB() gets a LEB128 variable-length number
225 | function Get() { return wasmBytes[i++]; }
226 | function GetLEB() { for (var s=i,r=0,n=128; n&128; i++) r|=((n=wasmBytes[i])&127)<<((i-s)*7); return r; }
227 | type = GetLEB(), length = GetLEB(), sectionEnd = i + length;
228 | if (type < 0 || type > 11 || length <= 0 || sectionEnd > wasmBytes.length) break;
229 | if (type == 6)
230 | {
231 | //Section 6 'Globals', llvm places the heap base pointer into the first value here
232 | let count = GetLEB(), gtype = Get(), mutable = Get(), opcode = GetLEB(), offset = GetLEB(), endcode = GetLEB();
233 | wasmHeapBase = offset;
234 | }
235 | if (type == 11)
236 | {
237 | //Section 11 'Data', contains data segments which the end of the last entry will indicate the start of the stack area
238 | for (let count = GetLEB(), j = 0; j != count && i < sectionEnd; j++)
239 | {
240 | let dindex = Get(), dopcode = GetLEB(), doffset = GetLEB(), dendcode = GetLEB(), dsize = GetLEB();
241 | wasmDataEnd = (doffset + dsize);
242 | wasmStackTop = (wasmDataEnd+15)>>4<<4;
243 | i += dsize;
244 | }
245 | }
246 | }
247 |
248 | // Validate the queried pointers
249 | if (wasmDataEnd <= 0 || wasmHeapBase <= wasmStackTop) abort('BOOT', 'Invalid memory layout (' + wasmDataEnd + '/' + wasmStackTop + '/' + wasmHeapBase + ')');
250 |
251 | // Set the initial wasm memory size to [DATA] + [STACK] + [256KB HEAP] (can be grown with sbrk)
252 | var wasmMemInitial = ((wasmHeapBase+65535)>>16<<16) + (256 * 1024);
253 | WASM_HEAP = wasmHeapBase;
254 | WASM_MEMORY = env.memory = new WebAssembly.Memory({initial: wasmMemInitial>>16, maximum: WASM_HEAP_MAX>>16 });
255 | MemorySetBufferViews();
256 |
257 | // Instantiate the wasm module by passing the prepared env object containing import functions for the wasm module
258 | WebAssembly.instantiate(wasmBytes, {env:env}).then(function (output)
259 | {
260 | // Store the list of the functions exported by the wasm module in WA.asm
261 | WA.asm = output.instance.exports;
262 |
263 | // If function '__wasm_call_ctors' (global C++ constructors) exists, call it
264 | if (WA.asm.__wasm_call_ctors) WA.asm.__wasm_call_ctors();
265 |
266 | // If function 'main' exists, call it
267 | if (WA.asm.main)
268 | {
269 | // Store the argument list with 1 entry at the far end of the stack to pass to main
270 | var argc = 1, argv = wasmStackTop, exe = 'wasmexe';
271 |
272 | // Store the program name string after the argv list
273 | WriteHeapString(exe, (argv + 8));
274 |
275 | // argv[0] contains the pointer to the exe string, argv[1] has a list terminating null pointer
276 | HEAPU32[(argv>>2) + 0] = (argv + 8)
277 | HEAPU32[(argv>>2) + 1] = 0;
278 |
279 | WA.asm.main(argc, argv);
280 | }
281 |
282 | // If the outer HTML file supplied a 'started' callback, call it
283 | if (WA.started) WA.started();
284 | })
285 | .catch(function (err)
286 | {
287 | // On an exception, if the err is 'abort' the error was already processed in the abort function above
288 | if (err !== 'abort') abort('BOOT', 'WASM instiantate error: ' + err + (err.stack ? "\n" + err.stack : ''));
289 | });
290 |
291 | });
292 |
--------------------------------------------------------------------------------
/Audio/main.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | This is free and unencumbered software released into the public domain.
3 |
4 | Anyone is free to copy, modify, publish, use, compile, sell, or
5 | distribute this software, either in source code form or as a compiled
6 | binary, for any purpose, commercial or non-commercial, and by any
7 | means.
8 |
9 | In jurisdictions that recognize copyright laws, the author or authors
10 | of this software dedicate any and all copyright interest in the
11 | software to the public domain. We make this dedication for the benefit
12 | of the public at large and to the detriment of our heirs and
13 | successors. We intend this dedication to be an overt act of
14 | relinquishment in perpetuity of all present and future rights to this
15 | software under copyright law.
16 |
17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
21 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
22 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23 | OTHER DEALINGS IN THE SOFTWARE.
24 |
25 | For more information, please refer to
26 | */
27 |
28 | #include
29 |
30 | // Function defined in loader.js
31 | extern "C" void WAJS_StartAudio();
32 |
33 | // This function is called at startup
34 | int main(int argc, char *argv[])
35 | {
36 | WAJS_StartAudio();
37 |
38 | return 0;
39 | }
40 |
41 | // This function is called by loader.js to feed audio
42 | extern "C" bool WAFNAudio(float* sample_buffer, unsigned int samples)
43 | {
44 | float *pLeft = sample_buffer, *pRight = sample_buffer + samples;
45 | for(unsigned int i = 0; i < samples; i++)
46 | {
47 | // Render 220 HZ sine wave at 25% volume into both channels
48 | static size_t waveCount;
49 | float wave = (((waveCount++) % 44100) / 44100.0f);
50 | pLeft[i] = pRight[i] = sinf(2.0f * 3.14159f * 220.0f * wave) * 0.25f;
51 | }
52 | return true;
53 | }
54 |
--------------------------------------------------------------------------------
/Audio/output.wasm:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/schellingb/ClangWasm/94203708c127a54c89c790caeb91c00b38cb4cef/Audio/output.wasm
--------------------------------------------------------------------------------
/Basic/Makefile:
--------------------------------------------------------------------------------
1 | #
2 | # This is free and unencumbered software released into the public domain.
3 | #
4 | # Anyone is free to copy, modify, publish, use, compile, sell, or
5 | # distribute this software, either in source code form or as a compiled
6 | # binary, for any purpose, commercial or non-commercial, and by any
7 | # means.
8 | #
9 | # In jurisdictions that recognize copyright laws, the author or authors
10 | # of this software dedicate any and all copyright interest in the
11 | # software to the public domain. We make this dedication for the benefit
12 | # of the public at large and to the detriment of our heirs and
13 | # successors. We intend this dedication to be an overt act of
14 | # relinquishment in perpetuity of all present and future rights to this
15 | # software under copyright law.
16 | #
17 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 | # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 | # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20 | # IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
21 | # OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
22 | # ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23 | # OTHER DEALINGS IN THE SOFTWARE.
24 | #
25 | # For more information, please refer to
26 | #
27 |
28 | LLVM_ROOT = D:/dev/wasm/llvm
29 | WASMOPT = D:/dev/wasm/wasm-opt.exe
30 |
31 | EXPORTS = square
32 | SOURCES = main.c
33 | BUILD = RELEASE
34 |
35 | #------------------------------------------------------------------------------------------------------
36 |
37 | ifeq ($(BUILD),RELEASE)
38 | OUTDIR := Release-wasm
39 | DBGCFLAGS := -DNDEBUG
40 | LDFLAGS := -strip-all -gc-sections
41 | WOPTFLAGS := -O3
42 | else
43 | OUTDIR := Debug-wasm
44 | DBGCFLAGS := -DDEBUG -D_DEBUG
45 | LDFLAGS :=
46 | WOPTFLAGS := -g -O0
47 | endif
48 |
49 | # Global compiler flags
50 | CXXFLAGS := $(DBGCFLAGS) -Ofast -std=c++11 -fno-rtti -Wno-writable-strings -Wno-unknown-pragmas
51 | CCFLAGS := $(DBGCFLAGS) -Ofast -std=c99
52 |
53 | # Global compiler flags for Wasm targeting
54 | CLANGFLAGS := -target wasm32 -nostdinc
55 | CLANGFLAGS += -D__EMSCRIPTEN__ -D_LIBCPP_ABI_VERSION=2
56 | CLANGFLAGS += -fvisibility=hidden -fno-builtin -fno-exceptions -fno-threadsafe-statics
57 |
58 | # Flags for wasm-ld
59 | LDFLAGS += -no-entry -allow-undefined -import-memory
60 | LDFLAGS += -export=__wasm_call_ctors -export=malloc -export=free -export=main
61 | LDFLAGS += $(addprefix -export=,$(patsubst _%,%,$(strip $(EXPORTS))))
62 |
63 | # Project Build flags, add defines from the make command line (e.g. D=MACRO=VALUE)
64 | FLAGS := $(subst \\\, ,$(foreach F,$(subst \ ,\\\,$(D)),"-D$(F)"))
65 |
66 | # Check if there are any source files
67 | ifeq ($(SOURCES),)
68 | $(error No source files found for build)
69 | endif
70 |
71 | # Compute tool paths
72 | ISWIN := $(findstring :,$(firstword $(subst \, ,$(subst /, ,$(abspath .)))))
73 | PIPETONULL := $(if $(ISWIN),>nul 2>nul,>/dev/null 2>/dev/null)
74 | ifeq ($(wildcard $(subst $(strip ) ,\ ,$(LLVM_ROOT))/clang*),)
75 | $(error clang executables not found in set LLVM_ROOT path ($(LLVM_ROOT)). Set custom path in this makefile with LLVM_ROOT = $(if $(ISWIN),d:)/path/to/clang)
76 | endif
77 | ifeq ($(wildcard $(subst $(strip ) ,\ ,$(WASMOPT))),)
78 | $(error wasm-opt executable not found in set WASMOPT path ($(WASMOPT)). Fix path in this makefile with WASMOPT = $(if $(ISWIN),d:)/path/to/wasm-opt$(if $(ISWIN),.exe))
79 | endif
80 |
81 | # Surround used commands with double quotes
82 | CC := "$(LLVM_ROOT)/clang"
83 | CXX := "$(LLVM_ROOT)/clang" -x c++
84 | LD := "$(LLVM_ROOT)/wasm-ld"
85 |
86 | all: $(OUTDIR)/loader.js $(OUTDIR)/loader.html $(OUTDIR)/output.wasm
87 | .PHONY: clean cleanall run analyze
88 |
89 | clean:
90 | $(info Removing all build files ...)
91 | @$(if $(wildcard $(OUTDIR)),$(if $(ISWIN),rmdir /S /Q,rm -rf) "$(OUTDIR)" $(PIPETONULL))
92 |
93 | # Generate a list of .o files to build, include dependency rules for source files, then compile files
94 | OBJS := $(addprefix $(OUTDIR)/,$(notdir $(patsubst %.c,%.o,$(patsubst %.cpp,%.o,$(SOURCES)))))
95 | -include $(OBJS:%.o=%.d)
96 | MAKEOBJ = $(OUTDIR)/$(basename $(notdir $(1))).o: $(1) ; $$(call COMPILE,$$@,$$<,$(2),$(3) $$(FLAGS))
97 | $(foreach F,$(filter %.cpp,$(SOURCES)),$(eval $(call MAKEOBJ,$(F),$$(CXX),$$(CXXFLAGS))))
98 | $(foreach F,$(filter %.c ,$(SOURCES)),$(eval $(call MAKEOBJ,$(F),$$(CC),$$(CCFLAGS))))
99 |
100 | $(OUTDIR)/output.wasm : Makefile $(OBJS)
101 | $(info Linking $@ ...)
102 | @$(LD) $(LDFLAGS) -o $@ $(OBJS)
103 | @"$(WASMOPT)" --legalize-js-interface $(WOPTFLAGS) $@ -o $@
104 |
105 | $(OUTDIR)/loader.js : loader.js
106 | $(info Copying $^ to $@ ...)
107 | @$(if $(wildcard $(OUTDIR)),,$(shell mkdir "$(OUTDIR)"))
108 | @$(if $(ISWIN),copy,cp) "$^" "$@" $(PIPETONULL)
109 |
110 | $(OUTDIR)/loader.html : loader.html
111 | $(if $(wildcard $(OUTDIR)),,$(shell mkdir "$(OUTDIR)"))
112 | @$(if $(ISWIN),copy,cp) "$^" "$@" $(PIPETONULL)
113 |
114 | define COMPILE
115 | $(info $2)
116 | @$(if $(wildcard $(dir $1)),,$(shell mkdir "$(dir $1)"))
117 | @$3 $4 $(CLANGFLAGS) -MMD -MP -MF $(patsubst %.o,%.d,$1) -o $1 -c $2
118 | endef
119 |
--------------------------------------------------------------------------------
/Basic/loader.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | WebAssembly Sample: Pure C
7 |
8 |
9 |
WebAssembly Sample: Pure C
10 |
11 |
Loading...
12 |
36 |
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/Basic/loader.js:
--------------------------------------------------------------------------------
1 | /*
2 | This is free and unencumbered software released into the public domain.
3 |
4 | Anyone is free to copy, modify, publish, use, compile, sell, or
5 | distribute this software, either in source code form or as a compiled
6 | binary, for any purpose, commercial or non-commercial, and by any
7 | means.
8 |
9 | In jurisdictions that recognize copyright laws, the author or authors
10 | of this software dedicate any and all copyright interest in the
11 | software to the public domain. We make this dedication for the benefit
12 | of the public at large and to the detriment of our heirs and
13 | successors. We intend this dedication to be an overt act of
14 | relinquishment in perpetuity of all present and future rights to this
15 | software under copyright law.
16 |
17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
21 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
22 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23 | OTHER DEALINGS IN THE SOFTWARE.
24 |
25 | For more information, please refer to
26 | */
27 |
28 | // Fetch the .wasm file and store its bytes into the byte array wasmBytes
29 | fetch(WA.module).then(res => res.arrayBuffer()).then(function(wasmBytes){'use strict';wasmBytes = new Uint8Array(wasmBytes);
30 |
31 | // Define print and error functions if not yet defined by the outer html file
32 | WA.print = WA.print || function (msg) { console.log(msg); };
33 | WA.error = WA.error || function (code, msg) { WA.print('[ERROR] ' + code + ': ' + msg + '\n'); };
34 |
35 | // A generic abort function that if called stops the execution of the program and shows an error
36 | function abort(code, msg)
37 | {
38 | WA.error(code, msg);
39 | throw 'abort';
40 | }
41 |
42 | // Find the start point of the heap to calculate the initial memory requirements
43 | var wasmHeapBase = 65536;
44 | // This code goes through the wasm file sections according the binary encoding description
45 | // https://webassembly.org/docs/binary-encoding/
46 | for (let i = 8, sectionEnd, type, length; i < wasmBytes.length; i = sectionEnd)
47 | {
48 | // Get() gets the next single byte, GetLEB() gets a LEB128 variable-length number
49 | function Get() { return wasmBytes[i++]; }
50 | function GetLEB() { for (var s=i,r=0,n=128; n&128; i++) r|=((n=wasmBytes[i])&127)<<((i-s)*7); return r; }
51 | type = GetLEB(), length = GetLEB(), sectionEnd = i + length;
52 | if (type < 0 || type > 11 || length <= 0 || sectionEnd > wasmBytes.length) break;
53 | if (type == 6)
54 | {
55 | //Section 6 'Globals', llvm places the heap base pointer into the first value here
56 | let count = GetLEB(), gtype = Get(), mutable = Get(), opcode = GetLEB(), offset = GetLEB(), endcode = GetLEB();
57 | wasmHeapBase = offset;
58 | break;
59 | }
60 | }
61 |
62 | // Set the wasm memory size to [DATA] + [STACK] + [256KB HEAP]
63 | // (This loader does not support memory growing so it stays at this size)
64 | var wasmMemInitial = ((wasmHeapBase+65535)>>16<<16) + (256 * 1024);
65 | var env = { memory: new WebAssembly.Memory({initial: wasmMemInitial>>16 }) };
66 |
67 | // Instantiate the wasm module by passing the prepared environment
68 | WebAssembly.instantiate(wasmBytes, {env:env}).then(function (output)
69 | {
70 | // Store the list of the functions exported by the wasm module in WA.asm
71 | WA.asm = output.instance.exports;
72 |
73 | // If function '__wasm_call_ctors' (global C++ constructors) exists, call it
74 | if (WA.asm.__wasm_call_ctors) WA.asm.__wasm_call_ctors();
75 |
76 | // If function 'main' exists, call it with dummy arguments
77 | if (WA.asm.main) WA.asm.main(0, 0);
78 |
79 | // If the outer HTML file supplied a 'started' callback, call it
80 | if (WA.started) WA.started();
81 | })
82 | .catch(function (err)
83 | {
84 | // On an exception, if the err is 'abort' the error was already processed in the abort function above
85 | if (err !== 'abort') abort('BOOT', 'WASM instiantate error: ' + err + (err.stack ? "\n" + err.stack : ''));
86 | });
87 |
88 | });
89 |
--------------------------------------------------------------------------------
/Basic/main.c:
--------------------------------------------------------------------------------
1 | /*
2 | This is free and unencumbered software released into the public domain.
3 |
4 | Anyone is free to copy, modify, publish, use, compile, sell, or
5 | distribute this software, either in source code form or as a compiled
6 | binary, for any purpose, commercial or non-commercial, and by any
7 | means.
8 |
9 | In jurisdictions that recognize copyright laws, the author or authors
10 | of this software dedicate any and all copyright interest in the
11 | software to the public domain. We make this dedication for the benefit
12 | of the public at large and to the detriment of our heirs and
13 | successors. We intend this dedication to be an overt act of
14 | relinquishment in perpetuity of all present and future rights to this
15 | software under copyright law.
16 |
17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
21 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
22 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23 | OTHER DEALINGS IN THE SOFTWARE.
24 |
25 | For more information, please refer to
26 | */
27 |
28 | int square(int num)
29 | {
30 | return num * num;
31 | }
32 |
--------------------------------------------------------------------------------
/Basic/output.wasm:
--------------------------------------------------------------------------------
1 | asm ` ` __wasm_call_ctors square
2 |
l
--------------------------------------------------------------------------------
/Cpp/Makefile:
--------------------------------------------------------------------------------
1 | #
2 | # This is free and unencumbered software released into the public domain.
3 | #
4 | # Anyone is free to copy, modify, publish, use, compile, sell, or
5 | # distribute this software, either in source code form or as a compiled
6 | # binary, for any purpose, commercial or non-commercial, and by any
7 | # means.
8 | #
9 | # In jurisdictions that recognize copyright laws, the author or authors
10 | # of this software dedicate any and all copyright interest in the
11 | # software to the public domain. We make this dedication for the benefit
12 | # of the public at large and to the detriment of our heirs and
13 | # successors. We intend this dedication to be an overt act of
14 | # relinquishment in perpetuity of all present and future rights to this
15 | # software under copyright law.
16 | #
17 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 | # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 | # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20 | # IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
21 | # OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
22 | # ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23 | # OTHER DEALINGS IN THE SOFTWARE.
24 | #
25 | # For more information, please refer to
26 | #
27 |
28 | LLVM_ROOT = D:/dev/wasm/llvm
29 | SYSTEM_ROOT = D:/dev/wasm/system
30 | WASMOPT = D:/dev/wasm/wasm-opt.exe
31 |
32 | SOURCES = main.cpp
33 | BUILD = RELEASE
34 |
35 | #------------------------------------------------------------------------------------------------------
36 |
37 | ifeq ($(BUILD),RELEASE)
38 | OUTDIR := Release-wasm
39 | DBGCFLAGS := -DNDEBUG
40 | LDFLAGS := -strip-all -gc-sections
41 | WOPTFLAGS := -O3
42 | else
43 | OUTDIR := Debug-wasm
44 | DBGCFLAGS := -DDEBUG -D_DEBUG
45 | LDFLAGS :=
46 | WOPTFLAGS := -g -O0
47 | endif
48 |
49 | # Global compiler flags
50 | CXXFLAGS := $(DBGCFLAGS) -Ofast -std=c++11 -fno-rtti -Wno-writable-strings -Wno-unknown-pragmas
51 | CCFLAGS := $(DBGCFLAGS) -Ofast -std=c99
52 |
53 | # Global compiler flags for Wasm targeting
54 | CLANGFLAGS := -target wasm32 -nostdinc
55 | CLANGFLAGS += -D__EMSCRIPTEN__ -D_LIBCPP_ABI_VERSION=2
56 | CLANGFLAGS += -fvisibility=hidden -fno-builtin -fno-exceptions -fno-threadsafe-statics
57 | CLANGFLAGS += -isystem$(SYSTEM_ROOT)/include/libcxx
58 | CLANGFLAGS += -isystem$(SYSTEM_ROOT)/include/compat
59 | CLANGFLAGS += -isystem$(SYSTEM_ROOT)/include
60 | CLANGFLAGS += -isystem$(SYSTEM_ROOT)/include/libc
61 | CLANGFLAGS += -isystem$(SYSTEM_ROOT)/lib/libc/musl/arch/emscripten
62 |
63 | # Flags for wasm-ld
64 | LDFLAGS += -no-entry -allow-undefined -import-memory
65 | LDFLAGS += -export=__wasm_call_ctors -export=malloc -export=free -export=main
66 | LDFLAGS += $(addprefix -export=,$(patsubst _%,%,$(strip $(EXPORTS))))
67 |
68 | # Project Build flags, add defines from the make command line (e.g. D=MACRO=VALUE)
69 | FLAGS := $(subst \\\, ,$(foreach F,$(subst \ ,\\\,$(D)),"-D$(F)"))
70 |
71 | # Check if there are any source files
72 | ifeq ($(SOURCES),)
73 | $(error No source files found for build)
74 | endif
75 |
76 | # Compute tool paths
77 | ISWIN := $(findstring :,$(firstword $(subst \, ,$(subst /, ,$(abspath .)))))
78 | PIPETONULL := $(if $(ISWIN),>nul 2>nul,>/dev/null 2>/dev/null)
79 | ifeq ($(wildcard $(subst $(strip ) ,\ ,$(LLVM_ROOT))/clang*),)
80 | $(error clang executables not found in set LLVM_ROOT path ($(LLVM_ROOT)). Set custom path in this makefile with LLVM_ROOT = $(if $(ISWIN),d:)/path/to/clang)
81 | endif
82 | ifeq ($(wildcard $(subst $(strip ) ,\ ,$(WASMOPT))),)
83 | $(error wasm-opt executable not found in set WASMOPT path ($(WASMOPT)). Fix path in this makefile with WASMOPT = $(if $(ISWIN),d:)/path/to/wasm-opt$(if $(ISWIN),.exe))
84 | endif
85 |
86 | # Surround used commands with double quotes
87 | CC := "$(LLVM_ROOT)/clang"
88 | CXX := "$(LLVM_ROOT)/clang" -x c++
89 | LD := "$(LLVM_ROOT)/wasm-ld"
90 |
91 | all: $(OUTDIR)/loader.js $(OUTDIR)/loader.html $(OUTDIR)/output.wasm
92 | .PHONY: clean cleanall run analyze
93 |
94 | clean:
95 | $(info Removing all build files ...)
96 | @$(if $(wildcard $(OUTDIR)),$(if $(ISWIN),rmdir /S /Q,rm -rf) "$(OUTDIR)" $(PIPETONULL))
97 |
98 | # Generate a list of .o files to build, include dependency rules for source files, then compile files
99 | OBJS := $(addprefix $(OUTDIR)/,$(notdir $(patsubst %.c,%.o,$(patsubst %.cpp,%.o,$(SOURCES)))))
100 | -include $(OBJS:%.o=%.d)
101 | MAKEOBJ = $(OUTDIR)/$(basename $(notdir $(1))).o: $(1) ; $$(call COMPILE,$$@,$$<,$(2),$(3) $$(FLAGS))
102 | $(foreach F,$(filter %.cpp,$(SOURCES)),$(eval $(call MAKEOBJ,$(F),$$(CXX),$$(CXXFLAGS))))
103 | $(foreach F,$(filter %.c ,$(SOURCES)),$(eval $(call MAKEOBJ,$(F),$$(CC),$$(CCFLAGS))))
104 |
105 | $(OUTDIR)/output.wasm : Makefile $(OBJS) System.bc
106 | $(info Linking $@ ...)
107 | @$(LD) $(LDFLAGS) -o $@ $(OBJS) System.bc
108 | @"$(WASMOPT)" --legalize-js-interface $(WOPTFLAGS) $@ -o $@
109 |
110 | $(OUTDIR)/loader.js : loader.js
111 | $(info Copying $^ to $@ ...)
112 | @$(if $(wildcard $(OUTDIR)),,$(shell mkdir "$(OUTDIR)"))
113 | @$(if $(ISWIN),copy,cp) "$^" "$@" $(PIPETONULL)
114 |
115 | $(OUTDIR)/loader.html : loader.html
116 | $(if $(wildcard $(OUTDIR)),,$(shell mkdir "$(OUTDIR)"))
117 | @$(if $(ISWIN),copy,cp) "$^" "$@" $(PIPETONULL)
118 |
119 | define COMPILE
120 | $(info $2)
121 | @$(if $(wildcard $(dir $1)),,$(shell mkdir "$(dir $1)"))
122 | @$3 $4 $(CLANGFLAGS) -MMD -MP -MF $(patsubst %.o,%.d,$1) -o $1 -c $2
123 | endef
124 |
125 | #------------------------------------------------------------------------------------------------------
126 | #if System.bc exists, don't even bother checking sources, build once and forget for now
127 | ifeq ($(if $(wildcard System.bc),1,0),0)
128 | SYS_ADDS := emmalloc.cpp libcxx/*.cpp libcxxabi/src/cxa_guard.cpp compiler-rt/lib/builtins/*.c libc/wasi-helpers.c
129 | SYS_MUSL := complex crypt ctype dirent errno fcntl fenv internal locale math misc mman multibyte prng regex select stat stdio stdlib string termios unistd
130 |
131 | # C++ streams and locale are not included on purpose because it can increase the output up to 500kb
132 | SYS_IGNORE := iostream.cpp strstream.cpp locale.cpp thread.cpp exception.cpp
133 | SYS_IGNORE += abs.c acos.c acosf.c acosl.c asin.c asinf.c asinl.c atan.c atan2.c atan2f.c atan2l.c atanf.c atanl.c ceil.c ceilf.c ceill.c cos.c cosf.c cosl.c exp.c expf.c expl.c
134 | SYS_IGNORE += fabs.c fabsf.c fabsl.c floor.c floorf.c floorl.c log.c logf.c logl.c pow.c powf.c powl.c rintf.c round.c roundf.c sin.c sinf.c sinl.c sqrt.c sqrtf.c sqrtl.c tan.c tanf.c tanl.c
135 | SYS_IGNORE += syscall.c wordexp.c initgroups.c getgrouplist.c popen.c _exit.c alarm.c usleep.c faccessat.c iconv.c
136 |
137 | SYS_SOURCES := $(filter-out $(SYS_IGNORE:%=\%/%),$(wildcard $(addprefix $(SYSTEM_ROOT)/lib/,$(SYS_ADDS) $(SYS_MUSL:%=libc/musl/src/%/*.c))))
138 | SYS_SOURCES := $(subst $(SYSTEM_ROOT)/lib/,,$(SYS_SOURCES))
139 |
140 | ifeq ($(findstring !,$(SYS_SOURCES)),!)
141 | $(error SYS_SOURCES contains a filename with a ! character in it - Unable to continue)
142 | endif
143 |
144 | SYS_MISSING := $(filter-out $(SYS_SOURCES) $(dir $(SYS_SOURCES)),$(subst *.c,,$(subst *.cpp,,$(SYS_ADDS))) $(SYS_MUSL:%=libc/musl/src/%/))
145 | ifeq ($(if $(SYS_MISSING),1,0),1)
146 | $(error SYS_SOURCES missing the following files in $(SYSTEM_ROOT)/lib: $(SYS_MISSING))
147 | endif
148 |
149 | SYS_OLDFILES := $(filter-out $(subst /,!,$(patsubst %.c,%.o,$(patsubst %.cpp,%.o,$(SYS_SOURCES)))),$(notdir $(wildcard temp/*.o)))
150 | $(foreach F,$(SYS_OLDFILES),$(shell $(if $(ISWIN),del "temp\,rm "temp/)$(F)" $(PIPETONULL)))
151 |
152 | SYS_CXXFLAGS := -Ofast -std=c++11 -fno-threadsafe-statics -fno-rtti -I$(SYSTEM_ROOT)/lib/libcxxabi/include
153 | SYS_CXXFLAGS += -DNDEBUG -D_LIBCPP_BUILDING_LIBRARY -D_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS
154 |
155 | SYS_CCFLAGS := -Ofast -std=gnu99 -fno-threadsafe-statics
156 | SYS_CCFLAGS += -DNDEBUG -Dunix -D__unix -D__unix__
157 | SYS_CCFLAGS += -isystem$(SYSTEM_ROOT)/lib/libc/musl/src/internal
158 | SYS_CCFLAGS += -Wno-dangling-else -Wno-ignored-attributes -Wno-bitwise-op-parentheses -Wno-logical-op-parentheses -Wno-shift-op-parentheses -Wno-string-plus-int
159 | SYS_CCFLAGS += -Wno-unknown-pragmas -Wno-shift-count-overflow -Wno-return-type -Wno-macro-redefined -Wno-unused-result -Wno-pointer-sign
160 |
161 | SYS_CPP_OBJS := $(addprefix temp/,$(subst /,!,$(patsubst %.cpp,%.o,$(filter %.cpp,$(SYS_SOURCES)))))
162 | SYS_CC_OBJS := $(addprefix temp/,$(subst /,!,$(patsubst %.c,%.o,$(filter %.c,$(SYS_SOURCES)))))
163 | $(SYS_CPP_OBJS) : ; $(call SYS_COMPILE,$@,$(subst !,/,$(patsubst temp/%.o,$(SYSTEM_ROOT)/lib/%.cpp,$@)),$(CXX),$(SYS_CXXFLAGS))
164 | $(SYS_CC_OBJS) : ; $(call SYS_COMPILE,$@,$(subst !,/,$(patsubst temp/%.o,$(SYSTEM_ROOT)/lib/%.c,$@)),$(CC),$(SYS_CCFLAGS))
165 |
166 | define SYS_COMPILE
167 | $(info $2)
168 | @$(if $(wildcard $(dir $1)),,$(shell mkdir "$(dir $1)"))
169 | @$3 $4 $(CLANGFLAGS) -o $1 -c $2
170 | endef
171 |
172 | System.bc : $(SYS_CPP_OBJS) $(SYS_CC_OBJS)
173 | $(info Creating archive $@ ...)
174 | @$(LD) $(if $(ISWIN),"temp/*.o",temp/*.o) -r -o $@
175 | @$(if $(ISWIN),rmdir /S /Q,rm -rf) "temp"
176 | endif #need System.bc
177 | #------------------------------------------------------------------------------------------------------
178 |
--------------------------------------------------------------------------------
/Cpp/loader.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | WebAssembly Sample: C++
7 |
8 |
9 |
WebAssembly Sample: C++
10 |
11 |
Loading...
12 |
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/Cpp/loader.js:
--------------------------------------------------------------------------------
1 | /*
2 | This is free and unencumbered software released into the public domain.
3 |
4 | Anyone is free to copy, modify, publish, use, compile, sell, or
5 | distribute this software, either in source code form or as a compiled
6 | binary, for any purpose, commercial or non-commercial, and by any
7 | means.
8 |
9 | In jurisdictions that recognize copyright laws, the author or authors
10 | of this software dedicate any and all copyright interest in the
11 | software to the public domain. We make this dedication for the benefit
12 | of the public at large and to the detriment of our heirs and
13 | successors. We intend this dedication to be an overt act of
14 | relinquishment in perpetuity of all present and future rights to this
15 | software under copyright law.
16 |
17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
21 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
22 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23 | OTHER DEALINGS IN THE SOFTWARE.
24 |
25 | For more information, please refer to
26 | */
27 |
28 | // Fetch the .wasm file and store its bytes into the byte array wasmBytes
29 | fetch(WA.module).then(res => res.arrayBuffer()).then(function(wasmBytes){'use strict';wasmBytes = new Uint8Array(wasmBytes);
30 |
31 | // Some global state variables and max heap definition
32 | var HEAP32, HEAPU8, HEAPU16, HEAPU32, HEAPF32;
33 | var WASM_MEMORY, WASM_HEAP, WASM_HEAP_MAX = 256*1024*1024; //max 256MB
34 |
35 | // Define print and error functions if not yet defined by the outer html file
36 | WA.print = WA.print || function (msg) { console.log(msg); };
37 | WA.error = WA.error || function (code, msg) { WA.print('[ERROR] ' + code + ': ' + msg + '\n'); };
38 |
39 | // A generic abort function that if called stops the execution of the program and shows an error
40 | function abort(code, msg)
41 | {
42 | WA.error(code, msg);
43 | throw 'abort';
44 | }
45 |
46 | // Puts a string from javascript onto the wasm memory heap (encoded as UTF8) (max_length is optional)
47 | function WriteHeapString(str, ptr, max_length)
48 | {
49 | for (var e=str,r=HEAPU8,f=ptr,i=(max_length?max_length:HEAPU8.length),a=f,t=f+i-1,b=0;b>6,r[f++]=128|63&k;}
54 | else if(k<=65535){if(t<=f+2)break;r[f++]=224|k>>12,r[f++]=128|k>>6&63,r[f++]=128|63&k;}
55 | else if(k<=2097151){if(t<=f+3)break;r[f++]=240|k>>18,r[f++]=128|k>>12&63,r[f++]=128|k>>6&63,r[f++]=128|63&k;}
56 | else if(k<=67108863){if(t<=f+4)break;r[f++]=248|k>>24,r[f++]=128|k>>18&63,r[f++]=128|k>>12&63,r[f++]=128|k>>6&63,r[f++]=128|63&k;}
57 | else{if(t<=f+5)break;r[f++]=252|k>>30,r[f++]=128|k>>24&63,r[f++]=128|k>>18&63,r[f++]=128|k>>12&63,r[f++]=128|k>>6&63,r[f++]=128|63&k;}
58 | }
59 | return r[f]=0,f-a;
60 | }
61 |
62 | // Reads a string from the wasm memory heap to javascript (decoded as UTF8)
63 | function ReadHeapString(ptr, length)
64 | {
65 | if (length === 0 || !ptr) return '';
66 | for (var hasUtf = 0, t, i = 0; !length || i != length; i++)
67 | {
68 | t = HEAPU8[((ptr)+(i))>>0];
69 | if (t == 0 && !length) break;
70 | hasUtf |= t;
71 | }
72 | if (!length) length = i;
73 | if (hasUtf & 128)
74 | {
75 | for(var r=HEAPU8,o=ptr,p=ptr+length,F=String.fromCharCode,e,f,i,n,C,t,a,g='';;)
76 | {
77 | if(o==p||(e=r[o++],!e)) return g;
78 | 128&e?(f=63&r[o++],192!=(224&e)?(i=63&r[o++],224==(240&e)?e=(15&e)<<12|f<<6|i:(n=63&r[o++],240==(248&e)?e=(7&e)<<18|f<<12|i<<6|n:(C=63&r[o++],248==(252&e)?e=(3&e)<<24|f<<18|i<<12|n<<6|C:(t=63&r[o++],e=(1&e)<<30|f<<24|i<<18|n<<12|C<<6|t))),65536>e?g+=F(e):(a=e-65536,g+=F(55296|a>>10,56320|1023&a))):g+=F((31&e)<<6|f)):g+=F(e);
79 | }
80 | }
81 | // split up into chunks, because .apply on a huge string can overflow the stack
82 | for (var ret = '', curr; length > 0; ptr += 1024, length -= 1024)
83 | ret += String.fromCharCode.apply(String, HEAPU8.subarray(ptr, ptr + Math.min(length, 1024)));
84 | return ret;
85 | }
86 |
87 | // Defines syscall emulation functions in the env and wasi object that get passed to the wasm module
88 | function SYSCALLS_WASM_IMPORTS(env, wasi)
89 | {
90 | // Function to decode Base64 encoded string to a byte array
91 | function Base64Decode(B)
92 | {
93 | var T=new Uint8Array(128),i,C=function(o){return T[B.charCodeAt(i+o)];};
94 | for (i=0;i<64;i++) T['ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'.charCodeAt(i)]=i;T[45]=62;T[95]=63;
95 | var L=B.length,PH=(B[L-2]==='='?2:(B[L-1]==='='?1:0)),a=new Uint8Array(L*3/4-PH),n=0,j=(PH>0?L-4:L),t=0;
96 | for (i=0;i>16)&255;a[n++]=(t>>8)&255;a[n++]=t&255; }
97 | if (PH===1) { t=(C(0)<<10)|(C(1)<<4)|(C(2)>>2); a[n]=(t>>8)&255;a[n+1]=t&255; }
98 | else if (PH===2) a[n]=((C(0)<<2)|(C(1)>>4))&255;
99 | return a;
100 | }
101 |
102 | // For the file open/file reading emulation, keep a seek cursor and the file data
103 | var PAYLOAD_CURSOR = 0;
104 | var PAYLOAD = (WA.payload ? Base64Decode(WA.payload) : new Uint8Array(0));
105 | delete WA.payload;
106 |
107 | // sys_open call to open a file (can only be used to open payload here)
108 | env.__sys_open = function(pPath, flags, pMode)
109 | {
110 | // Opening just resets the seek cursor to 0
111 | PAYLOAD_CURSOR = 0;
112 | //var pathname = ReadHeapString(pPath); //read the file name passed to open
113 | //console.log('__sys_open open - path: ' + pathname + ' - flags: ' + flags + ' - mode: ' + HEAPU32[pMode>>2]);
114 | return 9; //return dummy file number
115 | };
116 |
117 | // fd_read call to read from a file (reads from payload)
118 | wasi.fd_read = function(fd, iov, iovcnt, pOutResult)
119 | {
120 | for (var ret = 0, i = 0; i < iovcnt; i++)
121 | {
122 | // Process list of IO commands
123 | var ptr = HEAPU32[((iov)+(i*8))>>2];
124 | var len = HEAPU32[((iov)+(i*8 + 4))>>2];
125 | var curr = Math.min(len, PAYLOAD.length - PAYLOAD_CURSOR);
126 | //console.log('fd_read - fd: ' + fd + ' - iov: ' + iov + ' - iovcnt: ' + iovcnt + ' - ptr: ' + ptr + ' - len: ' + len + ' - reading: ' + curr + ' (from ' + PAYLOAD_CURSOR + ' to ' + (PAYLOAD_CURSOR + curr) + ')');
127 |
128 | // Write the requested data onto the heap and advance the seek cursor
129 | HEAPU8.set(PAYLOAD.subarray(PAYLOAD_CURSOR, PAYLOAD_CURSOR + curr), ptr);
130 | PAYLOAD_CURSOR += curr;
131 |
132 | ret += curr;
133 | if (curr < len) break; // nothing more to read
134 | }
135 |
136 | // Write the amount of data actually read to the result pointer
137 | HEAPU32[pOutResult>>2] = ret;
138 | //console.log('fd_read - ret: ' + ret);
139 | return 0; // no error
140 | };
141 |
142 | // fd_seek call to seek in a file (seeks in payload)
143 | wasi.fd_seek = function(fd, offset_low, offset_high, whence, pOutResult)
144 | {
145 | // Move seek cursor according to fseek behavior
146 | if (whence == 0) PAYLOAD_CURSOR = offset_low; //set
147 | if (whence == 1) PAYLOAD_CURSOR += offset_low; //cur
148 | if (whence == 2) PAYLOAD_CURSOR = PAYLOAD.length - offset_low; //end
149 | if (PAYLOAD_CURSOR < 0) PAYLOAD_CURSOR = 0;
150 | if (PAYLOAD_CURSOR > PAYLOAD.length) PAYLOAD_CURSOR = PAYLOAD.length;
151 |
152 | // Write the result back (write only lower 32-bit of 64-bit number)
153 | HEAPU32[(pOutResult+0)>>2] = PAYLOAD_CURSOR;
154 | HEAPU32[(pOutResult+4)>>2] = 0;
155 | //console.log('fd_seek - fd: ' + fd + ' - offset_high: ' + offset_high + ' - offset_low: ' + offset_low + ' - pOutResult: ' + pOutResult + ' - whence: ' +whence + ' - seek to: ' + PAYLOAD_CURSOR);
156 | return 0; // no error
157 | };
158 |
159 | // fd_write call to write to a file/pipe (can only be used to write to stdout here)
160 | wasi.fd_write = function(fd, iov, iovcnt, pOutResult)
161 | {
162 | for (var ret = 0, str = '', i = 0; i < iovcnt; i++)
163 | {
164 | // Process list of IO commands, read passed strings from heap
165 | var ptr = HEAPU32[((iov)+(i*8))>>2];
166 | var len = HEAPU32[((iov)+(i*8 + 4))>>2];
167 | if (len < 0) return -1;
168 | ret += len;
169 | str += ReadHeapString(ptr, len);
170 | //console.log('fd_write - fd: ' + fd + ' - ['+i+'][len:'+len+']: ' + ReadHeapString(ptr, len).replace(/\n/g, '\\n'));
171 | }
172 |
173 | // Print the passed string and write the number of bytes read to the result pointer
174 | WA.print(str);
175 | HEAPU32[pOutResult>>2] = ret;
176 | return 0; // no error
177 | };
178 |
179 | // fd_close to close a file (no real file system emulation, so this does nothing)
180 | wasi.fd_close = function(fd)
181 | {
182 | //console.log('fd_close - fd: ' + fd);
183 | return 0; // no error
184 | };
185 |
186 | // sys_fcntl64 and sys_ioctl set file and IO modes/flags which are not emulated here
187 | env.__sys_fcntl64 = env.__sys_ioctl = function(fd, param)
188 | {
189 | return 0; // no error
190 | };
191 | }
192 |
193 | // Set the array views of various data types used to read/write to the wasm memory from JavaScript
194 | function MemorySetBufferViews()
195 | {
196 | var buf = WASM_MEMORY.buffer;
197 | HEAP32 = new Int32Array(buf);
198 | HEAPU8 = new Uint8Array(buf);
199 | HEAPU16 = new Uint16Array(buf);
200 | HEAPU32 = new Uint32Array(buf);
201 | HEAPF32 = new Float32Array(buf);
202 | }
203 |
204 | // Set up the env and wasi objects that contains the functions passed to the wasm module
205 | var env =
206 | {
207 | // sbrk gets called to increase the size of the memory heap by an increment
208 | sbrk: function(increment)
209 | {
210 | var heapOld = WASM_HEAP, heapNew = heapOld + increment, heapGrow = heapNew - WASM_MEMORY.buffer.byteLength;
211 | //console.log('[SBRK] Increment: ' + increment + ' - HEAP: ' + heapOld + ' -> ' + heapNew + (heapGrow > 0 ? ' - GROW BY ' + heapGrow + ' (' + (heapGrow>>16) + ' pages)' : ''));
212 | if (heapNew > WASM_HEAP_MAX) abort('MEM', 'Out of memory');
213 | if (heapGrow > 0) { WASM_MEMORY.grow((heapGrow+65535)>>16); MemorySetBufferViews(); }
214 | WASM_HEAP = heapNew;
215 | return heapOld|0;
216 | },
217 |
218 | // Functions querying the system time
219 | time: function(ptr) { var ret = (Date.now()/1000)|0; if (ptr) HEAPU32[ptr>>2] = ret; return ret; },
220 | gettimeofday: function(ptr) { var now = Date.now(); HEAPU32[ptr>>2]=(now/1000)|0; HEAPU32[(ptr+4)>>2]=((now % 1000)*1000)|0; },
221 |
222 | // Various functions thet can be called from wasm that abort the program
223 | __assert_fail: function(condition, filename, line, func) { abort('CRASH', 'Assert ' + ReadHeapString(condition) + ', at: ' + (filename ? ReadHeapString(filename) : 'unknown filename'), line, (func ? ReadHeapString(func) : 'unknown function')); },
224 | __cxa_uncaught_exception: function() { abort('CRASH', 'Uncaught exception!'); },
225 | __cxa_pure_virtual: function() { abort('CRASH', 'pure virtual'); },
226 | abort: function() { abort('CRASH', 'Abort called'); },
227 | longjmp: function() { abort('CRASH', 'Unsupported longjmp called'); },
228 | }, wasi = {};
229 |
230 | // Functions that do nothing in this wasm context
231 | env.setjmp = env.__cxa_atexit = env.__lock = env.__unlock = function() {};
232 |
233 | // Math functions
234 | env.ceil = env.ceilf = Math.ceil;
235 | env.exp = env.expf = Math.exp;
236 | env.floor = env.floorf = Math.floor;
237 | env.log = env.logf = Math.log;
238 | env.pow = env.powf = Math.pow;
239 | env.cos = env.cosf = Math.cos;
240 | env.sin = env.sinf = Math.sin;
241 | env.tan = env.tanf = Math.tan;
242 | env.acos = env.acosf = Math.acos;
243 | env.asin = env.asinf = Math.asin;
244 | env.sqrt = env.sqrtf = Math.sqrt;
245 | env.atan = env.atanf = Math.atan;
246 | env.atan2 = env.atan2f = Math.atan2;
247 | env.fabs = env.fabsf = env.abs = Math.abs;
248 | env.round = env.roundf = env.rint = env.rintf = Math.round;
249 |
250 | // Extend the objects with the syscall IO emulation
251 | SYSCALLS_WASM_IMPORTS(env, wasi);
252 |
253 | // Find the start point of the stack and the heap to calculate the initial memory requirements
254 | var wasmDataEnd = 64, wasmStackTop = 4096, wasmHeapBase = 65536;
255 | // This code goes through the wasm file sections according the binary encoding description
256 | // https://webassembly.org/docs/binary-encoding/
257 | for (let i = 8, sectionEnd, type, length; i < wasmBytes.length; i = sectionEnd)
258 | {
259 | // Get() gets the next single byte, GetLEB() gets a LEB128 variable-length number
260 | function Get() { return wasmBytes[i++]; }
261 | function GetLEB() { for (var s=i,r=0,n=128; n&128; i++) r|=((n=wasmBytes[i])&127)<<((i-s)*7); return r; }
262 | type = GetLEB(), length = GetLEB(), sectionEnd = i + length;
263 | if (type < 0 || type > 11 || length <= 0 || sectionEnd > wasmBytes.length) break;
264 | if (type == 6)
265 | {
266 | //Section 6 'Globals', llvm places the heap base pointer into the first value here
267 | let count = GetLEB(), gtype = Get(), mutable = Get(), opcode = GetLEB(), offset = GetLEB(), endcode = GetLEB();
268 | wasmHeapBase = offset;
269 | }
270 | if (type == 11)
271 | {
272 | //Section 11 'Data', contains data segments which the end of the last entry will indicate the start of the stack area
273 | for (let count = GetLEB(), j = 0; j != count && i < sectionEnd; j++)
274 | {
275 | let dindex = Get(), dopcode = GetLEB(), doffset = GetLEB(), dendcode = GetLEB(), dsize = GetLEB();
276 | wasmDataEnd = (doffset + dsize);
277 | wasmStackTop = (wasmDataEnd+15)>>4<<4;
278 | i += dsize;
279 | }
280 | }
281 | }
282 |
283 | // Validate the queried pointers
284 | if (wasmDataEnd <= 0 || wasmHeapBase <= wasmStackTop) abort('BOOT', 'Invalid memory layout (' + wasmDataEnd + '/' + wasmStackTop + '/' + wasmHeapBase + ')');
285 |
286 | // Set the initial wasm memory size to [DATA] + [STACK] + [256KB HEAP] (can be grown with sbrk)
287 | var wasmMemInitial = ((wasmHeapBase+65535)>>16<<16) + (256 * 1024);
288 | WASM_HEAP = wasmHeapBase;
289 | WASM_MEMORY = env.memory = new WebAssembly.Memory({initial: wasmMemInitial>>16, maximum: WASM_HEAP_MAX>>16 });
290 | MemorySetBufferViews();
291 |
292 | // Instantiate the wasm module by passing the prepared env and wasi objects containing import functions for the wasm module
293 | WebAssembly.instantiate(wasmBytes, {env:env,wasi_unstable:wasi,wasi_snapshot_preview1:wasi,wasi:wasi}).then(function (output)
294 | {
295 | // Store the list of the functions exported by the wasm module in WA.asm
296 | WA.asm = output.instance.exports;
297 |
298 | // If function '__wasm_call_ctors' (global C++ constructors) exists, call it
299 | if (WA.asm.__wasm_call_ctors) WA.asm.__wasm_call_ctors();
300 |
301 | // If function 'main' exists, call it
302 | if (WA.asm.main)
303 | {
304 | // Store the argument list with 1 entry at the far end of the stack to pass to main
305 | var argc = 1, argv = wasmStackTop, exe = 'wasmexe';
306 |
307 | // Store the program name string after the argv list
308 | WriteHeapString(exe, (argv + 8));
309 |
310 | // argv[0] contains the pointer to the exe string, argv[1] has a list terminating null pointer
311 | HEAPU32[(argv>>2) + 0] = (argv + 8)
312 | HEAPU32[(argv>>2) + 1] = 0;
313 |
314 | WA.asm.main(argc, argv);
315 | }
316 |
317 | // If the outer HTML file supplied a 'started' callback, call it
318 | if (WA.started) WA.started();
319 | })
320 | .catch(function (err)
321 | {
322 | // On an exception, if the err is 'abort' the error was already processed in the abort function above
323 | if (err !== 'abort') abort('BOOT', 'WASM instiantate error: ' + err + (err.stack ? "\n" + err.stack : ''));
324 | });
325 |
326 | });
327 |
--------------------------------------------------------------------------------
/Cpp/main.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | This is free and unencumbered software released into the public domain.
3 |
4 | Anyone is free to copy, modify, publish, use, compile, sell, or
5 | distribute this software, either in source code form or as a compiled
6 | binary, for any purpose, commercial or non-commercial, and by any
7 | means.
8 |
9 | In jurisdictions that recognize copyright laws, the author or authors
10 | of this software dedicate any and all copyright interest in the
11 | software to the public domain. We make this dedication for the benefit
12 | of the public at large and to the detriment of our heirs and
13 | successors. We intend this dedication to be an overt act of
14 | relinquishment in perpetuity of all present and future rights to this
15 | software under copyright law.
16 |
17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
21 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
22 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23 | OTHER DEALINGS IN THE SOFTWARE.
24 |
25 | For more information, please refer to
26 | */
27 |
28 | #include
29 | #include
30 | #include
31 | #include
32 |
33 | int main(int argc, char *argv[])
34 | {
35 | std::string string = "Hello C++";
36 | string += " World";
37 | printf("%s\n\n", string.c_str());
38 |
39 | std::vector vec;
40 | vec.push_back(1);
41 | vec.push_back(2);
42 | vec.push_back(3);
43 | vec.erase(vec.begin() + 1);
44 | for (int i : vec)
45 | printf("Vector element: %d\n", i);
46 | printf("\n");
47 |
48 | int* ptr = new int;
49 | printf("Allocated memory with new at %p\n\n", ptr);
50 | delete ptr;
51 |
52 | return 0;
53 | }
54 |
--------------------------------------------------------------------------------
/Cpp/output.wasm:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/schellingb/ClangWasm/94203708c127a54c89c790caeb91c00b38cb4cef/Cpp/output.wasm
--------------------------------------------------------------------------------
/Embed/Makefile:
--------------------------------------------------------------------------------
1 | #
2 | # This is free and unencumbered software released into the public domain.
3 | #
4 | # Anyone is free to copy, modify, publish, use, compile, sell, or
5 | # distribute this software, either in source code form or as a compiled
6 | # binary, for any purpose, commercial or non-commercial, and by any
7 | # means.
8 | #
9 | # In jurisdictions that recognize copyright laws, the author or authors
10 | # of this software dedicate any and all copyright interest in the
11 | # software to the public domain. We make this dedication for the benefit
12 | # of the public at large and to the detriment of our heirs and
13 | # successors. We intend this dedication to be an overt act of
14 | # relinquishment in perpetuity of all present and future rights to this
15 | # software under copyright law.
16 | #
17 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 | # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 | # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20 | # IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
21 | # OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
22 | # ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23 | # OTHER DEALINGS IN THE SOFTWARE.
24 | #
25 | # For more information, please refer to
26 | #
27 |
28 | LLVM_ROOT = D:/dev/wasm/llvm
29 | SYSTEM_ROOT = D:/dev/wasm/system
30 | WASMOPT = D:/dev/wasm/wasm-opt.exe
31 | PYTHON = D:/dev/python/python.exe
32 |
33 | PROJECT = test
34 | SOURCES = main.cpp
35 | EXPORTS = WAFNDraw WAFNAudio
36 | BUILD = RELEASE
37 |
38 | #------------------------------------------------------------------------------------------------------
39 |
40 | SPACE := $(strip ) $(strip )
41 | THIS_MAKEFILE := $(patsubst ./%,%,$(subst \,/,$(lastword $(MAKEFILE_LIST))))
42 | ISWIN := $(findstring :,$(firstword $(subst \, ,$(subst /, ,$(abspath .)))))
43 |
44 | ifeq ($(BUILD),RELEASE)
45 | SYSOUTDIR := $(dir $(THIS_MAKEFILE))system
46 | OUTDIR := Release-wasm
47 | DBGCFLAGS := -DNDEBUG
48 | LDFLAGS := -strip-all -gc-sections
49 | WOPTFLAGS := -O3
50 | LOADERJS := $(dir $(THIS_MAKEFILE))loader.minified.js
51 | else
52 | SYSOUTDIR := $(dir $(THIS_MAKEFILE))system
53 | OUTDIR := Debug-wasm
54 | DBGCFLAGS := -DDEBUG -D_DEBUG
55 | LDFLAGS :=
56 | WOPTFLAGS := -g -O0
57 | LOADERJS := $(dir $(THIS_MAKEFILE))loader.js
58 | endif
59 |
60 | # Global compiler flags
61 | CXXFLAGS := $(DBGCFLAGS) -Ofast -std=c++11 -fno-rtti -Wno-writable-strings -Wno-unknown-pragmas
62 | CCFLAGS := $(DBGCFLAGS) -Ofast -std=c99
63 |
64 | # Global compiler flags for Wasm targeting
65 | CLANGFLAGS := -target wasm32 -nostdinc
66 | CLANGFLAGS += -D__EMSCRIPTEN__ -D_LIBCPP_ABI_VERSION=2
67 | CLANGFLAGS += -fvisibility=hidden -fno-builtin -fno-exceptions -fno-threadsafe-statics
68 | CLANGFLAGS += -isystem$(SYSTEM_ROOT)/include/libcxx
69 | CLANGFLAGS += -isystem$(SYSTEM_ROOT)/include/compat
70 | CLANGFLAGS += -isystem$(SYSTEM_ROOT)/include
71 | CLANGFLAGS += -isystem$(SYSTEM_ROOT)/include/libc
72 | CLANGFLAGS += -isystem$(SYSTEM_ROOT)/lib/libc/musl/arch/emscripten
73 |
74 | # Flags for wasm-ld
75 | LDFLAGS += -no-entry -allow-undefined -import-memory
76 | LDFLAGS += -export=__wasm_call_ctors -export=malloc -export=free -export=main
77 | LDFLAGS += $(addprefix -export=,$(patsubst _%,%,$(strip $(EXPORTS))))
78 |
79 | # Project Build flags, add defines from the make command line (e.g. D=MACRO=VALUE)
80 | FLAGS := $(subst \\\, ,$(foreach F,$(subst \ ,\\\,$(D)),"-D$(F)"))
81 |
82 | # Check if there are any source files
83 | ifeq ($(SOURCES),)
84 | $(error No source files found for build)
85 | endif
86 |
87 | # Compute tool paths
88 | ifeq ($(wildcard $(subst $(SPACE),\ ,$(LLVM_ROOT))/clang*),)
89 | $(error clang executables not found in set LLVM_ROOT path ($(LLVM_ROOT)). Set custom path in $(THIS_MAKEFILE) with LLVM_ROOT = $(if $(ISWIN),d:)/path/to/clang)
90 | endif
91 | ifeq ($(wildcard $(subst $(SPACE),\ ,$(WASMOPT))),)
92 | $(error wasm-opt executable not found in set WASMOPT path ($(WASMOPT)). Fix path in $(THIS_MAKEFILE) with WASMOPT = $(if $(ISWIN),d:)/path/to/wasm-opt$(if $(ISWIN),.exe))
93 | endif
94 | PYTHON_FIND := $(if $(PYTHON),$(wildcard $(PYTHON)),$(if $(shell python -c "print 1" 2>$(if $(ISWIN),nul,/dev/null)),python))
95 | ifeq ($(PYTHON_FIND),)
96 | $(error Python executable not found in PATH and not correctly set with PYTHON setting ($(PYTHON)). Set custom path in $(THIS_MAKEFILE) with PYTHON = $(if $(ISWIN),d:)/path/to/python/python$(if $(ISWIN),.exe))
97 | endif
98 |
99 | # Surround used commands with double quotes
100 | CC := "$(LLVM_ROOT)/clang"
101 | CXX := "$(LLVM_ROOT)/clang" -x c++
102 | LD := "$(LLVM_ROOT)/wasm-ld"
103 | WASMOPT := "$(WASMOPT)"
104 | PYTHON := "$(PYTHON_FIND)"
105 |
106 | # Python one liner to delete multiple files with existance check and no stdout output
107 | CMD_DEL_FILES := $(PYTHON) -c "import sys,os;[os.path.exists(a) and os.remove(a) for a in sys.argv[1:]]"
108 |
109 | # Python one liner generate an output loader js file with base64 encoded wasm file appended to the top
110 | CMD_MAKE_JS := $(PYTHON) -c "import sys,os,base64;b=open(sys.argv[3],'rb').read();open(sys.argv[1],'w').write('WA.wasm='+chr(39)+(base64.b64encode(b) if sys.version_info[0]<3 else base64.b64encode(b).decode('ascii'))+chr(39)+';'+chr(10)+open(sys.argv[2],'r').read())"
111 |
112 | # Python one liner to gzip a file
113 | CMD_MAKE_GZ := $(PYTHON) -c "import sys,gzip;gzip.GzipFile('','wb',9,open(sys.argv[1],'wb'),0).write(open(sys.argv[2],'rb').read())"
114 |
115 | # Python one liner to generate an output loader html file from the template with tags replaced
116 | CMD_MAKE_HTML := $(PYTHON) -c "import sys;open(sys.argv[1],'w').write(open(sys.argv[2],'r').read().replace('{{PROJECT}}','$(PROJECT)').replace('{{SCRIPT}}',''))"
117 |
118 | all: $(OUTDIR)/$(PROJECT).js$(if $(filter RELEASE,$(BUILD)),.gz) $(OUTDIR)/$(PROJECT).html #analyze #run
119 | .PHONY: clean cleanall run analyze
120 |
121 | clean:
122 | $(info Removing all build files ...)
123 | @$(CMD_DEL_FILES) $(OBJS) $(OBJS:%.o=%.d) $(OUTDIR)/$(PROJECT).wasm $(OUTDIR)/$(PROJECT).js $(OUTDIR)/$(PROJECT).js.gz \
124 |
125 | # Generate a list of .o files to build, include dependency rules for source files, then compile files
126 | OBJS := $(addprefix $(OUTDIR)/,$(notdir $(patsubst %.c,%.o,$(patsubst %.cpp,%.o,$(SOURCES)))))
127 | -include $(OBJS:%.o=%.d)
128 | MAKEOBJ = $(OUTDIR)/$(basename $(notdir $(1))).o: $(1) ; $$(call COMPILE,$$@,$$<,$(2),$(3) $$(FLAGS))
129 | $(foreach F,$(filter %.cpp,$(SOURCES)),$(eval $(call MAKEOBJ,$(F),$$(CXX),$$(CXXFLAGS))))
130 | $(foreach F,$(filter %.c ,$(SOURCES)),$(eval $(call MAKEOBJ,$(F),$$(CC),$$(CCFLAGS))))
131 |
132 | $(OUTDIR)/$(PROJECT).wasm : $(THIS_MAKEFILE) $(OBJS) $(SYSOUTDIR)/System.bc
133 | $(info Linking $@ ...)
134 | @$(LD) $(LDFLAGS) -o $@ $(OBJS) $(SYSOUTDIR)/System.bc
135 | @$(WASMOPT) --legalize-js-interface $(WOPTFLAGS) $@ -o $@
136 |
137 | $(OUTDIR)/$(PROJECT).js : $(LOADERJS) $(OUTDIR)/$(PROJECT).wasm
138 | $(info Generating $@ from $^ ...)
139 | @$(CMD_MAKE_JS) $@ $^
140 |
141 | $(OUTDIR)/%.js.gz : $(OUTDIR)/%.js
142 | $(info Compressing $^ to $@ ...)
143 | @$(if $(wildcard $@),$(if $(ISWIN),del "$(subst /,\,$@)" ,rm "$@" >/dev/null),)
144 | @$(CMD_MAKE_GZ) $@ $^
145 |
146 | $(OUTDIR)/$(PROJECT).html : $(dir $(THIS_MAKEFILE))loader.html
147 | $(info $(if $(wildcard $@),Warning: Template $^ is newer than $@ - delete the local build file to have it regenerated,Generating $@ ...))
148 | @$(if $(wildcard $@),,$(CMD_MAKE_HTML) "$@" "$^")
149 |
150 | run : $(OUTDIR)/$(PROJECT).js $(OUTDIR)/$(PROJECT).html
151 | $(if $(wildcard $(BROWSER)),,$(error browser not found in set BROWSER path ($(BROWSER)). Set custom path in $(THIS_MAKEFILE) with BROWSER = $(if $(ISWIN),c:)/path/to/browser$(if $(ISWIN),.exe)))
152 | $(info Running browser '$(BROWSER)' with output '$(OUTDIR)/$(PROJECT).html' ...)
153 | @$(BROWSER) "$(OUTDIR)/$(PROJECT).html"
154 |
155 | analyze : $(OUTDIR)/$(PROJECT).wasm
156 | $(if $(wildcard $(WABT_ROOT)/wasm-objdump*),,$(error WebAssembly Binary Toolkit not found in set WABT_ROOT path ($(WABT_ROOT)). Set custom path in $(THIS_MAKEFILE) with WABT_ROOT = $(if $(ISWIN),c:)/path/to/wabt))
157 | $(info Creating $^.objdump, $^.decompile and $^.c)
158 | $(WABT_ROOT)/wasm-objdump -xd $^ >$^.objdump
159 | $(WABT_ROOT)/wasm-decompile $^ -o $^.decompile
160 | $(WABT_ROOT)/wasm2c $^ -o $^.c
161 |
162 | define COMPILE
163 | $(info $2)
164 | @$(if $(wildcard $(dir $1)),,$(shell mkdir "$(dir $1)"))
165 | @$3 $4 $(CLANGFLAGS) -MMD -MP -MF $(patsubst %.o,%.d,$1) -o $1 -c $2
166 | endef
167 |
168 | #------------------------------------------------------------------------------------------------------
169 | #if System.bc exists, don't even bother checking sources, build once and forget for now
170 | ifeq ($(if $(wildcard $(SYSOUTDIR)/System.bc),1,0),0)
171 | SYS_ADDS := emmalloc.cpp libcxx/*.cpp libcxxabi/src/cxa_guard.cpp compiler-rt/lib/builtins/*.c libc/wasi-helpers.c
172 | SYS_MUSL := complex crypt ctype dirent errno fcntl fenv internal locale math misc mman multibyte prng regex select stat stdio stdlib string termios unistd
173 |
174 | # C++ streams and locale are not included on purpose because it can increase the output up to 500kb
175 | SYS_IGNORE := iostream.cpp strstream.cpp locale.cpp thread.cpp exception.cpp
176 | SYS_IGNORE += abs.c acos.c acosf.c acosl.c asin.c asinf.c asinl.c atan.c atan2.c atan2f.c atan2l.c atanf.c atanl.c ceil.c ceilf.c ceill.c cos.c cosf.c cosl.c exp.c expf.c expl.c
177 | SYS_IGNORE += fabs.c fabsf.c fabsl.c floor.c floorf.c floorl.c log.c logf.c logl.c pow.c powf.c powl.c rintf.c round.c roundf.c sin.c sinf.c sinl.c sqrt.c sqrtf.c sqrtl.c tan.c tanf.c tanl.c
178 | SYS_IGNORE += syscall.c wordexp.c initgroups.c getgrouplist.c popen.c _exit.c alarm.c usleep.c faccessat.c iconv.c
179 |
180 | SYS_SOURCES := $(filter-out $(SYS_IGNORE:%=\%/%),$(wildcard $(addprefix $(SYSTEM_ROOT)/lib/,$(SYS_ADDS) $(SYS_MUSL:%=libc/musl/src/%/*.c))))
181 | SYS_SOURCES := $(subst $(SYSTEM_ROOT)/lib/,,$(SYS_SOURCES))
182 |
183 | ifeq ($(findstring !,$(SYS_SOURCES)),!)
184 | $(error SYS_SOURCES contains a filename with a ! character in it - Unable to continue)
185 | endif
186 |
187 | SYS_MISSING := $(filter-out $(SYS_SOURCES) $(dir $(SYS_SOURCES)),$(subst *.c,,$(subst *.cpp,,$(SYS_ADDS))) $(SYS_MUSL:%=libc/musl/src/%/))
188 | ifeq ($(if $(SYS_MISSING),1,0),1)
189 | $(error SYS_SOURCES missing the following files in $(SYSTEM_ROOT)/lib: $(SYS_MISSING))
190 | endif
191 |
192 | SYS_OLDFILES := $(filter-out $(subst /,!,$(patsubst %.c,%.o,$(patsubst %.cpp,%.o,$(SYS_SOURCES)))),$(notdir $(wildcard $(SYSOUTDIR)/temp/*.o)))
193 | ifeq ($(if $(SYS_OLDFILES),1,0),1)
194 | $(shell $(CMD_DEL_FILES) $(addprefix $(SYSOUTDIR)/temp/,$(SYS_OLDFILES)) $(SYSOUTDIR)/System.bc)
195 | endif
196 |
197 | SYS_CXXFLAGS := -Ofast -std=c++11 -fno-threadsafe-statics -fno-rtti -I$(SYSTEM_ROOT)/lib/libcxxabi/include
198 | SYS_CXXFLAGS += -DNDEBUG -D_LIBCPP_BUILDING_LIBRARY -D_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS
199 |
200 | SYS_CCFLAGS := -Ofast -std=gnu99 -fno-threadsafe-statics
201 | SYS_CCFLAGS += -DNDEBUG -Dunix -D__unix -D__unix__
202 | SYS_CCFLAGS += -isystem$(SYSTEM_ROOT)/lib/libc/musl/src/internal
203 | SYS_CCFLAGS += -Wno-dangling-else -Wno-ignored-attributes -Wno-bitwise-op-parentheses -Wno-logical-op-parentheses -Wno-shift-op-parentheses -Wno-string-plus-int
204 | SYS_CCFLAGS += -Wno-unknown-pragmas -Wno-shift-count-overflow -Wno-return-type -Wno-macro-redefined -Wno-unused-result -Wno-pointer-sign
205 |
206 | SYS_CPP_OBJS := $(addprefix $(SYSOUTDIR)/temp/,$(subst /,!,$(patsubst %.cpp,%.o,$(filter %.cpp,$(SYS_SOURCES)))))
207 | SYS_CC_OBJS := $(addprefix $(SYSOUTDIR)/temp/,$(subst /,!,$(patsubst %.c,%.o,$(filter %.c,$(SYS_SOURCES)))))
208 | $(SYS_CPP_OBJS) : ; $(call SYS_COMPILE,$@,$(subst !,/,$(patsubst $(SYSOUTDIR)/temp/%.o,$(SYSTEM_ROOT)/lib/%.cpp,$@)),$(CXX),$(SYS_CXXFLAGS))
209 | $(SYS_CC_OBJS) : ; $(call SYS_COMPILE,$@,$(subst !,/,$(patsubst $(SYSOUTDIR)/temp/%.o,$(SYSTEM_ROOT)/lib/%.c,$@)),$(CC),$(SYS_CCFLAGS))
210 |
211 | define SYS_COMPILE
212 | $(info $2)
213 | @$(if $(wildcard $(dir $1)),,$(shell mkdir "$(dir $1)"))
214 | @$3 $4 $(CLANGFLAGS) -o $1 -c $2
215 | endef
216 |
217 | $(SYSOUTDIR)/System.bc : $(SYS_CPP_OBJS) $(SYS_CC_OBJS)
218 | $(info Creating archive $@ ...)
219 | @$(LD) $(if $(ISWIN),"$(SYSOUTDIR)/temp/*.o",$(SYSOUTDIR)/temp/*.o) -r -o $@
220 | @$(if $(ISWIN),rmdir /S /Q,rm -rf) "$(SYSOUTDIR)/temp"
221 | endif #need System.bc
222 | #------------------------------------------------------------------------------------------------------
223 |
--------------------------------------------------------------------------------
/Embed/loader.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | {{PROJECT}}
7 |
8 |
9 |
{{PROJECT}}
10 |
Status: Loading...
11 |
12 |
13 |
38 | {{SCRIPT}}
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/Embed/loader.minified.js:
--------------------------------------------------------------------------------
1 | !function(){'use strict';function e(e,r){throw _=!0,WA.error(e,r),'abort'}function r(e,r,t){var n,a,o,f,u,l,c;for(n=e,a=i,f=o=r,u=o+(t||i.length)-1,l=0;l=55296&&57343>=c&&(c=65536+((1023&c)<<10)|1023&n.charCodeAt(++l)),c>127)if(c>2047)if(c>65535)if(c>2097151)if(c>67108863){if(o+5>=u)break;a[o++]=252|c>>30,a[o++]=128|c>>24&63,a[o++]=128|c>>18&63,a[o++]=128|c>>12&63,a[o++]=128|c>>6&63,a[o++]=128|63&c}else{if(o+4>=u)break;a[o++]=248|c>>24,a[o++]=128|c>>18&63,a[o++]=128|c>>12&63,a[o++]=128|c>>6&63,a[o++]=128|63&c}else{if(o+3>=u)break;a[o++]=240|c>>18,a[o++]=128|c>>12&63,a[o++]=128|c>>6&63,a[o++]=128|63&c}else{if(o+2>=u)break;a[o++]=224|c>>12,a[o++]=128|c>>6&63,a[o++]=128|63&c}else{if(o+1>=u)break;a[o++]=192|c>>6,a[o++]=128|63&c}else{if(o>=u)break;a[o++]=c}return a[o]=0,o-f}function t(e,r){var t,n,a,o,f,u,l,c,s,g,m,d,h,b;if(0===r||!e)return'';for(t=0,a=0;(!r||a!=r)&&(0!=(n=i[e+a>>0])||r);a++)t|=n;if(r||(r=a),128&t)for(o=i,f=e,u=e+r,l=String.fromCharCode,h='';;){if(f==u||!(c=o[f++]))return h;128&c?(s=63&o[f++],192!=(224&c)?(a=63&o[f++],224==(240&c)?c=(15&c)<<12|s<<6|a:(g=63&o[f++],240==(248&c)?c=(7&c)<<18|s<<12|a<<6|g:(m=63&o[f++],c=248==(252&c)?(3&c)<<24|s<<18|a<<12|g<<6|m:(1&c)<<30|s<<24|a<<18|g<<12|m<<6|(n=63&o[f++]))),h+=65536>c?l(c):l(55296|(d=c-65536)>>10,56320|1023&d)):h+=l((31&c)<<6|s)):h+=l(c)}for(b='';r>0;e+=1024,r-=1024)b+=String.fromCharCode.apply(String,i.subarray(e,e+Math.min(r,1024)));return b}function n(e){var r,t,n,a,o,i,f,u=new Uint8Array(128),l=function(t){return u[e.charCodeAt(r+t)]};for(r=0;64>r;r++)u['ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'.charCodeAt(r)]=r;for(u[45]=62,u[95]=63,t=e.length,n='='===e[t-2]?2:'='===e[t-1]?1:0,a=new Uint8Array(3*t/4-n),o=0,i=n>0?t-4:t,f=0,r=0;i>r;r+=4)f=l(0)<<18|l(1)<<12|l(2)<<6|l(3),a[o++]=f>>16&255,a[o++]=f>>8&255,a[o++]=255&f;return 1===n?(f=l(0)<<10|l(1)<<4|l(2)>>2,a[o]=f>>8&255,a[o+1]=255&f):2===n&&(a[o]=255&(l(0)<<2|l(1)>>4)),a}function a(){var e=c.buffer;o=new Int32Array(e),i=new Uint8Array(e),f=new Uint16Array(e),u=new Uint32Array(e),l=new Float32Array(e)}var o,i,f,u,l,c,s,g,m,d,h,b,A,v,x,_=!1;WA.print=WA.print||function(e){console.log(e)},WA.error=WA.error||function(e,r){WA.print('[ERROR] '+e+': '+r+'\n')},d={},(m={sbrk:function(r){var t=s,n=t+r,o=n-c.buffer.byteLength;return n>268435456&&e('MEM','Out of memory'),o>0&&(c.grow(o+65535>>16),a()),s=n,0|t},time:function(e){var r=Date.now()/1e3|0;return e&&(u[e>>2]=r),r},gettimeofday:function(e){var r=Date.now();u[e>>2]=r/1e3|0,u[e+4>>2]=r%1e3*1e3|0},__assert_fail:function(r,n,a,o){e('CRASH','Assert '+t(r)+', at: '+(n?t(n):'unknown filename'),o&&t(o))},__cxa_uncaught_exception:function(){e('CRASH','Uncaught exception!')},__cxa_pure_virtual:function(){e('CRASH','pure virtual')},abort:function(){e('CRASH','Abort called')},longjmp:function(){e('CRASH','Unsupported longjmp called')}}).setjmp=m.__cxa_atexit=m.__lock=m.__unlock=function(){},m.ceil=m.ceilf=Math.ceil,m.exp=m.expf=Math.exp,m.floor=m.floorf=Math.floor,m.log=m.logf=Math.log,m.pow=m.powf=Math.pow,m.cos=m.cosf=Math.cos,m.sin=m.sinf=Math.sin,m.tan=m.tanf=Math.tan,m.acos=m.acosf=Math.acos,m.asin=m.asinf=Math.asin,m.sqrt=m.sqrtf=Math.sqrt,m.atan=m.atanf=Math.atan,m.atan2=m.atan2f=Math.atan2,m.fabs=m.fabsf=m.abs=Math.abs,m.round=m.roundf=m.rint=m.rintf=Math.round,function(e,r){var a=0,o=WA.payload?n(WA.payload):new Uint8Array(0);delete WA.payload,e.__sys_open=function(){return a=0,9},r.fd_read=function(e,r,t,n){var f,l,c,s,g;for(f=0,l=0;t>l&&(c=u[r+8*l>>2],s=u[r+(8*l+4)>>2],g=Math.min(s,o.length-a),i.set(o.subarray(a,a+g),c),a+=g,f+=g,g>=s);l++);return u[n>>2]=f,0},r.fd_seek=function(e,r,t,n,i){return 0==n&&(a=r),1==n&&(a+=r),2==n&&(a=o.length-r),0>a&&(a=0),a>o.length&&(a=o.length),u[i+0>>2]=a,u[i+4>>2]=0,0},r.fd_write=function(e,r,n,a){var o,i,f,l,c;if(0==n)return 0;for(o=0,i='',f=0;n>f;f++){if(l=u[r+8*f>>2],0>(c=u[r+(8*f+4)>>2]))return-1;o+=c,i+=t(l,c)}return WA.print(i),u[a>>2]=o,0},r.fd_close=function(){return 0},e.__sys_fcntl64=e.__sys_ioctl=function(){return 0}}(m,d),function(n){function a(e){var r,t=h++;for(r=e.length;t>r;r++)e[r]=null;return t}function c(e){GLlastError||(GLlastError=e)}function s(e,r,t,n,a){var o,s,g,m,d;switch(r){case 6406:case 6409:case 6402:s=1;break;case 6410:s=2;break;case 6407:case 35904:s=3;break;case 6408:case 35906:s=4;break;default:return c(1280),null}switch(e){case 5121:o=1*s;break;case 5123:case 36193:o=2*s;break;case 5125:case 5126:o=4*s;break;case 34042:o=4;break;case 33635:case 32819:case 32820:o=2;break;default:return c(1280),null}switch(g=t*o,d=y,m=n>0?Math.floor((g+d-1)/d)*d*(n-1)+g:0,e){case 5121:return i.subarray(a,a+m);case 5126:return l.subarray(a>>2,a+m>>2);case 5125:case 34042:return u.subarray(a>>2,a+m>>2);case 5123:case 33635:case 32819:case 32820:case 36193:return f.subarray(a>>1,a+m>>1);default:return c(1280),null}}var m,d,h=1,b=[],A=[],v=[],x=[],_=[],w=[],p={},y=4,S=null,W=[0];for(S=new Float32Array(256),d=0;256>d;d++)W[d]=S.subarray(0,d+1);g=function(r,t){var n,a,o,i,f,u,l,c;t={majorVersion:1,minorVersion:0,antialias:!0,alpha:!1},n='';try{let a=function(e){n=e.statusMessage||n};r.addEventListener('webglcontextcreationerror',a,!1);try{m=r.getContext('webgl',t)||r.getContext('experimental-webgl',t)}finally{r.removeEventListener('webglcontextcreationerror',a,!1)}if(!m)throw'Could not create context'}catch(r){e('WEBGL',r+(n?' ('+n+')':''))}return(a=m.getSupportedExtensions())&&a.length>0&&(c=[(i='OES_')+(u='texture_')+'float',i+u+'half_float',i+'standard_derivatives',i+'vertex_array_object',(o='WEBGL_')+(l='compressed_'+u)+'s3tc',o+'depth_texture',i+'element_index_uint',(f='EXT_')+u+'filter_anisotropic',f+'frag_depth',o+'draw_buffers','ANGLE_instanced_arrays',i+u+'float_linear',i+u+'half_float_linear',f+'blend_minmax',f+'shader_texture_lod',o+l+'pvrtc',f+'color_buffer_half_float',o+'color_buffer_float',f+'sRGB',o+l+'etc1',f+'disjoint_timer_query',o+l+'etc',o+l+'astc',f+'color_buffer_float',o+l+'s3tc_srgb',f+'disjoint_timer_query_webgl2'],a.forEach(function(e){-1!=c.indexOf(e)&&m.getExtension(e)})),!0},n.glActiveTexture=function(e){m.activeTexture(e)},n.glAttachShader=function(e,r){m.attachShader(A[e],w[r])},n.glBindAttribLocation=function(e,r,n){m.bindAttribLocation(A[e],r,t(n))},n.glBindBuffer=function(e,r){m.bindBuffer(e,r?b[r]:null)},n.glBindFramebuffer=function(e,r){m.bindFramebuffer(e,r?v[r]:null)},n.glBindTexture=function(e,r){m.bindTexture(e,r?x[r]:null)},n.glBlendFunc=function(e,r){m.blendFunc(e,r)},n.glBlendFuncSeparate=function(e,r,t,n){m.blendFuncSeparate(e,r,t,n)},n.glBlendColor=function(e,r,t,n){m.blendColor(e,r,t,n)},n.glBlendEquation=function(e){m.blendEquation(e)},n.glBlendEquationSeparate=function(e,r){m.blendEquationSeparate(e,r)},n.glBufferData=function(e,r,t,n){t?m.bufferData(e,i.subarray(t,t+r),n):m.bufferData(e,r,n)},n.glBufferSubData=function(e,r,t,n){m.bufferSubData(e,r,i.subarray(n,n+t))},n.glClear=function(e){m.clear(e)},n.glClearColor=function(e,r,t,n){m.clearColor(e,r,t,n)},n.glColorMask=function(e,r,t,n){m.colorMask(!!e,!!r,!!t,!!n)},n.glCompileShader=function(e){m.compileShader(w[e])},n.glCreateProgram=function(){var e=a(A),r=m.createProgram();return r.name=e,A[e]=r,e},n.glCreateShader=function(e){var r=a(w);return w[r]=m.createShader(e),r},n.glDeleteBuffers=function(e,r){var t,n,a;for(t=0;e>t;t++)n=o[r+4*t>>2],(a=b[n])&&(m.deleteBuffer(a),a.name=0,b[n]=null)},n.glDeleteFramebuffers=function(e,r){var t,n,a;for(t=0;e>t;++t)n=o[r+4*t>>2],(a=v[n])&&(m.deleteFramebuffer(a),a.name=0,v[n]=null)},n.glDeleteProgram=function(e){if(e){var r=A[e];r?(m.deleteProgram(r),r.name=0,A[e]=null,p[e]=null):c(1281)}},n.glDeleteShader=function(e){if(e){var r=w[e];r?(m.deleteShader(r),w[e]=null):c(1281)}},n.glDeleteTextures=function(e,r){var t,n,a;for(t=0;e>t;t++)n=o[r+4*t>>2],(a=x[n])&&(m.deleteTexture(a),a.name=0,x[n]=null)},n.glDepthFunc=function(e){m.depthFunc(e)},n.glDepthMask=function(e){m.depthMask(!!e)},n.glDetachShader=function(e,r){m.detachShader(A[e],w[r])},n.glDisable=function(e){m.disable(e)},n.glDisableVertexAttribArray=function(e){m.disableVertexAttribArray(e)},n.glDrawArrays=function(e,r,t){m.drawArrays(e,r,t)},n.glDrawElements=function(e,r,t,n){m.drawElements(e,r,t,n)},n.glEnable=function(e){m.enable(e)},n.glEnableVertexAttribArray=function(e){m.enableVertexAttribArray(e)},n.glFramebufferTexture2D=function(e,r,t,n,a){m.framebufferTexture2D(e,r,t,x[n],a)},n.glGenBuffers=function(e,r){var t,n,i;for(t=0;e>t;t++){if(!(n=m.createBuffer())){for(c(1282);e>t;)o[r+4*t++>>2]=0;return}i=a(b),n.name=i,b[i]=n,o[r+4*t>>2]=i}},n.glGenFramebuffers=function(e,r){var t,n,i;for(t=0;e>t;++t){if(!(n=m.createFramebuffer())){for(c(1282);e>t;)o[r+4*t++>>2]=0;return}i=a(v),n.name=i,v[i]=n,o[r+4*t>>2]=i}},n.glGenTextures=function(e,r){var t,n,i;for(t=0;e>t;t++){if(!(n=m.createTexture())){for(c(1282);e>t;)o[r+4*t++>>2]=0;return}i=a(x),n.name=i,x[i]=n,o[r+4*t>>2]=i}},n.glGetActiveUniform=function(e,t,n,a,i,f,u){var l,c;e=A[e],(l=m.getActiveUniform(e,t))&&(n>0&&u?(c=r(l.name,u,n),a&&(o[a>>2]=c)):a&&(o[a>>2]=0),i&&(o[i>>2]=l.size),f&&(o[f>>2]=l.type))},n.glGetAttribLocation=function(e,r){return e=A[e],r=t(r),m.getAttribLocation(e,r)},n.glGetError=function(){if(GLlastError){var e=GLlastError;return GLlastError=0,e}return m.getError()},n.glGetIntegerv=function(e,r){!function(e,r){var t,n,a;if(r){switch(t=void 0,e){case 36346:t=1;break;case 36344:return;case 36345:t=0;break;case 34466:t=m.getParameter(34467).length}if(void 0===t)switch(typeof(n=m.getParameter(e))){case'number':t=n;break;case'boolean':t=n?1:0;break;case'string':return void c(1280);case'object':if(null===n)switch(e){case 34964:case 35725:case 34965:case 36006:case 36007:case 32873:case 34068:t=0;break;default:return void c(1280)}else{if(n instanceof Float32Array||n instanceof Uint32Array||n instanceof Int32Array||n instanceof Array){for(a=0;a>2]=n[a];return}if(!(n instanceof WebGLBuffer||n instanceof WebGLProgram||n instanceof WebGLFramebuffer||n instanceof WebGLRenderbuffer||n instanceof WebGLTexture))return void c(1280);t=0|n.name}break;default:return void c(1280)}o[r>>2]=t}else c(1281)}(e,r)},n.glGetProgramInfoLog=function(e,t,n,a){var i,f=m.getProgramInfoLog(A[e]);null===f&&(f='(unknown error)'),t>0&&a?(i=r(f,a,t),n&&(o[n>>2]=i)):n&&(o[n>>2]=0)},n.glGetProgramiv=function(e,r,t){var n,a,i,f,u,l,s;if(t)if(h>e)if(n=p[e])if(35716==r)null===(a=m.getProgramInfoLog(A[e]))&&(a='(unknown error)'),o[t>>2]=a.length+1;else if(35719==r)o[t>>2]=n.maxUniformLength;else if(35722==r){if(-1==n.maxAttributeLength)for(e=A[e],i=m.getProgramParameter(e,m.ACTIVE_ATTRIBUTES),n.maxAttributeLength=0,f=0;i>f;++f)u=m.getActiveAttrib(e,f),n.maxAttributeLength=Math.max(n.maxAttributeLength,u.name.length+1);o[t>>2]=n.maxAttributeLength}else if(35381==r){if(-1==n.maxUniformBlockNameLength)for(e=A[e],l=m.getProgramParameter(e,m.ACTIVE_UNIFORM_BLOCKS),n.maxUniformBlockNameLength=0,f=0;l>f;++f)s=m.getActiveUniformBlockName(e,f),n.maxUniformBlockNameLength=Math.max(n.maxUniformBlockNameLength,s.length+1);o[t>>2]=n.maxUniformBlockNameLength}else o[t>>2]=m.getProgramParameter(A[e],r);else c(1282);else c(1281);else c(1281)},n.glGetShaderInfoLog=function(e,t,n,a){var i,f=m.getShaderInfoLog(w[e]);null===f&&(f='(unknown error)'),t>0&&a?(i=r(f,a,t),n&&(o[n>>2]=i)):n&&(o[n>>2]=0)},n.glGetShaderiv=function(e,r,t){var n,a,i;t?35716==r?(null===(n=m.getShaderInfoLog(w[e]))&&(n='(unknown error)'),o[t>>2]=n.length+1):35720==r?(i=null===(a=m.getShaderSource(w[e]))||0==a.length?0:a.length+1,o[t>>2]=i):o[t>>2]=m.getShaderParameter(w[e],r):c(1281)},n.glGetUniformLocation=function(e,r){var n,a,o,i,f;if(n=0,-1!==(r=t(r)).indexOf(']',r.length-1)){if(a=r.lastIndexOf('['),(o=r.slice(a+1,-1)).length>0&&0>(n=parseInt(o)))return-1;r=r.slice(0,a)}return(i=p[e])&&(f=i.uniforms[r])&&no;++o)if(f=(i=m.getActiveUniform(d,o)).name,r.maxUniformLength=Math.max(r.maxUniformLength,f.length+1),-1!==f.indexOf(']',f.length-1)&&(u=f.lastIndexOf('['),f=f.slice(0,u)),null!=(l=m.getUniformLocation(d,f)))for(c=a(_),t[f]=[i.size,c],_[c]=l,s=1;si;++i)u+=a?0>(f=o[a+4*i>>2])?t(o[n+4*i>>2]):t(o[n+4*i>>2],f):t(o[n+4*i>>2]);return u}(0,r,n,a);m.shaderSource(w[e],i)},n.glTexImage2D=function(e,r,t,n,a,o,i,f,u){var l=null;u&&(l=s(f,i,n,a,u)),m.texImage2D(e,r,t,n,a,o,i,f,l)},n.glTexParameteri=function(e,r,t){m.texParameteri(e,r,t)},n.glTexSubImage2D=function(e,r,t,n,a,o,i,f,u){var l=null;u&&(l=s(f,i,a,o,u)),m.texSubImage2D(e,r,t,n,a,o,i,f,l)},n.glUniform1f=function(e,r){m.uniform1f(_[e],r)},n.glUniform1i=function(e,r){m.uniform1i(_[e],r)},n.glUniform2f=function(e,r,t){m.uniform2f(_[e],r,t)},n.glUniform3f=function(e,r,t,n){m.uniform3f(_[e],r,t,n)},n.glUniform3fv=function(e,r,t){var n,a,o;if(3*r>256)n=l.subarray(t>>2,t+12*r>>2);else for(n=W[3*r-1],a=t>>2,o=0;o!=3*r;o++)n[o]=l[a+o];m.uniform3fv(_[e],n)},n.glUniform4f=function(e,r,t,n,a){m.uniform4f(_[e],r,t,n,a)},n.glUniformMatrix4fv=function(e,r,t,n){var a,o,i;if((r<<=4)>256)a=l.subarray(n>>2,n+4*r>>2);else for(a=W[r-1],o=n>>2,i=0;i!=r;i+=4)a[i]=l[o+i],a[i+1]=l[o+i+1],a[i+2]=l[o+i+2],a[i+3]=l[o+i+3];m.uniformMatrix4fv(_[e],!!t,a)},n.glUseProgram=function(e){m.useProgram(e?A[e]:null)},n.glVertexAttrib4f=function(e,r,t,n,a){m.vertexAttrib4f(e,r,t,n,a)},n.glVertexAttrib4fv=function(e,r){m.vertexAttrib4f(e,l[r>>2],l[r+4>>2],l[r+8>>2],l[r+12>>2])},n.glVertexAttribPointer=function(e,r,t,n,a,o){m.vertexAttribPointer(e,r,t,!!n,a,o)},n.glViewport=function(e,r,t,n){m.viewport(e,r,t,n)}}(m),function(e){var r;e.WAJS_SetupCanvas=function(e,t){var n,a=WA.canvas;a.width=e,a.height=t,a.height=a.clientHeight,a.width=a.clientWidth,g(a)&&(r=Date.now(),n=function(){_||(window.requestAnimationFrame(n),WA.asm.WAFNDraw())},window.requestAnimationFrame(n))},e.WAJS_GetTime=function(){return Date.now()-r},e.WAJS_StartAudio=function(){var e,r,t,n,a,o,i,f,u,c;try{e=new((u=window)[c='AudioContext']||u['moz'+c]||u['webkit'+c]||u['ms'+c])}catch(e){}e?(r=0,n=(t=882)/44100,a=0,o=0,i=[{length:0}],f=0,setInterval(function(){var u,c,s,g;if(('suspended'!=e.state||(e.resume(),'suspended'!=e.state))&&(0==(u=e.currentTime)&&(r=0),n>=r-u)){if(i[0].length!=t)for(WA.asm.free(a),o=(a=WA.asm.malloc(t<<3))>>2,c=0;4!=c;c++)i[c]=e.createBuffer(2,t,44100);WA.asm.WAFNAudio(a,t)&&((s=i[f=(f+1)%4]).getChannelData(0).set(l.subarray(o,o+t)),s.getChannelData(1).set(l.subarray(o+t,o+(t<<1))),(g=e.createBufferSource()).connect(e.destination),g.buffer=s,g[g.start?'start':'noteOn'](.005+r)),u>r&&u>.5&&(10*n>u-r&&11025>t&&document.hasFocus()&&(n=(t+=441)/44100,WA.print('Warning: Audio callback had starved sending audio by '+(u-r)+' seconds. (extending samples to: '+t+')\n')),r=u+(document.hasFocus()?0:1.5)),r+=n}},10)):WA.print('Warning: WebAudio not supported\n')}}(m),WA.wasm||e('BOOT','Missing Wasm data'),h=n(WA.wasm),delete WA.wasm,b=64,A=4096,v=65536;for(let e,r,t,n=8;nr||r>11||0>=t||e>h.length)break;if(6==r){p(),w(),w(),p();let e=p();p(),v=e}if(11==r)for(let r=p(),t=0;t!=r&&e>n;t++){w(),p();let e=p(),r=(p(),p());A=(b=e+r)+15>>4<<4,n+=r}}b>0&&v>A||e('BOOT','Invalid memory layout ('+b+'/'+A+'/'+v+')'),x=262144+(v+65535>>16<<16),s=v,c=m.memory=new WebAssembly.Memory({initial:x>>16,maximum:4096}),a(),WebAssembly.instantiate(h,{env:m,wasi_unstable:d,wasi_snapshot_preview1:d,wasi:d}).then(function(e){if(WA.asm=e.instance.exports,WA.asm.__wasm_call_ctors&&WA.asm.__wasm_call_ctors(),WA.asm.main){var t=A;r('wasmexe',t+8),u[0+(t>>2)]=t+8,u[1+(t>>2)]=0,WA.asm.main(1,t)}WA.started&&WA.started()}).catch(function(r){'abort'!==r&&e('BOOT','WASM instiantate error: '+r+(r.stack?'\n'+r.stack:''))})}();
--------------------------------------------------------------------------------
/Embed/main.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | This is free and unencumbered software released into the public domain.
3 |
4 | Anyone is free to copy, modify, publish, use, compile, sell, or
5 | distribute this software, either in source code form or as a compiled
6 | binary, for any purpose, commercial or non-commercial, and by any
7 | means.
8 |
9 | In jurisdictions that recognize copyright laws, the author or authors
10 | of this software dedicate any and all copyright interest in the
11 | software to the public domain. We make this dedication for the benefit
12 | of the public at large and to the detriment of our heirs and
13 | successors. We intend this dedication to be an overt act of
14 | relinquishment in perpetuity of all present and future rights to this
15 | software under copyright law.
16 |
17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
21 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
22 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23 | OTHER DEALINGS IN THE SOFTWARE.
24 |
25 | For more information, please refer to
26 | */
27 |
28 | #include
29 | #include
30 | #include
31 |
32 | #define GL_GLEXT_PROTOTYPES
33 | #define EGL_EGLEXT_PROTOTYPES
34 | #include
35 | #include
36 |
37 | // Functions defined in loader.js
38 | extern "C" void WAJS_SetupCanvas(int width, int height);
39 | extern "C" unsigned int WAJS_GetTime();
40 | extern "C" void WAJS_StartAudio();
41 |
42 | static const char* vertex_shader_text =
43 | "precision lowp float;"
44 | "uniform mat4 uMVP;"
45 | "attribute vec4 aPos;"
46 | "attribute vec3 aCol;"
47 | "varying vec3 vCol;"
48 | "void main()"
49 | "{"
50 | "vCol = aCol;"
51 | "gl_Position = uMVP * aPos;"
52 | "}";
53 |
54 | static const char* fragment_shader_text =
55 | "precision lowp float;"
56 | "varying vec3 vCol;"
57 | "void main()"
58 | "{"
59 | "gl_FragColor = vec4(vCol, 1.0);"
60 | "}";
61 |
62 | typedef struct Vertex { float x, y, r, g, b; } Vertex;
63 | static GLuint program, vertex_buffer;
64 | static GLint uMVP_location, aPos_location, aCol_location;
65 |
66 | // This function is called at startup
67 | int main(int argc, char *argv[])
68 | {
69 |
70 | std::string string = "Hello C++";
71 | string += " World";
72 | printf("%s\n\n", string.c_str());
73 |
74 | std::vector vec;
75 | vec.push_back(1);
76 | vec.push_back(2);
77 | vec.push_back(3);
78 | vec.erase(vec.begin() + 1);
79 | for (int i : vec)
80 | printf("Vector element: %d\n", i);
81 | printf("\n");
82 |
83 | int* ptr = new int();
84 | printf("Allocated memory with new at %p\n\n", ptr);
85 | delete ptr;
86 |
87 | printf("Setting up rendering canvas...\n\n", ptr);
88 | WAJS_SetupCanvas(640, 480);
89 | glViewport(0, 0, 640, 480);
90 |
91 | GLuint vertex_shader = glCreateShader(GL_VERTEX_SHADER);
92 | glShaderSource(vertex_shader, 1, &vertex_shader_text, NULL);
93 | glCompileShader(vertex_shader);
94 |
95 | GLuint fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);
96 | glShaderSource(fragment_shader, 1, &fragment_shader_text, NULL);
97 | glCompileShader(fragment_shader);
98 |
99 | program = glCreateProgram();
100 | glAttachShader(program, vertex_shader);
101 | glAttachShader(program, fragment_shader);
102 | glLinkProgram(program);
103 |
104 | uMVP_location = glGetUniformLocation(program, "uMVP");
105 | aPos_location = glGetAttribLocation(program, "aPos");
106 | aCol_location = glGetAttribLocation(program, "aCol");
107 |
108 | glGenBuffers(1, &vertex_buffer);
109 | glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer);
110 |
111 | glEnableVertexAttribArray(aPos_location);
112 | glVertexAttribPointer(aPos_location, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)0);
113 | glEnableVertexAttribArray(aCol_location);
114 | glVertexAttribPointer(aCol_location, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)(sizeof(float) * 2));
115 |
116 | printf("Starting audio output...\n\n", ptr);
117 | WAJS_StartAudio();
118 |
119 | return 0;
120 | }
121 |
122 | // This function is called by loader.js every frame
123 | extern "C" void WAFNDraw()
124 | {
125 | float f = ((WAJS_GetTime() % 1000) / 1000.0f);
126 |
127 | glClear(GL_COLOR_BUFFER_BIT);
128 |
129 | Vertex vertices[3] =
130 | {
131 | { -0.6f, -0.4f, 1.f, 0.f, 0.f },
132 | { 0.6f, -0.4f, 0.f, 1.f, 0.f },
133 | { 0.f, 0.6f, 0.f, 0.f, 1.f },
134 | };
135 | vertices[0].x = sinf(f * 3.14159f) * 0.6f;
136 | vertices[1].x = sinf(f * 3.14159f) * -0.6f;
137 | glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer);
138 | glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
139 |
140 | GLfloat mvp[4*4] = { 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 1 };
141 | glUseProgram(program);
142 | glUniformMatrix4fv(uMVP_location, 1, GL_FALSE, mvp);
143 | glDrawArrays(GL_TRIANGLES, 0, 3);
144 | }
145 |
146 | // This function is called by loader.js to feed audio
147 | extern "C" bool WAFNAudio(float* sample_buffer, unsigned int samples)
148 | {
149 | // Render 220~440 HZ sine wave at 25% volume into both channels
150 | float f = ((WAJS_GetTime() % 1000) / 1000.0f);
151 | float delta = (220.0f * (1.5f + 0.5f * sinf(f * 3.14159f))) / 44100.0f;
152 |
153 | float *pLeft = sample_buffer, *pRight = sample_buffer + samples;
154 | for(unsigned int i = 0; i < samples; i++)
155 | {
156 | static float wave;
157 | wave = fmod(wave + delta, 1.0f);
158 | pLeft[i] = pRight[i] = sinf(2.0f * 3.14159f * wave) * 0.25f;
159 | }
160 | return true;
161 | }
162 |
--------------------------------------------------------------------------------
/GenJS/Makefile:
--------------------------------------------------------------------------------
1 | #
2 | # This is free and unencumbered software released into the public domain.
3 | #
4 | # Anyone is free to copy, modify, publish, use, compile, sell, or
5 | # distribute this software, either in source code form or as a compiled
6 | # binary, for any purpose, commercial or non-commercial, and by any
7 | # means.
8 | #
9 | # In jurisdictions that recognize copyright laws, the author or authors
10 | # of this software dedicate any and all copyright interest in the
11 | # software to the public domain. We make this dedication for the benefit
12 | # of the public at large and to the detriment of our heirs and
13 | # successors. We intend this dedication to be an overt act of
14 | # relinquishment in perpetuity of all present and future rights to this
15 | # software under copyright law.
16 | #
17 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 | # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 | # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20 | # IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
21 | # OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
22 | # ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23 | # OTHER DEALINGS IN THE SOFTWARE.
24 | #
25 | # For more information, please refer to
26 | #
27 |
28 | LLVM_ROOT = D:/dev/wasm/llvm
29 | SYSTEM_ROOT = D:/dev/wasm/system
30 | WASMOPT = D:/dev/wasm/wasm-opt.exe
31 |
32 | SOURCES = main.c
33 | BUILD = RELEASE
34 |
35 | #------------------------------------------------------------------------------------------------------
36 |
37 | ifeq ($(BUILD),RELEASE)
38 | OUTDIR := Release-wasm
39 | DBGCFLAGS := -DNDEBUG
40 | LDFLAGS := -strip-all -gc-sections
41 | WOPTFLAGS := -O3
42 | else
43 | OUTDIR := Debug-wasm
44 | DBGCFLAGS := -DDEBUG -D_DEBUG
45 | LDFLAGS :=
46 | WOPTFLAGS := -g -O0
47 | endif
48 |
49 | # Global compiler flags
50 | CXXFLAGS := $(DBGCFLAGS) -Ofast -std=c++11 -fno-rtti -Wno-writable-strings -Wno-unknown-pragmas
51 | CCFLAGS := $(DBGCFLAGS) -Ofast -std=c99
52 |
53 | # Global compiler flags for Wasm targeting
54 | CLANGFLAGS := -target wasm32 -nostdinc
55 | CLANGFLAGS += -D__EMSCRIPTEN__ -D_LIBCPP_ABI_VERSION=2
56 | CLANGFLAGS += -fvisibility=hidden -fno-builtin -fno-exceptions -fno-threadsafe-statics
57 | CLANGFLAGS += -isystem$(SYSTEM_ROOT)/include/libcxx
58 | CLANGFLAGS += -isystem$(SYSTEM_ROOT)/include/compat
59 | CLANGFLAGS += -isystem$(SYSTEM_ROOT)/include
60 | CLANGFLAGS += -isystem$(SYSTEM_ROOT)/include/libc
61 | CLANGFLAGS += -isystem$(SYSTEM_ROOT)/lib/libc/musl/arch/emscripten
62 |
63 | # Flags for wasm-ld
64 | LDFLAGS += -no-entry -allow-undefined -import-memory
65 | LDFLAGS += -export=__wasm_call_ctors -export=malloc -export=free -export=main
66 | LDFLAGS += $(addprefix -export=,$(patsubst _%,%,$(strip $(EXPORTS))))
67 |
68 | # Project Build flags, add defines from the make command line (e.g. D=MACRO=VALUE)
69 | FLAGS := $(subst \\\, ,$(foreach F,$(subst \ ,\\\,$(D)),"-D$(F)"))
70 |
71 | # Check if there are any source files
72 | ifeq ($(SOURCES),)
73 | $(error No source files found for build)
74 | endif
75 |
76 | # Compute tool paths
77 | ISWIN := $(findstring :,$(firstword $(subst \, ,$(subst /, ,$(abspath .)))))
78 | PIPETONULL := $(if $(ISWIN),>nul 2>nul,>/dev/null 2>/dev/null)
79 | ifeq ($(wildcard $(subst $(strip ) ,\ ,$(LLVM_ROOT))/clang*),)
80 | $(error clang executables not found in set LLVM_ROOT path ($(LLVM_ROOT)). Set custom path in this makefile with LLVM_ROOT = $(if $(ISWIN),d:)/path/to/clang)
81 | endif
82 | ifeq ($(wildcard $(subst $(strip ) ,\ ,$(WASMOPT))),)
83 | $(error wasm-opt executable not found in set WASMOPT path ($(WASMOPT)). Fix path in this makefile with WASMOPT = $(if $(ISWIN),d:)/path/to/wasm-opt$(if $(ISWIN),.exe))
84 | endif
85 |
86 | # Surround used commands with double quotes
87 | CC := "$(LLVM_ROOT)/clang"
88 | CXX := "$(LLVM_ROOT)/clang" -x c++
89 | LD := "$(LLVM_ROOT)/wasm-ld"
90 |
91 | all: $(OUTDIR)/loader.js $(OUTDIR)/loader.html $(OUTDIR)/output.wasm
92 | .PHONY: clean cleanall run analyze
93 |
94 | clean:
95 | $(info Removing all build files ...)
96 | @$(if $(wildcard $(OUTDIR)),$(if $(ISWIN),rmdir /S /Q,rm -rf) "$(OUTDIR)" $(PIPETONULL))
97 |
98 | # Generate a list of .o files to build, include dependency rules for source files, then compile files
99 | OBJS := $(addprefix $(OUTDIR)/,$(notdir $(patsubst %.c,%.o,$(patsubst %.cpp,%.o,$(SOURCES)))))
100 | -include $(OBJS:%.o=%.d)
101 | MAKEOBJ = $(OUTDIR)/$(basename $(notdir $(1))).o: $(1) ; $$(call COMPILE,$$@,$$<,$(2),$(3) $$(FLAGS))
102 | $(foreach F,$(filter %.cpp,$(SOURCES)),$(eval $(call MAKEOBJ,$(F),$$(CXX),$$(CXXFLAGS))))
103 | $(foreach F,$(filter %.c ,$(SOURCES)),$(eval $(call MAKEOBJ,$(F),$$(CC),$$(CCFLAGS))))
104 |
105 | $(OUTDIR)/output.wasm : Makefile $(OBJS) System.bc
106 | $(info Linking $@ ...)
107 | @$(LD) $(LDFLAGS) -o $@ $(OBJS) System.bc
108 | @"$(WASMOPT)" --legalize-js-interface $(WOPTFLAGS) $@ -o $@
109 |
110 | $(OUTDIR)/loader.js : loader.js
111 | $(info Copying $^ to $@ ...)
112 | @$(if $(wildcard $(OUTDIR)),,$(shell mkdir "$(OUTDIR)"))
113 | @$(if $(ISWIN),copy,cp) "$^" "$@" $(PIPETONULL)
114 |
115 | $(OUTDIR)/loader.html : loader.html
116 | $(if $(wildcard $(OUTDIR)),,$(shell mkdir "$(OUTDIR)"))
117 | @$(if $(ISWIN),copy,cp) "$^" "$@" $(PIPETONULL)
118 |
119 | define COMPILE
120 | $(info $2)
121 | @$(if $(wildcard $(dir $1)),,$(shell mkdir "$(dir $1)"))
122 | @$3 $4 $(CLANGFLAGS) -MMD -MP -MF $(patsubst %.o,%.d,$1) -o $1 -c $2
123 | endef
124 |
125 | #------------------------------------------------------------------------------------------------------
126 | #if System.bc exists, don't even bother checking sources, build once and forget for now
127 | ifeq ($(if $(wildcard System.bc),1,0),0)
128 | SYS_ADDS := emmalloc.cpp libcxx/*.cpp libcxxabi/src/cxa_guard.cpp compiler-rt/lib/builtins/*.c libc/wasi-helpers.c
129 | SYS_MUSL := complex crypt ctype dirent errno fcntl fenv internal locale math misc mman multibyte prng regex select stat stdio stdlib string termios unistd
130 |
131 | # C++ streams and locale are not included on purpose because it can increase the output up to 500kb
132 | SYS_IGNORE := iostream.cpp strstream.cpp locale.cpp thread.cpp exception.cpp
133 | SYS_IGNORE += abs.c acos.c acosf.c acosl.c asin.c asinf.c asinl.c atan.c atan2.c atan2f.c atan2l.c atanf.c atanl.c ceil.c ceilf.c ceill.c cos.c cosf.c cosl.c exp.c expf.c expl.c
134 | SYS_IGNORE += fabs.c fabsf.c fabsl.c floor.c floorf.c floorl.c log.c logf.c logl.c pow.c powf.c powl.c rintf.c round.c roundf.c sin.c sinf.c sinl.c sqrt.c sqrtf.c sqrtl.c tan.c tanf.c tanl.c
135 | SYS_IGNORE += syscall.c wordexp.c initgroups.c getgrouplist.c popen.c _exit.c alarm.c usleep.c faccessat.c iconv.c
136 |
137 | SYS_SOURCES := $(filter-out $(SYS_IGNORE:%=\%/%),$(wildcard $(addprefix $(SYSTEM_ROOT)/lib/,$(SYS_ADDS) $(SYS_MUSL:%=libc/musl/src/%/*.c))))
138 | SYS_SOURCES := $(subst $(SYSTEM_ROOT)/lib/,,$(SYS_SOURCES))
139 |
140 | ifeq ($(findstring !,$(SYS_SOURCES)),!)
141 | $(error SYS_SOURCES contains a filename with a ! character in it - Unable to continue)
142 | endif
143 |
144 | SYS_MISSING := $(filter-out $(SYS_SOURCES) $(dir $(SYS_SOURCES)),$(subst *.c,,$(subst *.cpp,,$(SYS_ADDS))) $(SYS_MUSL:%=libc/musl/src/%/))
145 | ifeq ($(if $(SYS_MISSING),1,0),1)
146 | $(error SYS_SOURCES missing the following files in $(SYSTEM_ROOT)/lib: $(SYS_MISSING))
147 | endif
148 |
149 | SYS_OLDFILES := $(filter-out $(subst /,!,$(patsubst %.c,%.o,$(patsubst %.cpp,%.o,$(SYS_SOURCES)))),$(notdir $(wildcard temp/*.o)))
150 | $(foreach F,$(SYS_OLDFILES),$(shell $(if $(ISWIN),del "temp\,rm "temp/)$(F)" $(PIPETONULL)))
151 |
152 | SYS_CXXFLAGS := -Ofast -std=c++11 -fno-threadsafe-statics -fno-rtti -I$(SYSTEM_ROOT)/lib/libcxxabi/include
153 | SYS_CXXFLAGS += -DNDEBUG -D_LIBCPP_BUILDING_LIBRARY -D_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS
154 |
155 | SYS_CCFLAGS := -Ofast -std=gnu99 -fno-threadsafe-statics
156 | SYS_CCFLAGS += -DNDEBUG -Dunix -D__unix -D__unix__
157 | SYS_CCFLAGS += -isystem$(SYSTEM_ROOT)/lib/libc/musl/src/internal
158 | SYS_CCFLAGS += -Wno-dangling-else -Wno-ignored-attributes -Wno-bitwise-op-parentheses -Wno-logical-op-parentheses -Wno-shift-op-parentheses -Wno-string-plus-int
159 | SYS_CCFLAGS += -Wno-unknown-pragmas -Wno-shift-count-overflow -Wno-return-type -Wno-macro-redefined -Wno-unused-result -Wno-pointer-sign
160 |
161 | SYS_CPP_OBJS := $(addprefix temp/,$(subst /,!,$(patsubst %.cpp,%.o,$(filter %.cpp,$(SYS_SOURCES)))))
162 | SYS_CC_OBJS := $(addprefix temp/,$(subst /,!,$(patsubst %.c,%.o,$(filter %.c,$(SYS_SOURCES)))))
163 | $(SYS_CPP_OBJS) : ; $(call SYS_COMPILE,$@,$(subst !,/,$(patsubst temp/%.o,$(SYSTEM_ROOT)/lib/%.cpp,$@)),$(CXX),$(SYS_CXXFLAGS))
164 | $(SYS_CC_OBJS) : ; $(call SYS_COMPILE,$@,$(subst !,/,$(patsubst temp/%.o,$(SYSTEM_ROOT)/lib/%.c,$@)),$(CC),$(SYS_CCFLAGS))
165 |
166 | define SYS_COMPILE
167 | $(info $2)
168 | @$(if $(wildcard $(dir $1)),,$(shell mkdir "$(dir $1)"))
169 | @$3 $4 $(CLANGFLAGS) -o $1 -c $2
170 | endef
171 |
172 | System.bc : $(SYS_CPP_OBJS) $(SYS_CC_OBJS)
173 | $(info Creating archive $@ ...)
174 | @$(LD) $(if $(ISWIN),"temp/*.o",temp/*.o) -r -o $@
175 | @$(if $(ISWIN),rmdir /S /Q,rm -rf) "temp"
176 | endif #need System.bc
177 | #------------------------------------------------------------------------------------------------------
178 |
--------------------------------------------------------------------------------
/GenJS/loader.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | WebAssembly Sample: Generate JavaScript Functions from C
7 |
8 |
9 |
WebAssembly Sample: Generate JavaScript Functions from C
10 |
11 |
Loading...
12 |
34 |
35 |
36 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/GenJS/loader.js:
--------------------------------------------------------------------------------
1 | /*
2 | This is free and unencumbered software released into the public domain.
3 |
4 | Anyone is free to copy, modify, publish, use, compile, sell, or
5 | distribute this software, either in source code form or as a compiled
6 | binary, for any purpose, commercial or non-commercial, and by any
7 | means.
8 |
9 | In jurisdictions that recognize copyright laws, the author or authors
10 | of this software dedicate any and all copyright interest in the
11 | software to the public domain. We make this dedication for the benefit
12 | of the public at large and to the detriment of our heirs and
13 | successors. We intend this dedication to be an overt act of
14 | relinquishment in perpetuity of all present and future rights to this
15 | software under copyright law.
16 |
17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
21 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
22 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23 | OTHER DEALINGS IN THE SOFTWARE.
24 |
25 | For more information, please refer to
26 | */
27 |
28 | // Fetch the .wasm file and store its bytes into the byte array wasmBytes
29 | fetch(WA.module).then(res => res.arrayBuffer()).then(function(wasmBytes){'use strict';wasmBytes = new Uint8Array(wasmBytes);
30 |
31 | // Some global state variables and max heap definition
32 | var HEAP32, HEAPU8, HEAPU16, HEAPU32, HEAPF32;
33 | var WASM_MEMORY, WASM_HEAP, WASM_HEAP_MAX = 256*1024*1024; //max 256MB
34 |
35 | // Define print and error functions if not yet defined by the outer html file
36 | WA.print = WA.print || function (msg) { console.log(msg); };
37 | WA.error = WA.error || function (code, msg) { WA.print('[ERROR] ' + code + ': ' + msg + '\n'); };
38 |
39 | // A generic abort function that if called stops the execution of the program and shows an error
40 | function abort(code, msg)
41 | {
42 | WA.error(code, msg);
43 | throw 'abort';
44 | }
45 |
46 | // Puts a string from javascript onto the wasm memory heap (encoded as UTF8) (max_length is optional)
47 | WA.WriteHeapString = function(str, ptr, max_length)
48 | {
49 | for (var e=str,r=HEAPU8,f=ptr,i=(max_length?max_length:HEAPU8.length),a=f,t=f+i-1,b=0;b>6,r[f++]=128|63&k;}
54 | else if(k<=65535){if(t<=f+2)break;r[f++]=224|k>>12,r[f++]=128|k>>6&63,r[f++]=128|63&k;}
55 | else if(k<=2097151){if(t<=f+3)break;r[f++]=240|k>>18,r[f++]=128|k>>12&63,r[f++]=128|k>>6&63,r[f++]=128|63&k;}
56 | else if(k<=67108863){if(t<=f+4)break;r[f++]=248|k>>24,r[f++]=128|k>>18&63,r[f++]=128|k>>12&63,r[f++]=128|k>>6&63,r[f++]=128|63&k;}
57 | else{if(t<=f+5)break;r[f++]=252|k>>30,r[f++]=128|k>>24&63,r[f++]=128|k>>18&63,r[f++]=128|k>>12&63,r[f++]=128|k>>6&63,r[f++]=128|63&k;}
58 | }
59 | return r[f]=0,f-a;
60 | }
61 |
62 | // Reads a string from the wasm memory heap to javascript (decoded as UTF8)
63 | WA.ReadHeapString = function(ptr, length)
64 | {
65 | if (length === 0 || !ptr) return '';
66 | for (var hasUtf = 0, t, i = 0; !length || i != length; i++)
67 | {
68 | t = HEAPU8[((ptr)+(i))>>0];
69 | if (t == 0 && !length) break;
70 | hasUtf |= t;
71 | }
72 | if (!length) length = i;
73 | if (hasUtf & 128)
74 | {
75 | for(var r=HEAPU8,o=ptr,p=ptr+length,F=String.fromCharCode,e,f,i,n,C,t,a,g='';;)
76 | {
77 | if(o==p||(e=r[o++],!e)) return g;
78 | 128&e?(f=63&r[o++],192!=(224&e)?(i=63&r[o++],224==(240&e)?e=(15&e)<<12|f<<6|i:(n=63&r[o++],240==(248&e)?e=(7&e)<<18|f<<12|i<<6|n:(C=63&r[o++],248==(252&e)?e=(3&e)<<24|f<<18|i<<12|n<<6|C:(t=63&r[o++],e=(1&e)<<30|f<<24|i<<18|n<<12|C<<6|t))),65536>e?g+=F(e):(a=e-65536,g+=F(55296|a>>10,56320|1023&a))):g+=F((31&e)<<6|f)):g+=F(e);
79 | }
80 | }
81 | // split up into chunks, because .apply on a huge string can overflow the stack
82 | for (var ret = '', curr; length > 0; ptr += 1024, length -= 1024)
83 | ret += String.fromCharCode.apply(String, HEAPU8.subarray(ptr, ptr + Math.min(length, 1024)));
84 | return ret;
85 | }
86 |
87 | // Set the array views of various data types used to read/write to the wasm memory from JavaScript
88 | function MemorySetBufferViews()
89 | {
90 | var buf = WASM_MEMORY.buffer;
91 | HEAP32 = new Int32Array(buf);
92 | HEAPU8 = new Uint8Array(buf);
93 | HEAPU16 = new Uint16Array(buf);
94 | HEAPU32 = new Uint32Array(buf);
95 | HEAPF32 = new Float32Array(buf);
96 | }
97 |
98 | // Set up the env and wasi objects that contains the functions passed to the wasm module
99 | var env =
100 | {
101 | // sbrk gets called to increase the size of the memory heap by an increment
102 | sbrk: function(increment)
103 | {
104 | var heapOld = WASM_HEAP, heapNew = heapOld + increment, heapGrow = heapNew - WASM_MEMORY.buffer.byteLength;
105 | //console.log('[SBRK] Increment: ' + increment + ' - HEAP: ' + heapOld + ' -> ' + heapNew + (heapGrow > 0 ? ' - GROW BY ' + heapGrow + ' (' + (heapGrow>>16) + ' pages)' : ''));
106 | if (heapNew > WASM_HEAP_MAX) abort('MEM', 'Out of memory');
107 | if (heapGrow > 0) { WASM_MEMORY.grow((heapGrow+65535)>>16); MemorySetBufferViews(); }
108 | WASM_HEAP = heapNew;
109 | return heapOld|0;
110 | },
111 |
112 | // Functions querying the system time
113 | time: function(ptr) { var ret = (Date.now()/1000)|0; if (ptr) HEAPU32[ptr>>2] = ret; return ret; },
114 | gettimeofday: function(ptr) { var now = Date.now(); HEAPU32[ptr>>2]=(now/1000)|0; HEAPU32[(ptr+4)>>2]=((now % 1000)*1000)|0; },
115 |
116 | // Various functions thet can be called from wasm that abort the program
117 | __assert_fail: function(condition, filename, line, func) { abort('CRASH', 'Assert ' + WA.ReadHeapString(condition) + ', at: ' + (filename ? WA.ReadHeapString(filename) : 'unknown filename'), line, (func ? WA.ReadHeapString(func) : 'unknown function')); },
118 | __cxa_uncaught_exception: function() { abort('CRASH', 'Uncaught exception!'); },
119 | __cxa_pure_virtual: function() { abort('CRASH', 'pure virtual'); },
120 | abort: function() { abort('CRASH', 'Abort called'); },
121 | longjmp: function() { abort('CRASH', 'Unsupported longjmp called'); },
122 | };
123 |
124 | // Functions that do nothing in this wasm context
125 | env.setjmp = env.__cxa_atexit = env.__lock = env.__unlock = function() {};
126 |
127 | // Math functions
128 | env.ceil = env.ceilf = Math.ceil;
129 | env.exp = env.expf = Math.exp;
130 | env.floor = env.floorf = Math.floor;
131 | env.log = env.logf = Math.log;
132 | env.pow = env.powf = Math.pow;
133 | env.cos = env.cosf = Math.cos;
134 | env.sin = env.sinf = Math.sin;
135 | env.tan = env.tanf = Math.tan;
136 | env.acos = env.acosf = Math.acos;
137 | env.asin = env.asinf = Math.asin;
138 | env.sqrt = env.sqrtf = Math.sqrt;
139 | env.atan = env.atanf = Math.atan;
140 | env.atan2 = env.atan2f = Math.atan2;
141 | env.fabs = env.fabsf = env.abs = Math.abs;
142 | env.round = env.roundf = env.rint = env.rintf = Math.round;
143 |
144 | // The wasi object contains functions for the IO emulation
145 | var wasi =
146 | {
147 | // This function can only be used to write strings to stdout
148 | fd_write: function(fd, iov, iovcnt, pOutResult)
149 | {
150 | for (var ret = 0, str = '', i = 0; i < iovcnt; i++)
151 | {
152 | // Process list of IO commands, read passed strings from heap
153 | var ptr = HEAPU32[(iov+(i*8))>>2], len = HEAPU32[(iov+(i*8+4))>>2];
154 | if (len < 0) return -1;
155 | ret += len;
156 | str += WA.ReadHeapString(ptr, len);
157 | //console.log('fd_write - fd: ' + fd + ' - ['+i+'][len:'+len+']: ' + WA.ReadHeapString(ptr, len).replace(/\n/g, '\\n'));
158 | }
159 |
160 | // Print the passed string and write the number of bytes read to the result pointer
161 | WA.print(str);
162 | HEAPU32[pOutResult>>2] = ret;
163 | return 0; // no error
164 | },
165 | // Empty dummy functions for operations not emulated
166 | fd_read: function(fd, iov, iovcnt, pOutResult) { return 0; },
167 | fd_seek: function(fd, offset_low, offset_high, whence, pOutResult) { return 0; },
168 | fd_close: function(fd) { return 0; },
169 | };
170 |
171 | // Find the start point of the stack and the heap to calculate the initial memory requirements and load generated functions
172 | var wasmDataEnd = 64, wasmStackTop = 4096, wasmHeapBase = 65536, JS = {};
173 | // This code goes through the wasm file sections according the binary encoding description
174 | // https://webassembly.org/docs/binary-encoding/
175 | for (let i = 8, sectionEnd, type, length; i < wasmBytes.length; i = sectionEnd)
176 | {
177 | // Get() gets the next single byte, GetLEB() gets a LEB128 variable-length number
178 | function Get() { return wasmBytes[i++]; }
179 | function GetLEB() { for (var s=i,r=0,n=128; n&128; i++) r|=((n=wasmBytes[i])&127)<<((i-s)*7); return r; }
180 | type = GetLEB(), length = GetLEB(), sectionEnd = i + length;
181 | if (type < 0 || type > 11 || length <= 0 || sectionEnd > wasmBytes.length) break;
182 | if (type == 2)
183 | {
184 | //Section 2 'Imports' contains the list of JavaScript functions imported by the wasm module
185 | for (let count = GetLEB(), j = 0; j != count && i < sectionEnd; j++)
186 | {
187 | let modlen = GetLEB(), modstr = i, fldlen = (i+=modlen,GetLEB()), fldstr = i, itype = (i+=fldlen,(Get()?Get():GetLEB()));
188 | if (modlen == 2 && wasmBytes[modstr] == 74 && wasmBytes[modstr+1] == 83) //JS module
189 | {
190 | // JavaScript functions can be generated by the compiled code (with WA_JS), their code is embedded in the field name
191 | let fld = new TextDecoder("utf-8").decode(new Uint8Array(wasmBytes.buffer, fldstr, fldlen));
192 | let iarr = fld.split('|', 2), iname = iarr[0], iargs = iarr[1], icode = fld.substr(iname.length + iargs.length + 2);
193 |
194 | // strip C types out of params list (change '(float p1, unsigned int p2)' to 'p1,p2' (function pointers not supported)
195 | iargs = iargs.replace(/\[.*?\]|^\(\s*(void|)\s*\)$/g, '').replace(/.*?(\w+)\s*[,\)]/g, ',$1').substr(1);
196 |
197 | // fix escaped character sequences
198 | icode = icode.replace(/[\x00-\x1F]/g, (m)=>'\\'+[0,0,0,0,0,0,0,'a','b','t','n','v','f','r',0,0,0,0,0,0,0,0,0,0,0,0,0,'e',0,0,0,0][m.charCodeAt(0)])
199 |
200 | // expose function with code to wasm module (but overwrite the source code in the name with whitespace)
201 | wasmBytes.fill(32, fldstr + iname.length, fldstr + fldlen)
202 | try { JS[iname + (' '.repeat(fldlen - iname.length))] = new Function(...(iargs ? iargs.split(',') : []).concat(icode)); }
203 | catch (err) { WA.error('BOOT', 'Error in WA_JS function ' + iname + ': ' + err); }
204 | }
205 | }
206 | }
207 | if (type == 6)
208 | {
209 | //Section 6 'Globals', llvm places the heap base pointer into the first value here
210 | let count = GetLEB(), gtype = Get(), mutable = Get(), opcode = GetLEB(), offset = GetLEB(), endcode = GetLEB();
211 | wasmHeapBase = offset;
212 | }
213 | if (type == 11)
214 | {
215 | //Section 11 'Data', contains data segments which the end of the last entry will indicate the start of the stack area
216 | for (let count = GetLEB(), j = 0, dsize; j != count && i < sectionEnd; i += dsize, j++)
217 | {
218 | let dindex = Get(), dopcode = GetLEB(), doffset = GetLEB(), dendcode = GetLEB();
219 | wasmDataEnd = (doffset + (dsize = GetLEB()));
220 | wasmStackTop = (wasmDataEnd+15)>>4<<4;
221 | }
222 | }
223 | }
224 |
225 | // Validate the queried pointers
226 | if (wasmDataEnd <= 0 || wasmHeapBase <= wasmStackTop) abort('BOOT', 'Invalid memory layout (' + wasmDataEnd + '/' + wasmStackTop + '/' + wasmHeapBase + ')');
227 |
228 | // Set the initial wasm memory size to [DATA] + [STACK] + [256KB HEAP] (can be grown with sbrk)
229 | var wasmMemInitial = ((wasmHeapBase+65535)>>16<<16) + (256 * 1024);
230 | WASM_HEAP = wasmHeapBase;
231 | WASM_MEMORY = env.memory = new WebAssembly.Memory({initial: wasmMemInitial>>16, maximum: WASM_HEAP_MAX>>16 });
232 | MemorySetBufferViews();
233 |
234 | // Instantiate the wasm module by passing the prepared env, wasi and JS objects containing import functions for the wasm module
235 | WebAssembly.instantiate(wasmBytes, {env:env,wasi_unstable:wasi,wasi_snapshot_preview1:wasi,wasi:wasi,JS:JS}).then(function (output)
236 | {
237 | // Store the list of the functions exported by the wasm module in WA.asm
238 | WA.asm = output.instance.exports;
239 |
240 | // If function '__wasm_call_ctors' (global C++ constructors) exists, call it
241 | if (WA.asm.__wasm_call_ctors) WA.asm.__wasm_call_ctors();
242 |
243 | // If function 'main' exists, call it
244 | if (WA.asm.main)
245 | {
246 | // Store the argument list with 1 entry at the far end of the stack to pass to main
247 | var argc = 1, argv = wasmStackTop, exe = 'wasmexe';
248 |
249 | // Store the program name string after the argv list
250 | WA.WriteHeapString(exe, (argv + 8));
251 |
252 | // argv[0] contains the pointer to the exe string, argv[1] has a list terminating null pointer
253 | HEAPU32[(argv>>2) + 0] = (argv + 8)
254 | HEAPU32[(argv>>2) + 1] = 0;
255 |
256 | WA.asm.main(argc, argv);
257 | }
258 |
259 | // If the outer HTML file supplied a 'started' callback, call it
260 | if (WA.started) WA.started();
261 | })
262 | .catch(function (err)
263 | {
264 | // On an exception, if the err is 'abort' the error was already processed in the abort function above
265 | if (err !== 'abort') abort('BOOT', 'WASM instiantate error: ' + err + (err.stack ? "\n" + err.stack : ''));
266 | });
267 |
268 | });
269 |
--------------------------------------------------------------------------------
/GenJS/main.c:
--------------------------------------------------------------------------------
1 | /*
2 | This is free and unencumbered software released into the public domain.
3 |
4 | Anyone is free to copy, modify, publish, use, compile, sell, or
5 | distribute this software, either in source code form or as a compiled
6 | binary, for any purpose, commercial or non-commercial, and by any
7 | means.
8 |
9 | In jurisdictions that recognize copyright laws, the author or authors
10 | of this software dedicate any and all copyright interest in the
11 | software to the public domain. We make this dedication for the benefit
12 | of the public at large and to the detriment of our heirs and
13 | successors. We intend this dedication to be an overt act of
14 | relinquishment in perpetuity of all present and future rights to this
15 | software under copyright law.
16 |
17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
21 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
22 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23 | OTHER DEALINGS IN THE SOFTWARE.
24 |
25 | For more information, please refer to
26 | */
27 |
28 | #include
29 |
30 | #ifdef __cplusplus
31 | #define WA_EXTERN extern "C"
32 | #else
33 | #define WA_EXTERN extern
34 | #endif
35 |
36 | // Macro to make a C function available from JavaScript
37 | #define WA_EXPORT(name) __attribute__((used, visibility("default"), export_name(name)))
38 |
39 | // Macro to generate a JavaScript function that can be called from C
40 | #define WA_JS(ret, name, args, ...) WA_EXTERN __attribute__((import_module("JS"), import_name(#name "|" #args "|" #__VA_ARGS__))) ret name args;
41 |
42 | // Create a JavaScript function that writes to the wa_log div
43 | WA_JS(void, direct_print, (const char* pstr),
44 | {
45 | document.getElementById('wa_log').innerHTML += WA.ReadHeapString(pstr).replace(/\n/g, ' ');
46 | });
47 |
48 | // C function 'add' that can be called from JavaScript
49 | WA_EXPORT("add") int add(int a, int b)
50 | {
51 | return a + b;
52 | }
53 |
54 | // Create a JavaScript function that calls the C function above
55 | WA_JS(void, call_add, (void),
56 | {
57 | WA.print('add(2, 3): ' + WA.asm.add(2, 3) + '\n\n');
58 | });
59 |
60 | // Create a JavaScript function that writes the content of document.location.href into the wasm memory
61 | WA_JS(int, get_document_location, (const char* pstr, int len),
62 | {
63 | return WA.WriteHeapString(document.location.href, pstr, len)
64 | });
65 |
66 | // An unused JavaScript function which doesn't get included in the .wasm binary
67 | WA_JS(void, unused_wa_js_func, (),
68 | {
69 | WA.print('This text does not even get included in the .wasm file\n');
70 | });
71 |
72 | int main(int argc, char *argv[])
73 | {
74 | char buf[256];
75 | int bufret;
76 |
77 | printf("Printing through printf\n\n");
78 |
79 | direct_print("Printing directly through WA_JS\n\n");
80 |
81 | call_add();
82 |
83 | printf("Requesting string document.location from JavaScript...\n");
84 | bufret = get_document_location(buf, sizeof(buf));
85 | printf("Got document.location: %s (len: %d)\n\n", buf, bufret);
86 |
87 | return 0;
88 | }
89 |
--------------------------------------------------------------------------------
/GenJS/output.wasm:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/schellingb/ClangWasm/94203708c127a54c89c790caeb91c00b38cb4cef/GenJS/output.wasm
--------------------------------------------------------------------------------
/LibC/Makefile:
--------------------------------------------------------------------------------
1 | #
2 | # This is free and unencumbered software released into the public domain.
3 | #
4 | # Anyone is free to copy, modify, publish, use, compile, sell, or
5 | # distribute this software, either in source code form or as a compiled
6 | # binary, for any purpose, commercial or non-commercial, and by any
7 | # means.
8 | #
9 | # In jurisdictions that recognize copyright laws, the author or authors
10 | # of this software dedicate any and all copyright interest in the
11 | # software to the public domain. We make this dedication for the benefit
12 | # of the public at large and to the detriment of our heirs and
13 | # successors. We intend this dedication to be an overt act of
14 | # relinquishment in perpetuity of all present and future rights to this
15 | # software under copyright law.
16 | #
17 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 | # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 | # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20 | # IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
21 | # OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
22 | # ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23 | # OTHER DEALINGS IN THE SOFTWARE.
24 | #
25 | # For more information, please refer to
26 | #
27 |
28 | LLVM_ROOT = D:/dev/wasm/llvm
29 | SYSTEM_ROOT = D:/dev/wasm/system
30 | WASMOPT = D:/dev/wasm/wasm-opt.exe
31 |
32 | SOURCES = main.c
33 | BUILD = RELEASE
34 |
35 | #------------------------------------------------------------------------------------------------------
36 |
37 | ifeq ($(BUILD),RELEASE)
38 | OUTDIR := Release-wasm
39 | DBGCFLAGS := -DNDEBUG
40 | LDFLAGS := -strip-all -gc-sections
41 | WOPTFLAGS := -O3
42 | else
43 | OUTDIR := Debug-wasm
44 | DBGCFLAGS := -DDEBUG -D_DEBUG
45 | LDFLAGS :=
46 | WOPTFLAGS := -g -O0
47 | endif
48 |
49 | # Global compiler flags
50 | CXXFLAGS := $(DBGCFLAGS) -Ofast -std=c++11 -fno-rtti -Wno-writable-strings -Wno-unknown-pragmas
51 | CCFLAGS := $(DBGCFLAGS) -Ofast -std=c99
52 |
53 | # Global compiler flags for Wasm targeting
54 | CLANGFLAGS := -target wasm32 -nostdinc
55 | CLANGFLAGS += -D__EMSCRIPTEN__ -D_LIBCPP_ABI_VERSION=2
56 | CLANGFLAGS += -fvisibility=hidden -fno-builtin -fno-exceptions -fno-threadsafe-statics
57 | CLANGFLAGS += -isystem$(SYSTEM_ROOT)/include/libcxx
58 | CLANGFLAGS += -isystem$(SYSTEM_ROOT)/include/compat
59 | CLANGFLAGS += -isystem$(SYSTEM_ROOT)/include
60 | CLANGFLAGS += -isystem$(SYSTEM_ROOT)/include/libc
61 | CLANGFLAGS += -isystem$(SYSTEM_ROOT)/lib/libc/musl/arch/emscripten
62 |
63 | # Flags for wasm-ld
64 | LDFLAGS += -no-entry -allow-undefined -import-memory
65 | LDFLAGS += -export=__wasm_call_ctors -export=malloc -export=free -export=main
66 | LDFLAGS += $(addprefix -export=,$(patsubst _%,%,$(strip $(EXPORTS))))
67 |
68 | # Project Build flags, add defines from the make command line (e.g. D=MACRO=VALUE)
69 | FLAGS := $(subst \\\, ,$(foreach F,$(subst \ ,\\\,$(D)),"-D$(F)"))
70 |
71 | # Check if there are any source files
72 | ifeq ($(SOURCES),)
73 | $(error No source files found for build)
74 | endif
75 |
76 | # Compute tool paths
77 | ISWIN := $(findstring :,$(firstword $(subst \, ,$(subst /, ,$(abspath .)))))
78 | PIPETONULL := $(if $(ISWIN),>nul 2>nul,>/dev/null 2>/dev/null)
79 | ifeq ($(wildcard $(subst $(strip ) ,\ ,$(LLVM_ROOT))/clang*),)
80 | $(error clang executables not found in set LLVM_ROOT path ($(LLVM_ROOT)). Set custom path in this makefile with LLVM_ROOT = $(if $(ISWIN),d:)/path/to/clang)
81 | endif
82 | ifeq ($(wildcard $(subst $(strip ) ,\ ,$(WASMOPT))),)
83 | $(error wasm-opt executable not found in set WASMOPT path ($(WASMOPT)). Fix path in this makefile with WASMOPT = $(if $(ISWIN),d:)/path/to/wasm-opt$(if $(ISWIN),.exe))
84 | endif
85 |
86 | # Surround used commands with double quotes
87 | CC := "$(LLVM_ROOT)/clang"
88 | CXX := "$(LLVM_ROOT)/clang" -x c++
89 | LD := "$(LLVM_ROOT)/wasm-ld"
90 |
91 | all: $(OUTDIR)/loader.js $(OUTDIR)/loader.html $(OUTDIR)/output.wasm
92 | .PHONY: clean cleanall run analyze
93 |
94 | clean:
95 | $(info Removing all build files ...)
96 | @$(if $(wildcard $(OUTDIR)),$(if $(ISWIN),rmdir /S /Q,rm -rf) "$(OUTDIR)" $(PIPETONULL))
97 |
98 | # Generate a list of .o files to build, include dependency rules for source files, then compile files
99 | OBJS := $(addprefix $(OUTDIR)/,$(notdir $(patsubst %.c,%.o,$(patsubst %.cpp,%.o,$(SOURCES)))))
100 | -include $(OBJS:%.o=%.d)
101 | MAKEOBJ = $(OUTDIR)/$(basename $(notdir $(1))).o: $(1) ; $$(call COMPILE,$$@,$$<,$(2),$(3) $$(FLAGS))
102 | $(foreach F,$(filter %.cpp,$(SOURCES)),$(eval $(call MAKEOBJ,$(F),$$(CXX),$$(CXXFLAGS))))
103 | $(foreach F,$(filter %.c ,$(SOURCES)),$(eval $(call MAKEOBJ,$(F),$$(CC),$$(CCFLAGS))))
104 |
105 | $(OUTDIR)/output.wasm : Makefile $(OBJS) System.bc
106 | $(info Linking $@ ...)
107 | @$(LD) $(LDFLAGS) -o $@ $(OBJS) System.bc
108 | @"$(WASMOPT)" --legalize-js-interface $(WOPTFLAGS) $@ -o $@
109 |
110 | $(OUTDIR)/loader.js : loader.js
111 | $(info Copying $^ to $@ ...)
112 | @$(if $(wildcard $(OUTDIR)),,$(shell mkdir "$(OUTDIR)"))
113 | @$(if $(ISWIN),copy,cp) "$^" "$@" $(PIPETONULL)
114 |
115 | $(OUTDIR)/loader.html : loader.html
116 | $(if $(wildcard $(OUTDIR)),,$(shell mkdir "$(OUTDIR)"))
117 | @$(if $(ISWIN),copy,cp) "$^" "$@" $(PIPETONULL)
118 |
119 | define COMPILE
120 | $(info $2)
121 | @$(if $(wildcard $(dir $1)),,$(shell mkdir "$(dir $1)"))
122 | @$3 $4 $(CLANGFLAGS) -MMD -MP -MF $(patsubst %.o,%.d,$1) -o $1 -c $2
123 | endef
124 |
125 | #------------------------------------------------------------------------------------------------------
126 | #if System.bc exists, don't even bother checking sources, build once and forget for now
127 | ifeq ($(if $(wildcard System.bc),1,0),0)
128 | SYS_ADDS := emmalloc.cpp libcxx/*.cpp libcxxabi/src/cxa_guard.cpp compiler-rt/lib/builtins/*.c libc/wasi-helpers.c
129 | SYS_MUSL := complex crypt ctype dirent errno fcntl fenv internal locale math misc mman multibyte prng regex select stat stdio stdlib string termios unistd
130 |
131 | # C++ streams and locale are not included on purpose because it can increase the output up to 500kb
132 | SYS_IGNORE := iostream.cpp strstream.cpp locale.cpp thread.cpp exception.cpp
133 | SYS_IGNORE += abs.c acos.c acosf.c acosl.c asin.c asinf.c asinl.c atan.c atan2.c atan2f.c atan2l.c atanf.c atanl.c ceil.c ceilf.c ceill.c cos.c cosf.c cosl.c exp.c expf.c expl.c
134 | SYS_IGNORE += fabs.c fabsf.c fabsl.c floor.c floorf.c floorl.c log.c logf.c logl.c pow.c powf.c powl.c rintf.c round.c roundf.c sin.c sinf.c sinl.c sqrt.c sqrtf.c sqrtl.c tan.c tanf.c tanl.c
135 | SYS_IGNORE += syscall.c wordexp.c initgroups.c getgrouplist.c popen.c _exit.c alarm.c usleep.c faccessat.c iconv.c
136 |
137 | SYS_SOURCES := $(filter-out $(SYS_IGNORE:%=\%/%),$(wildcard $(addprefix $(SYSTEM_ROOT)/lib/,$(SYS_ADDS) $(SYS_MUSL:%=libc/musl/src/%/*.c))))
138 | SYS_SOURCES := $(subst $(SYSTEM_ROOT)/lib/,,$(SYS_SOURCES))
139 |
140 | ifeq ($(findstring !,$(SYS_SOURCES)),!)
141 | $(error SYS_SOURCES contains a filename with a ! character in it - Unable to continue)
142 | endif
143 |
144 | SYS_MISSING := $(filter-out $(SYS_SOURCES) $(dir $(SYS_SOURCES)),$(subst *.c,,$(subst *.cpp,,$(SYS_ADDS))) $(SYS_MUSL:%=libc/musl/src/%/))
145 | ifeq ($(if $(SYS_MISSING),1,0),1)
146 | $(error SYS_SOURCES missing the following files in $(SYSTEM_ROOT)/lib: $(SYS_MISSING))
147 | endif
148 |
149 | SYS_OLDFILES := $(filter-out $(subst /,!,$(patsubst %.c,%.o,$(patsubst %.cpp,%.o,$(SYS_SOURCES)))),$(notdir $(wildcard temp/*.o)))
150 | $(foreach F,$(SYS_OLDFILES),$(shell $(if $(ISWIN),del "temp\,rm "temp/)$(F)" $(PIPETONULL)))
151 |
152 | SYS_CXXFLAGS := -Ofast -std=c++11 -fno-threadsafe-statics -fno-rtti -I$(SYSTEM_ROOT)/lib/libcxxabi/include
153 | SYS_CXXFLAGS += -DNDEBUG -D_LIBCPP_BUILDING_LIBRARY -D_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS
154 |
155 | SYS_CCFLAGS := -Ofast -std=gnu99 -fno-threadsafe-statics
156 | SYS_CCFLAGS += -DNDEBUG -Dunix -D__unix -D__unix__
157 | SYS_CCFLAGS += -isystem$(SYSTEM_ROOT)/lib/libc/musl/src/internal
158 | SYS_CCFLAGS += -Wno-dangling-else -Wno-ignored-attributes -Wno-bitwise-op-parentheses -Wno-logical-op-parentheses -Wno-shift-op-parentheses -Wno-string-plus-int
159 | SYS_CCFLAGS += -Wno-unknown-pragmas -Wno-shift-count-overflow -Wno-return-type -Wno-macro-redefined -Wno-unused-result -Wno-pointer-sign
160 |
161 | SYS_CPP_OBJS := $(addprefix temp/,$(subst /,!,$(patsubst %.cpp,%.o,$(filter %.cpp,$(SYS_SOURCES)))))
162 | SYS_CC_OBJS := $(addprefix temp/,$(subst /,!,$(patsubst %.c,%.o,$(filter %.c,$(SYS_SOURCES)))))
163 | $(SYS_CPP_OBJS) : ; $(call SYS_COMPILE,$@,$(subst !,/,$(patsubst temp/%.o,$(SYSTEM_ROOT)/lib/%.cpp,$@)),$(CXX),$(SYS_CXXFLAGS))
164 | $(SYS_CC_OBJS) : ; $(call SYS_COMPILE,$@,$(subst !,/,$(patsubst temp/%.o,$(SYSTEM_ROOT)/lib/%.c,$@)),$(CC),$(SYS_CCFLAGS))
165 |
166 | define SYS_COMPILE
167 | $(info $2)
168 | @$(if $(wildcard $(dir $1)),,$(shell mkdir "$(dir $1)"))
169 | @$3 $4 $(CLANGFLAGS) -o $1 -c $2
170 | endef
171 |
172 | System.bc : $(SYS_CPP_OBJS) $(SYS_CC_OBJS)
173 | $(info Creating archive $@ ...)
174 | @$(LD) $(if $(ISWIN),"temp/*.o",temp/*.o) -r -o $@
175 | @$(if $(ISWIN),rmdir /S /Q,rm -rf) "temp"
176 | endif #need System.bc
177 | #------------------------------------------------------------------------------------------------------
178 |
--------------------------------------------------------------------------------
/LibC/loader.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | WebAssembly Sample: C standard library
7 |
8 |
9 |
WebAssembly Sample: C standard library
10 |
11 |
Loading...
12 |
35 |
36 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/LibC/loader.js:
--------------------------------------------------------------------------------
1 | /*
2 | This is free and unencumbered software released into the public domain.
3 |
4 | Anyone is free to copy, modify, publish, use, compile, sell, or
5 | distribute this software, either in source code form or as a compiled
6 | binary, for any purpose, commercial or non-commercial, and by any
7 | means.
8 |
9 | In jurisdictions that recognize copyright laws, the author or authors
10 | of this software dedicate any and all copyright interest in the
11 | software to the public domain. We make this dedication for the benefit
12 | of the public at large and to the detriment of our heirs and
13 | successors. We intend this dedication to be an overt act of
14 | relinquishment in perpetuity of all present and future rights to this
15 | software under copyright law.
16 |
17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
21 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
22 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23 | OTHER DEALINGS IN THE SOFTWARE.
24 |
25 | For more information, please refer to
26 | */
27 |
28 | // Fetch the .wasm file and store its bytes into the byte array wasmBytes
29 | fetch(WA.module).then(res => res.arrayBuffer()).then(function(wasmBytes){'use strict';wasmBytes = new Uint8Array(wasmBytes);
30 |
31 | // Some global state variables and max heap definition
32 | var HEAP32, HEAPU8, HEAPU16, HEAPU32, HEAPF32;
33 | var WASM_MEMORY, WASM_HEAP, WASM_HEAP_MAX = 256*1024*1024; //max 256MB
34 |
35 | // Define print and error functions if not yet defined by the outer html file
36 | WA.print = WA.print || function (msg) { console.log(msg); };
37 | WA.error = WA.error || function (code, msg) { WA.print('[ERROR] ' + code + ': ' + msg + '\n'); };
38 |
39 | // A generic abort function that if called stops the execution of the program and shows an error
40 | function abort(code, msg)
41 | {
42 | WA.error(code, msg);
43 | throw 'abort';
44 | }
45 |
46 | // Puts a string from javascript onto the wasm memory heap (encoded as UTF8) (max_length is optional)
47 | function WriteHeapString(str, ptr, max_length)
48 | {
49 | for (var e=str,r=HEAPU8,f=ptr,i=(max_length?max_length:HEAPU8.length),a=f,t=f+i-1,b=0;b>6,r[f++]=128|63&k;}
54 | else if(k<=65535){if(t<=f+2)break;r[f++]=224|k>>12,r[f++]=128|k>>6&63,r[f++]=128|63&k;}
55 | else if(k<=2097151){if(t<=f+3)break;r[f++]=240|k>>18,r[f++]=128|k>>12&63,r[f++]=128|k>>6&63,r[f++]=128|63&k;}
56 | else if(k<=67108863){if(t<=f+4)break;r[f++]=248|k>>24,r[f++]=128|k>>18&63,r[f++]=128|k>>12&63,r[f++]=128|k>>6&63,r[f++]=128|63&k;}
57 | else{if(t<=f+5)break;r[f++]=252|k>>30,r[f++]=128|k>>24&63,r[f++]=128|k>>18&63,r[f++]=128|k>>12&63,r[f++]=128|k>>6&63,r[f++]=128|63&k;}
58 | }
59 | return r[f]=0,f-a;
60 | }
61 |
62 | // Reads a string from the wasm memory heap to javascript (decoded as UTF8)
63 | function ReadHeapString(ptr, length)
64 | {
65 | if (length === 0 || !ptr) return '';
66 | for (var hasUtf = 0, t, i = 0; !length || i != length; i++)
67 | {
68 | t = HEAPU8[((ptr)+(i))>>0];
69 | if (t == 0 && !length) break;
70 | hasUtf |= t;
71 | }
72 | if (!length) length = i;
73 | if (hasUtf & 128)
74 | {
75 | for(var r=HEAPU8,o=ptr,p=ptr+length,F=String.fromCharCode,e,f,i,n,C,t,a,g='';;)
76 | {
77 | if(o==p||(e=r[o++],!e)) return g;
78 | 128&e?(f=63&r[o++],192!=(224&e)?(i=63&r[o++],224==(240&e)?e=(15&e)<<12|f<<6|i:(n=63&r[o++],240==(248&e)?e=(7&e)<<18|f<<12|i<<6|n:(C=63&r[o++],248==(252&e)?e=(3&e)<<24|f<<18|i<<12|n<<6|C:(t=63&r[o++],e=(1&e)<<30|f<<24|i<<18|n<<12|C<<6|t))),65536>e?g+=F(e):(a=e-65536,g+=F(55296|a>>10,56320|1023&a))):g+=F((31&e)<<6|f)):g+=F(e);
79 | }
80 | }
81 | // split up into chunks, because .apply on a huge string can overflow the stack
82 | for (var ret = '', curr; length > 0; ptr += 1024, length -= 1024)
83 | ret += String.fromCharCode.apply(String, HEAPU8.subarray(ptr, ptr + Math.min(length, 1024)));
84 | return ret;
85 | }
86 |
87 | // Defines syscall emulation functions in the env and wasi object that get passed to the wasm module
88 | function SYSCALLS_WASM_IMPORTS(env, wasi)
89 | {
90 | // Function to decode Base64 encoded string to a byte array
91 | function Base64Decode(B)
92 | {
93 | var T=new Uint8Array(128),i,C=function(o){return T[B.charCodeAt(i+o)];};
94 | for (i=0;i<64;i++) T['ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'.charCodeAt(i)]=i;T[45]=62;T[95]=63;
95 | var L=B.length,PH=(B[L-2]==='='?2:(B[L-1]==='='?1:0)),a=new Uint8Array(L*3/4-PH),n=0,j=(PH>0?L-4:L),t=0;
96 | for (i=0;i>16)&255;a[n++]=(t>>8)&255;a[n++]=t&255; }
97 | if (PH===1) { t=(C(0)<<10)|(C(1)<<4)|(C(2)>>2); a[n]=(t>>8)&255;a[n+1]=t&255; }
98 | else if (PH===2) a[n]=((C(0)<<2)|(C(1)>>4))&255;
99 | return a;
100 | }
101 |
102 | // For the file open/file reading emulation, keep a seek cursor and the file data
103 | var PAYLOAD_CURSOR = 0;
104 | var PAYLOAD = (WA.payload ? Base64Decode(WA.payload) : new Uint8Array(0));
105 | delete WA.payload;
106 |
107 | // sys_open call to open a file (can only be used to open payload here)
108 | env.__sys_open = function(pPath, flags, pMode)
109 | {
110 | // Opening just resets the seek cursor to 0
111 | PAYLOAD_CURSOR = 0;
112 | //var pathname = ReadHeapString(pPath); //read the file name passed to open
113 | //console.log('__sys_open open - path: ' + pathname + ' - flags: ' + flags + ' - mode: ' + HEAPU32[pMode>>2]);
114 | return 9; //return dummy file number
115 | };
116 |
117 | // fd_read call to read from a file (reads from payload)
118 | wasi.fd_read = function(fd, iov, iovcnt, pOutResult)
119 | {
120 | for (var ret = 0, i = 0; i < iovcnt; i++)
121 | {
122 | // Process list of IO commands
123 | var ptr = HEAPU32[((iov)+(i*8))>>2];
124 | var len = HEAPU32[((iov)+(i*8 + 4))>>2];
125 | var curr = Math.min(len, PAYLOAD.length - PAYLOAD_CURSOR);
126 | //console.log('fd_read - fd: ' + fd + ' - iov: ' + iov + ' - iovcnt: ' + iovcnt + ' - ptr: ' + ptr + ' - len: ' + len + ' - reading: ' + curr + ' (from ' + PAYLOAD_CURSOR + ' to ' + (PAYLOAD_CURSOR + curr) + ')');
127 |
128 | // Write the requested data onto the heap and advance the seek cursor
129 | HEAPU8.set(PAYLOAD.subarray(PAYLOAD_CURSOR, PAYLOAD_CURSOR + curr), ptr);
130 | PAYLOAD_CURSOR += curr;
131 |
132 | ret += curr;
133 | if (curr < len) break; // nothing more to read
134 | }
135 |
136 | // Write the amount of data actually read to the result pointer
137 | HEAPU32[pOutResult>>2] = ret;
138 | //console.log('fd_read - ret: ' + ret);
139 | return 0; // no error
140 | };
141 |
142 | // fd_seek call to seek in a file (seeks in payload)
143 | wasi.fd_seek = function(fd, offset_low, offset_high, whence, pOutResult)
144 | {
145 | // Move seek cursor according to fseek behavior
146 | if (whence == 0) PAYLOAD_CURSOR = offset_low; //set
147 | if (whence == 1) PAYLOAD_CURSOR += offset_low; //cur
148 | if (whence == 2) PAYLOAD_CURSOR = PAYLOAD.length - offset_low; //end
149 | if (PAYLOAD_CURSOR < 0) PAYLOAD_CURSOR = 0;
150 | if (PAYLOAD_CURSOR > PAYLOAD.length) PAYLOAD_CURSOR = PAYLOAD.length;
151 |
152 | // Write the result back (write only lower 32-bit of 64-bit number)
153 | HEAPU32[(pOutResult+0)>>2] = PAYLOAD_CURSOR;
154 | HEAPU32[(pOutResult+4)>>2] = 0;
155 | //console.log('fd_seek - fd: ' + fd + ' - offset_high: ' + offset_high + ' - offset_low: ' + offset_low + ' - pOutResult: ' + pOutResult + ' - whence: ' +whence + ' - seek to: ' + PAYLOAD_CURSOR);
156 | return 0; // no error
157 | };
158 |
159 | // fd_write call to write to a file/pipe (can only be used to write to stdout here)
160 | wasi.fd_write = function(fd, iov, iovcnt, pOutResult)
161 | {
162 | for (var ret = 0, str = '', i = 0; i < iovcnt; i++)
163 | {
164 | // Process list of IO commands, read passed strings from heap
165 | var ptr = HEAPU32[((iov)+(i*8))>>2];
166 | var len = HEAPU32[((iov)+(i*8 + 4))>>2];
167 | if (len < 0) return -1;
168 | ret += len;
169 | str += ReadHeapString(ptr, len);
170 | //console.log('fd_write - fd: ' + fd + ' - ['+i+'][len:'+len+']: ' + ReadHeapString(ptr, len).replace(/\n/g, '\\n'));
171 | }
172 |
173 | // Print the passed string and write the number of bytes read to the result pointer
174 | WA.print(str);
175 | HEAPU32[pOutResult>>2] = ret;
176 | return 0; // no error
177 | };
178 |
179 | // fd_close to close a file (no real file system emulation, so this does nothing)
180 | wasi.fd_close = function(fd)
181 | {
182 | //console.log('fd_close - fd: ' + fd);
183 | return 0; // no error
184 | };
185 |
186 | // sys_fcntl64 and sys_ioctl set file and IO modes/flags which are not emulated here
187 | env.__sys_fcntl64 = env.__sys_ioctl = function(fd, param)
188 | {
189 | return 0; // no error
190 | };
191 | }
192 |
193 | // Set the array views of various data types used to read/write to the wasm memory from JavaScript
194 | function MemorySetBufferViews()
195 | {
196 | var buf = WASM_MEMORY.buffer;
197 | HEAP32 = new Int32Array(buf);
198 | HEAPU8 = new Uint8Array(buf);
199 | HEAPU16 = new Uint16Array(buf);
200 | HEAPU32 = new Uint32Array(buf);
201 | HEAPF32 = new Float32Array(buf);
202 | }
203 |
204 | // Set up the env and wasi objects that contains the functions passed to the wasm module
205 | var env =
206 | {
207 | // sbrk gets called to increase the size of the memory heap by an increment
208 | sbrk: function(increment)
209 | {
210 | var heapOld = WASM_HEAP, heapNew = heapOld + increment, heapGrow = heapNew - WASM_MEMORY.buffer.byteLength;
211 | //console.log('[SBRK] Increment: ' + increment + ' - HEAP: ' + heapOld + ' -> ' + heapNew + (heapGrow > 0 ? ' - GROW BY ' + heapGrow + ' (' + (heapGrow>>16) + ' pages)' : ''));
212 | if (heapNew > WASM_HEAP_MAX) abort('MEM', 'Out of memory');
213 | if (heapGrow > 0) { WASM_MEMORY.grow((heapGrow+65535)>>16); MemorySetBufferViews(); }
214 | WASM_HEAP = heapNew;
215 | return heapOld|0;
216 | },
217 |
218 | // Functions querying the system time
219 | time: function(ptr) { var ret = (Date.now()/1000)|0; if (ptr) HEAPU32[ptr>>2] = ret; return ret; },
220 | gettimeofday: function(ptr) { var now = Date.now(); HEAPU32[ptr>>2]=(now/1000)|0; HEAPU32[(ptr+4)>>2]=((now % 1000)*1000)|0; },
221 |
222 | // Various functions thet can be called from wasm that abort the program
223 | __assert_fail: function(condition, filename, line, func) { abort('CRASH', 'Assert ' + ReadHeapString(condition) + ', at: ' + (filename ? ReadHeapString(filename) : 'unknown filename'), line, (func ? ReadHeapString(func) : 'unknown function')); },
224 | __cxa_uncaught_exception: function() { abort('CRASH', 'Uncaught exception!'); },
225 | __cxa_pure_virtual: function() { abort('CRASH', 'pure virtual'); },
226 | abort: function() { abort('CRASH', 'Abort called'); },
227 | longjmp: function() { abort('CRASH', 'Unsupported longjmp called'); },
228 | }, wasi = {};
229 |
230 | // Functions that do nothing in this wasm context
231 | env.setjmp = env.__cxa_atexit = env.__lock = env.__unlock = function() {};
232 |
233 | // Math functions
234 | env.ceil = env.ceilf = Math.ceil;
235 | env.exp = env.expf = Math.exp;
236 | env.floor = env.floorf = Math.floor;
237 | env.log = env.logf = Math.log;
238 | env.pow = env.powf = Math.pow;
239 | env.cos = env.cosf = Math.cos;
240 | env.sin = env.sinf = Math.sin;
241 | env.tan = env.tanf = Math.tan;
242 | env.acos = env.acosf = Math.acos;
243 | env.asin = env.asinf = Math.asin;
244 | env.sqrt = env.sqrtf = Math.sqrt;
245 | env.atan = env.atanf = Math.atan;
246 | env.atan2 = env.atan2f = Math.atan2;
247 | env.fabs = env.fabsf = env.abs = Math.abs;
248 | env.round = env.roundf = env.rint = env.rintf = Math.round;
249 |
250 | // Extend the objects with the syscall IO emulation
251 | SYSCALLS_WASM_IMPORTS(env, wasi);
252 |
253 | // Find the start point of the stack and the heap to calculate the initial memory requirements
254 | var wasmDataEnd = 64, wasmStackTop = 4096, wasmHeapBase = 65536;
255 | // This code goes through the wasm file sections according the binary encoding description
256 | // https://webassembly.org/docs/binary-encoding/
257 | for (let i = 8, sectionEnd, type, length; i < wasmBytes.length; i = sectionEnd)
258 | {
259 | // Get() gets the next single byte, GetLEB() gets a LEB128 variable-length number
260 | function Get() { return wasmBytes[i++]; }
261 | function GetLEB() { for (var s=i,r=0,n=128; n&128; i++) r|=((n=wasmBytes[i])&127)<<((i-s)*7); return r; }
262 | type = GetLEB(), length = GetLEB(), sectionEnd = i + length;
263 | if (type < 0 || type > 11 || length <= 0 || sectionEnd > wasmBytes.length) break;
264 | if (type == 6)
265 | {
266 | //Section 6 'Globals', llvm places the heap base pointer into the first value here
267 | let count = GetLEB(), gtype = Get(), mutable = Get(), opcode = GetLEB(), offset = GetLEB(), endcode = GetLEB();
268 | wasmHeapBase = offset;
269 | }
270 | if (type == 11)
271 | {
272 | //Section 11 'Data', contains data segments which the end of the last entry will indicate the start of the stack area
273 | for (let count = GetLEB(), j = 0; j != count && i < sectionEnd; j++)
274 | {
275 | let dindex = Get(), dopcode = GetLEB(), doffset = GetLEB(), dendcode = GetLEB(), dsize = GetLEB();
276 | wasmDataEnd = (doffset + dsize);
277 | wasmStackTop = (wasmDataEnd+15)>>4<<4;
278 | i += dsize;
279 | }
280 | }
281 | }
282 |
283 | // Validate the queried pointers
284 | if (wasmDataEnd <= 0 || wasmHeapBase <= wasmStackTop) abort('BOOT', 'Invalid memory layout (' + wasmDataEnd + '/' + wasmStackTop + '/' + wasmHeapBase + ')');
285 |
286 | // Set the initial wasm memory size to [DATA] + [STACK] + [256KB HEAP] (can be grown with sbrk)
287 | var wasmMemInitial = ((wasmHeapBase+65535)>>16<<16) + (256 * 1024);
288 | WASM_HEAP = wasmHeapBase;
289 | WASM_MEMORY = env.memory = new WebAssembly.Memory({initial: wasmMemInitial>>16, maximum: WASM_HEAP_MAX>>16 });
290 | MemorySetBufferViews();
291 |
292 | // Instantiate the wasm module by passing the prepared env and wasi objects containing import functions for the wasm module
293 | WebAssembly.instantiate(wasmBytes, {env:env,wasi_unstable:wasi,wasi_snapshot_preview1:wasi,wasi:wasi}).then(function (output)
294 | {
295 | // Store the list of the functions exported by the wasm module in WA.asm
296 | WA.asm = output.instance.exports;
297 |
298 | // If function '__wasm_call_ctors' (global C++ constructors) exists, call it
299 | if (WA.asm.__wasm_call_ctors) WA.asm.__wasm_call_ctors();
300 |
301 | // If function 'main' exists, call it
302 | if (WA.asm.main)
303 | {
304 | // Store the argument list with 1 entry at the far end of the stack to pass to main
305 | var argc = 1, argv = wasmStackTop, exe = 'wasmexe';
306 |
307 | // Store the program name string after the argv list
308 | WriteHeapString(exe, (argv + 8));
309 |
310 | // argv[0] contains the pointer to the exe string, argv[1] has a list terminating null pointer
311 | HEAPU32[(argv>>2) + 0] = (argv + 8)
312 | HEAPU32[(argv>>2) + 1] = 0;
313 |
314 | WA.asm.main(argc, argv);
315 | }
316 |
317 | // If the outer HTML file supplied a 'started' callback, call it
318 | if (WA.started) WA.started();
319 | })
320 | .catch(function (err)
321 | {
322 | // On an exception, if the err is 'abort' the error was already processed in the abort function above
323 | if (err !== 'abort') abort('BOOT', 'WASM instiantate error: ' + err + (err.stack ? "\n" + err.stack : ''));
324 | });
325 |
326 | });
327 |
--------------------------------------------------------------------------------
/LibC/main.c:
--------------------------------------------------------------------------------
1 | /*
2 | This is free and unencumbered software released into the public domain.
3 |
4 | Anyone is free to copy, modify, publish, use, compile, sell, or
5 | distribute this software, either in source code form or as a compiled
6 | binary, for any purpose, commercial or non-commercial, and by any
7 | means.
8 |
9 | In jurisdictions that recognize copyright laws, the author or authors
10 | of this software dedicate any and all copyright interest in the
11 | software to the public domain. We make this dedication for the benefit
12 | of the public at large and to the detriment of our heirs and
13 | successors. We intend this dedication to be an overt act of
14 | relinquishment in perpetuity of all present and future rights to this
15 | software under copyright law.
16 |
17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
21 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
22 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23 | OTHER DEALINGS IN THE SOFTWARE.
24 |
25 | For more information, please refer to
26 | */
27 |
28 | #include
29 | #include
30 | #include
31 | #include
32 |
33 | int main(int argc, char *argv[])
34 | {
35 | printf("Hello printf World\n\n");
36 |
37 | printf("main argc: %d - argv[0]: %s\n\n", argc, argv[0]);
38 |
39 | printf("sinf(1.0f): %f\n\n", sinf(1.0f));
40 |
41 | char file_buf[20] = {0};
42 | FILE* file = fopen("payload", "r");
43 | printf("Opened payload file %p\n", file);
44 | fseek(file, 0, SEEK_END);
45 | long file_size = ftell(file);
46 | fseek(file, 0, SEEK_SET);
47 | printf("Size of payload is %d\n", file_size);
48 | size_t file_read = fread(file_buf, 1, sizeof(file_buf), file);
49 | fclose(file);
50 | printf("Read %d bytes from file '%s'\n\n", (int)file_read, file_buf);
51 |
52 | void* alloc_buf = malloc(1024);
53 | printf("Allocated 1KB at address %p\n", alloc_buf);
54 | alloc_buf = realloc(alloc_buf, 10*1024*1024);
55 | printf("Reallocated to 10MB at address %p\n\n", alloc_buf);
56 | free(alloc_buf);
57 |
58 | return 0;
59 | }
60 |
--------------------------------------------------------------------------------
/LibC/output.wasm:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/schellingb/ClangWasm/94203708c127a54c89c790caeb91c00b38cb4cef/LibC/output.wasm
--------------------------------------------------------------------------------
/LoadUrl/Makefile:
--------------------------------------------------------------------------------
1 | #
2 | # This is free and unencumbered software released into the public domain.
3 | #
4 | # Anyone is free to copy, modify, publish, use, compile, sell, or
5 | # distribute this software, either in source code form or as a compiled
6 | # binary, for any purpose, commercial or non-commercial, and by any
7 | # means.
8 | #
9 | # In jurisdictions that recognize copyright laws, the author or authors
10 | # of this software dedicate any and all copyright interest in the
11 | # software to the public domain. We make this dedication for the benefit
12 | # of the public at large and to the detriment of our heirs and
13 | # successors. We intend this dedication to be an overt act of
14 | # relinquishment in perpetuity of all present and future rights to this
15 | # software under copyright law.
16 | #
17 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 | # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 | # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20 | # IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
21 | # OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
22 | # ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23 | # OTHER DEALINGS IN THE SOFTWARE.
24 | #
25 | # For more information, please refer to
26 | #
27 |
28 | LLVM_ROOT = D:/dev/wasm/llvm
29 | SYSTEM_ROOT = D:/dev/wasm/system
30 | WASMOPT = D:/dev/wasm/wasm-opt.exe
31 |
32 | EXPORTS = WAFNHTTP
33 | SOURCES = main.cpp
34 | BUILD = RELEASE
35 |
36 | #------------------------------------------------------------------------------------------------------
37 |
38 | ifeq ($(BUILD),RELEASE)
39 | OUTDIR := Release-wasm
40 | DBGCFLAGS := -DNDEBUG
41 | LDFLAGS := -strip-all -gc-sections
42 | WOPTFLAGS := -O3
43 | else
44 | OUTDIR := Debug-wasm
45 | DBGCFLAGS := -DDEBUG -D_DEBUG
46 | LDFLAGS :=
47 | WOPTFLAGS := -g -O0
48 | endif
49 |
50 | # Global compiler flags
51 | CXXFLAGS := $(DBGCFLAGS) -Ofast -std=c++11 -fno-rtti -Wno-writable-strings -Wno-unknown-pragmas
52 | CCFLAGS := $(DBGCFLAGS) -Ofast -std=c99
53 |
54 | # Global compiler flags for Wasm targeting
55 | CLANGFLAGS := -target wasm32 -nostdinc
56 | CLANGFLAGS += -D__EMSCRIPTEN__ -D_LIBCPP_ABI_VERSION=2
57 | CLANGFLAGS += -fvisibility=hidden -fno-builtin -fno-exceptions -fno-threadsafe-statics
58 | CLANGFLAGS += -isystem$(SYSTEM_ROOT)/include/libcxx
59 | CLANGFLAGS += -isystem$(SYSTEM_ROOT)/include/compat
60 | CLANGFLAGS += -isystem$(SYSTEM_ROOT)/include
61 | CLANGFLAGS += -isystem$(SYSTEM_ROOT)/include/libc
62 | CLANGFLAGS += -isystem$(SYSTEM_ROOT)/lib/libc/musl/arch/emscripten
63 |
64 | # Flags for wasm-ld
65 | LDFLAGS += -no-entry -allow-undefined -import-memory
66 | LDFLAGS += -export=__wasm_call_ctors -export=malloc -export=free -export=main
67 | LDFLAGS += $(addprefix -export=,$(patsubst _%,%,$(strip $(EXPORTS))))
68 |
69 | # Project Build flags, add defines from the make command line (e.g. D=MACRO=VALUE)
70 | FLAGS := $(subst \\\, ,$(foreach F,$(subst \ ,\\\,$(D)),"-D$(F)"))
71 |
72 | # Check if there are any source files
73 | ifeq ($(SOURCES),)
74 | $(error No source files found for build)
75 | endif
76 |
77 | # Compute tool paths
78 | ISWIN := $(findstring :,$(firstword $(subst \, ,$(subst /, ,$(abspath .)))))
79 | PIPETONULL := $(if $(ISWIN),>nul 2>nul,>/dev/null 2>/dev/null)
80 | ifeq ($(wildcard $(subst $(strip ) ,\ ,$(LLVM_ROOT))/clang*),)
81 | $(error clang executables not found in set LLVM_ROOT path ($(LLVM_ROOT)). Set custom path in this makefile with LLVM_ROOT = $(if $(ISWIN),d:)/path/to/clang)
82 | endif
83 | ifeq ($(wildcard $(subst $(strip ) ,\ ,$(WASMOPT))),)
84 | $(error wasm-opt executable not found in set WASMOPT path ($(WASMOPT)). Fix path in this makefile with WASMOPT = $(if $(ISWIN),d:)/path/to/wasm-opt$(if $(ISWIN),.exe))
85 | endif
86 |
87 | # Surround used commands with double quotes
88 | CC := "$(LLVM_ROOT)/clang"
89 | CXX := "$(LLVM_ROOT)/clang" -x c++
90 | LD := "$(LLVM_ROOT)/wasm-ld"
91 |
92 | all: $(OUTDIR)/loader.js $(OUTDIR)/loader.html $(OUTDIR)/output.wasm
93 | .PHONY: clean cleanall run analyze
94 |
95 | clean:
96 | $(info Removing all build files ...)
97 | @$(if $(wildcard $(OUTDIR)),$(if $(ISWIN),rmdir /S /Q,rm -rf) "$(OUTDIR)" $(PIPETONULL))
98 |
99 | # Generate a list of .o files to build, include dependency rules for source files, then compile files
100 | OBJS := $(addprefix $(OUTDIR)/,$(notdir $(patsubst %.c,%.o,$(patsubst %.cpp,%.o,$(SOURCES)))))
101 | -include $(OBJS:%.o=%.d)
102 | MAKEOBJ = $(OUTDIR)/$(basename $(notdir $(1))).o: $(1) ; $$(call COMPILE,$$@,$$<,$(2),$(3) $$(FLAGS))
103 | $(foreach F,$(filter %.cpp,$(SOURCES)),$(eval $(call MAKEOBJ,$(F),$$(CXX),$$(CXXFLAGS))))
104 | $(foreach F,$(filter %.c ,$(SOURCES)),$(eval $(call MAKEOBJ,$(F),$$(CC),$$(CCFLAGS))))
105 |
106 | $(OUTDIR)/output.wasm : Makefile $(OBJS) System.bc
107 | $(info Linking $@ ...)
108 | @$(LD) $(LDFLAGS) -o $@ $(OBJS) System.bc
109 | @"$(WASMOPT)" --legalize-js-interface $(WOPTFLAGS) $@ -o $@
110 |
111 | $(OUTDIR)/loader.js : loader.js
112 | $(info Copying $^ to $@ ...)
113 | @$(if $(wildcard $(OUTDIR)),,$(shell mkdir "$(OUTDIR)"))
114 | @$(if $(ISWIN),copy,cp) "$^" "$@" $(PIPETONULL)
115 |
116 | $(OUTDIR)/loader.html : loader.html
117 | $(if $(wildcard $(OUTDIR)),,$(shell mkdir "$(OUTDIR)"))
118 | @$(if $(ISWIN),copy,cp) "$^" "$@" $(PIPETONULL)
119 |
120 | define COMPILE
121 | $(info $2)
122 | @$(if $(wildcard $(dir $1)),,$(shell mkdir "$(dir $1)"))
123 | @$3 $4 $(CLANGFLAGS) -MMD -MP -MF $(patsubst %.o,%.d,$1) -o $1 -c $2
124 | endef
125 |
126 | #------------------------------------------------------------------------------------------------------
127 | #if System.bc exists, don't even bother checking sources, build once and forget for now
128 | ifeq ($(if $(wildcard System.bc),1,0),0)
129 | SYS_ADDS := emmalloc.cpp libcxx/*.cpp libcxxabi/src/cxa_guard.cpp compiler-rt/lib/builtins/*.c libc/wasi-helpers.c
130 | SYS_MUSL := complex crypt ctype dirent errno fcntl fenv internal locale math misc mman multibyte prng regex select stat stdio stdlib string termios unistd
131 |
132 | # C++ streams and locale are not included on purpose because it can increase the output up to 500kb
133 | SYS_IGNORE := iostream.cpp strstream.cpp locale.cpp thread.cpp exception.cpp
134 | SYS_IGNORE += abs.c acos.c acosf.c acosl.c asin.c asinf.c asinl.c atan.c atan2.c atan2f.c atan2l.c atanf.c atanl.c ceil.c ceilf.c ceill.c cos.c cosf.c cosl.c exp.c expf.c expl.c
135 | SYS_IGNORE += fabs.c fabsf.c fabsl.c floor.c floorf.c floorl.c log.c logf.c logl.c pow.c powf.c powl.c rintf.c round.c roundf.c sin.c sinf.c sinl.c sqrt.c sqrtf.c sqrtl.c tan.c tanf.c tanl.c
136 | SYS_IGNORE += syscall.c wordexp.c initgroups.c getgrouplist.c popen.c _exit.c alarm.c usleep.c faccessat.c iconv.c
137 |
138 | SYS_SOURCES := $(filter-out $(SYS_IGNORE:%=\%/%),$(wildcard $(addprefix $(SYSTEM_ROOT)/lib/,$(SYS_ADDS) $(SYS_MUSL:%=libc/musl/src/%/*.c))))
139 | SYS_SOURCES := $(subst $(SYSTEM_ROOT)/lib/,,$(SYS_SOURCES))
140 |
141 | ifeq ($(findstring !,$(SYS_SOURCES)),!)
142 | $(error SYS_SOURCES contains a filename with a ! character in it - Unable to continue)
143 | endif
144 |
145 | SYS_MISSING := $(filter-out $(SYS_SOURCES) $(dir $(SYS_SOURCES)),$(subst *.c,,$(subst *.cpp,,$(SYS_ADDS))) $(SYS_MUSL:%=libc/musl/src/%/))
146 | ifeq ($(if $(SYS_MISSING),1,0),1)
147 | $(error SYS_SOURCES missing the following files in $(SYSTEM_ROOT)/lib: $(SYS_MISSING))
148 | endif
149 |
150 | SYS_OLDFILES := $(filter-out $(subst /,!,$(patsubst %.c,%.o,$(patsubst %.cpp,%.o,$(SYS_SOURCES)))),$(notdir $(wildcard temp/*.o)))
151 | $(foreach F,$(SYS_OLDFILES),$(shell $(if $(ISWIN),del "temp\,rm "temp/)$(F)" $(PIPETONULL)))
152 |
153 | SYS_CXXFLAGS := -Ofast -std=c++11 -fno-threadsafe-statics -fno-rtti -I$(SYSTEM_ROOT)/lib/libcxxabi/include
154 | SYS_CXXFLAGS += -DNDEBUG -D_LIBCPP_BUILDING_LIBRARY -D_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS
155 |
156 | SYS_CCFLAGS := -Ofast -std=gnu99 -fno-threadsafe-statics
157 | SYS_CCFLAGS += -DNDEBUG -Dunix -D__unix -D__unix__
158 | SYS_CCFLAGS += -isystem$(SYSTEM_ROOT)/lib/libc/musl/src/internal
159 | SYS_CCFLAGS += -Wno-dangling-else -Wno-ignored-attributes -Wno-bitwise-op-parentheses -Wno-logical-op-parentheses -Wno-shift-op-parentheses -Wno-string-plus-int
160 | SYS_CCFLAGS += -Wno-unknown-pragmas -Wno-shift-count-overflow -Wno-return-type -Wno-macro-redefined -Wno-unused-result -Wno-pointer-sign
161 |
162 | SYS_CPP_OBJS := $(addprefix temp/,$(subst /,!,$(patsubst %.cpp,%.o,$(filter %.cpp,$(SYS_SOURCES)))))
163 | SYS_CC_OBJS := $(addprefix temp/,$(subst /,!,$(patsubst %.c,%.o,$(filter %.c,$(SYS_SOURCES)))))
164 | $(SYS_CPP_OBJS) : ; $(call SYS_COMPILE,$@,$(subst !,/,$(patsubst temp/%.o,$(SYSTEM_ROOT)/lib/%.cpp,$@)),$(CXX),$(SYS_CXXFLAGS))
165 | $(SYS_CC_OBJS) : ; $(call SYS_COMPILE,$@,$(subst !,/,$(patsubst temp/%.o,$(SYSTEM_ROOT)/lib/%.c,$@)),$(CC),$(SYS_CCFLAGS))
166 |
167 | define SYS_COMPILE
168 | $(info $2)
169 | @$(if $(wildcard $(dir $1)),,$(shell mkdir "$(dir $1)"))
170 | @$3 $4 $(CLANGFLAGS) -o $1 -c $2
171 | endef
172 |
173 | System.bc : $(SYS_CPP_OBJS) $(SYS_CC_OBJS)
174 | $(info Creating archive $@ ...)
175 | @$(LD) $(if $(ISWIN),"temp/*.o",temp/*.o) -r -o $@
176 | @$(if $(ISWIN),rmdir /S /Q,rm -rf) "temp"
177 | endif #need System.bc
178 | #------------------------------------------------------------------------------------------------------
179 |
--------------------------------------------------------------------------------
/LoadUrl/loader.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | WebAssembly Sample: Load URL
7 |
8 |
9 |
WebAssembly Sample: Load URL
10 |
11 |
Loading...
12 |
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/LoadUrl/loader.js:
--------------------------------------------------------------------------------
1 | /*
2 | This is free and unencumbered software released into the public domain.
3 |
4 | Anyone is free to copy, modify, publish, use, compile, sell, or
5 | distribute this software, either in source code form or as a compiled
6 | binary, for any purpose, commercial or non-commercial, and by any
7 | means.
8 |
9 | In jurisdictions that recognize copyright laws, the author or authors
10 | of this software dedicate any and all copyright interest in the
11 | software to the public domain. We make this dedication for the benefit
12 | of the public at large and to the detriment of our heirs and
13 | successors. We intend this dedication to be an overt act of
14 | relinquishment in perpetuity of all present and future rights to this
15 | software under copyright law.
16 |
17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
21 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
22 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23 | OTHER DEALINGS IN THE SOFTWARE.
24 |
25 | For more information, please refer to
26 | */
27 |
28 | // Fetch the .wasm file and store its bytes into the byte array wasmBytes
29 | fetch(WA.module).then(res => res.arrayBuffer()).then(function(wasmBytes){'use strict';wasmBytes = new Uint8Array(wasmBytes);
30 |
31 | // Some global state variables and max heap definition
32 | var HEAP32, HEAPU8, HEAPU16, HEAPU32, HEAPF32;
33 | var WASM_MEMORY, WASM_HEAP, WASM_HEAP_MAX = 256*1024*1024; //max 256MB
34 |
35 | // Define print and error functions if not yet defined by the outer html file
36 | WA.print = WA.print || function (msg) { console.log(msg); };
37 | WA.error = WA.error || function (code, msg) { WA.print('[ERROR] ' + code + ': ' + msg + '\n'); };
38 |
39 | // A generic abort function that if called stops the execution of the program and shows an error
40 | function abort(code, msg)
41 | {
42 | WA.error(code, msg);
43 | throw 'abort';
44 | }
45 |
46 | // Puts a string from javascript onto the wasm memory heap (encoded as UTF8) (max_length is optional)
47 | function WriteHeapString(str, ptr, max_length)
48 | {
49 | for (var e=str,r=HEAPU8,f=ptr,i=(max_length?max_length:HEAPU8.length),a=f,t=f+i-1,b=0;b>6,r[f++]=128|63&k;}
54 | else if(k<=65535){if(t<=f+2)break;r[f++]=224|k>>12,r[f++]=128|k>>6&63,r[f++]=128|63&k;}
55 | else if(k<=2097151){if(t<=f+3)break;r[f++]=240|k>>18,r[f++]=128|k>>12&63,r[f++]=128|k>>6&63,r[f++]=128|63&k;}
56 | else if(k<=67108863){if(t<=f+4)break;r[f++]=248|k>>24,r[f++]=128|k>>18&63,r[f++]=128|k>>12&63,r[f++]=128|k>>6&63,r[f++]=128|63&k;}
57 | else{if(t<=f+5)break;r[f++]=252|k>>30,r[f++]=128|k>>24&63,r[f++]=128|k>>18&63,r[f++]=128|k>>12&63,r[f++]=128|k>>6&63,r[f++]=128|63&k;}
58 | }
59 | return r[f]=0,f-a;
60 | }
61 |
62 | // Reads a string from the wasm memory heap to javascript (decoded as UTF8)
63 | function ReadHeapString(ptr, length)
64 | {
65 | if (length === 0 || !ptr) return '';
66 | for (var hasUtf = 0, t, i = 0; !length || i != length; i++)
67 | {
68 | t = HEAPU8[((ptr)+(i))>>0];
69 | if (t == 0 && !length) break;
70 | hasUtf |= t;
71 | }
72 | if (!length) length = i;
73 | if (hasUtf & 128)
74 | {
75 | for(var r=HEAPU8,o=ptr,p=ptr+length,F=String.fromCharCode,e,f,i,n,C,t,a,g='';;)
76 | {
77 | if(o==p||(e=r[o++],!e)) return g;
78 | 128&e?(f=63&r[o++],192!=(224&e)?(i=63&r[o++],224==(240&e)?e=(15&e)<<12|f<<6|i:(n=63&r[o++],240==(248&e)?e=(7&e)<<18|f<<12|i<<6|n:(C=63&r[o++],248==(252&e)?e=(3&e)<<24|f<<18|i<<12|n<<6|C:(t=63&r[o++],e=(1&e)<<30|f<<24|i<<18|n<<12|C<<6|t))),65536>e?g+=F(e):(a=e-65536,g+=F(55296|a>>10,56320|1023&a))):g+=F((31&e)<<6|f)):g+=F(e);
79 | }
80 | }
81 | // split up into chunks, because .apply on a huge string can overflow the stack
82 | for (var ret = '', curr; length > 0; ptr += 1024, length -= 1024)
83 | ret += String.fromCharCode.apply(String, HEAPU8.subarray(ptr, ptr + Math.min(length, 1024)));
84 | return ret;
85 | }
86 |
87 | // Allocate and store a byte array on the wasm heap
88 | function malloc_array(a)
89 | {
90 | var ptr = WA.asm.malloc(Math.max(a.length, 1));
91 | if (a.subarray || a.slice) HEAPU8.set(a, ptr);
92 | else HEAPU8.set(new Uint8Array(a), ptr);
93 | return ptr;
94 | }
95 |
96 | // Defines syscall emulation functions in the env and wasi object that get passed to the wasm module
97 | function SYSCALLS_WASM_IMPORTS(env, wasi)
98 | {
99 | // Function to decode Base64 encoded string to a byte array
100 | function Base64Decode(B)
101 | {
102 | var T=new Uint8Array(128),i,C=function(o){return T[B.charCodeAt(i+o)];};
103 | for (i=0;i<64;i++) T['ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'.charCodeAt(i)]=i;T[45]=62;T[95]=63;
104 | var L=B.length,PH=(B[L-2]==='='?2:(B[L-1]==='='?1:0)),a=new Uint8Array(L*3/4-PH),n=0,j=(PH>0?L-4:L),t=0;
105 | for (i=0;i>16)&255;a[n++]=(t>>8)&255;a[n++]=t&255; }
106 | if (PH===1) { t=(C(0)<<10)|(C(1)<<4)|(C(2)>>2); a[n]=(t>>8)&255;a[n+1]=t&255; }
107 | else if (PH===2) a[n]=((C(0)<<2)|(C(1)>>4))&255;
108 | return a;
109 | }
110 |
111 | // For the file open/file reading emulation, keep a seek cursor and the file data
112 | var PAYLOAD_CURSOR = 0;
113 | var PAYLOAD = (WA.payload ? Base64Decode(WA.payload) : new Uint8Array(0));
114 | delete WA.payload;
115 |
116 | // sys_open call to open a file (can only be used to open payload here)
117 | env.__sys_open = function(pPath, flags, pMode)
118 | {
119 | // Opening just resets the seek cursor to 0
120 | PAYLOAD_CURSOR = 0;
121 | //var pathname = ReadHeapString(pPath); //read the file name passed to open
122 | //console.log('__sys_open open - path: ' + pathname + ' - flags: ' + flags + ' - mode: ' + HEAPU32[pMode>>2]);
123 | return 9; //return dummy file number
124 | };
125 |
126 | // fd_read call to read from a file (reads from payload)
127 | wasi.fd_read = function(fd, iov, iovcnt, pOutResult)
128 | {
129 | for (var ret = 0, i = 0; i < iovcnt; i++)
130 | {
131 | // Process list of IO commands
132 | var ptr = HEAPU32[((iov)+(i*8))>>2];
133 | var len = HEAPU32[((iov)+(i*8 + 4))>>2];
134 | var curr = Math.min(len, PAYLOAD.length - PAYLOAD_CURSOR);
135 | //console.log('fd_read - fd: ' + fd + ' - iov: ' + iov + ' - iovcnt: ' + iovcnt + ' - ptr: ' + ptr + ' - len: ' + len + ' - reading: ' + curr + ' (from ' + PAYLOAD_CURSOR + ' to ' + (PAYLOAD_CURSOR + curr) + ')');
136 |
137 | // Write the requested data onto the heap and advance the seek cursor
138 | HEAPU8.set(PAYLOAD.subarray(PAYLOAD_CURSOR, PAYLOAD_CURSOR + curr), ptr);
139 | PAYLOAD_CURSOR += curr;
140 |
141 | ret += curr;
142 | if (curr < len) break; // nothing more to read
143 | }
144 |
145 | // Write the amount of data actually read to the result pointer
146 | HEAPU32[pOutResult>>2] = ret;
147 | //console.log('fd_read - ret: ' + ret);
148 | return 0; // no error
149 | };
150 |
151 | // fd_seek call to seek in a file (seeks in payload)
152 | wasi.fd_seek = function(fd, offset_low, offset_high, whence, pOutResult)
153 | {
154 | // Move seek cursor according to fseek behavior
155 | if (whence == 0) PAYLOAD_CURSOR = offset_low; //set
156 | if (whence == 1) PAYLOAD_CURSOR += offset_low; //cur
157 | if (whence == 2) PAYLOAD_CURSOR = PAYLOAD.length - offset_low; //end
158 | if (PAYLOAD_CURSOR < 0) PAYLOAD_CURSOR = 0;
159 | if (PAYLOAD_CURSOR > PAYLOAD.length) PAYLOAD_CURSOR = PAYLOAD.length;
160 |
161 | // Write the result back (write only lower 32-bit of 64-bit number)
162 | HEAPU32[(pOutResult+0)>>2] = PAYLOAD_CURSOR;
163 | HEAPU32[(pOutResult+4)>>2] = 0;
164 | //console.log('fd_seek - fd: ' + fd + ' - offset_high: ' + offset_high + ' - offset_low: ' + offset_low + ' - pOutResult: ' + pOutResult + ' - whence: ' +whence + ' - seek to: ' + PAYLOAD_CURSOR);
165 | return 0; // no error
166 | };
167 |
168 | // fd_write call to write to a file/pipe (can only be used to write to stdout here)
169 | wasi.fd_write = function(fd, iov, iovcnt, pOutResult)
170 | {
171 | for (var ret = 0, str = '', i = 0; i < iovcnt; i++)
172 | {
173 | // Process list of IO commands, read passed strings from heap
174 | var ptr = HEAPU32[((iov)+(i*8))>>2];
175 | var len = HEAPU32[((iov)+(i*8 + 4))>>2];
176 | if (len < 0) return -1;
177 | ret += len;
178 | str += ReadHeapString(ptr, len);
179 | //console.log('fd_write - fd: ' + fd + ' - ['+i+'][len:'+len+']: ' + ReadHeapString(ptr, len).replace(/\n/g, '\\n'));
180 | }
181 |
182 | // Print the passed string and write the number of bytes read to the result pointer
183 | WA.print(str);
184 | HEAPU32[pOutResult>>2] = ret;
185 | return 0; // no error
186 | };
187 |
188 | // fd_close to close a file (no real file system emulation, so this does nothing)
189 | wasi.fd_close = function(fd)
190 | {
191 | //console.log('fd_close - fd: ' + fd);
192 | return 0; // no error
193 | };
194 |
195 | // sys_fcntl64 and sys_ioctl set file and IO modes/flags which are not emulated here
196 | env.__sys_fcntl64 = env.__sys_ioctl = function(fd, param)
197 | {
198 | return 0; // no error
199 | };
200 | }
201 |
202 | // Defines our custom functions in the env object that get passed to the wasm module
203 | function WAJS_WASM_IMPORTS(env)
204 | {
205 | // Load data from a URL and pass the result (or error) back to wasm with WAFNHTTP
206 | env.WAJS_AsyncLoad = function(url, userdata, postdata, postlength, timeout)
207 | {
208 | var xhr = new XMLHttpRequest(), WAFNHTTP = WA.asm.WAFNHTTP;
209 | xhr.open((postlength ? 'POST' : 'GET'), ReadHeapString(url), true);
210 | xhr.responseType = 'arraybuffer';
211 | if (timeout) xhr.timeout = timeout;
212 | xhr.onload = function()
213 | {
214 | if (xhr.status == 200)
215 | {
216 | var b = malloc_array(new Uint8Array(xhr.response));
217 | WAFNHTTP(200, b, xhr.response.byteLength, userdata);
218 | WA.asm.free(b);
219 | }
220 | else WAFNHTTP(xhr.status, 0, 0, userdata);
221 | };
222 | xhr.ontimeout = xhr.onerror = function(event)
223 | {
224 | // This could be called synchronously by xhr.send() so force it to arrive async
225 | setTimeout(function() { WAFNHTTP(xhr.status||-1, 0, 0, userdata); });
226 | };
227 | if (postlength) try { xhr.send(HEAPU8.subarray(postdata, postdata+postlength)); } catch (e) { xhr.send(HEAPU8.buffer.slice(postdata, postdata+postlength)); }
228 | else xhr.send(null);
229 | };
230 | }
231 |
232 | // Set the array views of various data types used to read/write to the wasm memory from JavaScript
233 | function MemorySetBufferViews()
234 | {
235 | var buf = WASM_MEMORY.buffer;
236 | HEAP32 = new Int32Array(buf);
237 | HEAPU8 = new Uint8Array(buf);
238 | HEAPU16 = new Uint16Array(buf);
239 | HEAPU32 = new Uint32Array(buf);
240 | HEAPF32 = new Float32Array(buf);
241 | }
242 |
243 | // Set up the env and wasi objects that contains the functions passed to the wasm module
244 | var env =
245 | {
246 | // sbrk gets called to increase the size of the memory heap by an increment
247 | sbrk: function(increment)
248 | {
249 | var heapOld = WASM_HEAP, heapNew = heapOld + increment, heapGrow = heapNew - WASM_MEMORY.buffer.byteLength;
250 | //console.log('[SBRK] Increment: ' + increment + ' - HEAP: ' + heapOld + ' -> ' + heapNew + (heapGrow > 0 ? ' - GROW BY ' + heapGrow + ' (' + (heapGrow>>16) + ' pages)' : ''));
251 | if (heapNew > WASM_HEAP_MAX) abort('MEM', 'Out of memory');
252 | if (heapGrow > 0) { WASM_MEMORY.grow((heapGrow+65535)>>16); MemorySetBufferViews(); }
253 | WASM_HEAP = heapNew;
254 | return heapOld|0;
255 | },
256 |
257 | // Functions querying the system time
258 | time: function(ptr) { var ret = (Date.now()/1000)|0; if (ptr) HEAPU32[ptr>>2] = ret; return ret; },
259 | gettimeofday: function(ptr) { var now = Date.now(); HEAPU32[ptr>>2]=(now/1000)|0; HEAPU32[(ptr+4)>>2]=((now % 1000)*1000)|0; },
260 |
261 | // Various functions thet can be called from wasm that abort the program
262 | __assert_fail: function(condition, filename, line, func) { abort('CRASH', 'Assert ' + ReadHeapString(condition) + ', at: ' + (filename ? ReadHeapString(filename) : 'unknown filename'), line, (func ? ReadHeapString(func) : 'unknown function')); },
263 | __cxa_uncaught_exception: function() { abort('CRASH', 'Uncaught exception!'); },
264 | __cxa_pure_virtual: function() { abort('CRASH', 'pure virtual'); },
265 | abort: function() { abort('CRASH', 'Abort called'); },
266 | longjmp: function() { abort('CRASH', 'Unsupported longjmp called'); },
267 | }, wasi = {};
268 |
269 | // Functions that do nothing in this wasm context
270 | env.setjmp = env.__cxa_atexit = env.__lock = env.__unlock = function() {};
271 |
272 | // Math functions
273 | env.ceil = env.ceilf = Math.ceil;
274 | env.exp = env.expf = Math.exp;
275 | env.floor = env.floorf = Math.floor;
276 | env.log = env.logf = Math.log;
277 | env.pow = env.powf = Math.pow;
278 | env.cos = env.cosf = Math.cos;
279 | env.sin = env.sinf = Math.sin;
280 | env.tan = env.tanf = Math.tan;
281 | env.acos = env.acosf = Math.acos;
282 | env.asin = env.asinf = Math.asin;
283 | env.sqrt = env.sqrtf = Math.sqrt;
284 | env.atan = env.atanf = Math.atan;
285 | env.atan2 = env.atan2f = Math.atan2;
286 | env.fabs = env.fabsf = env.abs = Math.abs;
287 | env.round = env.roundf = env.rint = env.rintf = Math.round;
288 |
289 | // Extend the objects with the syscall IO emulation and our custom functions
290 | SYSCALLS_WASM_IMPORTS(env, wasi);
291 | WAJS_WASM_IMPORTS(env);
292 |
293 | // Find the start point of the stack and the heap to calculate the initial memory requirements
294 | var wasmDataEnd = 64, wasmStackTop = 4096, wasmHeapBase = 65536;
295 | // This code goes through the wasm file sections according the binary encoding description
296 | // https://webassembly.org/docs/binary-encoding/
297 | for (let i = 8, sectionEnd, type, length; i < wasmBytes.length; i = sectionEnd)
298 | {
299 | // Get() gets the next single byte, GetLEB() gets a LEB128 variable-length number
300 | function Get() { return wasmBytes[i++]; }
301 | function GetLEB() { for (var s=i,r=0,n=128; n&128; i++) r|=((n=wasmBytes[i])&127)<<((i-s)*7); return r; }
302 | type = GetLEB(), length = GetLEB(), sectionEnd = i + length;
303 | if (type < 0 || type > 11 || length <= 0 || sectionEnd > wasmBytes.length) break;
304 | if (type == 6)
305 | {
306 | //Section 6 'Globals', llvm places the heap base pointer into the first value here
307 | let count = GetLEB(), gtype = Get(), mutable = Get(), opcode = GetLEB(), offset = GetLEB(), endcode = GetLEB();
308 | wasmHeapBase = offset;
309 | }
310 | if (type == 11)
311 | {
312 | //Section 11 'Data', contains data segments which the end of the last entry will indicate the start of the stack area
313 | for (let count = GetLEB(), j = 0; j != count && i < sectionEnd; j++)
314 | {
315 | let dindex = Get(), dopcode = GetLEB(), doffset = GetLEB(), dendcode = GetLEB(), dsize = GetLEB();
316 | wasmDataEnd = (doffset + dsize);
317 | wasmStackTop = (wasmDataEnd+15)>>4<<4;
318 | i += dsize;
319 | }
320 | }
321 | }
322 |
323 | // Validate the queried pointers
324 | if (wasmDataEnd <= 0 || wasmHeapBase <= wasmStackTop) abort('BOOT', 'Invalid memory layout (' + wasmDataEnd + '/' + wasmStackTop + '/' + wasmHeapBase + ')');
325 |
326 | // Set the initial wasm memory size to [DATA] + [STACK] + [256KB HEAP] (can be grown with sbrk)
327 | var wasmMemInitial = ((wasmHeapBase+65535)>>16<<16) + (256 * 1024);
328 | WASM_HEAP = wasmHeapBase;
329 | WASM_MEMORY = env.memory = new WebAssembly.Memory({initial: wasmMemInitial>>16, maximum: WASM_HEAP_MAX>>16 });
330 | MemorySetBufferViews();
331 |
332 | // Instantiate the wasm module by passing the prepared env and wasi objects containing import functions for the wasm module
333 | WebAssembly.instantiate(wasmBytes, {env:env,wasi_unstable:wasi,wasi_snapshot_preview1:wasi,wasi:wasi}).then(function (output)
334 | {
335 | // Store the list of the functions exported by the wasm module in WA.asm
336 | WA.asm = output.instance.exports;
337 |
338 | // If function '__wasm_call_ctors' (global C++ constructors) exists, call it
339 | if (WA.asm.__wasm_call_ctors) WA.asm.__wasm_call_ctors();
340 |
341 | // If function 'main' exists, call it
342 | if (WA.asm.main)
343 | {
344 | // Store the argument list with 1 entry at the far end of the stack to pass to main
345 | var argc = 1, argv = wasmStackTop, exe = 'wasmexe';
346 |
347 | // Store the program name string after the argv list
348 | WriteHeapString(exe, (argv + 8));
349 |
350 | // argv[0] contains the pointer to the exe string, argv[1] has a list terminating null pointer
351 | HEAPU32[(argv>>2) + 0] = (argv + 8)
352 | HEAPU32[(argv>>2) + 1] = 0;
353 |
354 | WA.asm.main(argc, argv);
355 | }
356 |
357 | // If the outer HTML file supplied a 'started' callback, call it
358 | if (WA.started) WA.started();
359 | })
360 | .catch(function (err)
361 | {
362 | // On an exception, if the err is 'abort' the error was already processed in the abort function above
363 | if (err !== 'abort') abort('BOOT', 'WASM instiantate error: ' + err + (err.stack ? "\n" + err.stack : ''));
364 | });
365 |
366 | });
367 |
--------------------------------------------------------------------------------
/LoadUrl/main.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | This is free and unencumbered software released into the public domain.
3 |
4 | Anyone is free to copy, modify, publish, use, compile, sell, or
5 | distribute this software, either in source code form or as a compiled
6 | binary, for any purpose, commercial or non-commercial, and by any
7 | means.
8 |
9 | In jurisdictions that recognize copyright laws, the author or authors
10 | of this software dedicate any and all copyright interest in the
11 | software to the public domain. We make this dedication for the benefit
12 | of the public at large and to the detriment of our heirs and
13 | successors. We intend this dedication to be an overt act of
14 | relinquishment in perpetuity of all present and future rights to this
15 | software under copyright law.
16 |
17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
21 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
22 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23 | OTHER DEALINGS IN THE SOFTWARE.
24 |
25 | For more information, please refer to
26 | */
27 |
28 | #include
29 |
30 | // Function defined in loader.js
31 | extern "C" void WAJS_AsyncLoad(const char* url, void* userdata = NULL, char* postdata = NULL, size_t postlength = 0, unsigned int timeout = 0);
32 |
33 | // This function is called at startup
34 | int main(int argc, char *argv[])
35 | {
36 | const char* url = "http://zillalib.github.io/TEST.TXT";
37 | printf("Requesting url '%s' ...\n", url);
38 | WAJS_AsyncLoad(url);
39 | printf("Sent async request, waiting for response\n");
40 |
41 | return 0;
42 | }
43 |
44 | // This function is called by loader.js when the HTTP request finishes (or has an error)
45 | extern "C" void WAFNHTTP(int status, char* data, size_t length, void* userdata)
46 | {
47 | printf("Received response - status: %d - length: %d - data: '%.*s'\n", status, (int)length, (int)length, data);
48 | }
49 |
--------------------------------------------------------------------------------
/LoadUrl/output.wasm:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/schellingb/ClangWasm/94203708c127a54c89c790caeb91c00b38cb4cef/LoadUrl/output.wasm
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # WebAssembly without Emscripten
2 |
3 | This is the repository that goes along my blog post "WebAssembly without Emscripten"
4 |
5 | How to get rid of Emscripten and build and compile WebAssembly applications with ease
6 |
7 | [https://schellcode.github.io/webassembly-without-emscripten](https://schellcode.github.io/webassembly-without-emscripten)
8 |
9 |
10 | ## Demos
11 |
12 | Demo (Click to run) | Download | Explanation
13 | --------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------|----------------------------------------------------------------
14 | 1 [Pure C function](https://schellingb.github.io/ClangWasm/Basic/loader.html) | [Download](https://github.com/schellingb/ClangWasm/releases/download/bin/ClangWasm_Basic.zip) | [Explanation](https://schellcode.github.io/webassembly-without-emscripten#demo-1-explaining-the-basic-process)
15 | 2 [With C Standard Library](https://schellingb.github.io/ClangWasm/LibC/loader.html) | [Download](https://github.com/schellingb/ClangWasm/releases/download/bin/ClangWasm_LibC.zip) | [Explanation](https://schellcode.github.io/webassembly-without-emscripten#demo-2-using-the-c-standard-library)
16 | 3 [With C++](https://schellingb.github.io/ClangWasm/Cpp/loader.html) | [Download](https://github.com/schellingb/ClangWasm/releases/download/bin/ClangWasm_Cpp.zip) | [Explanation](https://schellcode.github.io/webassembly-without-emscripten#demo-3-using-c-and-the-c-standard-library)
17 | 4 [WebGL rendering](https://schellingb.github.io/ClangWasm/WebGL/loader.html) | [Download](https://github.com/schellingb/ClangWasm/releases/download/bin/ClangWasm_WebGL.zip) | [Explanation](https://schellcode.github.io/webassembly-without-emscripten#demo-4-webgl-rendering)
18 | 5 [Audio output](https://schellingb.github.io/ClangWasm/Audio/loader.html) | [Download](https://github.com/schellingb/ClangWasm/releases/download/bin/ClangWasm_Audio.zip) | [Explanation](https://schellcode.github.io/webassembly-without-emscripten#demo-5-audio-output)
19 | 6 [Loading a URL](https://schellingb.github.io/ClangWasm/LoadUrl/loader.html) | [Download](https://github.com/schellingb/ClangWasm/releases/download/bin/ClangWasm_LoadUrl.zip) | [Explanation](https://schellcode.github.io/webassembly-without-emscripten#demo-6-loading-data-from-url)
20 | 7 [Embedding WASM](https://schellingb.github.io/ClangWasm/Embed/output.html) | [Download](https://github.com/schellingb/ClangWasm/releases/download/bin/ClangWasm_Embed.zip) | [Explanation](https://schellcode.github.io/webassembly-without-emscripten#demo-7-advanced-build-script-with-embedding)
21 | 8 [Generate JS from C](https://schellingb.github.io/ClangWasm/GenJS/loader.html) | [Download](https://github.com/schellingb/ClangWasm/releases/download/bin/ClangWasm_GenJS.zip) | TODO
22 |
23 |
24 | ## License
25 | All code here available as [Public Domain](https://www.unlicense.org).
26 |
--------------------------------------------------------------------------------
/UNLICENSE:
--------------------------------------------------------------------------------
1 | This is free and unencumbered software released into the public domain.
2 |
3 | Anyone is free to copy, modify, publish, use, compile, sell, or
4 | distribute this software, either in source code form or as a compiled
5 | binary, for any purpose, commercial or non-commercial, and by any
6 | means.
7 |
8 | In jurisdictions that recognize copyright laws, the author or authors
9 | of this software dedicate any and all copyright interest in the
10 | software to the public domain. We make this dedication for the benefit
11 | of the public at large and to the detriment of our heirs and
12 | successors. We intend this dedication to be an overt act of
13 | relinquishment in perpetuity of all present and future rights to this
14 | software under copyright law.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22 | OTHER DEALINGS IN THE SOFTWARE.
23 |
24 | For more information, please refer to
25 |
--------------------------------------------------------------------------------
/WebGL/Makefile:
--------------------------------------------------------------------------------
1 | #
2 | # This is free and unencumbered software released into the public domain.
3 | #
4 | # Anyone is free to copy, modify, publish, use, compile, sell, or
5 | # distribute this software, either in source code form or as a compiled
6 | # binary, for any purpose, commercial or non-commercial, and by any
7 | # means.
8 | #
9 | # In jurisdictions that recognize copyright laws, the author or authors
10 | # of this software dedicate any and all copyright interest in the
11 | # software to the public domain. We make this dedication for the benefit
12 | # of the public at large and to the detriment of our heirs and
13 | # successors. We intend this dedication to be an overt act of
14 | # relinquishment in perpetuity of all present and future rights to this
15 | # software under copyright law.
16 | #
17 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 | # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 | # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20 | # IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
21 | # OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
22 | # ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23 | # OTHER DEALINGS IN THE SOFTWARE.
24 | #
25 | # For more information, please refer to
26 | #
27 |
28 | LLVM_ROOT = D:/dev/wasm/llvm
29 | SYSTEM_ROOT = D:/dev/wasm/system
30 | WASMOPT = D:/dev/wasm/wasm-opt.exe
31 |
32 | EXPORTS = WAFNDraw
33 | SOURCES = main.cpp
34 | BUILD = RELEASE
35 |
36 | #------------------------------------------------------------------------------------------------------
37 |
38 | ifeq ($(BUILD),RELEASE)
39 | OUTDIR := Release-wasm
40 | DBGCFLAGS := -DNDEBUG
41 | LDFLAGS := -strip-all -gc-sections
42 | WOPTFLAGS := -O3
43 | else
44 | OUTDIR := Debug-wasm
45 | DBGCFLAGS := -DDEBUG -D_DEBUG
46 | LDFLAGS :=
47 | WOPTFLAGS := -g -O0
48 | endif
49 |
50 | # Global compiler flags
51 | CXXFLAGS := $(DBGCFLAGS) -Ofast -std=c++11 -fno-rtti -Wno-writable-strings -Wno-unknown-pragmas
52 | CCFLAGS := $(DBGCFLAGS) -Ofast -std=c99
53 |
54 | # Global compiler flags for Wasm targeting
55 | CLANGFLAGS := -target wasm32 -nostdinc
56 | CLANGFLAGS += -D__EMSCRIPTEN__ -D_LIBCPP_ABI_VERSION=2
57 | CLANGFLAGS += -fvisibility=hidden -fno-builtin -fno-exceptions -fno-threadsafe-statics
58 | CLANGFLAGS += -isystem$(SYSTEM_ROOT)/include/libcxx
59 | CLANGFLAGS += -isystem$(SYSTEM_ROOT)/include/compat
60 | CLANGFLAGS += -isystem$(SYSTEM_ROOT)/include
61 | CLANGFLAGS += -isystem$(SYSTEM_ROOT)/include/libc
62 | CLANGFLAGS += -isystem$(SYSTEM_ROOT)/lib/libc/musl/arch/emscripten
63 |
64 | # Flags for wasm-ld
65 | LDFLAGS += -no-entry -allow-undefined -import-memory
66 | LDFLAGS += -export=__wasm_call_ctors -export=malloc -export=free -export=main
67 | LDFLAGS += $(addprefix -export=,$(patsubst _%,%,$(strip $(EXPORTS))))
68 |
69 | # Project Build flags, add defines from the make command line (e.g. D=MACRO=VALUE)
70 | FLAGS := $(subst \\\, ,$(foreach F,$(subst \ ,\\\,$(D)),"-D$(F)"))
71 |
72 | # Check if there are any source files
73 | ifeq ($(SOURCES),)
74 | $(error No source files found for build)
75 | endif
76 |
77 | # Compute tool paths
78 | ISWIN := $(findstring :,$(firstword $(subst \, ,$(subst /, ,$(abspath .)))))
79 | PIPETONULL := $(if $(ISWIN),>nul 2>nul,>/dev/null 2>/dev/null)
80 | ifeq ($(wildcard $(subst $(strip ) ,\ ,$(LLVM_ROOT))/clang*),)
81 | $(error clang executables not found in set LLVM_ROOT path ($(LLVM_ROOT)). Set custom path in this makefile with LLVM_ROOT = $(if $(ISWIN),d:)/path/to/clang)
82 | endif
83 | ifeq ($(wildcard $(subst $(strip ) ,\ ,$(WASMOPT))),)
84 | $(error wasm-opt executable not found in set WASMOPT path ($(WASMOPT)). Fix path in this makefile with WASMOPT = $(if $(ISWIN),d:)/path/to/wasm-opt$(if $(ISWIN),.exe))
85 | endif
86 |
87 | # Surround used commands with double quotes
88 | CC := "$(LLVM_ROOT)/clang"
89 | CXX := "$(LLVM_ROOT)/clang" -x c++
90 | LD := "$(LLVM_ROOT)/wasm-ld"
91 |
92 | all: $(OUTDIR)/loader.js $(OUTDIR)/loader.html $(OUTDIR)/output.wasm
93 | .PHONY: clean cleanall run analyze
94 |
95 | clean:
96 | $(info Removing all build files ...)
97 | @$(if $(wildcard $(OUTDIR)),$(if $(ISWIN),rmdir /S /Q,rm -rf) "$(OUTDIR)" $(PIPETONULL))
98 |
99 | # Generate a list of .o files to build, include dependency rules for source files, then compile files
100 | OBJS := $(addprefix $(OUTDIR)/,$(notdir $(patsubst %.c,%.o,$(patsubst %.cpp,%.o,$(SOURCES)))))
101 | -include $(OBJS:%.o=%.d)
102 | MAKEOBJ = $(OUTDIR)/$(basename $(notdir $(1))).o: $(1) ; $$(call COMPILE,$$@,$$<,$(2),$(3) $$(FLAGS))
103 | $(foreach F,$(filter %.cpp,$(SOURCES)),$(eval $(call MAKEOBJ,$(F),$$(CXX),$$(CXXFLAGS))))
104 | $(foreach F,$(filter %.c ,$(SOURCES)),$(eval $(call MAKEOBJ,$(F),$$(CC),$$(CCFLAGS))))
105 |
106 | $(OUTDIR)/output.wasm : Makefile $(OBJS) System.bc
107 | $(info Linking $@ ...)
108 | @$(LD) $(LDFLAGS) -o $@ $(OBJS) System.bc
109 | @"$(WASMOPT)" --legalize-js-interface $(WOPTFLAGS) $@ -o $@
110 |
111 | $(OUTDIR)/loader.js : loader.js
112 | $(info Copying $^ to $@ ...)
113 | @$(if $(wildcard $(OUTDIR)),,$(shell mkdir "$(OUTDIR)"))
114 | @$(if $(ISWIN),copy,cp) "$^" "$@" $(PIPETONULL)
115 |
116 | $(OUTDIR)/loader.html : loader.html
117 | $(if $(wildcard $(OUTDIR)),,$(shell mkdir "$(OUTDIR)"))
118 | @$(if $(ISWIN),copy,cp) "$^" "$@" $(PIPETONULL)
119 |
120 | define COMPILE
121 | $(info $2)
122 | @$(if $(wildcard $(dir $1)),,$(shell mkdir "$(dir $1)"))
123 | @$3 $4 $(CLANGFLAGS) -MMD -MP -MF $(patsubst %.o,%.d,$1) -o $1 -c $2
124 | endef
125 |
126 | #------------------------------------------------------------------------------------------------------
127 | #if System.bc exists, don't even bother checking sources, build once and forget for now
128 | ifeq ($(if $(wildcard System.bc),1,0),0)
129 | SYS_ADDS := emmalloc.cpp libcxx/*.cpp libcxxabi/src/cxa_guard.cpp compiler-rt/lib/builtins/*.c libc/wasi-helpers.c
130 | SYS_MUSL := complex crypt ctype dirent errno fcntl fenv internal locale math misc mman multibyte prng regex select stat stdio stdlib string termios unistd
131 |
132 | # C++ streams and locale are not included on purpose because it can increase the output up to 500kb
133 | SYS_IGNORE := iostream.cpp strstream.cpp locale.cpp thread.cpp exception.cpp
134 | SYS_IGNORE += abs.c acos.c acosf.c acosl.c asin.c asinf.c asinl.c atan.c atan2.c atan2f.c atan2l.c atanf.c atanl.c ceil.c ceilf.c ceill.c cos.c cosf.c cosl.c exp.c expf.c expl.c
135 | SYS_IGNORE += fabs.c fabsf.c fabsl.c floor.c floorf.c floorl.c log.c logf.c logl.c pow.c powf.c powl.c rintf.c round.c roundf.c sin.c sinf.c sinl.c sqrt.c sqrtf.c sqrtl.c tan.c tanf.c tanl.c
136 | SYS_IGNORE += syscall.c wordexp.c initgroups.c getgrouplist.c popen.c _exit.c alarm.c usleep.c faccessat.c iconv.c
137 |
138 | SYS_SOURCES := $(filter-out $(SYS_IGNORE:%=\%/%),$(wildcard $(addprefix $(SYSTEM_ROOT)/lib/,$(SYS_ADDS) $(SYS_MUSL:%=libc/musl/src/%/*.c))))
139 | SYS_SOURCES := $(subst $(SYSTEM_ROOT)/lib/,,$(SYS_SOURCES))
140 |
141 | ifeq ($(findstring !,$(SYS_SOURCES)),!)
142 | $(error SYS_SOURCES contains a filename with a ! character in it - Unable to continue)
143 | endif
144 |
145 | SYS_MISSING := $(filter-out $(SYS_SOURCES) $(dir $(SYS_SOURCES)),$(subst *.c,,$(subst *.cpp,,$(SYS_ADDS))) $(SYS_MUSL:%=libc/musl/src/%/))
146 | ifeq ($(if $(SYS_MISSING),1,0),1)
147 | $(error SYS_SOURCES missing the following files in $(SYSTEM_ROOT)/lib: $(SYS_MISSING))
148 | endif
149 |
150 | SYS_OLDFILES := $(filter-out $(subst /,!,$(patsubst %.c,%.o,$(patsubst %.cpp,%.o,$(SYS_SOURCES)))),$(notdir $(wildcard temp/*.o)))
151 | $(foreach F,$(SYS_OLDFILES),$(shell $(if $(ISWIN),del "temp\,rm "temp/)$(F)" $(PIPETONULL)))
152 |
153 | SYS_CXXFLAGS := -Ofast -std=c++11 -fno-threadsafe-statics -fno-rtti -I$(SYSTEM_ROOT)/lib/libcxxabi/include
154 | SYS_CXXFLAGS += -DNDEBUG -D_LIBCPP_BUILDING_LIBRARY -D_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS
155 |
156 | SYS_CCFLAGS := -Ofast -std=gnu99 -fno-threadsafe-statics
157 | SYS_CCFLAGS += -DNDEBUG -Dunix -D__unix -D__unix__
158 | SYS_CCFLAGS += -isystem$(SYSTEM_ROOT)/lib/libc/musl/src/internal
159 | SYS_CCFLAGS += -Wno-dangling-else -Wno-ignored-attributes -Wno-bitwise-op-parentheses -Wno-logical-op-parentheses -Wno-shift-op-parentheses -Wno-string-plus-int
160 | SYS_CCFLAGS += -Wno-unknown-pragmas -Wno-shift-count-overflow -Wno-return-type -Wno-macro-redefined -Wno-unused-result -Wno-pointer-sign
161 |
162 | SYS_CPP_OBJS := $(addprefix temp/,$(subst /,!,$(patsubst %.cpp,%.o,$(filter %.cpp,$(SYS_SOURCES)))))
163 | SYS_CC_OBJS := $(addprefix temp/,$(subst /,!,$(patsubst %.c,%.o,$(filter %.c,$(SYS_SOURCES)))))
164 | $(SYS_CPP_OBJS) : ; $(call SYS_COMPILE,$@,$(subst !,/,$(patsubst temp/%.o,$(SYSTEM_ROOT)/lib/%.cpp,$@)),$(CXX),$(SYS_CXXFLAGS))
165 | $(SYS_CC_OBJS) : ; $(call SYS_COMPILE,$@,$(subst !,/,$(patsubst temp/%.o,$(SYSTEM_ROOT)/lib/%.c,$@)),$(CC),$(SYS_CCFLAGS))
166 |
167 | define SYS_COMPILE
168 | $(info $2)
169 | @$(if $(wildcard $(dir $1)),,$(shell mkdir "$(dir $1)"))
170 | @$3 $4 $(CLANGFLAGS) -o $1 -c $2
171 | endef
172 |
173 | System.bc : $(SYS_CPP_OBJS) $(SYS_CC_OBJS)
174 | $(info Creating archive $@ ...)
175 | @$(LD) $(if $(ISWIN),"temp/*.o",temp/*.o) -r -o $@
176 | @$(if $(ISWIN),rmdir /S /Q,rm -rf) "temp"
177 | endif #need System.bc
178 | #------------------------------------------------------------------------------------------------------
179 |
--------------------------------------------------------------------------------
/WebGL/loader.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | WebAssembly Sample: WebGL
7 |
8 |
9 |
WebAssembly Sample: WebGL
10 |
Status: Loading...
11 |
12 |
13 |
38 |
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/WebGL/main.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | This is free and unencumbered software released into the public domain.
3 |
4 | Anyone is free to copy, modify, publish, use, compile, sell, or
5 | distribute this software, either in source code form or as a compiled
6 | binary, for any purpose, commercial or non-commercial, and by any
7 | means.
8 |
9 | In jurisdictions that recognize copyright laws, the author or authors
10 | of this software dedicate any and all copyright interest in the
11 | software to the public domain. We make this dedication for the benefit
12 | of the public at large and to the detriment of our heirs and
13 | successors. We intend this dedication to be an overt act of
14 | relinquishment in perpetuity of all present and future rights to this
15 | software under copyright law.
16 |
17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
21 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
22 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23 | OTHER DEALINGS IN THE SOFTWARE.
24 |
25 | For more information, please refer to
26 | */
27 |
28 | #define GL_GLEXT_PROTOTYPES
29 | #define EGL_EGLEXT_PROTOTYPES
30 | #include
31 | #include
32 |
33 | // Functions defined in loader.js
34 | extern "C" void WAJS_SetupCanvas(int width, int height);
35 | extern "C" unsigned int WAJS_GetTime();
36 |
37 | static const char* vertex_shader_text =
38 | "precision lowp float;"
39 | "uniform mat4 uMVP;"
40 | "attribute vec4 aPos;"
41 | "attribute vec3 aCol;"
42 | "varying vec3 vCol;"
43 | "void main()"
44 | "{"
45 | "vCol = aCol;"
46 | "gl_Position = uMVP * aPos;"
47 | "}";
48 |
49 | static const char* fragment_shader_text =
50 | "precision lowp float;"
51 | "varying vec3 vCol;"
52 | "void main()"
53 | "{"
54 | "gl_FragColor = vec4(vCol, 1.0);"
55 | "}";
56 |
57 | typedef struct Vertex { float x, y, r, g, b; } Vertex;
58 | static GLuint program, vertex_buffer;
59 | static GLint uMVP_location, aPos_location, aCol_location;
60 |
61 | // This function is called at startup
62 | int main(int argc, char *argv[])
63 | {
64 | WAJS_SetupCanvas(640, 480);
65 | glViewport(0, 0, 640, 480);
66 |
67 | GLuint vertex_shader = glCreateShader(GL_VERTEX_SHADER);
68 | glShaderSource(vertex_shader, 1, &vertex_shader_text, NULL);
69 | glCompileShader(vertex_shader);
70 |
71 | GLuint fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);
72 | glShaderSource(fragment_shader, 1, &fragment_shader_text, NULL);
73 | glCompileShader(fragment_shader);
74 |
75 | program = glCreateProgram();
76 | glAttachShader(program, vertex_shader);
77 | glAttachShader(program, fragment_shader);
78 | glLinkProgram(program);
79 |
80 | uMVP_location = glGetUniformLocation(program, "uMVP");
81 | aPos_location = glGetAttribLocation(program, "aPos");
82 | aCol_location = glGetAttribLocation(program, "aCol");
83 |
84 | glGenBuffers(1, &vertex_buffer);
85 | glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer);
86 |
87 | glEnableVertexAttribArray(aPos_location);
88 | glVertexAttribPointer(aPos_location, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)0);
89 | glEnableVertexAttribArray(aCol_location);
90 | glVertexAttribPointer(aCol_location, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)(sizeof(float) * 2));
91 |
92 | return 0;
93 | }
94 |
95 | // This function is called by loader.js every frame
96 | extern "C" void WAFNDraw()
97 | {
98 | float f = ((WAJS_GetTime() % 1000) / 1000.0f);
99 |
100 | glClear(GL_COLOR_BUFFER_BIT);
101 |
102 | Vertex vertices[3] =
103 | {
104 | { -0.6f, -0.4f, 1.f, 0.f, 0.f },
105 | { 0.6f, -0.4f, 0.f, 0.f, 1.f },
106 | { 0.f, 0.6f, 1.f, 1.f, 1.f },
107 | };
108 | vertices[0].r = 0.5f + sinf(f * 3.14159f * 2.0f) * 0.5f;
109 | vertices[1].b = 0.5f + cosf(f * 3.14159f * 2.0f) * 0.5f;
110 | glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer);
111 | glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
112 |
113 | GLfloat mvp[4*4] = { 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 1 };
114 | glUseProgram(program);
115 | glUniformMatrix4fv(uMVP_location, 1, GL_FALSE, mvp);
116 | glDrawArrays(GL_TRIANGLES, 0, 3);
117 | }
118 |
--------------------------------------------------------------------------------
/WebGL/output.wasm:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/schellingb/ClangWasm/94203708c127a54c89c790caeb91c00b38cb4cef/WebGL/output.wasm
--------------------------------------------------------------------------------
/showsource.js:
--------------------------------------------------------------------------------
1 | /*
2 | This is free and unencumbered software released into the public domain.
3 |
4 | Anyone is free to copy, modify, publish, use, compile, sell, or
5 | distribute this software, either in source code form or as a compiled
6 | binary, for any purpose, commercial or non-commercial, and by any
7 | means.
8 |
9 | In jurisdictions that recognize copyright laws, the author or authors
10 | of this software dedicate any and all copyright interest in the
11 | software to the public domain. We make this dedication for the benefit
12 | of the public at large and to the detriment of our heirs and
13 | successors. We intend this dedication to be an overt act of
14 | relinquishment in perpetuity of all present and future rights to this
15 | software under copyright law.
16 |
17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
21 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
22 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23 | OTHER DEALINGS IN THE SOFTWARE.
24 |
25 | For more information, please refer to
26 | */
27 |
28 | // Helper script to show source code with highlight in the HTML pages
29 | (function(){'use strict';
30 | var src = document.currentScript.getAttribute('data-source');
31 | document.write(''
32 | +'Download source '+src+' (License: Public Domain/Unlicense)'
33 | +'