Skip to content

style: run prettier on webassembly #20405

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Sep 10, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
119 changes: 59 additions & 60 deletions files/en-us/webassembly/c_to_wasm/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ tags:
- WebAssembly
- wasm
---

{{WebAssemblySidebar}}

When you've written a new code module in a language like C/C++, you can compile it into WebAssembly using a tool like [Emscripten](https://emscripten.org/). Let's look at how it works.
Expand Down Expand Up @@ -36,20 +37,20 @@ This is the simplest case we'll look at, whereby you get emscripten to generate

1. First we need an example to compile. Take a copy of the following simple C example, and save it in a file called `hello.c` in a new directory on your local drive:

```cpp
#include <stdio.h>
```cpp
#include <stdio.h>

int main() {
printf("Hello World\n");
return 0;
}
```
int main() {
printf("Hello World\n");
return 0;
}
```

2. Now, using the terminal window you used to enter the Emscripten compiler environment, navigate to the same directory as your `hello.c` file, and run the following command:

```bash
emcc hello.c -o hello.html
```
```bash
emcc hello.c -o hello.html
```

The options we've passed in with the command are as follows:

Expand All @@ -76,26 +77,26 @@ Sometimes you will want to use a custom HTML template. Let's look at how we can

1. First of all, save the following C code in a file called `hello2.c`, in a new directory:

```cpp
#include <stdio.h>
```cpp
#include <stdio.h>

int main() {
printf("Hello World\n");
return 0;
}
```
int main() {
printf("Hello World\n");
return 0;
}
```

2. Search for the file `shell_minimal.html` in your emsdk repo. Copy it into a subdirectory called `html_template` inside your previous new directory.
3. Now navigate into your new directory (again, in your Emscripten compiler environment terminal window), and run the following command:

```bash
emcc -o hello2.html hello2.c -O3 --shell-file html_template/shell_minimal.html
```
```bash
emcc -o hello2.html hello2.c -O3 --shell-file html_template/shell_minimal.html
```

The options we've passed are slightly different this time:
The options we've passed are slightly different this time:

- We've specified `-o hello2.html`, meaning that the compiler will still output the JavaScript glue code and `.html`.
- We've also specified `--shell-file html_template/shell_minimal.html` — this provides the path to the HTML template you want to use to create the HTML you will run your example through.
- We've specified `-o hello2.html`, meaning that the compiler will still output the JavaScript glue code and `.html`.
- We've also specified `--shell-file html_template/shell_minimal.html` — this provides the path to the HTML template you want to use to create the HTML you will run your example through.

4. Now let's run this example. The above command will have generated `hello2.html`, which will have much the same content as the template with some glue code added into load the generated wasm, run it, etc. Open it in your browser and you'll see much the same output as the last example.

Expand All @@ -109,60 +110,58 @@ If you have a function defined in your C code that you want to call as needed fr

1. To start with, save the following code as `hello3.c` in a new directory:

```cpp
#include <stdio.h>
#include <emscripten/emscripten.h>
```cpp
#include <stdio.h>
#include <emscripten/emscripten.h>

int main() {
printf("Hello World\n");
return 0;
}
int main() {
printf("Hello World\n");
return 0;
}

#ifdef __cplusplus
#define EXTERN extern "C"
#else
#define EXTERN
#endif
#ifdef __cplusplus
#define EXTERN extern "C"
#else
#define EXTERN
#endif

EXTERN EMSCRIPTEN_KEEPALIVE void myFunction(int argc, char ** argv) {
printf("MyFunction Called\n");
}
```
EXTERN EMSCRIPTEN_KEEPALIVE void myFunction(int argc, char ** argv) {
printf("MyFunction Called\n");
}
```

By default, Emscripten-generated code always just calls the `main()` function, and other functions are eliminated as dead code. Putting `EMSCRIPTEN_KEEPALIVE` before a function name stops this from happening. You also need to import the `emscripten.h` library to use `EMSCRIPTEN_KEEPALIVE`.
By default, Emscripten-generated code always just calls the `main()` function, and other functions are eliminated as dead code. Putting `EMSCRIPTEN_KEEPALIVE` before a function name stops this from happening. You also need to import the `emscripten.h` library to use `EMSCRIPTEN_KEEPALIVE`.

> **Note:** We are including the `#ifdef` blocks so that if you are trying to include this in C++ code, the example will still work. Due to C versus C++ name mangling rules, this would otherwise break, but here we are setting it so that it treats it as an external C function if you are using C++.
> **Note:** We are including the `#ifdef` blocks so that if you are trying to include this in C++ code, the example will still work. Due to C versus C++ name mangling rules, this would otherwise break, but here we are setting it so that it treats it as an external C function if you are using C++.

2. Now add `html_template/shell_minimal.html` with `\{\{{ SCRIPT }}}` as content into this new directory too, just for convenience (you'd obviously put this in a central place in your real dev environment).
3. Now let's run the compilation step again. From inside your latest directory (and while inside your Emscripten compiler environment terminal window), compile your C code with the following command. (Note that we need to compile with `NO_EXIT_RUNTIME`, which is necessary as otherwise when `main()` exits the runtime would be shut down — necessary for proper C emulation, e.g., atexits are called — and it wouldn't be valid to call compiled code.)

```bash
emcc -o hello3.html hello3.c -O3 --shell-file html_template/shell_minimal.html -s NO_EXIT_RUNTIME=1 -s "EXPORTED_RUNTIME_METHODS=['ccall']"
```
```bash
emcc -o hello3.html hello3.c -O3 --shell-file html_template/shell_minimal.html -s NO_EXIT_RUNTIME=1 -s "EXPORTED_RUNTIME_METHODS=['ccall']"
```

4. If you load the example in your browser again, you'll see the same thing as before!
5. Now we need to run our new `myFunction()` function from JavaScript. First of all, open up your hello3.html file in a text editor.
6. Add a {{HTMLElement("button")}} element as shown below, just above the first opening `<script type='text/javascript'>` tag.

```html
<button id="mybutton">Run myFunction</button>
```
```html
<button id="mybutton">Run myFunction</button>
```

7. Now add the following code at the end of the first {{HTMLElement("script")}} element:

```js
document
.getElementById("mybutton")
.addEventListener("click", () => {
alert("check console");
const result = Module.ccall(
"myFunction", // name of C function
null, // return type
null, // argument types
null, // arguments
);
});
```
```js
document.getElementById("mybutton").addEventListener("click", () => {
alert("check console");
const result = Module.ccall(
"myFunction", // name of C function
null, // return type
null, // argument types
null // arguments
);
});
```

This illustrates how `ccall()` is used to call the exported function.

Expand Down
87 changes: 47 additions & 40 deletions files/en-us/webassembly/caching_modules/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ tags:
- compile
- wasm
---

{{WebAssemblySidebar}}

> **Warning:** Experimental {{jsxref("WebAssembly.Module")}} IndexedDB serialization support is being removed from browsers; see {{bug("1469395")}} and [this spec issue](https://github.com/WebAssembly/spec/issues/821).
Expand Down Expand Up @@ -43,56 +44,62 @@ function instantiateCachedURL(dbVersion, url, importObject) {
The first helper function contained inside `instantiateCachedURL()` — `openDatabase()` — creates an object store for storing wasm modules, and also handles clearing out the database if the `dbVersion` is updated; it returns a promise resolving to the new database.

```js
function openDatabase() {
return new Promise((resolve, reject) => {
const request = indexedDB.open(dbName, dbVersion);
request.onerror = reject.bind(null, 'Error opening wasm cache database');
request.onsuccess = () => { resolve(request.result) };
request.onupgradeneeded = (event) => {
const db = request.result;
if (db.objectStoreNames.contains(storeName)) {
console.log(`Clearing out version ${event.oldVersion} wasm cache`);
db.deleteObjectStore(storeName);
}
console.log(`Creating version ${event.newVersion} wasm cache`);
db.createObjectStore(storeName)
};
});
}
function openDatabase() {
return new Promise((resolve, reject) => {
const request = indexedDB.open(dbName, dbVersion);
request.onerror = reject.bind(null, "Error opening wasm cache database");
request.onsuccess = () => {
resolve(request.result);
};
request.onupgradeneeded = (event) => {
const db = request.result;
if (db.objectStoreNames.contains(storeName)) {
console.log(`Clearing out version ${event.oldVersion} wasm cache`);
db.deleteObjectStore(storeName);
}
console.log(`Creating version ${event.newVersion} wasm cache`);
db.createObjectStore(storeName);
};
});
}
```

### Looking up modules in the database

Our next function — `lookupInDatabase()` — provides a simple promise-based operation for looking up the given `url` in the object store we created above. It resolves with the stored compiled module, or rejects with an error.

```js
function lookupInDatabase(db) {
return new Promise((resolve, reject) => {
const store = db.transaction([storeName]).objectStore(storeName);
const request = store.get(url);
request.onerror = reject.bind(null, `Error getting wasm module ${url}`);
request.onsuccess = (event) => {
if (request.result) {
resolve(request.result);
} else {
reject(`Module ${url} was not found in wasm cache`);
}
function lookupInDatabase(db) {
return new Promise((resolve, reject) => {
const store = db.transaction([storeName]).objectStore(storeName);
const request = store.get(url);
request.onerror = reject.bind(null, `Error getting wasm module ${url}`);
request.onsuccess = (event) => {
if (request.result) {
resolve(request.result);
} else {
reject(`Module ${url} was not found in wasm cache`);
}
});
}
};
});
}
```

### Storing and instantiating modules

Next, we define a function `storeInDatabase()` that fires off an async operation to store a given wasm module in a given database.

```js
function storeInDatabase(db, module) {
const store = db.transaction([storeName], 'readwrite').objectStore(storeName);
const request = store.put(module, url);
request.onerror = (err) => { console.log(`Failed to store in wasm cache: ${err}`) };
request.onsuccess = (err) => { console.log(`Successfully stored ${url} in wasm cache`) };
}
function storeInDatabase(db, module) {
const store = db.transaction([storeName], "readwrite").objectStore(storeName);
const request = store.put(module, url);
request.onerror = (err) => {
console.log(`Failed to store in wasm cache: ${err}`);
};
request.onsuccess = (err) => {
console.log(`Successfully stored ${url} in wasm cache`);
};
}
```

### Using our helper functions
Expand Down Expand Up @@ -150,11 +157,11 @@ With the above library function defined, getting a wasm module instance and usin
```js
const wasmCacheVersion = 1;

instantiateCachedURL(wasmCacheVersion, 'test.wasm').then((instance) =>
console.log(`Instance says the answer is: ${instance.exports.answer()}`)
).catch((err) =>
console.error(`Failure to instantiate: ${err}`)
);
instantiateCachedURL(wasmCacheVersion, "test.wasm")
.then((instance) =>
console.log(`Instance says the answer is: ${instance.exports.answer()}`)
)
.catch((err) => console.error(`Failure to instantiate: ${err}`));
```

## Browser support
Expand Down
1 change: 1 addition & 0 deletions files/en-us/webassembly/concepts/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ tags:
- text format
- web platform
---

{{WebAssemblySidebar}}

This article explains the concepts behind how WebAssembly works including its goals, the problems it solves, and how it runs inside the web browser's rendering engine.
Expand Down
31 changes: 18 additions & 13 deletions files/en-us/webassembly/existing_c_to_wasm/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ tags:
- WebAssembly
- wasm
---

{{WebAssemblySidebar}}

A core use-case for WebAssembly is to take the existing ecosystem of C libraries and allow developers to use them on the web.
Expand Down Expand Up @@ -52,7 +53,7 @@ Now you only need some HTML and JavaScript to load your new module:
<script>
Module.onRuntimeInitialized = async () => {
const api = {
version: Module.cwrap('version', 'number', []),
version: Module.cwrap("version", "number", []),
};
console.log(api.version());
};
Expand All @@ -72,16 +73,16 @@ Getting the encoder's version number is great, but encoding an actual image woul
The first question you need to answer is: how do I get the image into wasm? Looking at the [encoding API of libwebp](https://developers.google.com/speed/webp/docs/api#simple_encoding_api), you'll find that it expects an array of bytes in RGB, RGBA, BGR or BGRA. Luckily, the Canvas API has {{domxref("CanvasRenderingContext2D.getImageData")}} — that gives you an {{jsxref("Uint8ClampedArray")}} containing the image data in RGBA:

```js
async function loadImage(src) {
async function loadImage(src) {
// Load image
const imgBlob = await fetch(src).then((resp) => resp.blob());
const img = await createImageBitmap(imgBlob);
// Make canvas same size as image
const canvas = document.createElement('canvas');
const canvas = document.createElement("canvas");
canvas.width = img.width;
canvas.height = img.height;
// Draw image onto canvas
const ctx = canvas.getContext('2d');
const ctx = canvas.getContext("2d");
ctx.drawImage(img, 0, 0);
return ctx.getImageData(0, 0, img.width, img.height);
}
Expand All @@ -107,16 +108,16 @@ The `create_buffer()` function allocates a buffer for the RGBA image — hence 4

```js
const api = {
version: Module.cwrap('version', 'number', []),
create_buffer: Module.cwrap('create_buffer', 'number', ['number', 'number']),
destroy_buffer: Module.cwrap('destroy_buffer', '', ['number']),
encode: Module.cwrap("encode", "", ["number","number","number","number",]),
version: Module.cwrap("version", "number", []),
create_buffer: Module.cwrap("create_buffer", "number", ["number", "number"]),
destroy_buffer: Module.cwrap("destroy_buffer", "", ["number"]),
encode: Module.cwrap("encode", "", ["number", "number", "number", "number"]),
free_result: Module.cwrap("free_result", "", ["number"]),
get_result_pointer: Module.cwrap("get_result_pointer", "number", []),
get_result_size: Module.cwrap("get_result_size", "number", []),
};

const image = await loadImage('./image.jpg');
const image = await loadImage("./image.jpg");
const p = api.create_buffer(image.width, image.height);
Module.HEAP8.set(image.data, p);
// ... call encoder ...
Expand Down Expand Up @@ -164,7 +165,11 @@ Now with all of that in place, you can call the encoding function, grab the poin
api.encode(p, image.width, image.height, 100);
const resultPointer = api.get_result_pointer();
const resultSize = api.get_result_size();
const resultView = new Uint8Array(Module.HEAP8.buffer, resultPointer, resultSize);
const resultView = new Uint8Array(
Module.HEAP8.buffer,
resultPointer,
resultSize
);
const result = new Uint8Array(resultView);
api.free_result(resultPointer);
```
Expand All @@ -180,11 +185,11 @@ Luckily, the solution to this problem is in the error message. You just need to
And there you have it. You have compiled a WebP encoder and transcoded a JPEG image to WebP. To prove that it worked, turn your result buffer into a blob and use it on an `<img>` element:

```js
const blob = new Blob([result], {type: 'image/webp'});
const blob = new Blob([result], { type: "image/webp" });
const blobURL = URL.createObjectURL(blob);
const img = document.createElement('img');
const img = document.createElement("img");
img.src = blobURL;
document.body.appendChild(img)
document.body.appendChild(img);
```

Behold, the glory of a new WebP image.
Expand Down
Loading