Skip to content

Commit ca4d196

Browse files
committed
Initial Commit
0 parents  commit ca4d196

File tree

13 files changed

+1033
-0
lines changed

13 files changed

+1033
-0
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
libs
2+
build
3+
tests/**/out.stl

.vscode/settings.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"deno.enable": true,
3+
"deno.lint": true,
4+
"deno.unstable": true
5+
}

COPYING

Lines changed: 339 additions & 0 deletions
Large diffs are not rendered by default.

Dockerfile

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
FROM emscripten/emsdk as boost
2+
COPY boost .
3+
RUN ./bootstrap.sh
4+
RUN ./b2 toolset=emscripten cxxflags="-std=c++11 -stdlib=libc++" linkflags="-stdlib=libc++" cxxflags=-DPTHREADS cxxflags=-DBOOST_THREAD_POSIX cxxflags=-pthread cxxflags=-DTHREAD release --disable-icu --with-regex --with-filesystem --with-system --with-thread --with-program_options install link=static runtime-link=static --prefix=/emsdk/upstream/emscripten/cache/sysroot
5+
6+
7+
FROM emscripten/emsdk as zlib
8+
COPY zlib .
9+
RUN emcmake cmake -B ../build . -DCMAKE_BUILD_TYPE=Release
10+
RUN cd ../build && make && make install
11+
12+
13+
FROM emscripten/emsdk as libzip
14+
COPY --from=zlib /emsdk/upstream/emscripten/cache/sysroot /emsdk/upstream/emscripten/cache/sysroot
15+
COPY libzip .
16+
RUN emcmake cmake -B ../build . -DCMAKE_BUILD_TYPE=Release
17+
RUN cd ../build && make && make install
18+
19+
20+
FROM emscripten/emsdk as glib
21+
COPY glib .
22+
RUN apt-get update \
23+
&& apt-get install -qqy \
24+
build-essential \
25+
prelink \
26+
autoconf \
27+
libtool \
28+
texinfo \
29+
pkgconf \
30+
# needed for Meson
31+
ninja-build \
32+
python3-pip \
33+
&& pip3 install meson
34+
ARG MESON_PATCH=https://github.com/kleisauke/wasm-vips/raw/master/build/patches/meson-emscripten.patch
35+
RUN cd $(dirname `python3 -c "import mesonbuild as _; print(_.__path__[0])"`) \
36+
&& curl -Ls $MESON_PATCH | patch -p1
37+
RUN chmod +x build.sh; ./build.sh
38+
39+
40+
FROM emscripten/emsdk as freetype
41+
COPY --from=zlib /emsdk/upstream/emscripten/cache/sysroot /emsdk/upstream/emscripten/cache/sysroot
42+
COPY freetype .
43+
RUN emcmake cmake -B ../build . -DFT_REQUIRE_ZLIB=TRUE -DCMAKE_BUILD_TYPE=Release
44+
RUN cd ../build && make && make install
45+
46+
47+
FROM emscripten/emsdk as libxml2
48+
COPY libxml2 .
49+
RUN emcmake cmake -B ../build . -DLIBXML2_WITH_PYTHON=OFF -DLIBXML2_WITH_LZMA=OFF -DLIBXML2_WITH_ZLIB=OFF -DCMAKE_BUILD_TYPE=Release
50+
RUN cd ../build && make && make install
51+
52+
53+
FROM emscripten/emsdk as fontconfig
54+
RUN apt-get update && apt-get install pkg-config gperf automake libtool gettext autopoint -y
55+
COPY --from=zlib /emsdk/upstream/emscripten/cache/sysroot /emsdk/upstream/emscripten/cache/sysroot
56+
COPY --from=freetype /emsdk/upstream/emscripten/cache/sysroot /emsdk/upstream/emscripten/cache/sysroot
57+
COPY --from=libxml2 /emsdk/upstream/emscripten/cache/sysroot /emsdk/upstream/emscripten/cache/sysroot
58+
COPY fontconfig .
59+
RUN FREETYPE_CFLAGS="-I/emsdk/upstream/emscripten/cache/sysroot/include/freetype2" FREETYPE_LIBS="-lfreetype -lz" emconfigure ./autogen.sh CFLAGS="-s USE_PTHREADS=1" --host none --disable-docs --disable-shared --enable-static --sysconfdir=/ --localstatedir=/ --with-default-fonts=/fonts --enable-libxml2 --prefix=/emsdk/upstream/emscripten/cache/sysroot
60+
RUN echo "all install:" > test/Makefile.in
61+
RUN emmake make
62+
RUN emmake make install || true
63+
64+
65+
FROM emscripten/emsdk as harfbuzz
66+
COPY --from=freetype /emsdk/upstream/emscripten/cache/sysroot /emsdk/upstream/emscripten/cache/sysroot
67+
COPY harfbuzz .
68+
RUN emcmake cmake -E env CXXFLAGS="-s USE_PTHREADS=1" cmake -B ../build . -DCMAKE_BUILD_TYPE=Release -DHB_HAVE_FREETYPE=ON
69+
RUN cd ../build && make && make install
70+
71+
72+
FROM emscripten/emsdk as eigen
73+
COPY eigen .
74+
RUN emcmake cmake -B ../build . -DCMAKE_BUILD_TYPE=Release
75+
RUN cd ../build && make && make install
76+
77+
78+
FROM emscripten/emsdk as cgal
79+
COPY cgal .
80+
RUN emcmake cmake -B ../build . -DCMAKE_BUILD_TYPE=Release
81+
RUN cd ../build && make && make install
82+
83+
84+
FROM emscripten/emsdk as gmp
85+
COPY gmp-6.1.2 .
86+
RUN emconfigure ./configure --disable-assembly --host none --enable-cxx --prefix=/emsdk/upstream/emscripten/cache/sysroot
87+
RUN make && make install
88+
89+
90+
FROM emscripten/emsdk as mpfr
91+
COPY --from=gmp /emsdk/upstream/emscripten/cache/sysroot /emsdk/upstream/emscripten/cache/sysroot
92+
COPY mpfr-4.1.0 .
93+
RUN emconfigure ./configure CFLAGS="-s USE_PTHREADS=1" --host none --with-gmp=/emsdk/upstream/emscripten/cache/sysroot --prefix=/emsdk/upstream/emscripten/cache/sysroot
94+
RUN make && make install
95+
96+
97+
FROM emscripten/emsdk as openscad
98+
RUN apt-get update && apt-get install pkg-config flex bison -y
99+
# Dependencies
100+
COPY --from=boost /emsdk/upstream/emscripten/cache/sysroot /emsdk/upstream/emscripten/cache/sysroot
101+
COPY --from=gmp /emsdk/upstream/emscripten/cache/sysroot /emsdk/upstream/emscripten/cache/sysroot
102+
COPY --from=mpfr /emsdk/upstream/emscripten/cache/sysroot /emsdk/upstream/emscripten/cache/sysroot
103+
COPY --from=cgal /emsdk/upstream/emscripten/cache/sysroot /emsdk/upstream/emscripten/cache/sysroot
104+
COPY --from=eigen /emsdk/upstream/emscripten/cache/sysroot /emsdk/upstream/emscripten/cache/sysroot
105+
COPY --from=harfbuzz /emsdk/upstream/emscripten/cache/sysroot /emsdk/upstream/emscripten/cache/sysroot
106+
COPY --from=fontconfig /emsdk/upstream/emscripten/cache/sysroot /emsdk/upstream/emscripten/cache/sysroot
107+
COPY --from=glib /emsdk/upstream/emscripten/cache/sysroot /emsdk/upstream/emscripten/cache/sysroot
108+
COPY --from=libzip /emsdk/upstream/emscripten/cache/sysroot /emsdk/upstream/emscripten/cache/sysroot
109+
# End Dependencies
110+
111+
COPY openscad .
112+
RUN export PKG_CONFIG_PATH="/emsdk/upstream/emscripten/cache/sysroot/lib/pkgconfig"
113+
RUN emcmake cmake -B ../build . -DNULLGL=ON \
114+
-DCMAKE_BUILD_TYPE=Release \
115+
-DHARFBUZZ_INCLUDE_DIRS=/emsdk/upstream/emscripten/cache/sysroot/include/harfbuzz \
116+
-DFONTCONFIG_INCLUDE_DIR=/emsdk/upstream/emscripten/cache/sysroot/include/fontconfig \
117+
-DFONTCONFIG_LIBRARIES=libfontconfig.a
118+
119+
# Hack to fix build includes
120+
RUN sed -e "s|-isystem /emsdk/upstream/emscripten/cache/sysroot/include||g" -i ../build/CMakeFiles/OpenSCAD.dir/includes_C.rsp
121+
RUN sed -e "s|-isystem /emsdk/upstream/emscripten/cache/sysroot/include||g" -i ../build/CMakeFiles/OpenSCAD.dir/includes_CXX.rsp
122+
RUN sed -e "s|-lfontconfig|/emsdk/upstream/emscripten/cache/sysroot/lib/libglib-2.0.a /emsdk/upstream/emscripten/cache/sysroot/lib/libzip.a /emsdk/upstream/emscripten/cache/sysroot/lib/libz.a /emsdk/upstream/emscripten/cache/sysroot/lib/libfontconfig.a|g" -i ../build/CMakeFiles/OpenSCAD.dir/linklibs.rsp
123+
124+
# Add emscripten flags here
125+
RUN sed -e "s|em++|em++ -s USE_PTHREADS=1 -s NO_DISABLE_EXCEPTION_CATCHING -s FORCE_FILESYSTEM=1 -s ALLOW_MEMORY_GROWTH=1 -s EXTRA_EXPORTED_RUNTIME_METHODS=['FS'] -s EXPORTED_RUNTIME_METHODS=callMain -s EXPORT_ES6=1 -s ENVIRONMENT=web,worker -s MODULARIZE=1 -s EXPORT_NAME=OpenSCAD -s EXIT_RUNTIME=1|g" -i ../build/CMakeFiles/OpenSCAD.dir/link.txt
126+
127+
RUN cd ../build && make -j12

Makefile

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
all: build/openscad.js
2+
3+
clean:
4+
rm -rf libs
5+
rm -rf build
6+
7+
test:
8+
cd tests; deno test --allow-read --allow-write
9+
10+
.PHONY: example
11+
example:
12+
cd example; deno run --allow-net --allow-read server.ts
13+
14+
build/openscad.js: build
15+
docker run --name tmpcpy openscad-wasm
16+
docker cp tmpcpy:/build/openscad.js build
17+
docker cp tmpcpy:/build/openscad.worker.js build
18+
docker cp tmpcpy:/build/openscad.wasm build
19+
docker rm tmpcpy
20+
21+
build: libs
22+
docker build libs -f Dockerfile --target openscad -t openscad-wasm
23+
mkdir build
24+
25+
libs: libs/cgal \
26+
libs/eigen \
27+
libs/fontconfig \
28+
libs/freetype \
29+
libs/glib \
30+
libs/harfbuzz \
31+
libs/lib3mf \
32+
libs/libexpat \
33+
libs/liblzma \
34+
libs/libzip \
35+
libs/openscad \
36+
libs/boost \
37+
libs/gmp-6.1.2 \
38+
libs/mpfr-4.1.0 \
39+
libs/zlib \
40+
libs/libxml2
41+
42+
SINGLE_BRANCH=--branch master --single-branch
43+
SHALLOW=--depth 1 ${SINGLE_BRANCH}
44+
45+
libs/cgal:
46+
git clone https://github.com/CGAL/cgal.git ${SHALLOW} $@
47+
48+
libs/eigen:
49+
git clone https://github.com/PX4/eigen.git ${SHALLOW} $@
50+
51+
libs/fontconfig:
52+
git clone https://gitlab.freedesktop.org/fontconfig/fontconfig.git ${SHALLOW} $@
53+
54+
libs/freetype:
55+
git clone https://gitlab.freedesktop.org/freetype/freetype.git ${SHALLOW} $@
56+
57+
libs/glib:
58+
git clone https://gist.github.com/acfa1c09522705efa5eb0541d2d00887.git ${SHALLOW} $@
59+
git -C $@ apply ../../patches/glib.patch
60+
61+
libs/harfbuzz:
62+
git clone https://github.com/harfbuzz/harfbuzz.git ${SHALLOW} $@
63+
64+
libs/lib3mf:
65+
git clone https://github.com/3MFConsortium/lib3mf.git ${SHALLOW} $@
66+
67+
libs/libexpat:
68+
git clone https://github.com/libexpat/libexpat ${SHALLOW} $@
69+
70+
libs/liblzma:
71+
git clone https://github.com/kobolabs/liblzma.git ${SHALLOW} $@
72+
73+
libs/libzip:
74+
git clone https://github.com/nih-at/libzip.git ${SHALLOW} $@
75+
76+
libs/zlib:
77+
git clone https://github.com/madler/zlib.git ${SHALLOW} $@
78+
79+
libs/libxml2:
80+
git clone https://gitlab.gnome.org/GNOME/libxml2.git ${SHALLOW} $@
81+
82+
libs/openscad:
83+
git clone --recurse https://github.com/openscad/openscad.git ${SINGLE_BRANCH} $@
84+
git -C $@ checkout f4d57fb3b2da39953c843c0372b5a0a8730b3189
85+
git -C $@ apply ../../patches/openscad-2019.patch
86+
87+
libs/boost:
88+
git clone --recurse https://github.com/boostorg/boost.git ${SHALLOW} $@
89+
git -C $@/libs/filesystem apply ../../../../patches/boost-filesystem.patch
90+
91+
libs/gmp-6.1.2:
92+
wget https://gmplib.org/download/gmp/gmp-6.1.2.tar.lz
93+
tar xf gmp-6.1.2.tar.lz -C libs
94+
rm gmp-6.1.2.tar.lz
95+
96+
libs/mpfr-4.1.0:
97+
wget https://www.mpfr.org/mpfr-current/mpfr-4.1.0.tar.xz
98+
tar xf mpfr-4.1.0.tar.xz -C libs
99+
rm mpfr-4.1.0.tar.xz

README.md

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
# OpenSCAD WASM Port
2+
3+
A full port of OpenSCAD to WASM.
4+
5+
This project cross compiles all of the project dependencies and created a headless OpenSCAD WASM module.
6+
7+
## Setup
8+
Make sure that you have the following installed:
9+
- Make
10+
- Docker
11+
- Deno
12+
13+
To build the project:
14+
```
15+
make all
16+
```
17+
18+
Or for specific steps:
19+
```
20+
# Generate the library files
21+
make libs
22+
23+
# Build the project
24+
make build
25+
```
26+
27+
## Usage
28+
29+
There is an example project in the example folder. Run it using:
30+
```
31+
cd example
32+
deno run --allow-net --allow-read server.ts
33+
34+
# or
35+
36+
make example
37+
```
38+
39+
There are also automated tests that can be run using:
40+
```
41+
cd tests
42+
deno test --allow-read --allow-write
43+
44+
# or
45+
46+
make test
47+
```
48+
49+
## Usage
50+
51+
The project is a ES6 module. Simply import the module:
52+
```ts
53+
import OpenSCAD from "./openscad.js";
54+
55+
// Instantiate the application
56+
const instance = await OpenSCAD({ noInitialRun: true });
57+
58+
// Write a file to the filesystem
59+
instance.FS.writeFile("/input.scad", `cube(10);`);
60+
61+
// Run OpenSCAD with the arguments "/input.scad -o cube.stl"
62+
instance.callMain(["/input.scad", "-o", "cube.stl"]);
63+
64+
// Read the data from cube.stl
65+
const output = instance.FS.readFile("/cube.stl");
66+
```
67+
68+
For more information on reading and writing files check out the [Emscripten File System API](https://emscripten.org/docs/api_reference/Filesystem-API.html).
69+
70+
## Project Status
71+
- [x] module builds
72+
- [x] module runs
73+
- [ ] library created
74+
- [ ] tests exist
75+
76+
## Future work
77+
- [ ] Fix NULLGL in OpenSCAD 2021
78+
- [ ] Merge WASM patch into Boost.Filesystem
79+
80+
## Known Issues
81+
- [ ] text does not render
82+
Fonts appear to be missing but FontConfig seems to be working correctly. This seems to just be a config issue at runtime.
83+
- [ ] CGAL error on intersection between cube and circle (might be a 2019 issue)

example/server.ts

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import { Application } from "https://deno.land/x/oak/mod.ts";
2+
import logger from "https://deno.land/x/oak_logger/mod.ts";
3+
import { join } from "https://deno.land/std/path/mod.ts";
4+
5+
const app = new Application();
6+
7+
app.use(logger.logger);
8+
9+
// Enable CORP headers for SharedArrayBuffer
10+
app.use(async (context, next) => {
11+
context.response.headers.append("Cross-Origin-Opener-Policy", "same-origin");
12+
context.response.headers.append("Cross-Origin-Embedder-Policy", "require-corp");
13+
await next();
14+
})
15+
16+
// Serve static files from example/www and build folders
17+
app.use(async (context, next) => {
18+
try {
19+
await context.send({ root: join(Deno.cwd(), "www") });
20+
} catch {
21+
try {
22+
await context.send({ root: join(Deno.cwd(), "../build") });
23+
} catch {
24+
await next();
25+
}
26+
}
27+
});
28+
29+
const port = 8080;
30+
console.log(`server listening on port ${port}...`);
31+
await app.listen({ port });

example/www/index.html

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<!DOCTYPE html>
2+
<html>
3+
4+
<body>
5+
<script type="module">
6+
import OpenScad from "./openscad.js";
7+
8+
function downloadFile(blob, fileName) {
9+
const link = document.createElement('a');
10+
link.href = URL.createObjectURL(blob);
11+
link.download = fileName;
12+
document.body.append(link);
13+
link.click();
14+
link.remove();
15+
};
16+
17+
const instance = await OpenScad({ noInitialRun: true });
18+
19+
instance.FS.writeFile("/input.scad", `cube(10);`);
20+
instance.callMain(["/input.scad", "-o", "cube.stl"]);
21+
const output = instance.FS.readFile("/cube.stl");
22+
23+
downloadFile(new Blob([output], { type: "application/octet-stream" }), "cube.stl");
24+
</script>
25+
</body>
26+
27+
</html>

0 commit comments

Comments
 (0)