aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--.gitignore1
-rwxr-xr-x00_hello_world/build.sh4
-rw-r--r--00_hello_world/hello.c5
-rwxr-xr-x00_hello_world/run-node.sh3
-rwxr-xr-x00_hello_world/run-server.sh3
-rwxr-xr-x01_library/build.sh4
-rw-r--r--01_library/index.html17
-rw-r--r--01_library/library.c3
-rw-r--r--01_library/program.js6
-rwxr-xr-x01_library/run-node.sh3
-rwxr-xr-x01_library/run-server.sh3
-rw-r--r--01_library/script.js10
-rwxr-xr-x02_library_modularized/build.sh5
-rw-r--r--02_library_modularized/index.html16
-rw-r--r--02_library_modularized/library.c3
-rw-r--r--02_library_modularized/mime.txt1
-rw-r--r--02_library_modularized/program.mjs6
-rwxr-xr-x02_library_modularized/run-node.sh3
-rwxr-xr-x02_library_modularized/run-server.sh3
-rw-r--r--02_library_modularized/script.mjs14
-rwxr-xr-x03_threads/build.sh6
-rw-r--r--03_threads/index.html19
-rw-r--r--03_threads/mime.txt1
-rw-r--r--03_threads/primes.c53
-rw-r--r--03_threads/program.mjs6
-rwxr-xr-x03_threads/run-node.sh3
-rwxr-xr-x03_threads/run-server.sh6
-rw-r--r--03_threads/script.mjs16
-rw-r--r--README.md65
29 files changed, 288 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..5c644e1
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
*/build
diff --git a/00_hello_world/build.sh b/00_hello_world/build.sh
new file mode 100755
index 0000000..9b6b576
--- /dev/null
+++ b/00_hello_world/build.sh
@@ -0,0 +1,4 @@
1#!/bin/sh
2
3mkdir -p build
4emcc -o build/index.html hello.c
diff --git a/00_hello_world/hello.c b/00_hello_world/hello.c
new file mode 100644
index 0000000..66e36aa
--- /dev/null
+++ b/00_hello_world/hello.c
@@ -0,0 +1,5 @@
1#include <stdio.h>
2
3int main() {
4 printf("Hello, web!\n");
5}
diff --git a/00_hello_world/run-node.sh b/00_hello_world/run-node.sh
new file mode 100755
index 0000000..3fdf61e
--- /dev/null
+++ b/00_hello_world/run-node.sh
@@ -0,0 +1,3 @@
1#!/bin/sh
2
3node build/index.js
diff --git a/00_hello_world/run-server.sh b/00_hello_world/run-server.sh
new file mode 100755
index 0000000..c0087d4
--- /dev/null
+++ b/00_hello_world/run-server.sh
@@ -0,0 +1,3 @@
1#!/bin/sh
2
3darkhttpd build
diff --git a/01_library/build.sh b/01_library/build.sh
new file mode 100755
index 0000000..5af8919
--- /dev/null
+++ b/01_library/build.sh
@@ -0,0 +1,4 @@
1#!/bin/sh
2
3mkdir -p build
4emcc -sEXPORTED_FUNCTIONS=_multiply -o build/library.js library.c
diff --git a/01_library/index.html b/01_library/index.html
new file mode 100644
index 0000000..84d8e10
--- /dev/null
+++ b/01_library/index.html
@@ -0,0 +1,17 @@
1<!doctype html>
2<html lang="en-US">
3<head>
4 <meta charset="utf-8" />
5 <meta name="viewport" content="width=device-width" />
6 <title>Multiply two numbers</title>
7 <script src="./build/library.js" defer></script>
8 <script src="./script.js" defer></script>
9</head>
10
11<body>
12 <input id="aInput" /> x <br />
13 <input id="bInput" /> <button id="goButton">=</button> <br />
14 <p id="resultText"></p>
15</body>
16
17</html>
diff --git a/01_library/library.c b/01_library/library.c
new file mode 100644
index 0000000..de68b76
--- /dev/null
+++ b/01_library/library.c
@@ -0,0 +1,3 @@
1int multiply(int a, int b) {
2 return a * b;
3}
diff --git a/01_library/program.js b/01_library/program.js
new file mode 100644
index 0000000..5cfc6c5
--- /dev/null
+++ b/01_library/program.js
@@ -0,0 +1,6 @@
1var library = require("./build/library.js");
2
3library.onRuntimeInitialized = () => {
4 const result = library._multiply(6, 7);
5 console.log("The answer is " + result);
6};
diff --git a/01_library/run-node.sh b/01_library/run-node.sh
new file mode 100755
index 0000000..238f51f
--- /dev/null
+++ b/01_library/run-node.sh
@@ -0,0 +1,3 @@
1#!/bin/sh
2
3node program.js
diff --git a/01_library/run-server.sh b/01_library/run-server.sh
new file mode 100755
index 0000000..cc9f1e0
--- /dev/null
+++ b/01_library/run-server.sh
@@ -0,0 +1,3 @@
1#!/bin/sh
2
3darkhttpd .
diff --git a/01_library/script.js b/01_library/script.js
new file mode 100644
index 0000000..9432402
--- /dev/null
+++ b/01_library/script.js
@@ -0,0 +1,10 @@
1var aInput = document.getElementById("aInput");
2var bInput = document.getElementById("bInput");
3var button = document.getElementById("goButton");
4var resultText = document.getElementById("resultText");
5
6button.addEventListener("click", () => {
7 var a = Number(aInput.value);
8 var b = Number(bInput.value);
9 resultText.innerText = Module._multiply(a, b);
10});
diff --git a/02_library_modularized/build.sh b/02_library_modularized/build.sh
new file mode 100755
index 0000000..f5564fc
--- /dev/null
+++ b/02_library_modularized/build.sh
@@ -0,0 +1,5 @@
1#!/bin/sh
2
3mkdir -p build
4emcc -sEXPORTED_FUNCTIONS=_multiply -sMODULARIZE -sEXPORT_NAME=MyLibrary \
5 -o build/library.mjs library.c
diff --git a/02_library_modularized/index.html b/02_library_modularized/index.html
new file mode 100644
index 0000000..4b31417
--- /dev/null
+++ b/02_library_modularized/index.html
@@ -0,0 +1,16 @@
1<!doctype html>
2<html lang="en-US">
3<head>
4 <meta charset="utf-8" />
5 <meta name="viewport" content="width=device-width" />
6 <title>Multiply two numbers</title>
7 <script src="./script.mjs" type="module" defer></script>
8</head>
9
10<body>
11 <input id="aInput" /> x <br />
12 <input id="bInput" /> <button id="goButton">=</button> <br />
13 <p id="resultText"></p>
14</body>
15
16</html>
diff --git a/02_library_modularized/library.c b/02_library_modularized/library.c
new file mode 100644
index 0000000..de68b76
--- /dev/null
+++ b/02_library_modularized/library.c
@@ -0,0 +1,3 @@
1int multiply(int a, int b) {
2 return a * b;
3}
diff --git a/02_library_modularized/mime.txt b/02_library_modularized/mime.txt
new file mode 100644
index 0000000..6a9a425
--- /dev/null
+++ b/02_library_modularized/mime.txt
@@ -0,0 +1 @@
text/javascript mjs
diff --git a/02_library_modularized/program.mjs b/02_library_modularized/program.mjs
new file mode 100644
index 0000000..5fc3fcd
--- /dev/null
+++ b/02_library_modularized/program.mjs
@@ -0,0 +1,6 @@
1import MyLibrary from "./build/library.mjs";
2
3var myLibraryInstance = await MyLibrary();
4
5const result = myLibraryInstance._multiply(6, 7);
6console.log("The answer is " + result);
diff --git a/02_library_modularized/run-node.sh b/02_library_modularized/run-node.sh
new file mode 100755
index 0000000..a6c9aa8
--- /dev/null
+++ b/02_library_modularized/run-node.sh
@@ -0,0 +1,3 @@
1#!/bin/sh
2
3node program.mjs
diff --git a/02_library_modularized/run-server.sh b/02_library_modularized/run-server.sh
new file mode 100755
index 0000000..12c1a1c
--- /dev/null
+++ b/02_library_modularized/run-server.sh
@@ -0,0 +1,3 @@
1#!/bin/sh
2
3darkhttpd . --mimetypes mime.txt
diff --git a/02_library_modularized/script.mjs b/02_library_modularized/script.mjs
new file mode 100644
index 0000000..bac26d4
--- /dev/null
+++ b/02_library_modularized/script.mjs
@@ -0,0 +1,14 @@
1import MyLibrary from "./build/library.mjs";
2
3var myLibraryInstance = await MyLibrary();
4
5var aInput = document.getElementById("aInput");
6var bInput = document.getElementById("bInput");
7var button = document.getElementById("goButton");
8var resultText = document.getElementById("resultText");
9
10button.addEventListener("click", () => {
11 var a = Number(aInput.value);
12 var b = Number(bInput.value);
13 resultText.innerText = myLibraryInstance._multiply(a, b);
14});
diff --git a/03_threads/build.sh b/03_threads/build.sh
new file mode 100755
index 0000000..2f08909
--- /dev/null
+++ b/03_threads/build.sh
@@ -0,0 +1,6 @@
1#!/bin/sh
2
3mkdir -p build
4emcc -sEXPORTED_FUNCTIONS=_primes_in_range -sMODULARIZE -sEXPORT_NAME=Primes \
5 -pthread -sPTHREAD_POOL_SIZE=16 \
6 -o build/primes.mjs primes.c
diff --git a/03_threads/index.html b/03_threads/index.html
new file mode 100644
index 0000000..29cfaf8
--- /dev/null
+++ b/03_threads/index.html
@@ -0,0 +1,19 @@
1<!doctype html>
2<html lang="en-US">
3<head>
4 <meta charset="utf-8" />
5 <meta name="viewport" content="width=device-width" />
6 <title>Multiply two numbers</title>
7 <script src="./script.mjs" type="module" defer></script>
8</head>
9
10<body>
11 <label for="aInput">Lower bound (included)</label><br />
12 <input id="aInput" name="aInput" /> x <br />
13 <label for="bInput">Upper bound (excluded)</label><br />
14 <input id="bInput" name="bInput" /> <br />
15 <button id="goButton">Compute</button> <br />
16 <p id="resultText"></p>
17</body>
18
19</html>
diff --git a/03_threads/mime.txt b/03_threads/mime.txt
new file mode 100644
index 0000000..6a9a425
--- /dev/null
+++ b/03_threads/mime.txt
@@ -0,0 +1 @@
text/javascript mjs
diff --git a/03_threads/primes.c b/03_threads/primes.c
new file mode 100644
index 0000000..a5076c6
--- /dev/null
+++ b/03_threads/primes.c
@@ -0,0 +1,53 @@
1#include <stdbool.h>
2#include <pthread.h>
3
4#define NTHREADS 16
5
6bool isprime(int);
7void *pthread_routine(void *);
8
9struct interval { int low; int high; int count; };
10
11int primes_in_range(int low, int high) {
12 pthread_t threads[NTHREADS];
13 struct interval args[NTHREADS];
14
15 if (low < 0 || high < low)
16 return 0;
17
18 int interval_size = (high-low)/NTHREADS + 1;
19 for (int i = 0; i < NTHREADS; i++) {
20 args[i].low = low + i*interval_size;
21 args[i].high = args[i].low + interval_size;
22 pthread_create(&threads[i], NULL, pthread_routine, &args[i]);
23 }
24
25 int result = 0;
26 for (int i = 0; i < NTHREADS; i++) {
27 pthread_join(threads[i], NULL);
28 result += args[i].count;
29 }
30
31 return result;
32}
33
34bool isprime(int n) {
35 if (n < 2)
36 return false;
37
38 for (int i = 2; i*i <= n; i++)
39 if (n % i == 0)
40 return false;
41 return true;
42}
43
44void *pthread_routine(void *arg) {
45 struct interval *interval = arg;
46
47 interval->count = 0;
48 for (int i = interval->low; i < interval->high; i++)
49 if (isprime(i))
50 interval->count++;
51
52 return NULL;
53}
diff --git a/03_threads/program.mjs b/03_threads/program.mjs
new file mode 100644
index 0000000..a5a89ce
--- /dev/null
+++ b/03_threads/program.mjs
@@ -0,0 +1,6 @@
1import Primes from "./build/primes.mjs"
2
3var primes = await Primes();
4
5const count = primes._primes_in_range(1, 100);
6console.log("There are " + count + " primes betwees 1 and 100");
diff --git a/03_threads/run-node.sh b/03_threads/run-node.sh
new file mode 100755
index 0000000..a6c9aa8
--- /dev/null
+++ b/03_threads/run-node.sh
@@ -0,0 +1,3 @@
1#!/bin/sh
2
3node program.mjs
diff --git a/03_threads/run-server.sh b/03_threads/run-server.sh
new file mode 100755
index 0000000..3a526f3
--- /dev/null
+++ b/03_threads/run-server.sh
@@ -0,0 +1,6 @@
1#!/bin/sh
2
3darkhttpd . \
4 --mimetypes mime.txt \
5 --header 'Cross-Origin-Opener-Policy: same-origin' \
6 --header 'Cross-Origin-Embedder-Policy: require-corp'
diff --git a/03_threads/script.mjs b/03_threads/script.mjs
new file mode 100644
index 0000000..4b52ae0
--- /dev/null
+++ b/03_threads/script.mjs
@@ -0,0 +1,16 @@
1import Primes from "./build/primes.mjs";
2
3var primes = await Primes();
4
5var aInput = document.getElementById("aInput");
6var bInput = document.getElementById("bInput");
7var button = document.getElementById("goButton");
8var resultText = document.getElementById("resultText");
9
10button.addEventListener("click", () => {
11 var a = Number(aInput.value);
12 var b = Number(bInput.value);
13 const count = primes._primes_in_range(a, b);
14 resultText.innerText = "There are " + count + " primes between " +
15 a + " and " + b;
16});
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..4326298
--- /dev/null
+++ b/README.md
@@ -0,0 +1,65 @@
1# How to port a complex C codebase to the web
2
3*This repository is still work in progress*
4
5This repository contains the source code for the examples discussed in
6a post walkthrough that is going to appear shortly on my website.
7It will be linked here once published.
8
9Each sub-folder is a self-contained example of a C program (or library)
10that can be compiled to [WebAssembly](https://webassembly.org/) using
11[Emscripten](https://emscripten.org), and some JavaScript and HTML code
12that can be used to run the C or C++ code in a web page or in a JavaScript
13runtime such as [Node.js](https://nodejs.org). Following these steps in
14order will walk you through the process of deploying a complex C or C++
15program (including multithreading, persistent storage, callback functions
16and so on) as a web app.
17
18Besides the source files, each folder contains a few one-line shell
19scripts, for convenience:
20
21* `build.sh`: to build the C / C++ code with Emscripten.
22* `run-node.sh`: to run an example program in Node.js.
23* `run-server.sh`: to start a web server on
24 [localhost:8080](http://localhost:8080) running an example web page
25 (require darkhttpd, see below).
26
27The examples have been tested only on Linux, but should work on any
28UNIX system, and should be easy to adapt to Windows or other OSes.
29Pull requests are welcome.
30
31## Prerequisites
32
33In order to follow this tutorial, you are going to need the following:
34
351. [Emscripten](https://emscripten.org)
362. A web server to run locally, such as
37 [darkhttpd](https://github.com/emikulic/darkhttpd)
383. [Node.js](https://nodejs.org) (this is optional, since a version
39 of Node.js is distributed together with emscripten).
40
41## 0. Hello world
42
43The folder `00_hello_world` contains the simplest possible example.
44
45## 1. Building a library
46
47A common use case for building C or C++ code to WebAssembly is using some
48high-performance library in a web app. In this situation, the code you
49want to build does not have a `main()` entry point, but instead its public
50functions are called from JavaScript. Motivated by this, in the folder
51`01_library` you'll find an extremely simple C library (with only one
52one-line function), and some JavaScript code to run it from a web page.
53
54## 2. Making it a module
55
56In `02_library_modularized` we review the previous example and we build it
57into a
58[module](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules). The result is the same, but more convenient to use.
59
60## 3. Multi-threading
61
62In `03_threads` we build a more complicated example based on
63[pthreads](https://en.wikipedia.org/wiki/Pthreads). To run this
64example, the web server has to be configured to provide the correct
65`Cross-Origin-*` headers, see `03_threads/run-server.sh` for details.

Generated with cgit - Back to sebastiano.tronto.net