Skip to content

Commit

Permalink
Initial Commit
Browse files Browse the repository at this point in the history
  • Loading branch information
DSchroer committed Feb 17, 2022
0 parents commit ca4d196
Show file tree
Hide file tree
Showing 13 changed files with 1,033 additions and 0 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
libs
build
tests/**/out.stl
5 changes: 5 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"deno.enable": true,
"deno.lint": true,
"deno.unstable": true
}
339 changes: 339 additions & 0 deletions COPYING

Large diffs are not rendered by default.

127 changes: 127 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
FROM emscripten/emsdk as boost
COPY boost .
RUN ./bootstrap.sh
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


FROM emscripten/emsdk as zlib
COPY zlib .
RUN emcmake cmake -B ../build . -DCMAKE_BUILD_TYPE=Release
RUN cd ../build && make && make install


FROM emscripten/emsdk as libzip
COPY --from=zlib /emsdk/upstream/emscripten/cache/sysroot /emsdk/upstream/emscripten/cache/sysroot
COPY libzip .
RUN emcmake cmake -B ../build . -DCMAKE_BUILD_TYPE=Release
RUN cd ../build && make && make install


FROM emscripten/emsdk as glib
COPY glib .
RUN apt-get update \
&& apt-get install -qqy \
build-essential \
prelink \
autoconf \
libtool \
texinfo \
pkgconf \
# needed for Meson
ninja-build \
python3-pip \
&& pip3 install meson
ARG MESON_PATCH=https://github.com/kleisauke/wasm-vips/raw/master/build/patches/meson-emscripten.patch
RUN cd $(dirname `python3 -c "import mesonbuild as _; print(_.__path__[0])"`) \
&& curl -Ls $MESON_PATCH | patch -p1
RUN chmod +x build.sh; ./build.sh


FROM emscripten/emsdk as freetype
COPY --from=zlib /emsdk/upstream/emscripten/cache/sysroot /emsdk/upstream/emscripten/cache/sysroot
COPY freetype .
RUN emcmake cmake -B ../build . -DFT_REQUIRE_ZLIB=TRUE -DCMAKE_BUILD_TYPE=Release
RUN cd ../build && make && make install


FROM emscripten/emsdk as libxml2
COPY libxml2 .
RUN emcmake cmake -B ../build . -DLIBXML2_WITH_PYTHON=OFF -DLIBXML2_WITH_LZMA=OFF -DLIBXML2_WITH_ZLIB=OFF -DCMAKE_BUILD_TYPE=Release
RUN cd ../build && make && make install


FROM emscripten/emsdk as fontconfig
RUN apt-get update && apt-get install pkg-config gperf automake libtool gettext autopoint -y
COPY --from=zlib /emsdk/upstream/emscripten/cache/sysroot /emsdk/upstream/emscripten/cache/sysroot
COPY --from=freetype /emsdk/upstream/emscripten/cache/sysroot /emsdk/upstream/emscripten/cache/sysroot
COPY --from=libxml2 /emsdk/upstream/emscripten/cache/sysroot /emsdk/upstream/emscripten/cache/sysroot
COPY fontconfig .
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
RUN echo "all install:" > test/Makefile.in
RUN emmake make
RUN emmake make install || true


FROM emscripten/emsdk as harfbuzz
COPY --from=freetype /emsdk/upstream/emscripten/cache/sysroot /emsdk/upstream/emscripten/cache/sysroot
COPY harfbuzz .
RUN emcmake cmake -E env CXXFLAGS="-s USE_PTHREADS=1" cmake -B ../build . -DCMAKE_BUILD_TYPE=Release -DHB_HAVE_FREETYPE=ON
RUN cd ../build && make && make install


FROM emscripten/emsdk as eigen
COPY eigen .
RUN emcmake cmake -B ../build . -DCMAKE_BUILD_TYPE=Release
RUN cd ../build && make && make install


FROM emscripten/emsdk as cgal
COPY cgal .
RUN emcmake cmake -B ../build . -DCMAKE_BUILD_TYPE=Release
RUN cd ../build && make && make install


FROM emscripten/emsdk as gmp
COPY gmp-6.1.2 .
RUN emconfigure ./configure --disable-assembly --host none --enable-cxx --prefix=/emsdk/upstream/emscripten/cache/sysroot
RUN make && make install


FROM emscripten/emsdk as mpfr
COPY --from=gmp /emsdk/upstream/emscripten/cache/sysroot /emsdk/upstream/emscripten/cache/sysroot
COPY mpfr-4.1.0 .
RUN emconfigure ./configure CFLAGS="-s USE_PTHREADS=1" --host none --with-gmp=/emsdk/upstream/emscripten/cache/sysroot --prefix=/emsdk/upstream/emscripten/cache/sysroot
RUN make && make install


FROM emscripten/emsdk as openscad
RUN apt-get update && apt-get install pkg-config flex bison -y
# Dependencies
COPY --from=boost /emsdk/upstream/emscripten/cache/sysroot /emsdk/upstream/emscripten/cache/sysroot
COPY --from=gmp /emsdk/upstream/emscripten/cache/sysroot /emsdk/upstream/emscripten/cache/sysroot
COPY --from=mpfr /emsdk/upstream/emscripten/cache/sysroot /emsdk/upstream/emscripten/cache/sysroot
COPY --from=cgal /emsdk/upstream/emscripten/cache/sysroot /emsdk/upstream/emscripten/cache/sysroot
COPY --from=eigen /emsdk/upstream/emscripten/cache/sysroot /emsdk/upstream/emscripten/cache/sysroot
COPY --from=harfbuzz /emsdk/upstream/emscripten/cache/sysroot /emsdk/upstream/emscripten/cache/sysroot
COPY --from=fontconfig /emsdk/upstream/emscripten/cache/sysroot /emsdk/upstream/emscripten/cache/sysroot
COPY --from=glib /emsdk/upstream/emscripten/cache/sysroot /emsdk/upstream/emscripten/cache/sysroot
COPY --from=libzip /emsdk/upstream/emscripten/cache/sysroot /emsdk/upstream/emscripten/cache/sysroot
# End Dependencies

COPY openscad .
RUN export PKG_CONFIG_PATH="/emsdk/upstream/emscripten/cache/sysroot/lib/pkgconfig"
RUN emcmake cmake -B ../build . -DNULLGL=ON \
-DCMAKE_BUILD_TYPE=Release \
-DHARFBUZZ_INCLUDE_DIRS=/emsdk/upstream/emscripten/cache/sysroot/include/harfbuzz \
-DFONTCONFIG_INCLUDE_DIR=/emsdk/upstream/emscripten/cache/sysroot/include/fontconfig \
-DFONTCONFIG_LIBRARIES=libfontconfig.a

# Hack to fix build includes
RUN sed -e "s|-isystem /emsdk/upstream/emscripten/cache/sysroot/include||g" -i ../build/CMakeFiles/OpenSCAD.dir/includes_C.rsp
RUN sed -e "s|-isystem /emsdk/upstream/emscripten/cache/sysroot/include||g" -i ../build/CMakeFiles/OpenSCAD.dir/includes_CXX.rsp
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

# Add emscripten flags here
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

RUN cd ../build && make -j12
99 changes: 99 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
all: build/openscad.js

clean:
rm -rf libs
rm -rf build

test:
cd tests; deno test --allow-read --allow-write

.PHONY: example
example:
cd example; deno run --allow-net --allow-read server.ts

build/openscad.js: build
docker run --name tmpcpy openscad-wasm
docker cp tmpcpy:/build/openscad.js build
docker cp tmpcpy:/build/openscad.worker.js build
docker cp tmpcpy:/build/openscad.wasm build
docker rm tmpcpy

build: libs
docker build libs -f Dockerfile --target openscad -t openscad-wasm
mkdir build

libs: libs/cgal \
libs/eigen \
libs/fontconfig \
libs/freetype \
libs/glib \
libs/harfbuzz \
libs/lib3mf \
libs/libexpat \
libs/liblzma \
libs/libzip \
libs/openscad \
libs/boost \
libs/gmp-6.1.2 \
libs/mpfr-4.1.0 \
libs/zlib \
libs/libxml2

SINGLE_BRANCH=--branch master --single-branch
SHALLOW=--depth 1 ${SINGLE_BRANCH}

libs/cgal:
git clone https://github.com/CGAL/cgal.git ${SHALLOW} $@

libs/eigen:
git clone https://github.com/PX4/eigen.git ${SHALLOW} $@

libs/fontconfig:
git clone https://gitlab.freedesktop.org/fontconfig/fontconfig.git ${SHALLOW} $@

libs/freetype:
git clone https://gitlab.freedesktop.org/freetype/freetype.git ${SHALLOW} $@

libs/glib:
git clone https://gist.github.com/acfa1c09522705efa5eb0541d2d00887.git ${SHALLOW} $@
git -C $@ apply ../../patches/glib.patch

libs/harfbuzz:
git clone https://github.com/harfbuzz/harfbuzz.git ${SHALLOW} $@

libs/lib3mf:
git clone https://github.com/3MFConsortium/lib3mf.git ${SHALLOW} $@

libs/libexpat:
git clone https://github.com/libexpat/libexpat ${SHALLOW} $@

libs/liblzma:
git clone https://github.com/kobolabs/liblzma.git ${SHALLOW} $@

libs/libzip:
git clone https://github.com/nih-at/libzip.git ${SHALLOW} $@

libs/zlib:
git clone https://github.com/madler/zlib.git ${SHALLOW} $@

libs/libxml2:
git clone https://gitlab.gnome.org/GNOME/libxml2.git ${SHALLOW} $@

libs/openscad:
git clone --recurse https://github.com/openscad/openscad.git ${SINGLE_BRANCH} $@
git -C $@ checkout f4d57fb3b2da39953c843c0372b5a0a8730b3189
git -C $@ apply ../../patches/openscad-2019.patch

libs/boost:
git clone --recurse https://github.com/boostorg/boost.git ${SHALLOW} $@
git -C $@/libs/filesystem apply ../../../../patches/boost-filesystem.patch

libs/gmp-6.1.2:
wget https://gmplib.org/download/gmp/gmp-6.1.2.tar.lz
tar xf gmp-6.1.2.tar.lz -C libs
rm gmp-6.1.2.tar.lz

libs/mpfr-4.1.0:
wget https://www.mpfr.org/mpfr-current/mpfr-4.1.0.tar.xz
tar xf mpfr-4.1.0.tar.xz -C libs
rm mpfr-4.1.0.tar.xz
83 changes: 83 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
# OpenSCAD WASM Port

A full port of OpenSCAD to WASM.

This project cross compiles all of the project dependencies and created a headless OpenSCAD WASM module.

## Setup
Make sure that you have the following installed:
- Make
- Docker
- Deno

To build the project:
```
make all
```

Or for specific steps:
```
# Generate the library files
make libs
# Build the project
make build
```

## Usage

There is an example project in the example folder. Run it using:
```
cd example
deno run --allow-net --allow-read server.ts
# or
make example
```

There are also automated tests that can be run using:
```
cd tests
deno test --allow-read --allow-write
# or
make test
```

## Usage

The project is a ES6 module. Simply import the module:
```ts
import OpenSCAD from "./openscad.js";

// Instantiate the application
const instance = await OpenSCAD({ noInitialRun: true });

// Write a file to the filesystem
instance.FS.writeFile("/input.scad", `cube(10);`);

// Run OpenSCAD with the arguments "/input.scad -o cube.stl"
instance.callMain(["/input.scad", "-o", "cube.stl"]);

// Read the data from cube.stl
const output = instance.FS.readFile("/cube.stl");
```

For more information on reading and writing files check out the [Emscripten File System API](https://emscripten.org/docs/api_reference/Filesystem-API.html).

## Project Status
- [x] module builds
- [x] module runs
- [ ] library created
- [ ] tests exist

## Future work
- [ ] Fix NULLGL in OpenSCAD 2021
- [ ] Merge WASM patch into Boost.Filesystem

## Known Issues
- [ ] text does not render
Fonts appear to be missing but FontConfig seems to be working correctly. This seems to just be a config issue at runtime.
- [ ] CGAL error on intersection between cube and circle (might be a 2019 issue)
31 changes: 31 additions & 0 deletions example/server.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { Application } from "https://deno.land/x/oak/mod.ts";
import logger from "https://deno.land/x/oak_logger/mod.ts";
import { join } from "https://deno.land/std/path/mod.ts";

const app = new Application();

app.use(logger.logger);

// Enable CORP headers for SharedArrayBuffer
app.use(async (context, next) => {
context.response.headers.append("Cross-Origin-Opener-Policy", "same-origin");
context.response.headers.append("Cross-Origin-Embedder-Policy", "require-corp");
await next();
})

// Serve static files from example/www and build folders
app.use(async (context, next) => {
try {
await context.send({ root: join(Deno.cwd(), "www") });
} catch {
try {
await context.send({ root: join(Deno.cwd(), "../build") });
} catch {
await next();
}
}
});

const port = 8080;
console.log(`server listening on port ${port}...`);
await app.listen({ port });
27 changes: 27 additions & 0 deletions example/www/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<!DOCTYPE html>
<html>

<body>
<script type="module">
import OpenScad from "./openscad.js";

function downloadFile(blob, fileName) {
const link = document.createElement('a');
link.href = URL.createObjectURL(blob);
link.download = fileName;
document.body.append(link);
link.click();
link.remove();
};

const instance = await OpenScad({ noInitialRun: true });

instance.FS.writeFile("/input.scad", `cube(10);`);
instance.callMain(["/input.scad", "-o", "cube.stl"]);
const output = instance.FS.readFile("/cube.stl");

downloadFile(new Blob([output], { type: "application/octet-stream" }), "cube.stl");
</script>
</body>

</html>
Loading

0 comments on commit ca4d196

Please sign in to comment.