├── .github └── workflows │ ├── docker-image.yml │ └── make-test.yml ├── .gitignore ├── Dockerfile ├── LICENSE ├── Makefile ├── README.md ├── bin ├── compile.py ├── cowasm-package-path ├── env.sh ├── make-all ├── make-all-clean ├── pnpm-exec ├── rebuild-all ├── z++ └── zcc ├── core ├── README.md ├── build │ ├── Makefile │ ├── Makefile-rules │ ├── Makefile-vars │ ├── README.md │ ├── make-dependencies.js │ └── src │ │ ├── Makefile-vars-build │ │ ├── cowasm-package-path │ │ └── zig │ │ ├── Makefile │ │ ├── bin │ │ └── zig_cowasm_compiler.py │ │ └── src │ │ └── patches │ │ └── 01-emscripten.patch ├── bzip2 │ ├── Makefile │ ├── README.md │ ├── index.js │ ├── package.json │ └── src │ │ └── extra_config.h ├── coreutils │ ├── Makefile │ ├── README.md │ ├── index.js │ ├── package.json │ └── src │ │ ├── compat │ │ ├── compat.h │ │ ├── config.h │ │ ├── fmt_scaled.c │ │ ├── getbsize.c │ │ ├── queue.h │ │ ├── recallocarray.c │ │ ├── strmode.c │ │ ├── tree.h │ │ └── util.h │ │ ├── uniq-sources.sh │ │ └── utils │ │ ├── basename │ │ ├── basename.1 │ │ └── basename.c │ │ ├── cat │ │ ├── cat.1 │ │ └── cat.c │ │ ├── chmod │ │ ├── chmod.1 │ │ └── chmod.c │ │ ├── comm │ │ ├── comm.1 │ │ └── comm.c │ │ ├── cp │ │ ├── cp.1 │ │ ├── cp.c │ │ ├── extern.h │ │ └── utils.c │ │ ├── csplit │ │ ├── csplit.1 │ │ └── csplit.c │ │ ├── cut │ │ ├── cut.1 │ │ └── cut.c │ │ ├── date │ │ ├── date.1 │ │ └── date.c │ │ ├── df │ │ ├── df.1 │ │ └── df.c │ │ ├── dirname │ │ ├── dirname.1 │ │ └── dirname.c │ │ ├── du │ │ ├── README.md │ │ ├── du.1 │ │ └── du.c │ │ ├── env │ │ ├── env.1 │ │ └── env.c │ │ ├── expand │ │ ├── expand.1 │ │ └── expand.c │ │ ├── expr │ │ ├── expr.1 │ │ └── expr.c │ │ ├── factor │ │ ├── factor.6 │ │ ├── factor.c │ │ ├── pattern.c │ │ ├── pr_tbl.c │ │ └── primes.h │ │ ├── false │ │ ├── false.1 │ │ └── false.c │ │ ├── find │ │ ├── README.md │ │ ├── extern.h │ │ ├── find-function.c │ │ ├── find-getdate.tab.c │ │ ├── find-getdate.y │ │ ├── find-ls.c │ │ ├── find-main.c │ │ ├── find-misc.c │ │ ├── find-operator.c │ │ ├── find-option.c │ │ ├── find.1 │ │ ├── find.c │ │ └── find.h │ │ ├── fmt │ │ ├── fmt.1 │ │ └── fmt.c │ │ ├── fold │ │ ├── fold.1 │ │ └── fold.c │ │ ├── grep │ │ ├── grep-file.c │ │ ├── grep-queue.c │ │ ├── grep-util.c │ │ ├── grep.1 │ │ ├── grep.c │ │ ├── grep.h │ │ ├── zgrep.1 │ │ └── zgrep.sh │ │ ├── head │ │ ├── head.1 │ │ └── head.c │ │ ├── id │ │ ├── groups.1 │ │ ├── id.1 │ │ ├── id.c │ │ └── whoami.1 │ │ ├── join │ │ ├── join.1 │ │ └── join.c │ │ ├── ln │ │ ├── ln.1 │ │ ├── ln.c │ │ └── symlink.7 │ │ ├── logname │ │ ├── logname.1 │ │ └── logname.c │ │ ├── ls │ │ ├── cmp.c │ │ ├── extern.h │ │ ├── ls.1 │ │ ├── ls.c │ │ ├── ls.h │ │ ├── print.c │ │ ├── utf8.c │ │ └── util.c │ │ ├── mkdir │ │ ├── mkdir.1 │ │ └── mkdir.c │ │ ├── mktemp │ │ ├── mktemp.1 │ │ └── mktemp.c │ │ ├── mv │ │ ├── mv-cp.c │ │ ├── mv-rm.c │ │ ├── mv.1 │ │ └── mv.c │ │ ├── nl │ │ ├── nl.1 │ │ └── nl.c │ │ ├── paste │ │ ├── paste.1 │ │ └── paste.c │ │ ├── pathchk │ │ ├── pathchk.1 │ │ └── pathchk.c │ │ ├── pr │ │ ├── extern.h │ │ ├── pr-egetopt.c │ │ ├── pr.1 │ │ ├── pr.c │ │ └── pr.h │ │ ├── readlink │ │ ├── readlink.1 │ │ └── readlink.c │ │ ├── realpath │ │ ├── CMakeLists.txt │ │ ├── realpath.1 │ │ └── realpath.c │ │ ├── rm │ │ ├── rm.1 │ │ └── rm.c │ │ ├── rmdir │ │ ├── rmdir.1 │ │ └── rmdir.c │ │ ├── seq │ │ ├── seq.1 │ │ └── seq.c │ │ ├── sleep │ │ ├── sleep.1 │ │ └── sleep.c │ │ ├── sort │ │ ├── bwstring.c │ │ ├── bwstring.h │ │ ├── coll.c │ │ ├── coll.h │ │ ├── file.c │ │ ├── file.h │ │ ├── mem.c │ │ ├── mem.h │ │ ├── sort.1 │ │ ├── sort.c │ │ ├── sort.h │ │ ├── vsort.c │ │ └── vsort.h │ │ ├── split │ │ ├── split.1 │ │ └── split.c │ │ ├── stat │ │ ├── stat.1 │ │ └── stat.c │ │ ├── tail │ │ ├── extern.h │ │ ├── forward.c │ │ ├── misc.c │ │ ├── read.c │ │ ├── reverse.c │ │ ├── tail.1 │ │ └── tail.c │ │ ├── tee │ │ ├── tee.1 │ │ └── tee.c │ │ ├── test │ │ ├── test-impl.c │ │ ├── test.1 │ │ └── test.c │ │ ├── touch │ │ ├── touch.1 │ │ └── touch.c │ │ ├── tr │ │ ├── tr-extern.h │ │ ├── tr-str.c │ │ ├── tr.1 │ │ └── tr.c │ │ ├── tsort │ │ ├── ohash.c │ │ ├── ohash.h │ │ ├── tsort.1 │ │ └── tsort.c │ │ ├── tty │ │ ├── tty.1 │ │ └── tty.c │ │ ├── uname │ │ ├── uname.1 │ │ └── uname.c │ │ ├── unexpand │ │ └── unexpand.c │ │ ├── uniq │ │ ├── uniq.1 │ │ └── uniq.c │ │ ├── wc │ │ ├── wc.1 │ │ └── wc.c │ │ ├── which │ │ ├── which.1 │ │ └── which.c │ │ ├── xargs │ │ ├── pathnames.h │ │ ├── strnsubst.c │ │ ├── xargs.1 │ │ └── xargs.c │ │ └── yes │ │ ├── yes.1 │ │ └── yes.c ├── dash-wasm │ ├── Makefile │ ├── README.md │ ├── bin │ │ └── dash-wasm │ ├── index.d.ts │ ├── package.json │ ├── src │ │ ├── browser.ts │ │ ├── common.ts │ │ ├── node-terminal.ts │ │ ├── node.ts │ │ ├── termcap │ │ ├── test │ │ │ └── no-stdio.test.ts │ │ └── util.ts │ └── tsconfig.json ├── dash │ ├── Makefile │ ├── README.md │ ├── bin │ │ ├── dash-native │ │ └── dash-wasm │ ├── index.js │ ├── package.json │ └── src │ │ ├── extra.h │ │ ├── patches │ │ ├── 01-jobs-extra-include.patch │ │ ├── 02-nodes-extra-include.patch │ │ ├── 03-emacs-default.patch │ │ └── 04-vforkexec.patch │ │ ├── rebuild.sh │ │ ├── signal.h │ │ └── update.sh ├── dylink │ ├── Makefile │ ├── README.md │ ├── package.json │ ├── src │ │ ├── dlopen.ts │ │ ├── function-table.ts │ │ ├── global-offset-table.ts │ │ ├── import.ts │ │ ├── index.ts │ │ ├── libc.ts │ │ ├── libpython.ts │ │ ├── metadata.ts │ │ ├── stub.ts │ │ ├── types.ts │ │ ├── util.ts │ │ └── wasm-export.ts │ ├── test │ │ ├── Makefile-common │ │ ├── libc-archive │ │ │ ├── Makefile │ │ │ ├── README.md │ │ │ ├── app.c │ │ │ ├── app.h │ │ │ ├── app.js │ │ │ └── hello.c │ │ ├── malloc │ │ │ ├── Makefile │ │ │ ├── README.md │ │ │ ├── app.c │ │ │ ├── app.h │ │ │ ├── app.js │ │ │ └── hellomodule.c │ │ ├── python-extension │ │ │ ├── Makefile │ │ │ ├── README.md │ │ │ ├── app.c │ │ │ ├── app.h │ │ │ ├── app.js │ │ │ └── hellomodule.c │ │ └── wasi │ │ │ ├── Makefile │ │ │ ├── README.md │ │ │ ├── app.c │ │ │ ├── app.h │ │ │ ├── app.js │ │ │ └── dynamic-library.c │ └── tsconfig.json ├── f2c │ ├── Makefile │ ├── README.md │ ├── index.js │ ├── package.json │ └── src │ │ ├── 00-wasm-makefile-ld.patch │ │ └── hello.f ├── kernel │ ├── Makefile │ ├── README.md │ ├── TODO.md │ ├── bin │ │ ├── cowasm │ │ └── cowasm-dev │ ├── index.d.ts │ ├── package.json │ ├── src │ │ ├── kernel │ │ │ ├── README.md │ │ │ ├── browser.ts │ │ │ ├── cowasm.zig │ │ │ ├── interface.zig │ │ │ ├── kernel.ts │ │ │ ├── node-terminal.ts │ │ │ └── node.ts │ │ ├── termcap │ │ ├── test-zig.sh │ │ ├── test │ │ │ ├── cowsay.c │ │ │ ├── hello.c │ │ │ └── misc.c │ │ └── wasm │ │ │ ├── constants.ts │ │ │ ├── import-browser.ts │ │ │ ├── import-node.ts │ │ │ ├── import.ts │ │ │ ├── io-using-atomics.ts │ │ │ ├── io-using-service-worker.ts │ │ │ ├── posix.zig │ │ │ ├── posix │ │ │ ├── README.md │ │ │ ├── constants.ts │ │ │ ├── constants.zig │ │ │ ├── epoll.ts │ │ │ ├── errno.ts │ │ │ ├── errno.zig │ │ │ ├── fork-exec.ts │ │ │ ├── index.ts │ │ │ ├── netdb.ts │ │ │ ├── netdb.zig │ │ │ ├── netif.ts │ │ │ ├── netif.zig │ │ │ ├── other.ts │ │ │ ├── other.zig │ │ │ ├── sched.ts │ │ │ ├── signal.ts │ │ │ ├── signal.zig │ │ │ ├── socket.ts │ │ │ ├── socket.zig │ │ │ ├── spawn.ts │ │ │ ├── spawn.zig │ │ │ ├── stat.ts │ │ │ ├── stat.zig │ │ │ ├── stdio.c │ │ │ ├── stdio.ts │ │ │ ├── stdio.zig │ │ │ ├── stdlib.c │ │ │ ├── stdlib.ts │ │ │ ├── stdlib.zig │ │ │ ├── string.zig │ │ │ ├── termios.ts │ │ │ ├── termios.zig │ │ │ ├── time.ts │ │ │ ├── unistd.ts │ │ │ ├── unistd.zig │ │ │ ├── util.ts │ │ │ ├── util.zig │ │ │ ├── wait.ts │ │ │ └── wait.zig │ │ │ ├── reuseInFlight.js │ │ │ ├── types.ts │ │ │ └── worker │ │ │ ├── browser.ts │ │ │ ├── import.ts │ │ │ ├── init.ts │ │ │ ├── instance.ts │ │ │ ├── io-using-atomics.ts │ │ │ ├── io-using-service-worker.ts │ │ │ ├── node.ts │ │ │ ├── posix-browser.ts │ │ │ ├── posix-context.ts │ │ │ ├── recv-from-wasm.ts │ │ │ ├── send-to-wasm.ts │ │ │ ├── service-worker.js │ │ │ ├── trampoline.ts │ │ │ └── types.ts │ └── tsconfig.json ├── less │ ├── Makefile │ ├── README.md │ ├── index.js │ ├── package.json │ └── src │ │ └── patches │ │ └── 01-disable-dumb-error.patch ├── libedit │ ├── Makefile │ ├── README.md │ ├── index.js │ ├── package.json │ └── src │ │ ├── README.md │ │ ├── bits │ │ └── setjmp.h │ │ ├── config.site │ │ ├── extra_config.h │ │ ├── readline.patch │ │ ├── readline │ │ ├── README.md │ │ ├── history.h │ │ ├── readline.h │ │ └── tilde.h │ │ └── signal.h ├── libffi │ ├── Makefile │ ├── README.md │ ├── index.js │ ├── package.json │ └── src │ │ ├── libffi-emscripten │ │ └── src │ │ │ └── wasm32 │ │ │ ├── ffi.c │ │ │ └── ffitarget.h │ │ └── patches │ │ └── 01-configure.patch ├── libgit2 │ ├── Makefile │ ├── README.md │ ├── index.js │ ├── package.json │ └── src │ │ ├── ar │ │ ├── patches │ │ ├── 00-fix_missing_max_align.patch │ │ ├── 01-realpath-cast.patch │ │ └── 02-validate_ownership.patch │ │ ├── ranlib │ │ ├── rebuild │ │ └── test-init.c ├── libpng │ ├── Makefile │ ├── README.md │ ├── index.js │ └── package.json ├── lua │ ├── Makefile │ ├── README.md │ ├── bin │ │ └── lua-wasm │ ├── index.js │ ├── package.json │ └── src │ │ └── sum.lua ├── luatex │ └── Makefile ├── lzma │ ├── Makefile │ ├── README.md │ ├── index.js │ └── package.json ├── man │ ├── Makefile │ ├── README.md │ ├── index.js │ ├── package.json │ └── src │ │ ├── Makefile.local │ │ ├── config.h │ │ └── mandoc-2022-10-14.tar.xz ├── ncurses │ ├── Makefile │ ├── README.md │ ├── index.js │ ├── package.json │ └── src │ │ ├── 00-terminfo.patch │ │ ├── hello.c │ │ └── patches │ │ └── 01-disable-ncurses-test.patch ├── openssl │ ├── Makefile │ ├── README.md │ ├── index.js │ ├── package.json │ └── src │ │ ├── patches │ │ ├── 00-af-unix.patch │ │ └── 01-cleanup-hack.patch │ │ └── rebuild ├── posix-browser │ ├── Makefile │ ├── README.md │ └── package.json ├── posix-node │ ├── .gitignore │ ├── LICENSE │ ├── Makefile │ ├── README.md │ ├── demo │ │ └── terminal.js │ ├── package.json │ ├── scratch │ │ ├── README.md │ │ ├── fork.js │ │ └── fork.zig │ ├── src │ │ ├── c.zig │ │ ├── constants.zig │ │ ├── fork_exec.test.ts │ │ ├── fork_exec.zig │ │ ├── index.ts │ │ ├── lib.zig │ │ ├── linux.zig │ │ ├── logging.ts │ │ ├── netdb.test.ts │ │ ├── netdb.zig │ │ ├── netif.test.ts │ │ ├── netif.zig │ │ ├── node.zig │ │ ├── other.test.ts │ │ ├── other.zig │ │ ├── signal.zig │ │ ├── socket.test.ts │ │ ├── socket.zig │ │ ├── spawn.test.ts │ │ ├── spawn.zig │ │ ├── termios.zig │ │ ├── unistd.test.ts │ │ ├── unistd.zig │ │ ├── util.zig │ │ └── wait.zig │ └── tsconfig.json ├── posix-wasm │ ├── Makefile │ ├── README.md │ ├── index.js │ ├── package.json │ └── src │ │ ├── bits │ │ └── setjmp.h │ │ ├── emscripten.h │ │ ├── lib │ │ ├── README.md │ │ ├── bsd │ │ │ ├── heapsort.c │ │ │ ├── merge.c │ │ │ ├── rpmatch.c │ │ │ ├── setmode.c │ │ │ ├── strtonum.c │ │ │ └── strtoq.c │ │ ├── builtins │ │ │ ├── README.md │ │ │ ├── int_endianness.h │ │ │ ├── int_lib.h │ │ │ ├── int_math.h │ │ │ ├── int_types.h │ │ │ ├── int_util.h │ │ │ ├── muldc3.c │ │ │ ├── mulsc3.c │ │ │ └── multc3.c │ │ ├── fts │ │ │ ├── config.h │ │ │ ├── cowasm_stat.c │ │ │ ├── fts.c │ │ │ └── fts.h │ │ ├── legacy │ │ │ └── err.c │ │ ├── stdlib │ │ │ └── qsort_nr.c │ │ └── temp │ │ │ ├── __randname.c │ │ │ ├── mkdtemp.c │ │ │ └── mkstemps.c │ │ ├── posix-wasm.c │ │ ├── posix-wasm.h │ │ ├── public.h │ │ ├── threads.c │ │ └── threads.h ├── rogue │ ├── Makefile │ ├── README.md │ ├── bin │ │ └── rogue │ ├── index.js │ └── package.json ├── sqlite │ ├── Makefile │ ├── README.md │ ├── bin │ │ └── sqlite3-wasm │ ├── index.js │ ├── package.json │ └── src │ │ ├── config.site │ │ └── patches │ │ ├── 00-syscall.patch │ │ └── 01-shell.patch ├── tar │ ├── Makefile │ ├── README.md │ ├── index.js │ ├── package.json │ └── src │ │ ├── config.h │ │ └── patches │ │ └── 01-main-visibility.patch ├── termcap │ ├── Makefile │ ├── index.js │ ├── package.json │ └── src │ │ └── config.h ├── tsconfig.json ├── viz │ ├── Makefile │ ├── README.md │ ├── bin │ │ ├── viz-native │ │ └── viz-wasm │ ├── index.js │ └── package.json ├── wasi-js │ ├── Makefile │ ├── README.md │ ├── bin │ │ └── run.js │ ├── package.json │ ├── src │ │ ├── bindings │ │ │ ├── browser-hrtime.ts │ │ │ ├── browser.ts │ │ │ └── node.ts │ │ ├── constants.ts │ │ ├── filesystem.ts │ │ ├── fs.ts │ │ ├── index.ts │ │ ├── runtime.ts │ │ ├── types.ts │ │ ├── unzip.ts │ │ └── wasi.ts │ └── tsconfig.json ├── wasm-opt │ ├── Makefile │ ├── package.json │ └── src │ │ └── cowasm_opt.py └── zlib │ ├── Makefile │ ├── README.md │ ├── index.js │ └── package.json ├── desktop ├── build └── electron │ ├── Makefile │ ├── README.md │ ├── forge.config.js │ ├── package.json │ ├── src │ ├── index.css │ ├── index.ts │ ├── preload.ts │ ├── python-frontend.ts │ ├── python-terminal.ts │ ├── python.ts │ ├── renderer.ts │ └── xterm-theme.ts │ ├── tsconfig.json │ └── webpack.config.js ├── docs ├── QuickStart.md ├── differences-from-pyodide.md ├── links.md └── python-packages.md ├── pnpm-lock.yaml ├── pnpm-workspace.yaml ├── python ├── README.md ├── bench │ ├── Makefile │ ├── README.md │ ├── package.json │ └── src │ │ ├── all.py │ │ ├── bench.py │ │ ├── brython.py │ │ ├── call.py │ │ ├── cython │ │ ├── Makefile │ │ ├── README.md │ │ ├── __pycache__ │ │ │ └── bench.cpython-311.pyc │ │ ├── all.py │ │ ├── bench.py │ │ ├── build │ │ │ ├── lib.wasi-0.0.0-wasm32-cpython-311 │ │ │ │ ├── fib.cpython-311-wasm32-wasi.so │ │ │ │ ├── nt.cpython-311-wasm32-wasi.so │ │ │ │ └── numbers.cpython-311-wasm32-wasi.so │ │ │ └── temp.wasi-0.0.0-wasm32-cpython-311 │ │ │ │ ├── fib.o │ │ │ │ ├── nt.o │ │ │ │ └── numbers.o │ │ ├── fib.c │ │ ├── fib.pyx │ │ ├── nt.c │ │ ├── nt.pxd │ │ ├── nt.pyx │ │ ├── numbers.c │ │ ├── numbers.pyx │ │ └── setup.py │ │ ├── fib.py │ │ ├── lambda_.py │ │ ├── mandel.py │ │ ├── misc.py │ │ ├── mypyc_micro.py │ │ ├── nbody.py │ │ ├── nt.py │ │ ├── numbers.py │ │ ├── p1list.py │ │ ├── parse_int.py │ │ ├── pystone.py │ │ ├── uuid_.py │ │ └── zig │ │ ├── Makefile │ │ ├── README.md │ │ ├── nt.pyx │ │ ├── nt.zig │ │ ├── setup.py │ │ └── zig-fPIC0 ├── build ├── cpython │ ├── Makefile │ ├── NOTES.md │ ├── README.md │ ├── bin │ │ ├── python-native │ │ └── python-wasm │ ├── index.js │ ├── package.json │ └── src │ │ ├── Setup.local │ │ ├── Setup.local-native │ │ ├── __pycache__ │ │ ├── cowasm_bundler.cpython-311.pyc │ │ ├── cowasm_importer.cpython-311.pyc │ │ ├── sitecustomize.cpython-311.pyc │ │ └── zython_importer.cpython-311.pyc │ │ ├── config.site │ │ ├── cowasm_bundler.py │ │ ├── cowasm_importer.py │ │ ├── patches │ │ ├── 01-main.patch │ │ ├── 02-pydoc.patch │ │ ├── 03-wasm-assets.patch │ │ ├── 04-enable-subprocess-tests.patch │ │ ├── 05-st_mode.patch │ │ ├── 06-platform.patch │ │ ├── 07-subprocess.patch │ │ ├── 09-set-inheritable.patch │ │ ├── 10-setuptools-c++.patch │ │ ├── 12-timemodule-clang15.patch │ │ ├── 13-socket-unmodified-headers.patch │ │ ├── 14-threading-warning.patch │ │ ├── 15-pip-no-mmap.patch │ │ ├── 16-pip-no-auto-refresh-progress.patch │ │ ├── 17-fix-sysconfigdata.py │ │ └── README.md │ │ ├── pyconfig.h │ │ ├── rebuild │ │ ├── sitecustomize.py │ │ ├── termcap │ │ ├── test_lib.py │ │ └── xgcd.py ├── libedit-native │ └── Makefile ├── lzma-native │ └── Makefile ├── py-cython │ ├── Makefile │ ├── README.md │ ├── bin │ │ └── cython │ ├── index.js │ └── package.json ├── py-matplotlib │ ├── Makefile │ └── package.json ├── py-mpmath │ ├── Makefile │ ├── README.md │ ├── index.js │ └── package.json ├── py-numpy │ ├── Makefile │ ├── README.md │ ├── index.js │ ├── package.json │ └── src │ │ ├── fake-bin │ │ └── gcc │ │ └── patches │ │ ├── 01-ENH-Add-support-for-platforms-with-missing-fenv-flag.patch │ │ ├── 02-cxx_compiler.patch │ │ ├── 03-disable-complex.patch │ │ ├── 04-random-no-lm.patch │ │ ├── 05-no-backtrace.patch │ │ └── 06-setup-setuptools.patch ├── py-pandas │ ├── Makefile │ ├── README.md │ ├── index.js │ └── package.json ├── py-pip │ ├── Makefile │ ├── README.md │ ├── index.js │ ├── package.json │ └── src │ │ └── patches │ │ ├── 01-pip-no-mmap.patch │ │ └── 02-pip-no-auto-refresh-progress.patch ├── py-setuptools │ ├── Makefile │ ├── README.md │ ├── index.js │ ├── package.json │ └── src │ │ └── patches │ │ └── 01-c++.patch ├── py-sympy │ ├── Makefile │ ├── README.md │ ├── index.js │ ├── package.json │ └── src │ │ ├── __pycache__ │ │ └── test_basic.cpython-311.pyc │ │ └── test_basic.py ├── pylang │ ├── CONTRIBUTORS.md │ ├── HACKING.md │ ├── LICENSE │ ├── Makefile │ ├── README.md │ ├── TODO.md │ ├── bin │ │ └── pylang │ ├── package.json │ ├── src │ │ ├── ast_types.py │ │ ├── baselib │ │ │ ├── builtins.py │ │ │ ├── containers.py │ │ │ ├── errors.py │ │ │ ├── internal.py │ │ │ ├── itertools.py │ │ │ └── str.py │ │ ├── compiler.py │ │ ├── errors.py │ │ ├── lib │ │ │ ├── aes.py │ │ │ ├── elementmaker.py │ │ │ ├── encodings.py │ │ │ ├── gettext.py │ │ │ ├── js.py │ │ │ ├── math.py │ │ │ ├── operator.py │ │ │ ├── pythonize.py │ │ │ ├── random.py │ │ │ ├── re.py │ │ │ ├── sys.py │ │ │ ├── time.py │ │ │ ├── traceback.py │ │ │ └── uuid.py │ │ ├── output │ │ │ ├── __init__.py │ │ │ ├── classes.py │ │ │ ├── codegen.py │ │ │ ├── comments.py │ │ │ ├── exceptions.py │ │ │ ├── functions.py │ │ │ ├── literals.py │ │ │ ├── loops.py │ │ │ ├── modules.py │ │ │ ├── operators.py │ │ │ ├── statements.py │ │ │ ├── stream.py │ │ │ └── utils.py │ │ ├── parse.py │ │ ├── string_interpolation.py │ │ ├── tokenizer.py │ │ ├── unicode_aliases.py │ │ └── utils.py │ ├── test │ │ ├── _import_one.py │ │ ├── _import_two │ │ │ ├── __init__.py │ │ │ ├── level2 │ │ │ │ ├── __init__.py │ │ │ │ └── deep.py │ │ │ ├── other.py │ │ │ └── sub.py │ │ ├── aes_vectors.py │ │ ├── annotations.py │ │ ├── baselib.py │ │ ├── classes.py │ │ ├── collections_.py │ │ ├── decorators.py │ │ ├── docstrings.py │ │ ├── elementmaker_.py │ │ ├── functions.py │ │ ├── generators.py │ │ ├── generic.py │ │ ├── imports.py │ │ ├── jsage.py │ │ ├── lambda_.py │ │ ├── lint.py │ │ ├── loops.py │ │ ├── newlines.py │ │ ├── operator_overloading.py │ │ ├── random_lib.py │ │ ├── regexp.py │ │ ├── repl.py │ │ ├── scoped_flags.py │ │ ├── starargs.py │ │ ├── str.py │ │ └── typing_.py │ ├── tools │ │ ├── cli.js │ │ ├── compile.ts │ │ ├── compiler.ts │ │ ├── completer.ts │ │ ├── embedded_compiler.js │ │ ├── ini.js │ │ ├── lint.js │ │ ├── msgfmt.js │ │ ├── repl.ts │ │ ├── self.js │ │ ├── test.ts │ │ ├── utils.ts │ │ └── web_repl.js │ ├── try.py │ └── tsconfig.json ├── python-wasm │ ├── Makefile │ ├── README.md │ ├── bin │ │ └── python-wasm │ ├── data │ │ ├── README.md │ │ ├── http │ │ │ ├── demo1.py │ │ │ └── wrap_socket.py │ │ ├── pip │ │ │ └── scratch.py │ │ ├── socket │ │ │ ├── client.py │ │ │ └── server.py │ │ └── ssl │ │ │ └── basic.py │ ├── index.d.ts │ ├── package.json │ ├── src │ │ ├── browser.ts │ │ ├── common.ts │ │ ├── extension │ │ │ ├── README.md │ │ │ ├── hello.py │ │ │ ├── hello.test.ts │ │ │ ├── hellomodule.c │ │ │ ├── hellozigmodule.c │ │ │ ├── hellozigmodule.zig │ │ │ └── sqlite.test.ts │ │ ├── node-terminal.ts │ │ ├── node.ts │ │ ├── packages.ts │ │ ├── python.zig │ │ ├── signal.test.ts │ │ ├── signal.zig │ │ ├── test │ │ │ ├── default.test.ts │ │ │ ├── home.test.ts │ │ │ ├── misc.test.ts │ │ │ ├── no-stdio.test.ts │ │ │ ├── posix │ │ │ │ ├── netdb.test.ts │ │ │ │ ├── netif.test.ts │ │ │ │ ├── other.test.ts │ │ │ │ ├── socket.test.ts │ │ │ │ ├── spawn.test.ts │ │ │ │ ├── stdlib.test.ts │ │ │ │ └── unistd.test.ts │ │ │ ├── python-async.test.ts │ │ │ └── python.test.ts │ │ └── util.ts │ └── tsconfig.json ├── termcap-native │ ├── Makefile │ └── src │ │ └── config.h ├── tsconfig.json └── zlib-native │ └── Makefile ├── sagemath ├── README.md ├── build ├── gmp │ ├── Makefile │ ├── README.md │ └── package.json └── pari │ ├── Makefile │ ├── TODO.md │ ├── package.json │ └── src │ └── patches │ └── 01-pipes.patch ├── upstream └── README.md └── web ├── README.md ├── browser ├── Makefile ├── README.md ├── package.json ├── src │ ├── index.ts │ ├── kernel.ts │ └── python.ts ├── tsconfig.json ├── webpack-min.config.js └── webpack.config.js ├── build ├── cowasm.org ├── .swcrc ├── Makefile ├── README.md ├── index.d.ts ├── package.json ├── src │ ├── _headers │ ├── favicon.ico │ ├── index.ts │ ├── terminal.ts │ └── theme.ts ├── tsconfig.json └── webpack.config.js ├── cowasm.sh ├── Makefile ├── README.md ├── index.d.ts ├── package.json ├── src │ ├── _headers │ ├── favicon.ico │ ├── index.ts │ ├── terminal.ts │ └── theme.ts ├── tsconfig.json └── webpack.config.js └── terminal ├── Makefile ├── README.md ├── package.json ├── src ├── index.ts ├── terminal.ts └── theme.ts ├── tsconfig.json └── webpack.config.js /.github/workflows/docker-image.yml: -------------------------------------------------------------------------------- 1 | name: Docker Image CI 2 | on: [push] 3 | jobs: 4 | build: 5 | runs-on: ubuntu-latest 6 | 7 | steps: 8 | - uses: actions/checkout@v3 9 | - name: Build the Docker image 10 | run: make docker 11 | -------------------------------------------------------------------------------- /.github/workflows/make-test.yml: -------------------------------------------------------------------------------- 1 | name: make core CI 2 | 3 | on: 4 | push: 5 | branches: [ "main" ] 6 | pull_request: 7 | branches: [ "main" ] 8 | 9 | jobs: 10 | build: 11 | 12 | runs-on: ubuntu-latest 13 | 14 | steps: 15 | - uses: actions/checkout@v3 16 | - run: npm install -g pnpm && make core 17 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | bin/lua-native 2 | bin/viz-native 3 | bin/zig 4 | bin/dash-native 5 | bin/dash-wasm* 6 | bin/python-native 7 | bin/zd 8 | bin/zdb 9 | bin/wasi-js 10 | bin/cython 11 | bin/cowasm* 12 | bin/*-wasm 13 | bin/wasm-opt 14 | bin-wasm/** 15 | **/dist 16 | **/build 17 | **/node_modules 18 | *.term 19 | .*.term.* 20 | *.wasm 21 | *.wat 22 | *.pyc 23 | *.o 24 | *.tsbuildinfo 25 | zig-cache 26 | .hypothesis 27 | upstream/sources/* 28 | scratch/* 29 | logs/* 30 | core/bench/src/cython/*.c 31 | core/rogue/warrior-rogue.scr 32 | -------------------------------------------------------------------------------- /bin/cowasm-package-path: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | node -e "console.log(require('$1').path ?? Error('path must be defined'))" -------------------------------------------------------------------------------- /bin/env.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | PACKAGES=`pwd`/packages 3 | 4 | # You have to run this via "source bin/env.sh" from the top level. It adds to your PATH: 5 | # - The scripts in this bin directory 6 | # - zig 7 | # - some scripts in python-wasm; in particular, the super useful wabt tools such as wasm-objdump and wasm-strip. 8 | 9 | export PATH=`pwd`/bin:$PATH 10 | -------------------------------------------------------------------------------- /bin/make-all: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -ev 3 | 4 | TARGET=$1 5 | shift 6 | ROOTDIR=`pwd` 7 | 8 | for PACKAGE in $* 9 | do 10 | cd "$ROOTDIR/$PACKAGE" 11 | echo $PACKAGE 12 | if [ $TARGET = "all" ]; then 13 | make 14 | else 15 | make $TARGET 16 | fi 17 | done 18 | 19 | set +v 20 | 21 | echo "##########################################################" 22 | echo "# #" 23 | echo "# CONGRATULATIONS -- $TARGET WORKED" 24 | echo "# PACKAGES: $*" 25 | echo "# #" 26 | echo "# `date`" 27 | echo "# `uname -s -m`" 28 | echo "# Git Branch: `git rev-parse --abbrev-ref HEAD`" 29 | echo "# #" 30 | echo "##########################################################" 31 | -------------------------------------------------------------------------------- /bin/make-all-clean: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -ev 3 | 4 | TARGET=$1 5 | shift 6 | ROOTDIR=`pwd` 7 | 8 | for PACKAGE in $* 9 | do 10 | cd "$ROOTDIR/" 11 | make -j4 clean 12 | cd "$ROOTDIR/$PACKAGE" 13 | echo $PACKAGE 14 | make all 15 | make $TARGET 16 | done -------------------------------------------------------------------------------- /bin/pnpm-exec: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | first_arg="$1" 4 | shift 5 | `pnpm root`/.bin/"$first_arg" "$@" 6 | 7 | 8 | # This script works around a weird and surprising behavior of pnpm exec, which 9 | # may also be valid (not sure). See https://github.com/pnpm/pnpm/issues/5068 10 | # Namely, if you do `pnpm exec cpython` say, then it'll run the relevant 11 | # node_modules/.bin/cpython script, but with the current working directory 12 | # as the directory containing node_modules. I can definitely understand how 13 | # in many settings that would be useful, but for CoWasm's build system it is 14 | # really bad. Hence this script. -------------------------------------------------------------------------------- /bin/rebuild-all: -------------------------------------------------------------------------------- 1 | set -ev 2 | 3 | echo "Sending logs to logs/" 4 | mkdir -p logs 5 | 6 | git pull 7 | make clean 8 | time make test >> logs/out 2>&1 || true 9 | tail -n 20 logs/out 10 | -------------------------------------------------------------------------------- /bin/z++: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | from compile import build 4 | 5 | def main(): 6 | build("c++") 7 | 8 | if __name__ == "__main__": 9 | main() 10 | -------------------------------------------------------------------------------- /bin/zcc: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | from compile import build 4 | 5 | def main(): 6 | build("cc") 7 | 8 | if __name__ == "__main__": 9 | main() 10 | -------------------------------------------------------------------------------- /core/README.md: -------------------------------------------------------------------------------- 1 | # The Core Packages of CoWasm 2 | 3 | This consists of a dynamic linker, a kernel, and many standard UNIX utilities. 4 | -------------------------------------------------------------------------------- /core/build/Makefile: -------------------------------------------------------------------------------- 1 | 2 | CWD := $(shell dirname $(realpath $(firstword $(MAKEFILE_LIST)))) 3 | BUILD = ${CWD}/build 4 | BIN = ${CWD}/../../bin 5 | SRC = ${CWD}/src 6 | 7 | all: ${BIN}/zig 8 | 9 | ${BUILD}/.build: ${TARBALL} 10 | rm -rf ${BUILD} 11 | cp -rv src ${BUILD} 12 | touch ${BUILD}/.build 13 | 14 | ${BIN}/zig: ${BUILD}/.build 15 | cd ${BUILD}/zig && make 16 | touch ${BIN}/zig 17 | 18 | .PHONEY: zig 19 | zig: ${BIN}/zig 20 | 21 | test: all 22 | echo "It installed." 23 | 24 | clean: 25 | rm -rf build -------------------------------------------------------------------------------- /core/build/README.md: -------------------------------------------------------------------------------- 1 | This downloads and install the two big programming environments -- Zig and 2 | Node.js -- that CoWasm depends on for building, and also provides some 3 | make rules and variables, which are included in the Makefiles for almost 4 | every package. 5 | -------------------------------------------------------------------------------- /core/build/src/Makefile-vars-build: -------------------------------------------------------------------------------- 1 | # This is a bootstrap version of Makefile-vars, just for installing some binaries. 2 | 3 | CWD:=$(shell dirname $(realpath $(firstword $(MAKEFILE_LIST)))) 4 | SRC = ${CWD}/src 5 | PACKAGES = ${CWD}/../../.. 6 | UPSTREAM = ${PACKAGES}/../upstream/sources 7 | BIN = ${PACKAGES}/../bin 8 | BUILD = ${CWD}/build 9 | BUILD_NATIVE = ${BUILD}/native 10 | DIST = ${CWD}/dist 11 | DIST_NATIVE = ${DIST}/native 12 | -------------------------------------------------------------------------------- /core/build/src/cowasm-package-path: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | node -e "console.log(require('$1').path ?? Error('path must be defined'))" -------------------------------------------------------------------------------- /core/bzip2/README.md: -------------------------------------------------------------------------------- 1 | # bzip2 compiled to WebAssembly -------------------------------------------------------------------------------- /core/bzip2/index.js: -------------------------------------------------------------------------------- 1 | const { join } = require("path"); 2 | exports.path = join(__dirname, "dist", "wasm"); 3 | -------------------------------------------------------------------------------- /core/bzip2/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@cowasm/bzip2", 3 | "version": "1.0.1", 4 | "description": "WebAssembly build of the bzip2 command (libarchive)", 5 | "main": "index.js", 6 | "files": ["dist/wasm/**", "README.md", "package.json", "index.js"], 7 | "scripts": { 8 | "preinstall": "npx only-allow pnpm", 9 | "build": "make wasm", 10 | "prepublishOnly": "npm run build && make test", 11 | "test": "make test" 12 | }, 13 | "repository": { 14 | "type": "git", 15 | "url": "git+ssh://git@github.com/sagemathinc/cowasm.git" 16 | }, 17 | "keywords": ["WebAssembly", "wasm"], 18 | "author": "William Stein ", 19 | "license": "BSD-3-Clause", 20 | "bugs": { 21 | "url": "https://github.com/sagemathinc/cowasm/issues" 22 | }, 23 | "homepage": "https://github.com/sagemathinc/cowasm/tree/main/core/bzip2" 24 | } 25 | -------------------------------------------------------------------------------- /core/bzip2/src/extra_config.h: -------------------------------------------------------------------------------- 1 | #ifndef EXTRA_CONFIG_H 2 | #define EXTRA_CONFIG_H 3 | 4 | #include 5 | int fchmod(int fd, mode_t mode); 6 | int fchown(int fd, uid_t owner, gid_t group); 7 | 8 | #endif // EXTRA_CONFIG_H 9 | -------------------------------------------------------------------------------- /core/coreutils/index.js: -------------------------------------------------------------------------------- 1 | const { join } = require("path"); 2 | exports.path = join(__dirname, "dist", "wasm"); 3 | -------------------------------------------------------------------------------- /core/coreutils/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@cowasm/coreutils", 3 | "version": "1.1.0", 4 | "description": "WebAssembly port of FreeBSD coreutils (and more!)", 5 | "main": "index.js", 6 | "files": ["dist/wasm/**", "README.md", "package.json", "index.js"], 7 | "scripts": { 8 | "preinstall": "npx only-allow pnpm", 9 | "build": "make -j8 all", 10 | "prepublishOnly": "npm run build && make test", 11 | "test": "make test" 12 | }, 13 | "repository": { 14 | "type": "git", 15 | "url": "git+ssh://git@github.com/sagemathinc/cowasm.git" 16 | }, 17 | "keywords": ["WebAssembly", "wasm"], 18 | "author": "William Stein ", 19 | "license": "BSD-3-Clause", 20 | "bugs": { 21 | "url": "https://github.com/sagemathinc/cowasm/issues" 22 | }, 23 | "homepage": "https://github.com/sagemathinc/cowasm/tree/main/core/coreutils", 24 | "devDependencies": { 25 | "@cowasm/bzip2": "workspace:*", 26 | "@cowasm/posix-wasm": "workspace:*", 27 | "@cowasm/zlib": "workspace:*" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /core/coreutils/src/uniq-sources.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | export A=`find . | grep .c$ | xargs -n1 basename | wc -l` 4 | 5 | export B=`find . | grep .c$ | xargs -n1 basename |sort | uniq | wc -l` 6 | 7 | if [ $A -eq $B ]; then 8 | echo "good -- $A unique sources files" 9 | else 10 | echo "ERROR: duplicate sources!" 11 | exit 1 12 | fi -------------------------------------------------------------------------------- /core/coreutils/src/utils/du/README.md: -------------------------------------------------------------------------------- 1 | I'm not building this yet, and it doesn't work. This 2 | is a copy of a linux port of it, and I'm not at all sure 3 | what this means on WASM, especially memfs. 4 | -------------------------------------------------------------------------------- /core/coreutils/src/utils/false/false.c: -------------------------------------------------------------------------------- 1 | /* $OpenBSD: false.c,v 1.1 2015/11/11 19:05:28 deraadt Exp $ */ 2 | 3 | /* Public domain - Theo de Raadt */ 4 | 5 | int main(int argc, char *argv[]) { return (1); } 6 | -------------------------------------------------------------------------------- /core/coreutils/src/utils/find/README.md: -------------------------------------------------------------------------------- 1 | Run 2 | 3 | bison find-getdate.y 4 | 5 | if you ever need to update the autogenerated find-getdate.tab.c 6 | -------------------------------------------------------------------------------- /core/coreutils/src/utils/realpath/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | 2 | add_executable(realpath realpath.c) 3 | 4 | INSTALL(TARGETS realpath DESTINATION ${CMAKE_INSTALL_BINDIR}) 5 | 6 | if(PROGRAM_PREFIX) 7 | set_target_properties(realpath PROPERTIES PREFIX ${PROGRAM_PREFIX}) 8 | endif() 9 | 10 | FILE(GLOB MAN1_FILES *.1) 11 | IF(MAN1_FILES) 12 | INSTALL(FILES ${MAN1_FILES} DESTINATION ${CMAKE_INSTALL_MANDIR}/man1 COMPONENT ManPages) 13 | ENDIF() 14 | FILE(GLOB MAN) -------------------------------------------------------------------------------- /core/dash-wasm/bin/dash-wasm: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | require('../dist/node-terminal'); -------------------------------------------------------------------------------- /core/dash-wasm/index.d.ts: -------------------------------------------------------------------------------- 1 | declare module '*.wasm'; 2 | declare module '*.zip'; 3 | -------------------------------------------------------------------------------- /core/dash-wasm/src/browser.ts: -------------------------------------------------------------------------------- 1 | import { asyncKernel, FileSystemSpec } from "@cowasm/kernel"; 2 | import { join } from "path"; 3 | import debug from "debug"; 4 | import { Options, DashWasmAsync, getEnv } from "./common"; 5 | 6 | const { ENV, USR } = getEnv(); 7 | 8 | const log = debug("dash-wasm:browser"); 9 | 10 | import fs_zip from "./fs.zip"; 11 | 12 | const DASH = join(USR, "bin", "sh"); 13 | 14 | export default async function asyncDash( 15 | opts?: Options 16 | ): Promise { 17 | log("creating async CoWasm kernel..."); 18 | const fs = getFilesystem(opts); 19 | const kernel = await asyncKernel({ 20 | env: ENV, 21 | fs, 22 | }); 23 | return new DashWasmAsync(kernel, DASH); 24 | } 25 | 26 | function getFilesystem(_opts?: Options): FileSystemSpec[] { 27 | return [ 28 | { 29 | type: "zipurl", 30 | zipurl: fs_zip, 31 | mountpoint: USR, 32 | }, 33 | // And the rest of the native filesystem. 34 | { type: "dev" }, 35 | ]; 36 | } 37 | -------------------------------------------------------------------------------- /core/dash-wasm/src/test/no-stdio.test.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Test disabling using stdio in node.js. 3 | */ 4 | 5 | import { asyncDash } from "../node"; 6 | import { delay } from "awaiting"; 7 | 8 | test("use noStdio", async () => { 9 | const dash = await asyncDash({ noStdio: true }); 10 | // capture stdout and stderr to a string. Actual stdout/stderr is a Buffer. 11 | let stdout = ""; 12 | dash.kernel.on("stdout", (data) => { 13 | stdout += data.toString(); 14 | }); 15 | 16 | dash.terminal(); 17 | 18 | // send 389 + 5077 19 | await dash.kernel.writeToStdin("echo $((389+5077))\n"); 20 | 21 | // output is buffered, so it can take a little while before it appears. 22 | const t0 = new Date().valueOf(); 23 | while ( 24 | new Date().valueOf() - t0 < 5000 && 25 | !stdout.includes(`${389 + 5077}`) 26 | ) { 27 | await delay(50); 28 | } 29 | expect(stdout).toContain(`${389 + 5077}`); 30 | 31 | await dash.kernel.terminate(); 32 | }); 33 | -------------------------------------------------------------------------------- /core/dash-wasm/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "rootDir": "src", 5 | "outDir": "dist", 6 | "tsBuildInfoFile": "dist/tsconfig.tsbuildinfo" 7 | }, 8 | "exclude": ["node_modules", "build", "dist"] 9 | } 10 | -------------------------------------------------------------------------------- /core/dash/README.md: -------------------------------------------------------------------------------- 1 | # dash posix shell compiled to WebAssembly 2 | 3 | -------------------------------------------------------------------------------- /core/dash/bin/dash-wasm: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | SCRIPTDIR=$(dirname $(readlink -f "$0")) 3 | "$SCRIPTDIR"/../../../bin/cowasm "$SCRIPTDIR"/../dist/wasm/bin/dash "$@" 4 | -------------------------------------------------------------------------------- /core/dash/index.js: -------------------------------------------------------------------------------- 1 | const { join } = require("path"); 2 | exports.path = join(__dirname, "dist", "wasm"); 3 | -------------------------------------------------------------------------------- /core/dash/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@cowasm/dash", 3 | "version": "1.1.0", 4 | "description": "WebAssembly build of the dash Posix shell", 5 | "main": "index.js", 6 | "files": ["dist/wasm/**", "README.md", "package.json", "index.js"], 7 | "scripts": { 8 | "preinstall": "npx only-allow pnpm", 9 | "build": "make wasm", 10 | "prepublishOnly": "npm run build && make test", 11 | "test": "make test" 12 | }, 13 | "repository": { 14 | "type": "git", 15 | "url": "git+ssh://git@github.com/sagemathinc/cowasm.git" 16 | }, 17 | "keywords": ["WebAssembly", "wasm"], 18 | "author": "William Stein ", 19 | "license": "BSD-3-Clause", 20 | "bugs": { 21 | "url": "https://github.com/sagemathinc/cowasm/issues" 22 | }, 23 | "homepage": "https://github.com/sagemathinc/cowasm/tree/main/core/dash", 24 | "devDependencies": { 25 | "@cowasm/kernel": "workspace:*", 26 | "@cowasm/libedit": "workspace:*", 27 | "@cowasm/posix-wasm": "workspace:*", 28 | "@cowasm/termcap": "workspace:*" 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /core/dash/src/extra.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include "posix-wasm.h" -------------------------------------------------------------------------------- /core/dash/src/patches/01-jobs-extra-include.patch: -------------------------------------------------------------------------------- 1 | --- native/src/jobs.c 2021-09-03 00:03:32.000000000 -0700 2 | +++ wasm/src/jobs.c 2022-09-26 16:39:55.000000000 -0700 3 | @@ -32,6 +32,7 @@ 4 | * SUCH DAMAGE. 5 | */ 6 | 7 | +#include "posix-wasm.h" 8 | #include 9 | #include 10 | #include 11 | -------------------------------------------------------------------------------- /core/dash/src/patches/02-nodes-extra-include.patch: -------------------------------------------------------------------------------- 1 | --- native/src/nodes.c.pat 2021-09-03 00:03:32.000000000 -0700 2 | +++ wasm/src/nodes.c.pat 2022-09-26 16:45:19.000000000 -0700 3 | @@ -34,6 +34,7 @@ 4 | * @(#)nodes.c.pat 8.2 (Berkeley) 5/4/95 5 | */ 6 | 7 | +#include "posix-wasm.h" 8 | #include 9 | /* 10 | * Routine for dealing with parsed shell commands. 11 | -------------------------------------------------------------------------------- /core/dash/src/patches/03-emacs-default.patch: -------------------------------------------------------------------------------- 1 | --- native/src/options.c 2022-10-01 09:10:53.000000000 -0700 2 | +++ wasm/src/options.c 2022-10-16 15:01:39.000000000 -0700 3 | @@ -169,6 +169,13 @@ 4 | shellparam.nparam++; 5 | xargv++; 6 | } 7 | + if(!Vflag && !Eflag) { 8 | + // Set emacs mode to be the default in case nothing specified. 9 | + // dash doesn't work at all interactively if neither emacs or 10 | + // vi mode are specified! Note that Eflag is "optlist[10]". 11 | + Eflag =1; 12 | + } 13 | + 14 | optschanged(); 15 | 16 | return login; 17 | -------------------------------------------------------------------------------- /core/dash/src/patches/04-vforkexec.patch: -------------------------------------------------------------------------------- 1 | --- native/src/jobs.c 2022-10-01 09:10:53.000000000 -0700 2 | +++ wasm/src/jobs.c 2022-10-07 15:05:01.000000000 -0700 3 | @@ -958,8 +958,12 @@ 4 | return pid; 5 | } 6 | 7 | +extern int cowasm_vforkexec(char **argv, const char *path); 8 | struct job *vforkexec(union node *n, char **argv, const char *path, int idx) 9 | { 10 | + exitstatus = cowasm_vforkexec(argv, path); 11 | + return 0; 12 | + 13 | struct job *jp; 14 | int pid; 15 | 16 | -------------------------------------------------------------------------------- /core/dash/src/rebuild.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -ev 4 | make -j8 5 | 6 | cp src/dash ../../dist/wasm/bin/dash 7 | -------------------------------------------------------------------------------- /core/dash/src/update.sh: -------------------------------------------------------------------------------- 1 | set -ev 2 | 3 | rsync -axvH ~/upstream/dash/src/ src/ 4 | cat ../../src/patches/* | patch -p1 5 | touch src/*.c 6 | ./rebuild.sh 7 | sh-wasm 8 | -------------------------------------------------------------------------------- /core/dylink/src/index.ts: -------------------------------------------------------------------------------- 1 | import importWebAssemblyDlopen, { Options } from "./import"; 2 | export default importWebAssemblyDlopen; 3 | export type { Options }; 4 | 5 | export { MBtoPages } from "./util"; 6 | 7 | export const path = __dirname; 8 | -------------------------------------------------------------------------------- /core/dylink/src/types.ts: -------------------------------------------------------------------------------- 1 | export interface Library { 2 | path: string; 3 | handle: number; 4 | instance: WebAssembly.Instance; 5 | symToPtr?: { [symName: string]: number }; 6 | stack_alloc?: number; 7 | } 8 | 9 | // Library but with path nonempty. 10 | export interface NonMainLibrary { 11 | path: string; 12 | handle: number; 13 | instance: WebAssembly.Instance; 14 | symToPtr: { [symName: string]: number }; 15 | stack_alloc: number; 16 | } 17 | 18 | export interface Env { 19 | __indirect_function_table?: WebAssembly.Table; 20 | memory?: WebAssembly.Memory; 21 | dlopen?: (pathnamePtr: number, flags: number) => number; 22 | dlsym?: (handle: number, symbolPtr: number) => number; 23 | dlerror?: () => number; // basically a stub right now 24 | dladdr?: () => number; // still a stub for now 25 | dlclose?: (handle: number) => number; // basically a stub right now 26 | } 27 | -------------------------------------------------------------------------------- /core/dylink/src/wasm-export.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Given a list of names of functions and symbols, generate C code that define functions 3 | that when called give a pointer to each of these. 4 | 5 | For functions, this ensures that these named functions are all placed in the WASM 6 | function table, which makes using them many orders of magnitude faster. 7 | 8 | For symbols, it ensures that we have access to them at all (and quickly) so that 9 | the GOTMemHandler (global offset table memory handler) can tell dynamic libraries 10 | where the symbols are in memory. 11 | */ 12 | 13 | const MACRO = ` 14 | #ifndef WASM_EXPORT 15 | #define WASM_EXPORT(x,y) __attribute__((visibility("default"))) void* __WASM_EXPORT__##x() { return &(y);} 16 | #endif 17 | `; 18 | 19 | export default function wasmExport(names: string[]): string { 20 | const v = Array.from(new Set(names)).sort(); 21 | return `${MACRO}\n 22 | ${v 23 | .filter((func) => func.trim()) 24 | .map((func) => `WASM_EXPORT(${func},${func})`) 25 | .join("\n")}`; 26 | } 27 | 28 | export function alias(name, value) { 29 | return `WASM_EXPORT(${name},${value})\n`; 30 | } 31 | -------------------------------------------------------------------------------- /core/dylink/test/Makefile-common: -------------------------------------------------------------------------------- 1 | 2 | BIN = $(shell pwd)/../../../../bin 3 | COWASM = ${BIN}/cowasm-cc 4 | ZIG = ${BIN}/zig 5 | 6 | clean: 7 | rm -rf build 8 | 9 | -------------------------------------------------------------------------------- /core/dylink/test/libc-archive/Makefile: -------------------------------------------------------------------------------- 1 | all: test-wasm 2 | 3 | include ../Makefile-common 4 | 5 | build/wasm/app.wasm: app.c 6 | mkdir -p build/wasm 7 | ${ZIG} cc -target wasm32-wasi \ 8 | app.c \ 9 | -rdynamic \ 10 | -L../../dist/wasm/ -ldylink \ 11 | -o build/wasm/app.wasm \ 12 | -Xlinker --import-memory \ 13 | -Xlinker --import-table 14 | 15 | build/wasm/hello.so: hello.c 16 | mkdir -p build/wasm 17 | ${COWASM} hello.c -o build/wasm/hello.so 18 | 19 | test-wasm: build/wasm/app.wasm build/wasm/hello.so 20 | cd build/wasm && node ../../app.js 21 | 22 | .PHONEY: test 23 | test: test-wasm 24 | -------------------------------------------------------------------------------- /core/dylink/test/libc-archive/README.md: -------------------------------------------------------------------------------- 1 | The goal here is to build libc into a shared library. 2 | 3 | We have stopped for now on that goal. It would require modifying zig/src/musl.zig to 4 | 5 | There's no good reason for our application to make libc dynamic. 6 | 7 | Instead we should work better to automatically and properly expose all of libc statically linked into the base. 8 | 9 | I copied libc.a from the zig cache (is there a better way)? 10 | Then got all the symbols defined there: 11 | 12 | ```sh 13 | nm -jgU libc.a |grep -v : | grep -v " W "|sort|uniq > all-symbols.txt 14 | nm -jgU libc.a |grep -v :|sort|uniq |grep -v ^_ > all-symbols.txt 15 | 16 | 17 | nm -gU libc.a |grep -v :|grep -v W|awk '{print $3}' |sort|uniq |grep -v ^_ > all-symbols.txt 18 | 19 | ``` 20 | 21 | -------------------------------------------------------------------------------- /core/dylink/test/libc-archive/app.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "app.h" 4 | 5 | extern void* dlopen(const char* filename, int flags); 6 | extern void* dlsym(void* handle, const char* symbol); 7 | 8 | int main() { 9 | printf("Loading hello dynamic library...\n"); 10 | void* handle = dlopen("./hello.so", 2); 11 | printf("Got handle=%p\n", handle); 12 | assert(handle != NULL); 13 | FUNCTION hello = (FUNCTION)dlsym(handle, "hello"); 14 | assert(hello != NULL); 15 | printf("Got hello=%p\n", hello); 16 | printf("hello():\n\n"); 17 | (*hello)(); 18 | 19 | printf("\nDone\n"); 20 | } 21 | 22 | -------------------------------------------------------------------------------- /core/dylink/test/libc-archive/app.h: -------------------------------------------------------------------------------- 1 | #define EXPORTED_SYMBOL __attribute__((visibility("default"))) 2 | 3 | typedef void (*FUNCTION)(); 4 | -------------------------------------------------------------------------------- /core/dylink/test/libc-archive/hello.c: -------------------------------------------------------------------------------- 1 | #include "app.h" 2 | #include 3 | #include 4 | 5 | 6 | EXPORTED_SYMBOL 7 | void hello(void) { 8 | // use a function from libc 9 | printf("hello using libc: %f\n", sin(1)); 10 | } 11 | -------------------------------------------------------------------------------- /core/dylink/test/malloc/README.md: -------------------------------------------------------------------------------- 1 | The point of this is to simulate the basics of the simplest Python 2 | extension module. This does not actually use Python. -------------------------------------------------------------------------------- /core/dylink/test/malloc/app.h: -------------------------------------------------------------------------------- 1 | #define EXPORTED_SYMBOL __attribute__((visibility("default"))) 2 | 3 | struct PyObjectX { 4 | int thingy; 5 | }; 6 | 7 | typedef struct PyObjectX PyObject; 8 | 9 | extern 10 | PyObject _Py_NoneStruct; 11 | 12 | #define PyNone (&_Py_NoneStruct) 13 | typedef PyObject *(*PyCFunction)(PyObject *, PyObject *); 14 | 15 | struct PyMethodDef { 16 | char *name; 17 | PyCFunction f; 18 | }; 19 | 20 | struct PyModuleDef { 21 | char *m_name; 22 | struct PyMethodDef* m_methods; 23 | }; 24 | 25 | extern int PyModuleDef_Init(struct PyModuleDef* module); 26 | 27 | 28 | -------------------------------------------------------------------------------- /core/dylink/test/malloc/hellomodule.c: -------------------------------------------------------------------------------- 1 | #include "app.h" 2 | #include 3 | #include 4 | #include 5 | 6 | extern int vecsum(int *v, int n); 7 | 8 | static PyObject *hello(PyObject *self, PyObject *args) { 9 | printf("hello...\n"); 10 | printf("allocate some memory...\n"); 11 | int n = 101; 12 | int *a = malloc(sizeof(int) * n); 13 | printf("got memory at a=%p\n", a); 14 | printf("\nNow summing up numbers placed there:\n"); 15 | for (int i = 0; i < n; i++) { 16 | a[i] = i; 17 | } 18 | printf("printf: sum is %d\n", vecsum(a, n)); 19 | assert(stdout != 0); 20 | printf("stdout=%d, &stdout=%p\n", stdout, &stdout); 21 | fprintf(stdout, "fprintf to stdout: sum is %d\n", vecsum(a, n)); 22 | return PyNone; 23 | } 24 | 25 | static struct PyMethodDef module_methods[] = {{"hello", &hello}, {NULL, NULL}}; 26 | 27 | struct PyModuleDef _hellomodule = { 28 | .m_name = "hello", 29 | .m_methods = module_methods, 30 | }; 31 | 32 | EXPORTED_SYMBOL int PyInit_hello(void) { 33 | printf("PyInit_hello\n"); 34 | // initialize the module: 35 | printf("the hello function is at %p\n", &hello); 36 | return PyModuleDef_Init(&_hellomodule); 37 | } -------------------------------------------------------------------------------- /core/dylink/test/python-extension/README.md: -------------------------------------------------------------------------------- 1 | The point of this is to simulate the basics of the simplest Python 2 | extension module. This does not actually use Python. -------------------------------------------------------------------------------- /core/dylink/test/python-extension/app.h: -------------------------------------------------------------------------------- 1 | #define EXPORTED_SYMBOL __attribute__((visibility("default"))) 2 | #define FUNCPTR(x) __attribute__((visibility("default"))) void* __FUNCPTR__##x() { return &(x);} 3 | 4 | struct PyObjectX { 5 | int thingy; 6 | }; 7 | 8 | typedef struct PyObjectX PyObject; 9 | 10 | extern 11 | PyObject _Py_NoneStruct; 12 | 13 | #define PyNone (&_Py_NoneStruct) 14 | 15 | typedef int (*FUN_PTR)(int); 16 | 17 | typedef PyObject *(*PyCFunction)(PyObject *, PyObject *); 18 | 19 | 20 | struct PyMethodDef { 21 | char *name; 22 | PyCFunction f; 23 | }; 24 | 25 | struct PyModuleDef { 26 | char *m_name; 27 | struct PyMethodDef* m_methods; 28 | }; 29 | 30 | extern int PyModuleDef_Init(struct PyModuleDef* module); 31 | 32 | 33 | -------------------------------------------------------------------------------- /core/dylink/test/wasi/README.md: -------------------------------------------------------------------------------- 1 | Example similar to basic, but with less back and forth, but with use of WASI. -------------------------------------------------------------------------------- /core/dylink/test/wasi/app.h: -------------------------------------------------------------------------------- 1 | #define EXPORTED_SYMBOL __attribute__((visibility("default"))) 2 | 3 | struct PyObjectX { 4 | int thingy; 5 | }; 6 | 7 | typedef struct PyObjectX PyObject; 8 | 9 | extern 10 | PyObject _Py_NoneStruct; 11 | 12 | #define PyNone (&_Py_NoneStruct) 13 | 14 | typedef int (*FUN_PTR)(int); 15 | -------------------------------------------------------------------------------- /core/dylink/test/wasi/dynamic-library.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | //#include 5 | #include "app.h" 6 | 7 | static int x = 388; 8 | int y = 1; 9 | 10 | EXPORTED_SYMBOL 11 | PyObject* pynone_b() { return PyNone; } 12 | 13 | EXPORTED_SYMBOL 14 | int add10(const int a) { return a + 10; } 15 | 16 | EXPORTED_SYMBOL 17 | FUN_PTR pointer_to_add10() { return &add10; } 18 | 19 | EXPORTED_SYMBOL 20 | int add389(const int a) { return a + x + y; } 21 | 22 | // This illustrates calling a function that is 23 | // defined in the main app.c. 24 | extern int add5077(int a); 25 | 26 | EXPORTED_SYMBOL 27 | int add5077_using_func_from_main(int a) { 28 | // This uses WASI! 29 | printf("Print from dynamic-library! add5077_using_func_from_main a=%d\n", a); 30 | void* mem = malloc(32); 31 | printf("I got some memory here: %p\n", mem); 32 | free(mem); 33 | int n = add5077(a - strlen("four") + 4); 34 | // doesn't work due to issue with __assert_fail not being defined: 35 | // assert(n == a + 5077); 36 | return n; 37 | } -------------------------------------------------------------------------------- /core/dylink/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "dist", 5 | "rootDir": "src", 6 | "tsBuildInfoFile": "dist/tsconfig.tsbuildinfo" 7 | }, 8 | "include": ["src/**/*"], 9 | "exclude": ["node_modules"] 10 | } 11 | -------------------------------------------------------------------------------- /core/f2c/README.md: -------------------------------------------------------------------------------- 1 | # WebAssembly build of the f2c Fortran-to-C compiler 2 | 3 | Currently only the WebAssembly libf2c.a is built, since we can hobble along 4 | some still using the native f2c binary. 5 | 6 | TODO: Also build the f2c binary to WebAssembly. -------------------------------------------------------------------------------- /core/f2c/index.js: -------------------------------------------------------------------------------- 1 | const { join } = require("path"); 2 | exports.path = join(__dirname, "dist", "wasm"); 3 | -------------------------------------------------------------------------------- /core/f2c/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@cowasm/f2c", 3 | "version": "1.0.0", 4 | "description": "WebAssembly build of the f2c Fortran-to-C compiler", 5 | "main": "index.js", 6 | "files": ["dist/wasm/**", "README.md", "package.json", "index.js"], 7 | "scripts": { 8 | "preinstall": "npx only-allow pnpm", 9 | "build": "make wasm", 10 | "prepublishOnly": "npm run build && make test", 11 | "test": "make test" 12 | }, 13 | "repository": { 14 | "type": "git", 15 | "url": "git+ssh://git@github.com/sagemathinc/cowasm.git" 16 | }, 17 | "keywords": ["WebAssembly", "wasm"], 18 | "author": "William Stein ", 19 | "license": "BSD-3-Clause", 20 | "bugs": { 21 | "url": "https://github.com/sagemathinc/cowasm/issues" 22 | }, 23 | "homepage": "https://github.com/sagemathinc/cowasm/tree/main/core/f2c", 24 | "devDependencies": { 25 | "wasi-js": "workspace:*" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /core/f2c/src/00-wasm-makefile-ld.patch: -------------------------------------------------------------------------------- 1 | --- native/libf2c/makefile.u 2022-09-09 09:06:24.000000000 -0700 2 | +++ wasm/libf2c/makefile.u 2022-09-09 10:03:35.000000000 -0700 3 | @@ -20,8 +20,7 @@ 4 | # compile, then strip unnecessary symbols 5 | .c.o: 6 | $(CC) -c -DSkip_f2c_Undefs $(CFLAGS) $*.c 7 | - ld -r -x -o $*.xxx $*.o 8 | - mv $*.xxx $*.o 9 | + 10 | ## Under Solaris (and other systems that do not understand ld -x), 11 | ## omit -x in the ld line above. 12 | ## If your system does not have the ld command, comment out 13 | @@ -72,8 +71,8 @@ 14 | all: f2c.h signal1.h sysdep1.h libf2c.a 15 | 16 | libf2c.a: $(OFILES) 17 | - ar r libf2c.a $? 18 | - -ranlib libf2c.a 19 | + zig ar r libf2c.a $? 20 | + -zig ranlib libf2c.a 21 | 22 | ## Shared-library variant: the following rule works on Linux 23 | ## systems. Details are system-dependent. Under Linux, -fPIC 24 | -------------------------------------------------------------------------------- /core/f2c/src/hello.f: -------------------------------------------------------------------------------- 1 | program main 2 | 3 | implicit none 4 | 5 | write ( *, '(a)' ) ' Hello, world!' 6 | 7 | stop 8 | end 9 | -------------------------------------------------------------------------------- /core/kernel/README.md: -------------------------------------------------------------------------------- 1 | # @cowasm/kernel: Collaborative WebAssembly for Servers and Browsers 2 | 3 | DEMOS: 4 | 5 | - https://cowasm.org (uses Atomics and SharedArrayBuffers) 6 | - https://zython.org (uses Service Workers) 7 | 8 | See [the main repo](https://github.com/sagemathinc/cowasm/blob/main/README.md) for more information. 9 | 10 | -------------------------------------------------------------------------------- /core/kernel/TODO.md: -------------------------------------------------------------------------------- 1 | Create a zig build system for the zig code in src. It's ugly having toexplicitly specify everywhere. [This discussion](https://www.reddit.com/r/Zig/comments/l5g9ku/the_zig_build_system/) looks helpful. 2 | -------------------------------------------------------------------------------- /core/kernel/bin/cowasm: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | export SCRIPTPATH="$( cd -- "$(dirname "`readlink -f $0`")" >/dev/null 2>&1 ; pwd -P )" 4 | 5 | node "$SCRIPTPATH"/../dist/kernel/node-terminal.js "$@" 6 | 7 | -------------------------------------------------------------------------------- /core/kernel/bin/cowasm-dev: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | export PROGRAM_NAME="`readlink -f $0`" 4 | export SCRIPTPATH="$( cd -- "$(dirname "`readlink -f $0`")" >/dev/null 2>&1 ; pwd -P )" 5 | 6 | "$SCRIPTPATH"/../../../bin/node "$SCRIPTPATH"/../dist/kernel/node-terminal.js "$@" 7 | 8 | -------------------------------------------------------------------------------- /core/kernel/index.d.ts: -------------------------------------------------------------------------------- 1 | declare module '*.wasm'; 2 | declare module '*.zip'; 3 | -------------------------------------------------------------------------------- /core/kernel/src/kernel/README.md: -------------------------------------------------------------------------------- 1 | TODO: -------------------------------------------------------------------------------- /core/kernel/src/kernel/cowasm.zig: -------------------------------------------------------------------------------- 1 | const std = @import("std"); 2 | const unistd = @cImport(@cInclude("unistd.h")); 3 | 4 | extern fn cowasm_vforkexec(argv: [*c][*c]u8, path: [*c]u8) c_int; 5 | 6 | pub fn exec(argc: i32, argv: [*c][*c]u8) !i32 { 7 | _ = argc; // actually argv is assumed null terminated itself. 8 | // We assume argv[0] is the full absolute path. 9 | var ret = cowasm_vforkexec(argv, 0); 10 | return ret; 11 | } 12 | 13 | fn print_args(argc: i32, argv: [*c][*c]u8) void { 14 | var i: usize = 0; 15 | while (i < argc) : (i += 1) { 16 | std.debug.print("argv[{d}] = '{s}'\n", .{ i, argv[i] }); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /core/kernel/src/kernel/node-terminal.ts: -------------------------------------------------------------------------------- 1 | import { resolve } from "path"; 2 | import { syncKernel } from "./node"; 3 | import posix from "posix-node"; 4 | 5 | async function main() { 6 | if (process.argv.length <= 2) { 7 | console.error(`Usage: cowasm program [args ...]`); 8 | process.exit(1); 9 | } 10 | // TODO: could get asyncKernel instead via command line option or env variable (?) 11 | const kernel = await syncKernel(); 12 | const program = resolve(process.argv[2]); 13 | const argv = [program].concat(process.argv.slice(3)); 14 | try { 15 | posix.enableRawInput?.(); 16 | } catch (_err) { 17 | // this will fail if stdin is not interactive; that's fine. 18 | try { 19 | posix.makeStdinBlocking?.(); 20 | } catch (_err) {} 21 | } 22 | const r = kernel.exec(argv); 23 | process.exit(r); 24 | } 25 | 26 | main(); 27 | -------------------------------------------------------------------------------- /core/kernel/src/test-zig.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | export SRC="$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )" 4 | 5 | export ZIG_SYSTEM_LINKER_HACK=1 6 | export TEST_CMD="$SRC"/../node_modules/.bin/wasi-run 7 | 8 | export TARGET="$1" 9 | shift 10 | 11 | echo zig test -target wasm32-wasi --test-cmd "$TEST_CMD" --test-cmd-bin -I. -I"$POSIX_WASM" -lc --main-pkg-path "$SRC" `pwd`/$TARGET "$@" 12 | zig test -target wasm32-wasi --test-cmd "$TEST_CMD" --test-cmd-bin -I. -I"$POSIX_WASM" -lc --main-pkg-path "$SRC" `pwd`/$TARGET "$@" 13 | -------------------------------------------------------------------------------- /core/kernel/src/wasm/constants.ts: -------------------------------------------------------------------------------- 1 | export const SIGINT = 2; 2 | 3 | -------------------------------------------------------------------------------- /core/kernel/src/wasm/posix.zig: -------------------------------------------------------------------------------- 1 | const constants = @import("./posix/constants.zig"); 2 | const errno = @import("./posix/errno.zig"); 3 | const netdb = @import("./posix/netdb.zig"); 4 | const other = @import("./posix/other.zig"); 5 | const spawn = @import("./posix/spawn.zig"); 6 | const socket = @import("./posix/socket.zig"); 7 | const stat = @import("./posix/stat.zig"); 8 | const stdio = @import("./posix/stdio.zig"); 9 | const stdlib = @import("./posix/stdlib.zig"); 10 | const string = @import("./posix/string.zig"); 11 | const termios = @import("./posix/termios.zig"); 12 | const unistd = @import("./posix/unistd.zig"); 13 | 14 | pub fn keepalive() void { 15 | constants.keepalive(); 16 | errno.keepalive(); 17 | netdb.keepalive(); 18 | other.keepalive(); 19 | socket.keepalive(); 20 | spawn.keepalive(); 21 | stdio.keepalive(); 22 | stdlib.keepalive(); 23 | stat.keepalive(); 24 | string.keepalive(); 25 | termios.keepalive(); 26 | unistd.keepalive(); 27 | } 28 | -------------------------------------------------------------------------------- /core/kernel/src/wasm/posix/README.md: -------------------------------------------------------------------------------- 1 | # POSIX 2 | 3 | This isn't strictly speaking exactly posix. It's more of a "clib that is missing from WASI that is needed to build interesting programs such as Python". That said, Python tries to support a large amount of POSIX, so this is pretty similar. 4 | 5 | ## Testing 6 | 7 | Note that a lot of the testing for this code is done in the python\-wasm package, 8 | because that is what motivated writing this, and it's easiest to write tests in python to test this calls that were motivated by that functionality. 9 | 10 | There will be similar remarks about other components of CoWasm, probably. 11 | 12 | In particular, lots of tests that you would expect to be here are in 13 | 14 | packages/python-wasm/src/test/posix/ -------------------------------------------------------------------------------- /core/kernel/src/wasm/posix/errno.zig: -------------------------------------------------------------------------------- 1 | pub fn keepalive() void {} 2 | pub const errno = @cImport(@cInclude("errno.h")); 3 | 4 | pub const constants = .{ .c_import = errno, .names = [_][:0]const u8{ "E2BIG", "EACCES", "EBADF", "EBUSY", "ECHILD", "EDEADLK", "EEXIST", "EFAULT", "EFBIG", "EINTR", "EINVAL", "EIO", "EISDIR", "EMFILE", "EMLINK", "ENFILE", "ENODEV", "ENOENT", "ENOEXEC", "ENOMEM", "ENOSPC", "ENOTDIR", "ENOTTY", "ENXIO", "EPERM", "EPIPE", "EROFS", "ESPIPE", "ESRCH", "ETXTBSY", "EXDEV", "ENOTSUP", "EADDRINUSE", "EADDRNOTAVAIL", "EAFNOSUPPORT", "EAGAIN", "EALREADY", "ECONNREFUSED", "EFAULT", "EHOSTUNREACH", "EINPROGRESS", "EISCONN", "ENETDOWN", "ENETUNREACH", "ENOBUFS", "ENOTSOCK", "ENOPROTOOPT", "EOPNOTSUPP", "EPROTOTYPE", "ETIMEDOUT", "ECONNRESET", "ELOOP", "ENAMETOOLONG", "ENOTCONN" } }; 5 | 6 | pub export fn setErrno(error_number: i32) void { 7 | errno.errno = error_number; 8 | } 9 | -------------------------------------------------------------------------------- /core/kernel/src/wasm/posix/netif.zig: -------------------------------------------------------------------------------- 1 | const std = @import("std"); 2 | const net_if = @cImport({ 3 | @cDefine("if_nameindex_struct", "struct if_nameindex"); 4 | @cInclude("net/if.h"); 5 | }); 6 | 7 | pub const constants = .{ 8 | .c_import = net_if, 9 | .names = [_][:0]const u8{"IFNAMSIZ"}, 10 | }; 11 | 12 | export fn createNameIndexArray(len: usize) ?[*]net_if.if_nameindex_struct { 13 | const voidPtr = std.c.malloc((len + 1) * @sizeOf(net_if.if_nameindex_struct)) orelse return null; 14 | const ni = @ptrCast([*]net_if.if_nameindex_struct, @alignCast(std.meta.alignment(*net_if.if_nameindex_struct), voidPtr)); 15 | setNameIndexElement(ni, len, 0, null); 16 | return ni; 17 | } 18 | 19 | export fn setNameIndexElement(ni: [*]net_if.if_nameindex_struct, i: usize, if_index: u32, if_name: ?[*:0]u8) void { 20 | ni[i].if_index = if_index; 21 | ni[i].if_name = if_name; 22 | } 23 | 24 | export fn freeNameIndexArray(ni: [*]net_if.if_nameindex_struct) void { 25 | var i: usize = 0; 26 | while (ni[i].if_index != 0) : (i += 1) { 27 | std.c.free(ni[i].if_name); 28 | } 29 | std.c.free(ni); 30 | } 31 | -------------------------------------------------------------------------------- /core/kernel/src/wasm/posix/sched.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Functions from sched.h. 3 | 4 | These are all very hard to implement with node, without just writing a node extension 5 | module which is what I'll likely have to do... 6 | */ 7 | 8 | import { notImplemented } from "./util"; 9 | 10 | export default function sched({}) { 11 | const names = 12 | "sched_get_priority_max sched_get_priority_min sched_getparam sched_getscheduler sched_rr_get_interval sched_setparam sched_setscheduler"; 13 | const sched: any = {}; 14 | for (const name of names.split(/\s+/)) { 15 | sched[name] = () => notImplemented(name); 16 | } 17 | return sched; 18 | } 19 | -------------------------------------------------------------------------------- /core/kernel/src/wasm/posix/signal.zig: -------------------------------------------------------------------------------- 1 | pub const constants = .{ .c_import = @cImport(@cInclude("posix-wasm.h")), .names = [_][:0]const u8{ "SIG_BLOCK", "SIG_UNBLOCK", "SIG_SETMASK" } }; 2 | 3 | -------------------------------------------------------------------------------- /core/kernel/src/wasm/posix/spawn.zig: -------------------------------------------------------------------------------- 1 | pub fn keepalive() void {} 2 | const posix_wasm = @cImport(@cInclude("posix-wasm.h")); 3 | 4 | // Defined in posix-wasm.h, since it's disabled in wasi: 5 | // struct sched_param 6 | // { 7 | // int sched_priority; 8 | // }; 9 | 10 | export fn get_posix_spawnattr_schedparam_sched_priority(schedparam: *const posix_wasm.sched_param) c_int { 11 | return schedparam.sched_priority; 12 | } 13 | 14 | export fn set_posix_spawnattr_schedparam_sched_priority(schedparam: *posix_wasm.sched_param, sched_priority: c_int) void { 15 | schedparam.sched_priority = sched_priority; 16 | } 17 | -------------------------------------------------------------------------------- /core/kernel/src/wasm/posix/stat.zig: -------------------------------------------------------------------------------- 1 | pub fn keepalive() void {} 2 | const stat = @cImport(@cInclude("sys/stat.h")); 3 | const std = @import("std"); 4 | const expect = std.testing.expect; 5 | 6 | 7 | // int fchmod(int fildes, mode_t mode); 8 | extern fn _fchmod(fildes : c_int, mode : stat.mode_t) c_int; 9 | export fn fchmod(fildes : c_int, mode : stat.mode_t) c_int { 10 | return _fchmod(fildes, mode); 11 | } -------------------------------------------------------------------------------- /core/kernel/src/wasm/posix/stdio.c: -------------------------------------------------------------------------------- 1 | // These two are missing from zig's libc for some reason. I don't think 2 | // it is possible to express these in ziglang either. 3 | #include 4 | #include 5 | int fiprintf(FILE *restrict stream, const char *restrict format, ...) { 6 | va_list va; 7 | va_start(va, format); 8 | vfprintf(stream, format, va); 9 | va_end(va); 10 | } 11 | PUBLIC(fiprintf) 12 | 13 | int siprintf(char *restrict s, const char *restrict format, ...) { 14 | va_list va; 15 | va_start(va, format); 16 | vsprintf(s, format, va); 17 | va_end(va); 18 | } 19 | -------------------------------------------------------------------------------- /core/kernel/src/wasm/posix/stdio.zig: -------------------------------------------------------------------------------- 1 | pub fn keepalive() void {} 2 | const stdio = @cImport(@cInclude("stdio.h")); 3 | const std = @import("std"); 4 | const expect = std.testing.expect; 5 | 6 | // These three functions are about locking files for *threads*, and we don't 7 | // support threads in any nontrivial way yet, so these are no-ops. 8 | export fn flockfile(filehandle: ?*stdio.FILE) void { 9 | _ = filehandle; 10 | } 11 | 12 | test "flockfile" { 13 | flockfile(null); 14 | } 15 | 16 | export fn ftrylockfile(filehandle: ?*stdio.FILE) c_int { 17 | _ = filehandle; 18 | return 0; 19 | } 20 | 21 | test "flockfile" { 22 | try expect(ftrylockfile(null) == 0); 23 | } 24 | 25 | export fn funlockfile(filehandle: ?*stdio.FILE) void { 26 | _ = filehandle; 27 | } 28 | 29 | test "funlockfile" { 30 | funlockfile(null); 31 | } 32 | 33 | -------------------------------------------------------------------------------- /core/kernel/src/wasm/posix/stdlib.zig: -------------------------------------------------------------------------------- 1 | pub fn keepalive() void {} 2 | const stdlib = @cImport(@cInclude("stdlib.h")); 3 | const std = @import("std"); 4 | const expect = std.testing.expect; 5 | 6 | // "The secure_getenv() function is intended for use in general-purpose libraries to avoid 7 | // vulnerabilities that could occur if set-user-ID or set-group-ID programs accidentally 8 | // trusted the environment." It is equal to getenv when this isn't an issue, and for 9 | // webassembly it isn't. 10 | export fn secure_getenv(name: [*:0]const u8) ?[*:0]u8 { 11 | return std.c.getenv(name); 12 | } 13 | 14 | // This is missing from zig's libc for some reason, so i just ported it from 15 | // zig/lib/libc/wasi/libc-top-half/musl/src/locale/strtod_l.c 16 | // since it is needed by numpy and is part of stdlib officially. 17 | 18 | // long double strtold_l(const char *restrict s, char **restrict p, locale_t l) 19 | export fn strtold_l(s: [*c]const u8, p: [*c][*c]u8, l: *anyopaque) f128 { 20 | _ = l; 21 | return stdlib.strtold(s, p); 22 | } 23 | -------------------------------------------------------------------------------- /core/kernel/src/wasm/posix/string.zig: -------------------------------------------------------------------------------- 1 | pub fn keepalive() void {} 2 | const string = @cImport(@cInclude("string.h")); 3 | const std = @import("std"); 4 | const expect = std.testing.expect; 5 | 6 | // This was fun to write, but it's also built into zig via -lwasi-emulated-signal 7 | // export fn strsignal(sig: c_int) [*:0]const u8 { 8 | // if (sig <= 0 or sig > 31) { 9 | // return "SIGINVALID"; 10 | // } 11 | // const SIGNALS: [32]([*:0]const u8) = .{ "SIGINVALID", "SIGHUP", "SIGINT", "SIGQUIT", "SIGILL", "SIGTRAP", "SIGABRT", "SIGBUS", "SIGFPE", "SIGKILL", "SIGUSR1", "SIGSEGV", "SIGUSR2", "SIGPIPE", "SIGALRM", "SIGTERM", "SIGSTKFLT", "SIGCHLD", "SIGCONT", "SIGSTOP", "SIGTSTP", "SIGTTIN", "SIGTTOU", "SIGURG", "SIGXCPU", "SIGXFSZ", "SIGVTALRM", "SIGPROF", "SIGWINCH", "SIGPOLL", "SIGPWR", "SIGSYS" }; 12 | // const n = @intCast(usize, sig); 13 | // return SIGNALS[n]; 14 | // } 15 | 16 | // test "strsignal" { 17 | // try expect(strsignal(1) == "SIGHUP"); 18 | // try expect(strsignal(2) == "SIGINT"); 19 | // try expect(strsignal(0) == "SIGINVALID"); 20 | // try expect(strsignal(32) == "SIGINVALID"); 21 | // try expect(strsignal(31) == "SIGSYS"); 22 | // } 23 | -------------------------------------------------------------------------------- /core/kernel/src/wasm/posix/unistd.zig: -------------------------------------------------------------------------------- 1 | pub fn keepalive() void {} 2 | const std = @import("std"); 3 | const unistd = @cImport({ 4 | @cInclude("unistd.h"); 5 | @cInclude("fcntl.h"); // just needed for constants 6 | @cInclude("poll.h"); 7 | @cInclude("sys/socket.h"); 8 | }); 9 | 10 | pub const constants = .{ 11 | .c_import = unistd, 12 | .names = [_][:0]const u8{ "O_CLOEXEC", "O_NONBLOCK", "O_APPEND", "F_ULOCK", "F_LOCK", "F_TLOCK", "F_TEST", "POLLIN", "POLLOUT", "SOL_SOCKET", "SHUT_RD", "SHUT_WR", "SHUT_RDWR" }, 13 | }; 14 | 15 | // uid_t geteuid(void); 16 | extern fn _geteuid() unistd.uid_t; 17 | export fn geteuid() unistd.uid_t { 18 | return _geteuid(); 19 | } 20 | 21 | // int fchown(int fd, uid_t owner, gid_t group); 22 | extern fn _fchown(fd: c_int, owner: unistd.uid_t, group: unistd.gid_t) c_int; 23 | export fn fchown(fd: c_int, owner: unistd.uid_t, group: unistd.gid_t) c_int { 24 | return _fchown(fd, owner, group); 25 | } 26 | -------------------------------------------------------------------------------- /core/kernel/src/wasm/posix/util.ts: -------------------------------------------------------------------------------- 1 | import debug from "debug"; 2 | const log = debug("posix"); 3 | 4 | export class NotImplementedError extends Error { 5 | ret: number; 6 | constructor(functionName: string, ret?: number) { 7 | super(`${functionName} is not implemented yet`); 8 | this.name = "NotImplementedError"; // name is a standard exception property. 9 | if (ret != null) { 10 | this.ret = ret; 11 | } 12 | } 13 | } 14 | 15 | export function notImplemented(functionName: string, ret: number = -1) { 16 | console.warn("WARNING: calling NOT IMPLEMENTED function", functionName); 17 | log("WARNING: calling NOT IMPLEMENTED function", functionName); 18 | throw new NotImplementedError(functionName, ret); 19 | } 20 | -------------------------------------------------------------------------------- /core/kernel/src/wasm/posix/wait.zig: -------------------------------------------------------------------------------- 1 | // These constants are actually only defined by us in posix-wasm.h, since they 2 | // aren't part of WASI at all. 3 | 4 | pub const constants = .{ .c_import = @cImport(@cInclude("posix-wasm.h")), .names = [_][:0]const u8{ "WNOHANG", "WUNTRACED" } }; 5 | -------------------------------------------------------------------------------- /core/kernel/src/wasm/worker/posix-browser.ts: -------------------------------------------------------------------------------- 1 | // Create a simulated posix environment for the browser. 2 | // We will want to move this to its own package. 3 | // It makes more sense though to put all the assumptions about what "posix in the browser" is in 4 | // its own module, rather than randomly in the files in src/wasm/posix. 5 | // Also, we can ensure this has the same interface as posix-node provides. 6 | // TODO: Maybe this goes in posix-node as the fallback in case we're on Windows (say). 7 | 8 | import type { Posix } from "posix-node"; 9 | 10 | const posix: Posix = { 11 | getpid: () => { 12 | return process.pid; 13 | }, 14 | 15 | getppid: () => { 16 | return posix.getpid?.() ?? 1; 17 | }, 18 | }; 19 | 20 | export default posix; 21 | -------------------------------------------------------------------------------- /core/kernel/src/wasm/worker/types.ts: -------------------------------------------------------------------------------- 1 | export enum Stream { 2 | STDOUT = 1, 3 | STDERR = 2, 4 | } 5 | 6 | export interface IOHandlerClass { 7 | sleep: (milliseconds: number) => void; 8 | getStdin: (milliseconds?: number) => Buffer; 9 | getSignalState: () => number; 10 | sendOutput(stream: Stream, data: Buffer): void; 11 | } 12 | -------------------------------------------------------------------------------- /core/kernel/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "rootDir": "src", 5 | "outDir": "dist", 6 | }, 7 | "exclude": ["node_modules", "build", "dist"] 8 | } 9 | -------------------------------------------------------------------------------- /core/less/README.md: -------------------------------------------------------------------------------- 1 | # Less: WebAssembly build of the less pager -------------------------------------------------------------------------------- /core/less/index.js: -------------------------------------------------------------------------------- 1 | const { join } = require("path"); 2 | exports.path = join(__dirname, "dist", "wasm"); 3 | -------------------------------------------------------------------------------- /core/less/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@cowasm/less", 3 | "version": "1.0.0", 4 | "description": "WebAssembly build of the less pager", 5 | "main": "index.js", 6 | "files": ["dist/wasm/**", "README.md", "package.json", "index.js"], 7 | "scripts": { 8 | "preinstall": "npx only-allow pnpm", 9 | "build": "make wasm", 10 | "prepublishOnly": "pnpm run build && make test", 11 | "test": "make test" 12 | }, 13 | "repository": { 14 | "type": "git", 15 | "url": "git+ssh://git@github.com/sagemathinc/cowasm.git" 16 | }, 17 | "keywords": ["WebAssembly", "wasm"], 18 | "author": "William Stein ", 19 | "license": "BSD-3-Clause", 20 | "bugs": { 21 | "url": "https://github.com/sagemathinc/cowasm/issues" 22 | }, 23 | "homepage": "https://github.com/sagemathinc/cowasm/tree/main/core/less", 24 | "devDependencies": { 25 | "@cowasm/kernel": "workspace:*", 26 | "@cowasm/ncurses": "workspace:*", 27 | "@cowasm/posix-wasm": "workspace:*", 28 | "@cowasm/termcap": "workspace:*" 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /core/less/src/patches/01-disable-dumb-error.patch: -------------------------------------------------------------------------------- 1 | --- build/wasm/opttbl.c 2022-11-04 10:44:26 2 | +++ build.0/wasm/opttbl.c 2022-11-04 10:43:24 3 | @@ -206,7 +206,7 @@ 4 | } 5 | }, 6 | { 'd', &d_optname, 7 | - BOOL|NO_TOGGLE, OPT_OFF, &know_dumb, NULL, 8 | + BOOL|NO_TOGGLE, OPT_ON, &know_dumb, NULL, 9 | { 10 | "Assume intelligent terminal", 11 | "Assume dumb terminal", 12 | -------------------------------------------------------------------------------- /core/libedit/README.md: -------------------------------------------------------------------------------- 1 | # libedit compiled to WebAssembly 2 | 3 | This is a static library that is used as a build dependency for other 4 | WebAssembly projects, such as sqlite and python. -------------------------------------------------------------------------------- /core/libedit/index.js: -------------------------------------------------------------------------------- 1 | const { join } = require("path"); 2 | exports.path = join(__dirname, "dist", "wasm"); 3 | -------------------------------------------------------------------------------- /core/libedit/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@cowasm/libedit", 3 | "version": "1.0.0", 4 | "description": "WebAssembly build of libedit", 5 | "main": "index.js", 6 | "files": ["dist/wasm/**", "README.md", "package.json", "index.js"], 7 | "scripts": { 8 | "preinstall": "npx only-allow pnpm", 9 | "build": "make wasm", 10 | "prepublishOnly": "pnpm run build && make test", 11 | "test": "make test" 12 | }, 13 | "repository": { 14 | "type": "git", 15 | "url": "git+ssh://git@github.com/sagemathinc/cowasm.git" 16 | }, 17 | "keywords": ["WebAssembly", "wasm"], 18 | "author": "William Stein ", 19 | "license": "BSD-3-Clause", 20 | "bugs": { 21 | "url": "https://github.com/sagemathinc/cowasm/issues" 22 | }, 23 | "homepage": "https://github.com/sagemathinc/cowasm/tree/main/core/libedit", 24 | "devDependencies": { 25 | "@cowasm/kernel": "workspace:*", 26 | "@cowasm/termcap": "workspace:*" 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /core/libedit/src/README.md: -------------------------------------------------------------------------------- 1 | I copied signal.h out of zig, and modified it a little to get things to 2 | compile. Ultimately this will all be in our posix wasm library. -------------------------------------------------------------------------------- /core/libedit/src/bits/setjmp.h: -------------------------------------------------------------------------------- 1 | typedef int __jmp_buf; 2 | -------------------------------------------------------------------------------- /core/libedit/src/config.site: -------------------------------------------------------------------------------- 1 | # This is stubbed on WASI and causes significant slowdown. I.e., the detection thinks 2 | # we have it, but we don't. 3 | ac_cv_func_strunvis=no -------------------------------------------------------------------------------- /core/libedit/src/extra_config.h: -------------------------------------------------------------------------------- 1 | /* 2 | We implement these (or stub them) in our runtime, but there's no headers available with them 3 | and declarations are required now for clang 15. So we defined them here. This may get 4 | refactored. 5 | */ 6 | 7 | int mkstemp(char *template); 8 | pid_t fork(void); 9 | int execlp(const char *file, const char *arg, ...); 10 | int fchmod(int fd, mode_t mode); 11 | uid_t getuid(void); 12 | int execvp(const char *file, char *const argv[]); 13 | -------------------------------------------------------------------------------- /core/libedit/src/readline.patch: -------------------------------------------------------------------------------- 1 | I don't understand why, but I had to make a small change in order to get 2 | control+d to work properly with Python + WASI. For some reason 3 | e->el_tty.t_c[TS_IO] is just all zeros, whereas e->el_tty.t_c[EX_IO] is 4 | interesting. Reading all the code (!), it makes way more sense to me 5 | to consider e->el_tty.t_c[EX_IO] rather than e->el_tty.t_c[TS_IO]. 6 | Maybe this is just a decades old bug in libedit, and people usually use 7 | readline, so they don't notice. I don't know. 8 | 9 | I found that using e->el_tty.t_c[EX_IO][C_EOF] led to a lot of problems in 10 | various states as well after revamping our IO and refactoring code. I'm 11 | now just hardcoding the number 4, which seems to work very well in all cases for us. 12 | 13 | --- readline-orig.c 2022-07-20 16:28:37.000000000 -0700 14 | +++ readline.c 2022-07-20 16:49:05.000000000 -0700 15 | @@ -2112,7 +2112,7 @@ 16 | el_set(e, EL_UNBUFFERED, 1); 17 | if (buf == NULL || count-- <= 0) 18 | return; 19 | - if (count == 0 && buf[0] == e->el_tty.t_c[TS_IO][C_EOF]) 20 | + if (count == 0 && buf[0] == 4) 21 | done = 1; 22 | if (buf[count] == '\n' || buf[count] == '\r') 23 | done = 2; 24 | -------------------------------------------------------------------------------- /core/libedit/src/readline/README.md: -------------------------------------------------------------------------------- 1 | I found these in FreeBSD. 2 | 3 | They are used, e.g., to provide line editing for lua. -------------------------------------------------------------------------------- /core/libffi/README.md: -------------------------------------------------------------------------------- 1 | # WebAssembly build of libffi (NOT FINISHED) 2 | 3 | SOURCES: The two files in libffi-emscripten are modified versions of files I found at https://github.com/hoodmane/libffi-emscripten 4 | 5 | **WARNING: This to actually not done yet!** 6 | 7 | There are several functions in `src/libffi-emscripten/src/wasm32/ffi.c` that need to be re-implemented to 8 | work in the context of CoWasm. Right now they are stubs that 9 | print that they are stubs. 10 | -------------------------------------------------------------------------------- /core/libffi/index.js: -------------------------------------------------------------------------------- 1 | const { join } = require("path"); 2 | exports.path = join(__dirname, "dist", "wasm"); 3 | -------------------------------------------------------------------------------- /core/libffi/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@cowasm/libffi", 3 | "version": "1.0.3", 4 | "description": "WebAssembly build of the libffi library", 5 | "main": "index.js", 6 | "files": ["dist/wasm/**", "README.md", "package.json", "index.js"], 7 | "scripts": { 8 | "preinstall": "npx only-allow pnpm", 9 | "build": "make wasm", 10 | "prepublishOnly": "pnpm run build && make test", 11 | "test": "make test" 12 | }, 13 | "repository": { 14 | "type": "git", 15 | "url": "git+ssh://git@github.com/sagemathinc/cowasm.git" 16 | }, 17 | "keywords": ["WebAssembly", "wasm"], 18 | "author": "William Stein ", 19 | "license": "BSD-3-Clause", 20 | "bugs": { 21 | "url": "https://github.com/sagemathinc/cowasm/issues" 22 | }, 23 | "homepage": "https://github.com/sagemathinc/cowasm/tree/main/core/libffi", 24 | "devDependencies": { 25 | "@cowasm/kernel": "workspace:*" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /core/libffi/src/patches/01-configure.patch: -------------------------------------------------------------------------------- 1 | --- native/configure.host 2022-10-23 17:17:29 2 | +++ wasm/configure.host 2022-12-02 14:53:36 3 | @@ -264,6 +264,11 @@ 4 | SOURCES="ffi.c elfbsd.S" 5 | ;; 6 | 7 | + wasm32-*-*) 8 | + TARGET=wasm32; TARGETDIR=wasm32 9 | + SOURCES="ffi.c" 10 | + ;; 11 | + 12 | xtensa*-*) 13 | TARGET=XTENSA; TARGETDIR=xtensa 14 | SOURCES="ffi.c sysv.S" 15 | -------------------------------------------------------------------------------- /core/libgit2/README.md: -------------------------------------------------------------------------------- 1 | # WebAssembly build of the libgit2 Git library 2 | -------------------------------------------------------------------------------- /core/libgit2/index.js: -------------------------------------------------------------------------------- 1 | const { join } = require("path"); 2 | exports.path = join(__dirname, "dist", "wasm"); 3 | -------------------------------------------------------------------------------- /core/libgit2/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@cowasm/libgit2", 3 | "version": "1.0.0", 4 | "description": "WebAssembly build of the libgit2 Git library", 5 | "main": "index.js", 6 | "files": ["dist/wasm/**", "README.md", "package.json", "index.js"], 7 | "scripts": { 8 | "preinstall": "npx only-allow pnpm", 9 | "build": "make wasm", 10 | "prepublishOnly": "pnpm run build && make test", 11 | "test": "make test" 12 | }, 13 | "repository": { 14 | "type": "git", 15 | "url": "git+ssh://git@github.com/sagemathinc/cowasm.git" 16 | }, 17 | "keywords": ["WebAssembly", "wasm"], 18 | "author": "William Stein ", 19 | "license": "BSD-3-Clause", 20 | "bugs": { 21 | "url": "https://github.com/sagemathinc/cowasm/issues" 22 | }, 23 | "homepage": "https://github.com/sagemathinc/cowasm/tree/main/core/libgit2", 24 | "devDependencies": { 25 | "@cowasm/kernel": "workspace:*", 26 | "@cowasm/zlib": "workspace:*" 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /core/libgit2/src/ar: -------------------------------------------------------------------------------- 1 | zig ar "$@" -------------------------------------------------------------------------------- /core/libgit2/src/patches/00-fix_missing_max_align.patch: -------------------------------------------------------------------------------- 1 | --- native/src/util/git2_util.h 2022-07-13 17:06:59.000000000 -0700 2 | +++ wasm/src/util/git2_util.h 2022-09-24 18:08:02.215458005 -0700 3 | @@ -93,6 +93,7 @@ 4 | # define st_mtim st_mtimespec 5 | #endif 6 | 7 | +typedef struct { long long __ll; long double __ld; } max_align_t; 8 | # include 9 | 10 | #endif 11 | -------------------------------------------------------------------------------- /core/libgit2/src/patches/01-realpath-cast.patch: -------------------------------------------------------------------------------- 1 | --- native/src/util/unix/realpath.c 2022-07-13 17:06:59.000000000 -0700 2 | +++ wasm/src/util/unix/realpath.c 2022-09-24 18:17:12.770325010 -0700 3 | @@ -17,7 +17,8 @@ 4 | char *p_realpath(const char *pathname, char *resolved) 5 | { 6 | char *ret; 7 | - if ((ret = realpath(pathname, resolved)) == NULL) 8 | + // cowasm - I don't know why this cast is needed since it's char* in the upstream header. 9 | + if ((ret = (char*) realpath(pathname, resolved)) == NULL) 10 | return NULL; 11 | 12 | #ifdef __OpenBSD__ 13 | -------------------------------------------------------------------------------- /core/libgit2/src/patches/02-validate_ownership.patch: -------------------------------------------------------------------------------- 1 | --- native/src/libgit2/repository.c 2022-07-13 17:06:59.000000000 -0700 2 | +++ wasm/src/libgit2/repository.c 2022-09-25 00:38:49.304410012 -0700 3 | @@ -548,6 +548,9 @@ 4 | 5 | static int validate_ownership(git_repository *repo) 6 | { 7 | + // CoWasm - We can't do this in WASI, due to lack of a permissions model. 8 | + return 0; 9 | + 10 | const char *validation_paths[3] = { NULL }, *path; 11 | size_t validation_len = 0, i; 12 | bool is_safe = false; 13 | -------------------------------------------------------------------------------- /core/libgit2/src/ranlib: -------------------------------------------------------------------------------- 1 | zig ranlib "$@" -------------------------------------------------------------------------------- /core/libgit2/src/rebuild: -------------------------------------------------------------------------------- 1 | set -ev 2 | 3 | make -j8 4 | 5 | zig ranlib liblibgit2package.a 6 | 7 | cp liblibgit2package.a ../../dist/wasm/lib/libgit2.a 8 | 9 | cd ../../../python-wasm 10 | 11 | make -j4 12 | -------------------------------------------------------------------------------- /core/libgit2/src/test-init.c: -------------------------------------------------------------------------------- 1 | /* 2 | A little test of libgit2 + cowasm. 3 | 4 | Make a git repo from scratch. 5 | */ 6 | 7 | #include 8 | #include "git2.h" 9 | 10 | int main(int argc, char** argv) { 11 | if (argc < 2) { 12 | fprintf(stderr, "usage: %s path\n", argv[0]); 13 | return 1; 14 | } 15 | if (git_libgit2_init() < 0) { 16 | fprintf(stderr, "ERROR in git_libgit2_init: %s\n", git_error_last()->message); 17 | return 1; 18 | } 19 | 20 | git_repository* repo = NULL; 21 | int status = git_repository_init(&repo, argv[1], 0); 22 | if (status < 0) { 23 | fprintf(stderr, "ERROR in git_libgit2_init: %s\n", git_error_last()->message); 24 | return 1; 25 | } 26 | printf("git init succeeded: %s\n", argv[1]); 27 | return 0; 28 | } -------------------------------------------------------------------------------- /core/libpng/README.md: -------------------------------------------------------------------------------- 1 | # libpng built for WebAssembly 2 | 3 | - This will be needed for LuaTex 4 | - This will also be used by matplotlib -------------------------------------------------------------------------------- /core/libpng/index.js: -------------------------------------------------------------------------------- 1 | const { join } = require("path"); 2 | exports.path = join(__dirname, "dist", "wasm"); 3 | -------------------------------------------------------------------------------- /core/libpng/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@cowasm/ligpng", 3 | "upstream_version": "1.6.35", 4 | "version": "1.0.0", 5 | "description": "WebAssembly build of the ligpng library", 6 | "main": "index.js", 7 | "files": ["dist/wasm/**", "README.md", "package.json", "index.js"], 8 | "scripts": { 9 | "preinstall": "npx only-allow pnpm", 10 | "build": "make wasm", 11 | "prepublishOnly": "pnpm run build && make test", 12 | "test": "make test" 13 | }, 14 | "repository": { 15 | "type": "git", 16 | "url": "git+ssh://git@github.com/sagemathinc/cowasm.git" 17 | }, 18 | "keywords": ["WebAssembly", "wasm"], 19 | "author": "William Stein ", 20 | "license": "BSD-3-Clause", 21 | "bugs": { 22 | "url": "https://github.com/sagemathinc/cowasm/issues" 23 | }, 24 | "homepage": "https://github.com/sagemathinc/cowasm/tree/main/core/ligpng", 25 | "devDependencies": { 26 | "@cowasm/kernel": "workspace:*", 27 | "@cowasm/zlib": "workspace:*" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /core/lua/README.md: -------------------------------------------------------------------------------- 1 | # WebAssembly build of the Lua interpreter -------------------------------------------------------------------------------- /core/lua/bin/lua-wasm: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | SCRIPTDIR=$(dirname $(readlink -f "$0")) 3 | "$SCRIPTDIR"/../../../bin/cowasm "$SCRIPTDIR"/../dist/wasm/bin/lua $@ 4 | -------------------------------------------------------------------------------- /core/lua/index.js: -------------------------------------------------------------------------------- 1 | const { join } = require("path"); 2 | exports.path = join(__dirname, "dist", "wasm"); 3 | -------------------------------------------------------------------------------- /core/lua/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@cowasm/lua", 3 | "version": "1.0.0", 4 | "description": "WebAssembly build of the Lua interpreter", 5 | "main": "index.js", 6 | "files": ["dist/wasm/**", "README.md", "package.json", "index.js"], 7 | "scripts": { 8 | "preinstall": "npx only-allow pnpm", 9 | "build": "make wasm", 10 | "prepublishOnly": "pnpm run build && make test", 11 | "test": "make test" 12 | }, 13 | "repository": { 14 | "type": "git", 15 | "url": "git+ssh://git@github.com/sagemathinc/cowasm.git" 16 | }, 17 | "keywords": ["WebAssembly", "wasm"], 18 | "author": "William Stein ", 19 | "license": "BSD-3-Clause", 20 | "bugs": { 21 | "url": "https://github.com/sagemathinc/cowasm/issues" 22 | }, 23 | "homepage": "https://github.com/sagemathinc/cowasm/tree/main/core/lua", 24 | "devDependencies": { 25 | "@cowasm/kernel": "^0.27.9", 26 | "@cowasm/libedit": "^1.0.0", 27 | "@cowasm/termcap": "^1.0.0" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /core/lua/src/sum.lua: -------------------------------------------------------------------------------- 1 | 2 | -- sum the integers from 1 up to n 3 | function sum (n) 4 | local s = 0 5 | for i = 1,n do 6 | s = s + i 7 | end 8 | return s 9 | end 10 | 11 | start = os.clock() 12 | s = sum(10000000) 13 | print(s, os.clock()-start) -------------------------------------------------------------------------------- /core/luatex/Makefile: -------------------------------------------------------------------------------- 1 | # This builds the luatex tex compiler 2 | 3 | ## TODO: doesn't work yet; this isn't a trivial port... 4 | 5 | include ../build/Makefile-vars 6 | 7 | # See https://github.com/TeX-Live/luatex/releases 8 | 9 | VERSION = 1.13.0-svn7420 10 | 11 | URL = https://github.com/TeX-Live/luatex/archive/refs/heads/trunk.zip 12 | 13 | #URL = https://github.com/TeX-Live/luatex/archive/refs/tags/${VERSION}.tar.gz 14 | TARBALL = ${UPSTREAM}/luatex-head.tar.gz 15 | 16 | 17 | all: 18 | #all: wasm 19 | 20 | include ../build/Makefile-rules 21 | 22 | ### 23 | # NATIVE 24 | ### 25 | 26 | 27 | ${DIST_NATIVE}/.built: ${BUILD_NATIVE}/.build 28 | rm -rf ${DIST_NATIVE} 29 | 30 | 31 | ### 32 | # WASM 33 | ### 34 | 35 | 36 | ${DIST_WASM}/.built: ${BUILD_WASM}/.build 37 | rm -rf ${DIST_WASM} 38 | 39 | 40 | test: 41 | echo "no tests yet" -------------------------------------------------------------------------------- /core/lzma/README.md: -------------------------------------------------------------------------------- 1 | # lzma web assembly 2 | 3 | This seems to work well to support tar and the python lzma module. 4 | 5 | When run standalone via cowasm it seems to work well, e.g. `make test` does this. 6 | 7 | It seems horribly broken when used from within `dash-wasm`, e.g., 8 | when used from cowasm.sh. -------------------------------------------------------------------------------- /core/lzma/index.js: -------------------------------------------------------------------------------- 1 | const { join } = require("path"); 2 | exports.path = join(__dirname, "dist", "wasm"); 3 | -------------------------------------------------------------------------------- /core/lzma/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@cowasm/lzma", 3 | "version": "1.0.3", 4 | "description": "WebAssembly build of the lzma compression library", 5 | "main": "index.js", 6 | "files": ["dist/wasm/**", "README.md", "package.json", "index.js"], 7 | "scripts": { 8 | "preinstall": "npx only-allow pnpm", 9 | "build": "make wasm", 10 | "prepublishOnly": "pnpm run build && make test", 11 | "test": "make test" 12 | }, 13 | "repository": { 14 | "type": "git", 15 | "url": "git+ssh://git@github.com/sagemathinc/cowasm.git" 16 | }, 17 | "keywords": ["WebAssembly", "wasm"], 18 | "author": "William Stein ", 19 | "license": "BSD-3-Clause", 20 | "bugs": { 21 | "url": "https://github.com/sagemathinc/cowasm/issues" 22 | }, 23 | "homepage": "https://github.com/sagemathinc/cowasm/tree/main/core/lzma", 24 | "devDependencies": { 25 | "@cowasm/kernel": "workspace:*", 26 | "@cowasm/posix-wasm": "workspace:*" 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /core/man/README.md: -------------------------------------------------------------------------------- 1 | Source tarball snapshot from 2 | 3 | https://github.com/freebsd/freebsd-src/contrib/mandoc -------------------------------------------------------------------------------- /core/man/index.js: -------------------------------------------------------------------------------- 1 | const { join } = require("path"); 2 | exports.path = join(__dirname, "dist", "wasm"); 3 | -------------------------------------------------------------------------------- /core/man/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@cowasm/man", 3 | "version": "1.0.1", 4 | "description": "WebAssembly build of the man command (shows man pages)", 5 | "main": "index.js", 6 | "files": ["dist/wasm/**", "README.md", "package.json", "index.js"], 7 | "scripts": { 8 | "preinstall": "npx only-allow pnpm", 9 | "build": "make wasm", 10 | "prepublishOnly": "pnpm run build && make test", 11 | "test": "make test" 12 | }, 13 | "repository": { 14 | "type": "git", 15 | "url": "git+ssh://git@github.com/sagemathinc/cowasm.git" 16 | }, 17 | "keywords": ["WebAssembly", "wasm"], 18 | "author": "William Stein ", 19 | "license": "BSD-3-Clause", 20 | "bugs": { 21 | "url": "https://github.com/sagemathinc/cowasm/issues" 22 | }, 23 | "homepage": "https://github.com/sagemathinc/cowasm/tree/main/core/man", 24 | "devDependencies": { 25 | "@cowasm/posix-wasm": "workspace:*", 26 | "@cowasm/zlib": "workspace:*" 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /core/man/src/Makefile.local: -------------------------------------------------------------------------------- 1 | BUILD_TARGETS = 2 | INSTALL_TARGETS = 3 | AR = ar 4 | CC = cc 5 | CFLAGS = -g -W -Wall -Wmissing-prototypes -Wstrict-prototypes -Wwrite-strings -Wno-unused-parameter 6 | LDADD = -lz 7 | LDFLAGS = 8 | MANDOC_COBJS = compat_ohash.o compat_reallocarray.o compat_recallocarray.o 9 | SOELIM_COBJS = compat_reallocarray.o 10 | STATIC = 11 | PREFIX = /usr/local 12 | BINDIR = /usr/local/bin 13 | SBINDIR = /usr/local/sbin 14 | BIN_FROM_SBIN = ../bin 15 | INCLUDEDIR = /usr/local/include/mandoc 16 | LIBDIR = /usr/local/lib/mandoc 17 | MANDIR = /usr/local/man 18 | WWWPREFIX = /var/www 19 | HTDOCDIR = /var/www/htdocs 20 | CGIBINDIR = /var/www/cgi-bin 21 | BINM_APROPOS = apropos 22 | BINM_CATMAN = catman 23 | BINM_MAKEWHATIS = makewhatis 24 | BINM_MAN = man 25 | BINM_SOELIM = soelim 26 | BINM_WHATIS = whatis 27 | MANM_MAN = man 28 | MANM_MANCONF = man.conf 29 | MANM_MDOC = mdoc 30 | MANM_ROFF = roff 31 | MANM_EQN = eqn 32 | MANM_TBL = tbl 33 | INSTALL = install 34 | INSTALL_PROGRAM = install -m 0555 35 | INSTALL_LIB = install -m 0444 36 | INSTALL_MAN = install -m 0444 37 | INSTALL_DATA = install -m 0444 38 | LN = ln -f 39 | -------------------------------------------------------------------------------- /core/man/src/mandoc-2022-10-14.tar.xz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sagemathinc/cowasm/3f8f231f96f330f80140de4d1350553caa5e6960/core/man/src/mandoc-2022-10-14.tar.xz -------------------------------------------------------------------------------- /core/ncurses/README.md: -------------------------------------------------------------------------------- 1 | # WebAssembly build of the ncurses library (and many demo programs) 2 | 3 | This is used by some of our CoWasm WebAssembly programs such as rogue. 4 | It's also used by the ncurses cpython library. -------------------------------------------------------------------------------- /core/ncurses/index.js: -------------------------------------------------------------------------------- 1 | const { join } = require("path"); 2 | exports.path = join(__dirname, "dist", "wasm"); 3 | -------------------------------------------------------------------------------- /core/ncurses/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@cowasm/ncurses", 3 | "version": "1.0.0", 4 | "description": "WebAssembly build of the ncurses library (and many demo programs)", 5 | "main": "index.js", 6 | "files": ["dist/wasm/**", "README.md", "package.json", "index.js"], 7 | "scripts": { 8 | "preinstall": "npx only-allow pnpm", 9 | "build": "make wasm", 10 | "prepublishOnly": "pnpm run build && make test", 11 | "test": "make test" 12 | }, 13 | "repository": { 14 | "type": "git", 15 | "url": "git+ssh://git@github.com/sagemathinc/cowasm.git" 16 | }, 17 | "keywords": ["WebAssembly", "wasm"], 18 | "author": "William Stein ", 19 | "license": "BSD-3-Clause", 20 | "bugs": { 21 | "url": "https://github.com/sagemathinc/cowasm/issues" 22 | }, 23 | "homepage": "https://github.com/sagemathinc/cowasm/tree/main/core/ncurses", 24 | "devDependencies": { 25 | "@cowasm/posix-wasm": "workspace:*", 26 | "@cowasm/termcap": "workspace:*" 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /core/ncurses/src/hello.c: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Hello world of ncurses, from 4 | https://tldp.org/HOWTO/pdf/NCURSES-Programming-HOWTO.pdf 5 | 6 | */ 7 | 8 | #include 9 | 10 | int main(int argc, char *argv[]) { 11 | initscr(); /* Start curses mode */ 12 | printw("Hello CoWasm !!!\n"); /* Print Hello World */ 13 | refresh(); /* Print it on to the real screen */ 14 | getch(); /* Wait for user input */ 15 | endwin(); /* End curses mode */ 16 | return 0; 17 | } 18 | -------------------------------------------------------------------------------- /core/openssl/README.md: -------------------------------------------------------------------------------- 1 | # WebAssembly build of the openssl library 2 | 3 | This is used by some of our CoWasm WebAssembly programs, including 4 | providing the library dependency for the ssl module in cpython. -------------------------------------------------------------------------------- /core/openssl/index.js: -------------------------------------------------------------------------------- 1 | const { join } = require("path"); 2 | exports.path = join(__dirname, "dist", "wasm"); 3 | -------------------------------------------------------------------------------- /core/openssl/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@cowasm/openssl", 3 | "version": "1.0.1", 4 | "description": "WebAssembly build of the openssl library", 5 | "main": "index.js", 6 | "files": ["dist/wasm/**", "README.md", "package.json", "index.js"], 7 | "scripts": { 8 | "preinstall": "npx only-allow pnpm", 9 | "build": "make wasm", 10 | "prepublishOnly": "pnpm run build && make test", 11 | "test": "make test" 12 | }, 13 | "repository": { 14 | "type": "git", 15 | "url": "git+ssh://git@github.com/sagemathinc/cowasm.git" 16 | }, 17 | "keywords": ["WebAssembly", "wasm"], 18 | "author": "William Stein ", 19 | "license": "BSD-3-Clause", 20 | "bugs": { 21 | "url": "https://github.com/sagemathinc/cowasm/issues" 22 | }, 23 | "homepage": "https://github.com/sagemathinc/cowasm/tree/main/core/openssl", 24 | "devDependencies": { 25 | "@cowasm/kernel": "workspace:*", 26 | "@cowasm/posix-wasm": "workspace:*" 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /core/openssl/src/patches/00-af-unix.patch: -------------------------------------------------------------------------------- 1 | This is a fix for a bug in the openssl build system. TODO: I will submit an upstream PR. 2 | Everywhere else in the source they do #ifdef AF_UNIX, but they missed exactly one spot. 3 | 4 | diff --git a/apps/lib/s_socket.c b/apps/lib/s_socket.c 5 | index 059afe4..4b75134 100644 6 | --- a/apps/lib/s_socket.c 7 | +++ b/apps/lib/s_socket.c 8 | @@ -179,7 +179,10 @@ int init_client(int *sock, const char *host, const char *port, 9 | BIO_ADDRINFO_family(res) == AF_INET6 ? "IPv6 " : 10 | #endif 11 | BIO_ADDRINFO_family(res) == AF_INET ? "IPv4 " : 12 | - BIO_ADDRINFO_family(res) == AF_UNIX ? "unix " : "", 13 | +#ifdef AF_UNIX 14 | + BIO_ADDRINFO_family(res) == AF_UNIX ? "unix " : 15 | +#endif 16 | + "", 17 | bindhost != NULL ? bindhost : "", 18 | bindport != NULL ? ":" : "", 19 | bindport != NULL ? bindport : ""); 20 | -------------------------------------------------------------------------------- /core/openssl/src/patches/01-cleanup-hack.patch: -------------------------------------------------------------------------------- 1 | --- native/crypto/init.c 2022-11-01 07:14:36 2 | +++ wasm/crypto/init.c 2022-11-15 00:21:33 3 | @@ -343,6 +343,11 @@ 4 | 5 | void OPENSSL_cleanup(void) 6 | { 7 | + // Hack on WebAssembly for now. I think there's an issue involving confusion and threads... 8 | + // Without this, when using the python ssl module, it frequently fails with "unknown error", 9 | + // basically since for some reason openssl is shut down and done. 10 | + return; 11 | + 12 | OPENSSL_INIT_STOP *currhandler, *lasthandler; 13 | 14 | /* 15 | -------------------------------------------------------------------------------- /core/openssl/src/rebuild: -------------------------------------------------------------------------------- 1 | make -j12 build_sw && make -j12 install_sw 2 | -------------------------------------------------------------------------------- /core/posix-browser/Makefile: -------------------------------------------------------------------------------- 1 | test: 2 | echo "no tests yet" 3 | 4 | clean: 5 | rm -rf node_modules 6 | -------------------------------------------------------------------------------- /core/posix-browser/README.md: -------------------------------------------------------------------------------- 1 | ## Posix-browser 2 | 3 | This will be an analogue of [https://www.npmjs.com/package/posix\-node](https://www.npmjs.com/package/posix-node) but for a web browser. The package posix\-node defines a Javascript API that can be used to fill in missing posix functionality for a node.js application. This module will provide the same API, but of course with much different or limited functionality in the browser, because there's no posix C api available there. The key thing this will provide is an implementation of a combined "fork_exec" to support webassembly subprocesses for python-wasm. 4 | 5 | **This does not exist yet, except in my brain.** It is key step in fully developing https://cowasm.org/ to have some similar functionality between the browser and server, when this makes sense. -------------------------------------------------------------------------------- /core/posix-browser/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "posix-browser", 3 | "version": "0.1.1", 4 | "description": "Missing Posix Functions for the Browser", 5 | "main": "dist/index.js", 6 | "files": ["src/*", "dist/*", "README.md", "package.json"], 7 | "scripts": { 8 | "preinstall": "npx only-allow pnpm" 9 | }, 10 | "repository": { 11 | "type": "git", 12 | "url": "git+https://github.com/sagemathinc/cowasm.git" 13 | }, 14 | "keywords": ["posix"], 15 | "author": "William Stein ", 16 | "license": "BSD-3-Clause", 17 | "bugs": { 18 | "url": "https://github.com/sagemathinc/cowasm/issues" 19 | }, 20 | "homepage": "https://github.com/sagemathinc/cowasm/tree/main/core/posix-browser#readme", 21 | "devDependencies": { 22 | "@types/jest": "^29.2.0", 23 | "@types/node": "^18.11.3", 24 | "jest": "^29.2.1", 25 | "typescript": "^4.8.4" 26 | }, 27 | "dependencies": { 28 | "debug": "^4.3.4" 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /core/posix-node/.gitignore: -------------------------------------------------------------------------------- 1 | deps/ 2 | dist/ 3 | zig-cache -------------------------------------------------------------------------------- /core/posix-node/demo/terminal.js: -------------------------------------------------------------------------------- 1 | /* 2 | Example of using setEcho and getChar from pour posix library. 3 | 4 | NOTE: You can accomplish basically the same thing as this demo in pure node as explained at 5 | 6 | https://stackoverflow.com/questions/5006821/nodejs-how-to-read-keystrokes-from-stdin 7 | 8 | */ 9 | 10 | const posix = require(".."); 11 | posix.setEcho(false); 12 | console.log( 13 | "This is a little terminal that capitalizes whatever you type, as you type it." 14 | ); 15 | console.log("Hit ctrl+c or ctrl+d to exit, and of course this is not burning cpu while waiting for input."); 16 | console.log("You can usé utf-8: 😀"); 17 | 18 | while (true) { 19 | const t = posix.getChar(); 20 | if (t.charCodeAt(0) == 4) break; 21 | process.stdout.write(t.toUpperCase()); 22 | } 23 | -------------------------------------------------------------------------------- /core/posix-node/scratch/README.md: -------------------------------------------------------------------------------- 1 | Little script that helped me to understand what is going on... 2 | -------------------------------------------------------------------------------- /core/posix-node/src/c.zig: -------------------------------------------------------------------------------- 1 | // posix-node binaries should work across a very wide range of nodejs versions 2 | // for their given architecture. 3 | // 4 | // "For an addon to remain ABI-compatible across Node.js major versions, it must use 5 | // Node-API exclusively by restricting itself to using #include ." 6 | // 7 | // -- https://nodejs.org/api/n-api.html 8 | // 9 | // TODO: In https://nodejs.org/api/n-api.html#usage they explain that we can do something 10 | // like "#define NAPI_VERSION 3" to ensure our code all works with a specific range 11 | // of nodejs versions. 12 | 13 | pub usingnamespace @cImport({ 14 | @cInclude("node_api.h"); 15 | @cInclude("stdlib.h"); 16 | }); 17 | -------------------------------------------------------------------------------- /core/posix-node/src/fork_exec.test.ts: -------------------------------------------------------------------------------- 1 | import posix from "./index"; 2 | 3 | test("setting and checking inheritable", () => { 4 | if (posix.set_inheritable == null) 5 | throw Error("set_inheritable must be defined"); 6 | if (posix.is_inheritable == null) 7 | throw Error("set_inheritable must be defined"); 8 | 9 | posix.set_inheritable(2, false); 10 | expect(posix.is_inheritable(2)).toBe(false); 11 | posix.set_inheritable(2, true); 12 | expect(posix.is_inheritable(2)).toBe(true); 13 | posix.set_inheritable(2, false); 14 | }); 15 | -------------------------------------------------------------------------------- /core/posix-node/src/logging.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Initialize debug logging. 3 | 4 | We use the standard debug logger with name "posix-node": https://www.npmjs.com/package/debug 5 | 6 | DEBUG_FILE option: 7 | 8 | To log to a file instead *also* set the env variable DEBUG_FILE to that 9 | filename. You need to log to a file in case you're debugging something that 10 | forks and doesn't have stdout/stderr anymore. Also, we do NOT reset the 11 | contents of the file and instead always append, because forking would be a 12 | problem, where the forked process might delete the file in the middle of the 13 | run. 14 | */ 15 | 16 | import debug from "debug"; 17 | import { format } from "util"; 18 | import { appendFileSync } from "fs"; 19 | 20 | if (process.env.DEBUG_FILE) { 21 | const debugFilename = process.env.DEBUG_FILE; 22 | debug.log = (...args) => { 23 | const s = format(...args); 24 | appendFileSync(debugFilename, s + "\n"); 25 | }; 26 | } 27 | 28 | export const log = debug("posix-node"); 29 | -------------------------------------------------------------------------------- /core/posix-node/src/other.test.ts: -------------------------------------------------------------------------------- 1 | import posix from "./index"; 2 | 3 | test("statvfs returns something", () => { 4 | expect(posix.statvfs?.("/")?.f_namemax).toBeGreaterThan(0); 5 | }); 6 | -------------------------------------------------------------------------------- /core/posix-node/src/socket.test.ts: -------------------------------------------------------------------------------- 1 | import posix from "./index"; 2 | 3 | test("create a socket", () => { 4 | if (posix.socket == null) { 5 | throw Error("socket must be defined"); 6 | } 7 | if (posix.constants == null) { 8 | throw Error("constants must be defined"); 9 | } 10 | 11 | const fd = posix.socket( 12 | posix.constants.AF_UNIX, 13 | posix.constants.SOCK_STREAM, 14 | 0 15 | ); 16 | expect(fd).toBeGreaterThan(0); 17 | }); 18 | -------------------------------------------------------------------------------- /core/posix-node/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "dist", 5 | "rootDir": "src", 6 | "tsBuildInfoFile": "dist/tsconfig.tsbuildinfo" 7 | }, 8 | "include": ["src/**/*"], 9 | "exclude": ["node_modules"] 10 | } 11 | -------------------------------------------------------------------------------- /core/posix-wasm/README.md: -------------------------------------------------------------------------------- 1 | # WASM-Posix library 2 | 3 | Note that this is not just implementing parts of POSIX. E.g., we 4 | add code from musl that is missing from WASI, and we add code from 5 | FreeBSD (say) that is needed to build tools from that OS, etc. 6 | 7 | It's also very much not about emulating the POSIX standard exactly, 8 | or one particular UNIX. 9 | -------------------------------------------------------------------------------- /core/posix-wasm/index.js: -------------------------------------------------------------------------------- 1 | const { join } = require("path"); 2 | exports.path = join(__dirname, "dist", "wasm"); 3 | -------------------------------------------------------------------------------- /core/posix-wasm/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@cowasm/posix-wasm", 3 | "version": "1.2.1", 4 | "description": "C headers and a lib archive to fill in some things missing from \"posix\"", 5 | "main": "index.js", 6 | "files": [ 7 | "dist/wasm/**", 8 | "README.md", 9 | "package.json", 10 | "index.js" 11 | ], 12 | "scripts": { 13 | "preinstall": "npx only-allow pnpm", 14 | "test": "echo \"Error: no tests yet\"" 15 | }, 16 | "repository": { 17 | "type": "git", 18 | "url": "git+ssh://git@github.com/sagemathinc/cowasm.git" 19 | }, 20 | "keywords": [ 21 | "WebAssembly", 22 | "wasm" 23 | ], 24 | "author": "William Stein ", 25 | "license": "BSD-3-Clause", 26 | "bugs": { 27 | "url": "https://github.com/sagemathinc/cowasm/issues" 28 | }, 29 | "homepage": "https://github.com/sagemathinc/cowasm/tree/main/core/posix-wasm" 30 | } 31 | -------------------------------------------------------------------------------- /core/posix-wasm/src/bits/setjmp.h: -------------------------------------------------------------------------------- 1 | typedef void* __jmp_buf; 2 | -------------------------------------------------------------------------------- /core/posix-wasm/src/emscripten.h: -------------------------------------------------------------------------------- 1 | /* 2 | Compatibility for things that assume they are building against emscripten, 3 | e.g., Python. 4 | */ 5 | 6 | #pragma once 7 | 8 | #define EM_IMPORT(NAME) 9 | 10 | #define _EM_JS(ret, c_name, js_name, params, code) \ 11 | ret c_name params EM_IMPORT(js_name); \ 12 | EMSCRIPTEN_KEEPALIVE \ 13 | __attribute__((section("em_js"), aligned(1))) char __em_js__##js_name[] = \ 14 | #params "<::>" code; \ 15 | 16 | #define EM_JS(ret, name, params, ...) \ 17 | _EM_JS(ret, name, name, params, #__VA_ARGS__) 18 | 19 | #define EMSCRIPTEN_KEEPALIVE 20 | -------------------------------------------------------------------------------- /core/posix-wasm/src/lib/README.md: -------------------------------------------------------------------------------- 1 | these are copied from zig, which is copied from musl... they are in zig but just not built as part of libc for mysterious reasons (e.g., not required by WASI?) -------------------------------------------------------------------------------- /core/posix-wasm/src/lib/builtins/README.md: -------------------------------------------------------------------------------- 1 | I found these math functions in emscripten, but they are copied from LLVM. 2 | 3 | They get used indirectly by code in Zig to implement things like csqrt. 4 | 5 | I'm only aware of this since I wrote code to scan for and explicitly link every 6 | single thing in libc-wasm-zig. It's clearly an upstream (in zig) bug to report 7 | and fix though, and here's the bug report: 8 | 9 | https://github.com/ziglang/zig/issues/12922 10 | 11 | -------------------------------------------------------------------------------- /core/posix-wasm/src/lib/stdlib/qsort_nr.c: -------------------------------------------------------------------------------- 1 | #define _BSD_SOURCE 2 | #include 3 | 4 | typedef int (*cmpfun)(const void *, const void *); 5 | 6 | static int wrapper_cmp(const void *v1, const void *v2, void *cmp) 7 | { 8 | return ((cmpfun)cmp)(v1, v2); 9 | } 10 | 11 | extern void __qsort_r(void *base, size_t nel, size_t width, cmpfun cmp, void *arg); 12 | void qsort(void *base, size_t nel, size_t width, cmpfun cmp) 13 | { 14 | __qsort_r(base, nel, width, wrapper_cmp, cmp); 15 | } 16 | -------------------------------------------------------------------------------- /core/posix-wasm/src/lib/temp/__randname.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | /* This assumes that a check for the 5 | template size has already been made */ 6 | char *__randname(char *template) 7 | { 8 | int i; 9 | struct timespec ts; 10 | unsigned long r; 11 | 12 | clock_gettime(CLOCK_REALTIME, &ts); 13 | r = ts.tv_nsec*65537 ^ (uintptr_t)&ts / 16 + (uintptr_t)template; 14 | for (i=0; i<6; i++, r>>=5) 15 | template[i] = 'A'+(r&15)+(r&16)*2; 16 | 17 | return template; 18 | } 19 | -------------------------------------------------------------------------------- /core/posix-wasm/src/lib/temp/mkdtemp.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | extern char *__randname(char *template); 7 | 8 | char *mkdtemp(char *template) 9 | { 10 | size_t l = strlen(template); 11 | int retries = 100; 12 | 13 | if (l<6 || memcmp(template+l-6, "XXXXXX", 6)) { 14 | errno = EINVAL; 15 | return 0; 16 | } 17 | 18 | do { 19 | __randname(template+l-6); 20 | if (!mkdir(template, 0700)) return template; 21 | } while (--retries && errno == EEXIST); 22 | 23 | memcpy(template+l-6, "XXXXXX", 6); 24 | return 0; 25 | } 26 | -------------------------------------------------------------------------------- /core/posix-wasm/src/lib/temp/mkstemps.c: -------------------------------------------------------------------------------- 1 | #define _BSD_SOURCE 2 | #include 3 | 4 | int __mkostemps(char *, int, int); 5 | int mkstemps(char *template, int len) 6 | { 7 | return __mkostemps(template, len, 0); 8 | } 9 | 10 | -------------------------------------------------------------------------------- /core/posix-wasm/src/public.h: -------------------------------------------------------------------------------- 1 | #ifndef PUBLIC 2 | #define PUBLIC(x) __attribute__((visibility("default"))) void* __WASM_EXPORT__##x() { return &(x);} 3 | #endif 4 | 5 | -------------------------------------------------------------------------------- /core/rogue/README.md: -------------------------------------------------------------------------------- 1 | # WebAssembly port of the ancient game of Rogue 2 | 3 | Try it from node.js (on Mac/Linux so curses is supported): 4 | 5 | ```sh 6 | npx @cowasm/rogue 7 | ``` 8 | 9 | or 10 | 11 | ```sh 12 | pnpm dlx @cowasm/rogue 13 | ``` 14 | 15 | You can also type `rogue` at https://cowasm.sh in your browser. 16 | -------------------------------------------------------------------------------- /core/rogue/bin/rogue: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | export SCRIPTPATH="$( cd -- "$(dirname "`readlink -f $0`")" >/dev/null 2>&1 ; pwd -P )" 4 | npx @cowasm/kernel "$SCRIPTPATH"/../dist/wasm/bin/rogue "$@" 5 | -------------------------------------------------------------------------------- /core/rogue/index.js: -------------------------------------------------------------------------------- 1 | const { join } = require("path"); 2 | exports.path = join(__dirname, "dist", "wasm"); 3 | -------------------------------------------------------------------------------- /core/rogue/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@cowasm/rogue", 3 | "version": "1.0.1", 4 | "description": "WebAssembly build of the classic Rogue game", 5 | "main": "index.js", 6 | "files": ["dist/wasm/**", "README.md", "package.json", "index.js"], 7 | "scripts": { 8 | "preinstall": "npx only-allow pnpm", 9 | "build": "make wasm", 10 | "prepublishOnly": "pnpm run build && make test", 11 | "test": "make test" 12 | }, 13 | "bin": "bin/rogue", 14 | "repository": { 15 | "type": "git", 16 | "url": "git+ssh://git@github.com/sagemathinc/cowasm.git" 17 | }, 18 | "keywords": ["WebAssembly", "wasm"], 19 | "author": "William Stein ", 20 | "license": "BSD-3-Clause", 21 | "bugs": { 22 | "url": "https://github.com/sagemathinc/cowasm/issues" 23 | }, 24 | "homepage": "https://github.com/sagemathinc/cowasm/tree/main/core/rogue", 25 | "devDependencies": { 26 | "@cowasm/ncurses": "workspace:*", 27 | "@cowasm/posix-wasm": "workspace:*", 28 | "@cowasm/termcap": "workspace:*" 29 | }, 30 | "dependencies": { 31 | "@cowasm/kernel": "workspace:*" 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /core/sqlite/README.md: -------------------------------------------------------------------------------- 1 | # @cowasm/sqlite: WebAssembly build of sqlite 2 | 3 | ## Status 4 | 5 | This is used as a library dependency when building cpython's sqlite3 module and that all 6 | works fine, except for the big problem mentioned below. 7 | 8 | ## Big problem: files don't work 9 | 10 | The main problem right now is that sqlite3\-wasm only works with an in memory database. So this breaks: 11 | 12 | ```sh 13 | $ sqlite3 a.sql # the native sqlite3 14 | create table foo(bar integer); 15 | ``` 16 | 17 | Now try to open it in sqlite3\-wasm \-\- BOOM! 18 | 19 | ```sh 20 | $ cowasm dist/wasm/bin/sqlite3 a.sql 21 | SQLite version 3.39.4 2022-09-29 15:55:41 22 | Enter ".help" for usage hints. 23 | sqlite> create table foo(title); 24 | Parse error: disk I/O error (10) 25 | sqlite> ^D 26 | ``` 27 | 28 | I think issues with mmap are involved. That said, I've disabled mmap and it doesn't help, so I don't yet know what the problem is. Maybe some other stub function returns invalid data that messes something up. 29 | 30 | ## References 31 | 32 | There's interesting discussion and links here https://news.ycombinator.com/item?id=33374402 33 | 34 | -------------------------------------------------------------------------------- /core/sqlite/bin/sqlite3-wasm: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | SCRIPTDIR=$(dirname $(readlink -f "$0")) 3 | "$SCRIPTDIR"/../../../bin/cowasm "$SCRIPTDIR"/../dist/wasm/bin/sqlite3 $@ 4 | -------------------------------------------------------------------------------- /core/sqlite/index.js: -------------------------------------------------------------------------------- 1 | const { join } = require("path"); 2 | exports.path = join(__dirname, "dist", "wasm"); 3 | -------------------------------------------------------------------------------- /core/sqlite/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@cowasm/sqlite", 3 | "version": "1.0.0", 4 | "description": "WebAssembly build of sqlite", 5 | "main": "index.js", 6 | "files": ["dist/wasm/**", "README.md", "package.json", "index.js"], 7 | "scripts": { 8 | "preinstall": "npx only-allow pnpm", 9 | "build": "make wasm", 10 | "prepublishOnly": "pnpm run build && make test", 11 | "test": "make test" 12 | }, 13 | "repository": { 14 | "type": "git", 15 | "url": "git+ssh://git@github.com/sagemathinc/cowasm.git" 16 | }, 17 | "keywords": ["WebAssembly", "wasm"], 18 | "author": "William Stein ", 19 | "license": "BSD-3-Clause", 20 | "bugs": { 21 | "url": "https://github.com/sagemathinc/cowasm/issues" 22 | }, 23 | "homepage": "https://github.com/sagemathinc/cowasm/tree/main/core/sqlite", 24 | "devDependencies": { 25 | "@cowasm/libedit": "workspace:*", 26 | "@cowasm/posix-wasm": "workspace:*", 27 | "@cowasm/termcap": "workspace:*", 28 | "@cowasm/zlib": "workspace:*" 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /core/sqlite/src/config.site: -------------------------------------------------------------------------------- 1 | ac_cv_func_strchrnul=no 2 | ac_cv_header_dlfcn_h=no 3 | -------------------------------------------------------------------------------- /core/sqlite/src/patches/01-shell.patch: -------------------------------------------------------------------------------- 1 | --- native/src/shell.c.in 2022-09-05 04:02:23.000000000 -0700 2 | +++ wasm/src/shell.c.in 2022-10-17 19:19:08.000000000 -0700 3 | @@ -234,7 +234,8 @@ 4 | ** WebAssembly (WASM) bundle and need to disable and rewire a few 5 | ** things. 6 | */ 7 | -#ifdef __EMSCRIPTEN__ 8 | +// NO: for CoWasm we are disabling this *toy* sqlite shell mode. 9 | +#ifdef __DISABLED_EMSCRIPTEN__ 10 | #define SQLITE_SHELL_WASM_MODE 11 | #else 12 | #undef SQLITE_SHELL_WASM_MODE 13 | -------------------------------------------------------------------------------- /core/tar/index.js: -------------------------------------------------------------------------------- 1 | const { join } = require("path"); 2 | exports.path = join(__dirname, "dist", "wasm"); 3 | -------------------------------------------------------------------------------- /core/tar/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@cowasm/tar", 3 | "version": "1.0.1", 4 | "description": "WebAssembly build of the tar command (libarchive)", 5 | "main": "index.js", 6 | "files": ["dist/wasm/**", "README.md", "package.json", "index.js"], 7 | "scripts": { 8 | "preinstall": "npx only-allow pnpm", 9 | "build": "make wasm", 10 | "prepublishOnly": "pnpm run build && make test", 11 | "test": "make test" 12 | }, 13 | "repository": { 14 | "type": "git", 15 | "url": "git+ssh://git@github.com/sagemathinc/cowasm.git" 16 | }, 17 | "keywords": ["WebAssembly", "wasm"], 18 | "author": "William Stein ", 19 | "license": "BSD-3-Clause", 20 | "bugs": { 21 | "url": "https://github.com/sagemathinc/cowasm/issues" 22 | }, 23 | "homepage": "https://github.com/sagemathinc/cowasm/tree/main/core/tar", 24 | "devDependencies": { 25 | "@cowasm/bzip2": "workspace:*", 26 | "@cowasm/lzma": "workspace:*", 27 | "@cowasm/posix-wasm": "workspace:*", 28 | "@cowasm/zlib": "workspace:*" 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /core/tar/src/config.h: -------------------------------------------------------------------------------- 1 | #include "posix-wasm.h" 2 | 3 | #undef HAVE_CHROOT 4 | #undef HAVE__LOCALTIME64_S 5 | #undef HAVE_LOCALTIME_R 6 | #undef HAVE__CTIME64_S 7 | #undef HAVE__GMTIME64_S 8 | #undef HAVE_FUTIMESAT 9 | #undef HAVE_FUTIMES 10 | #undef HAVE_READPASSPHRASE 11 | #undef HAVE_FLISTXATTR 12 | #undef ARCHIVE_XATTR_LINUX 13 | #undef HAVE_GETGRGID_R 14 | #undef HAVE_GETGRNAM_R 15 | #undef HAVE_LUTIMES 16 | #undef HAVE_READDIR_R -------------------------------------------------------------------------------- /core/tar/src/patches/01-main-visibility.patch: -------------------------------------------------------------------------------- 1 | --- native/tar/bsdtar.c 2022-04-08 04:40:26.000000000 -0700 2 | +++ wasm/tar/bsdtar.c 2022-10-22 13:27:09.000000000 -0700 3 | @@ -147,6 +147,7 @@ 4 | NULL 5 | }; 6 | 7 | +__attribute__((visibility("default"))) 8 | int 9 | main(int argc, char **argv) 10 | { 11 | --- native/cat/bsdcat.c 2022-04-08 04:40:26.000000000 -0700 12 | +++ wasm/cat/bsdcat.c 2022-10-22 14:15:18.000000000 -0700 13 | @@ -112,6 +112,7 @@ 14 | a = NULL; 15 | } 16 | 17 | +__attribute__((visibility("default"))) 18 | int 19 | main(int argc, char **argv) 20 | { 21 | --- native/cpio/cpio.c 2022-04-08 04:40:26.000000000 -0700 22 | +++ wasm/cpio/cpio.c 2022-10-22 14:15:35.000000000 -0700 23 | @@ -127,6 +127,7 @@ 24 | static const char * passphrase_callback(struct archive *, void *); 25 | static void passphrase_free(char *); 26 | 27 | +__attribute__((visibility("default"))) 28 | int 29 | main(int argc, char *argv[]) 30 | { 31 | -------------------------------------------------------------------------------- /core/termcap/index.js: -------------------------------------------------------------------------------- 1 | const { join } = require("path"); 2 | exports.path = join(__dirname, "dist", "wasm"); 3 | -------------------------------------------------------------------------------- /core/termcap/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@cowasm/termcap", 3 | "version": "1.0.0", 4 | "description": "WebAssembly build of the termcap library", 5 | "main": "index.js", 6 | "files": ["dist/wasm/**", "README.md", "package.json", "index.js"], 7 | "scripts": { 8 | "preinstall": "npx only-allow pnpm", 9 | "build": "make wasm", 10 | "prepublishOnly": "pnpm run build && make test", 11 | "test": "make test" 12 | }, 13 | "repository": { 14 | "type": "git", 15 | "url": "git+ssh://git@github.com/sagemathinc/cowasm.git" 16 | }, 17 | "keywords": ["WebAssembly", "wasm"], 18 | "author": "William Stein ", 19 | "license": "BSD-3-Clause", 20 | "bugs": { 21 | "url": "https://github.com/sagemathinc/cowasm/issues" 22 | }, 23 | "homepage": "https://github.com/sagemathinc/cowasm/tree/main/core/termcap" 24 | } 25 | -------------------------------------------------------------------------------- /core/termcap/src/config.h: -------------------------------------------------------------------------------- 1 | #define STDC_HEADERS 1 2 | #include 3 | #include 4 | #include 5 | -------------------------------------------------------------------------------- /core/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "incremental": true, 4 | "target": "es2020", 5 | "module": "commonjs", 6 | "lib": ["es5", "es6", "es2017", "dom"], 7 | "allowJs": true, 8 | "declaration": true, 9 | "downlevelIteration": true, 10 | "esModuleInterop": true, 11 | "forceConsistentCasingInFileNames": true, 12 | "isolatedModules": true, 13 | "noImplicitThis": true, 14 | "noUnusedLocals": true, 15 | "noUnusedParameters": true, 16 | "skipLibCheck": true, 17 | "sourceMap": true, 18 | "strictNullChecks": true, 19 | "moduleResolution": "node" 20 | }, 21 | } 22 | -------------------------------------------------------------------------------- /core/viz/README.md: -------------------------------------------------------------------------------- 1 | # WebAssembly build of the Viz editor 2 | 3 | -------------------------------------------------------------------------------- /core/viz/bin/viz-native: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | SCRIPTDIR=$(dirname $(readlink -f "$0")) 3 | "$SCRIPTDIR"/../dist/native/bin/viz "$@" 4 | -------------------------------------------------------------------------------- /core/viz/bin/viz-wasm: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | SCRIPTDIR=$(dirname $(readlink -f "$0")) 3 | "$SCRIPTDIR"/../../../bin/cowasm "$SCRIPTDIR"/../dist/wasm/bin/viz "$@" 4 | -------------------------------------------------------------------------------- /core/viz/index.js: -------------------------------------------------------------------------------- 1 | const { join } = require("path"); 2 | exports.path = join(__dirname, "dist", "wasm"); 3 | -------------------------------------------------------------------------------- /core/viz/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@cowasm/viz", 3 | "version": "1.0.0", 4 | "description": "WebAssembly build of the viz editor (vim like editor)", 5 | "main": "index.js", 6 | "files": ["dist/wasm/**", "README.md", "package.json", "index.js"], 7 | "scripts": { 8 | "preinstall": "npx only-allow pnpm", 9 | "build": "make wasm", 10 | "prepublishOnly": "pnpm run build && make test", 11 | "test": "make test" 12 | }, 13 | "repository": { 14 | "type": "git", 15 | "url": "git+ssh://git@github.com/sagemathinc/cowasm.git" 16 | }, 17 | "keywords": ["WebAssembly", "wasm"], 18 | "author": "William Stein ", 19 | "license": "BSD-3-Clause", 20 | "bugs": { 21 | "url": "https://github.com/sagemathinc/cowasm/issues" 22 | }, 23 | "homepage": "https://github.com/sagemathinc/cowasm/tree/main/core/viz", 24 | "devDependencies": { 25 | "@cowasm/lua": "workspace:*", 26 | "@cowasm/ncurses": "workspace:*", 27 | "@cowasm/posix-wasm": "workspace:*" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /core/wasi-js/Makefile: -------------------------------------------------------------------------------- 1 | include ../build/Makefile-vars 2 | 3 | all: ${DIST}/.built ${BIN}/wasi-js 4 | 5 | include ../build/Makefile-rules 6 | 7 | ${DIST}/.built: node_modules 8 | pnpm install 9 | pnpm run build 10 | touch ${DIST}/.built 11 | 12 | # eventually ${BIN}/cowasm should jsut call wasi-js when the executable isn't a DLL 13 | # For now we just directly run this wasi-js script. This is used by zcc and z++. 14 | ${BIN}/wasi-js: ${DIST}/.built 15 | ln -sf `pwd`/bin/run.js ${BIN}/wasi-js 16 | touch ${BIN}/wasi-js 17 | 18 | 19 | # There's a lot of testing of this in cowasm-python right now... 20 | 21 | test: ${DIST}/.built 22 | echo "it built" 23 | -------------------------------------------------------------------------------- /core/wasi-js/bin/run.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | const { run } = require("../dist/runtime"); 3 | if (process.argv.length <= 2) { 4 | throw Error("must provide path to .wasm code"); 5 | } 6 | process.argv = process.argv.slice(2); 7 | let [name] = process.argv; 8 | run(name); 9 | -------------------------------------------------------------------------------- /core/wasi-js/src/bindings/browser.ts: -------------------------------------------------------------------------------- 1 | import { randomFillSync } from "randomfill"; 2 | import path from "path-browserify"; 3 | import hrtime from "./browser-hrtime"; 4 | import { WASIBindings, WASIExitError, WASIKillError } from "../types"; 5 | 6 | const bindings: WASIBindings = { 7 | hrtime: hrtime.bigint, 8 | exit: (code: number | null) => { 9 | throw new WASIExitError(code); 10 | }, 11 | kill: (signal: string) => { 12 | throw new WASIKillError(signal); 13 | }, 14 | randomFillSync, 15 | isTTY: () => true, 16 | path, 17 | 18 | // Let the user attach the fs at runtime 19 | fs: null, 20 | }; 21 | 22 | export default bindings; 23 | -------------------------------------------------------------------------------- /core/wasi-js/src/bindings/node.ts: -------------------------------------------------------------------------------- 1 | import { randomFillSync } from "crypto"; 2 | import fs from "fs"; 3 | import { isatty as isTTY } from "tty"; 4 | import path from "path"; 5 | 6 | import { WASIBindings } from "../types"; 7 | 8 | const bindings: WASIBindings = { 9 | hrtime: process.hrtime.bigint, 10 | exit: (code: number) => { 11 | process.exit(code); 12 | }, 13 | kill: (signal: string) => { 14 | process.kill(process.pid, signal); 15 | }, 16 | randomFillSync, 17 | isTTY, 18 | fs, 19 | path, 20 | }; 21 | 22 | export default bindings; 23 | -------------------------------------------------------------------------------- /core/wasi-js/src/index.ts: -------------------------------------------------------------------------------- 1 | import WASI, { SOCKET_DEFAULT_RIGHTS } from "./wasi"; 2 | export default WASI; 3 | export { SOCKET_DEFAULT_RIGHTS }; 4 | export type { WASIBindings, WASIConfig, WASIFileSystem } from "./types"; 5 | export type { FileSystemSpec } from "./fs"; 6 | export { createFileSystem } from "./fs"; 7 | import * as constants from "./constants"; 8 | export { constants }; 9 | -------------------------------------------------------------------------------- /core/wasi-js/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "dist", 5 | "rootDir": "src", 6 | "tsBuildInfoFile": "dist/tsconfig.tsbuildinfo" 7 | }, 8 | "include": ["src/**/*"], 9 | "exclude": ["node_modules"] 10 | } 11 | -------------------------------------------------------------------------------- /core/wasm-opt/Makefile: -------------------------------------------------------------------------------- 1 | # We could try to build binaryen from source with zig, etc., but that's probably 2 | # a difficult challenge, and could also take several minutes (?), since it's nontrivial 3 | # C++ code. See https://github.com/sagemathinc/cowasm/issues/39 where the author 4 | # of binaryen suggests just this. 5 | 6 | # For now we're just installing the cross-platform WASM binary, since it works everywhere. 7 | # NOTE that it can be 10x slower than a native binary, but native binaries aren't available 8 | # for all of our supported platforms. 9 | 10 | include ../build/Makefile-vars 11 | 12 | all: ${DIST}/.built ${BIN}/wasm-opt ${BIN}/cowasm-opt 13 | 14 | include ../build/Makefile-rules 15 | 16 | ${DIST}/.built: node_modules 17 | pnpm install 18 | mkdir ${DIST} 19 | touch ${DIST}/.built 20 | 21 | ${BIN}/wasm-opt: ${DIST}/.built 22 | ln -sf `pwd`/node_modules/.bin/wasm-opt ${BIN}/wasm-opt 23 | touch ${BIN}/wasm-opt 24 | 25 | ${BIN}/cowasm-opt: ${BIN}/wasm-opt ${SRC}/cowasm_opt.py 26 | ln -sf ${SRC}/cowasm_opt.py ${BIN}/cowasm-opt 27 | touch ${BIN}/cowasm-opt 28 | 29 | test: ${BIN}/wasm-opt ${BIN}/cowasm-opt 30 | ${BIN}/cowasm-opt | grep Usage -------------------------------------------------------------------------------- /core/wasm-opt/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "binaryen", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "preinstall": "npx only-allow pnpm", 8 | "test": "echo \"Error: no test specified\" && exit 1" 9 | }, 10 | "keywords": [], 11 | "author": "", 12 | "license": "ISC", 13 | "dependencies": { 14 | "binaryen": "^110.0.0" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /core/zlib/README.md: -------------------------------------------------------------------------------- 1 | # zlib compiled to WebAssembly 2 | 3 | This is a static library that is used as a build dependency for other 4 | WebAssembly projects, such as sqlite and python. -------------------------------------------------------------------------------- /core/zlib/index.js: -------------------------------------------------------------------------------- 1 | const { join } = require("path"); 2 | exports.path = join(__dirname, "dist", "wasm"); 3 | -------------------------------------------------------------------------------- /core/zlib/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@cowasm/zlib", 3 | "version": "1.0.0", 4 | "description": "WebAssembly build of zlib", 5 | "main": "index.js", 6 | "files": ["dist/wasm/**", "README.md", "package.json", "index.js"], 7 | "scripts": { 8 | "preinstall": "npx only-allow pnpm", 9 | "build": "make wasm", 10 | "prepublishOnly": "pnpm run build && make test", 11 | "test": "make test" 12 | }, 13 | "repository": { 14 | "type": "git", 15 | "url": "git+ssh://git@github.com/sagemathinc/cowasm.git" 16 | }, 17 | "keywords": ["WebAssembly", "wasm"], 18 | "author": "William Stein ", 19 | "license": "BSD-3-Clause", 20 | "bugs": { 21 | "url": "https://github.com/sagemathinc/cowasm/issues" 22 | }, 23 | "homepage": "https://github.com/sagemathinc/cowasm/tree/main/core/zlib" 24 | } 25 | -------------------------------------------------------------------------------- /desktop/build: -------------------------------------------------------------------------------- 1 | ../core/build -------------------------------------------------------------------------------- /desktop/electron/Makefile: -------------------------------------------------------------------------------- 1 | include ../build/Makefile-vars 2 | 3 | all: deps ${DIST}/.built 4 | 5 | include ../build/Makefile-rules 6 | 7 | ${DIST}/.built: node_modules src/index.ts 8 | pnpm run build 9 | touch ${DIST}/.built 10 | 11 | clean-build:: 12 | pnpm run clean 13 | 14 | test: 15 | echo "no tests yet" 16 | -------------------------------------------------------------------------------- /desktop/electron/forge.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | packagerConfig: {}, 3 | rebuildConfig: {}, 4 | makers: [ 5 | { 6 | name: '@electron-forge/maker-squirrel', 7 | config: {}, 8 | }, 9 | { 10 | name: '@electron-forge/maker-zip', 11 | platforms: ['darwin'], 12 | }, 13 | { 14 | name: '@electron-forge/maker-deb', 15 | config: {}, 16 | }, 17 | { 18 | name: '@electron-forge/maker-rpm', 19 | config: {}, 20 | }, 21 | ], 22 | }; 23 | -------------------------------------------------------------------------------- /desktop/electron/src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, 3 | Arial, sans-serif; 4 | margin: auto; 5 | max-width: 38rem; 6 | padding: 2rem; 7 | } 8 | -------------------------------------------------------------------------------- /desktop/electron/src/preload.ts: -------------------------------------------------------------------------------- 1 | import { contextBridge, ipcRenderer } from "electron"; 2 | 3 | contextBridge.exposeInMainWorld("electronAPI", { 4 | pythonExec: (arg: string) => ipcRenderer.invoke("python:exec", arg), 5 | pythonRepr: (arg: string) => ipcRenderer.invoke("python:repr", arg), 6 | pythonStdin: (data: string) => ipcRenderer.send("python:stdin", data), 7 | pythonTerminal: () => ipcRenderer.send("python:terminal"), 8 | onPythonStdout: (cb: (data: string) => void) => 9 | ipcRenderer.on("python:stdout", (_event, data) => cb(data)), 10 | onPythonStderr: (cb: (data: string) => void) => 11 | ipcRenderer.on("python:stderr", (_event, data) => cb(data)), 12 | }); 13 | -------------------------------------------------------------------------------- /desktop/electron/src/python.ts: -------------------------------------------------------------------------------- 1 | import debug from "debug"; 2 | import { asyncPython } from "python-wasm"; 3 | 4 | // TODO: will get exported in future version of python-wasm. 5 | type PythonWasmAsync = Awaited>; 6 | 7 | const log = debug("python"); 8 | 9 | let python: PythonWasmAsync | null = null; 10 | 11 | // todo: reuseInFlight...? 12 | export default async function getPython() { 13 | if (python == null) { 14 | // Very important to explicitly set the fs, since that's not the default yet. 15 | python = await asyncPython({ noStdio: true, fs: "everything" }); 16 | } 17 | return python; 18 | } 19 | 20 | export function pythonTerminate() { 21 | if (python == null) return; 22 | const kernel = python.kernel; 23 | python = null; 24 | kernel.terminate(); 25 | } 26 | -------------------------------------------------------------------------------- /desktop/electron/src/renderer.ts: -------------------------------------------------------------------------------- 1 | //import python from "./python-frontend"; 2 | //python(); 3 | 4 | import pythonTerminal from "./python-terminal"; 5 | 6 | const element = document.createElement("div"); 7 | document.body.appendChild(element); 8 | pythonTerminal(element); 9 | -------------------------------------------------------------------------------- /desktop/electron/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2020", 4 | "allowJs": true, 5 | "module": "commonjs", 6 | "skipLibCheck": true, 7 | "esModuleInterop": true, 8 | "noImplicitAny": true, 9 | "sourceMap": true, 10 | "baseUrl": ".", 11 | "outDir": "dist/main", 12 | "moduleResolution": "node", 13 | "resolveJsonModule": true, 14 | "paths": { 15 | "*": ["node_modules/*"] 16 | } 17 | }, 18 | "include": ["src/**/*"] 19 | } 20 | -------------------------------------------------------------------------------- /docs/links.md: -------------------------------------------------------------------------------- 1 | # Relevant Links 2 | 3 | - [Python mailing list about WebAssembly](https://discuss.python.org/c/webassembly/28) -------------------------------------------------------------------------------- /pnpm-workspace.yaml: -------------------------------------------------------------------------------- 1 | packages: 2 | - "core/*" 3 | - "python/*" 4 | - "web/*" 5 | - "desktop/*" 6 | -------------------------------------------------------------------------------- /python/bench/Makefile: -------------------------------------------------------------------------------- 1 | include ../build/Makefile-vars 2 | 3 | # TODO 4 | all: 5 | echo "Nothing yet -- could be install later." 6 | 7 | include ../build/Makefile-rules 8 | 9 | python-wasm: deps 10 | echo "Starting benchmarks with python-wasm" 11 | pnpm dlx python-wasm src/all.py 12 | 13 | pylang: deps 14 | echo "Starting benchmarks with pylang" 15 | pnpm dlx pylang src/all.py 16 | 17 | native: 18 | cd ../cpython && make native 19 | echo "Starting benchmarks with python-native" 20 | ${BIN}/python-native src/all.py 21 | 22 | pypy3: 23 | echo "Starting benchmarks with pypy (you must install pypy3 yourself)" 24 | pypy3 src/all.py 25 | 26 | # Running all the benchmark programs tests something about python-wasm actually working. 27 | test: 28 | make python-wasm 29 | ##cd src/cython && make all # good test of cython 30 | 31 | .PHONY: clean 32 | clean:: 33 | rm -rf src/__pycache__ 34 | 35 | clean-build:: clean 36 | -------------------------------------------------------------------------------- /python/bench/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@cowasm/bench", 3 | "version": "1.0.0", 4 | "description": "Some Python Benchmarks", 5 | "main": "index.js", 6 | "files": ["dist/wasm/**", "README.md", "package.json", "index.js"], 7 | "scripts": { 8 | "preinstall": "npx only-allow pnpm", 9 | "build": "make wasm", 10 | "prepublishOnly": "pnpm run build && make test", 11 | "test": "make test" 12 | }, 13 | "repository": { 14 | "type": "git", 15 | "url": "git+ssh://git@github.com/sagemathinc/cowasm.git" 16 | }, 17 | "keywords": ["WebAssembly", "wasm"], 18 | "author": "William Stein ", 19 | "license": "BSD-3-Clause", 20 | "bugs": { 21 | "url": "https://github.com/sagemathinc/cowasm/issues" 22 | }, 23 | "homepage": "https://github.com/sagemathinc/cowasm/tree/main/python/py-setuptools", 24 | "devDependencies": { 25 | "python-wasm": "workspace:*", 26 | "pylang": "workspace:*" 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /python/bench/src/all.py: -------------------------------------------------------------------------------- 1 | import misc 2 | import brython 3 | import numbers 4 | import pystone 5 | import p1list 6 | import nbody 7 | import uuid_ 8 | import fib 9 | import lambda_ 10 | import call 11 | #import mandel 12 | import mypyc_micro 13 | import parse_int 14 | 15 | from time import time 16 | from bench import all 17 | 18 | 19 | def run_all_benchmarks(): 20 | t = time() 21 | all() 22 | print("=" * 20) 23 | print("Grand total time: ", int((time() - t) * 1000), "ms") 24 | 25 | 26 | if __name__ == '__main__': 27 | run_all_benchmarks() 28 | -------------------------------------------------------------------------------- /python/bench/src/bench.py: -------------------------------------------------------------------------------- 1 | # mypy 2 | from typing import Callable 3 | 4 | 5 | def time(name: str, f: Callable, *args) -> int: 6 | from time import time as time0 7 | t = time0() 8 | try: 9 | f(*args) 10 | except: 11 | print("\n**WARNING: there was an error running", name, "**\n") 12 | return int((time0() - t) * 1000) 13 | 14 | 15 | benchmarks = [] 16 | 17 | 18 | def register(name: str, f: Callable) -> None: 19 | global benchmarks 20 | benchmarks.append((name, f)) 21 | 22 | 23 | def reset() -> None: 24 | benchmarks.clear() 25 | 26 | 27 | def all(desc: str = '') -> None: 28 | print("-" * 20) 29 | print("Running...", desc) 30 | t = 0 31 | for (name, f) in benchmarks: 32 | s = time(name, f) 33 | t += s 34 | print(name, s, "ms") 35 | print("Total: ", t, "ms") 36 | -------------------------------------------------------------------------------- /python/bench/src/call.py: -------------------------------------------------------------------------------- 1 | from bench import register, all 2 | 3 | 4 | # Test speed of basic function call 5 | def basic_function_call(n=10**6): 6 | def cardinality(n): 7 | return n 8 | 9 | for i in range(n): 10 | cardinality(i) 11 | 12 | 13 | register("basic function call", basic_function_call) 14 | 15 | 16 | # Test speed of object __call__ 17 | def object_function_call(n=10**6): 18 | class IntegerRing: 19 | def __call__(self, n): 20 | return n 21 | 22 | ZZ = IntegerRing() 23 | for i in range(n): 24 | ZZ(i) 25 | 26 | 27 | register("dunder __call__ function call", object_function_call) 28 | 29 | if __name__ == '__main__': 30 | all() 31 | -------------------------------------------------------------------------------- /python/bench/src/cython/Makefile: -------------------------------------------------------------------------------- 1 | all: build bench 2 | 3 | build: 4 | python-wasm setup.py build 5 | .PHONY: build 6 | 7 | bench: 8 | python-wasm all.py 9 | 10 | clean: 11 | rm -rf *.c build -------------------------------------------------------------------------------- /python/bench/src/cython/README.md: -------------------------------------------------------------------------------- 1 | # Cython version 2 | 3 | I just started writing this and only translated some number theory benchmarks. 4 | 5 | For gcd and xgcd, Cython running under WebAssembly beats both pypy and pylang running 6 | natively. -------------------------------------------------------------------------------- /python/bench/src/cython/__pycache__/bench.cpython-311.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sagemathinc/cowasm/3f8f231f96f330f80140de4d1350553caa5e6960/python/bench/src/cython/__pycache__/bench.cpython-311.pyc -------------------------------------------------------------------------------- /python/bench/src/cython/all.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | sys.path.insert(0, ".") 4 | sys.path.insert(0, "build/lib.wasi-0.0.0-wasm32-cpython-311/") 5 | 6 | import fib 7 | import numbers 8 | 9 | from time import time 10 | from bench import all 11 | 12 | 13 | def run_all_benchmarks(): 14 | t = time() 15 | all() 16 | print("=" * 20) 17 | print("Grand total time: ", int((time() - t) * 1000), "ms") 18 | 19 | 20 | if __name__ == '__main__': 21 | run_all_benchmarks() 22 | -------------------------------------------------------------------------------- /python/bench/src/cython/bench.py: -------------------------------------------------------------------------------- 1 | # mypy 2 | from typing import Callable 3 | 4 | 5 | def time(f: Callable, *args) -> int: 6 | from time import time as time0 7 | t = time0() 8 | f(*args) 9 | return int((time0() - t) * 1000) 10 | 11 | 12 | benchmarks = [] 13 | 14 | 15 | def register(name: str, f: Callable) -> None: 16 | global benchmarks 17 | benchmarks.append((name, f)) 18 | 19 | 20 | def reset() -> None: 21 | benchmarks.clear() 22 | 23 | 24 | def all(desc: str = '') -> None: 25 | print("-" * 20) 26 | print("(Cython) Running...", desc) 27 | t = 0 28 | for (name, f) in benchmarks: 29 | s = time(f) 30 | t += s 31 | print(name, s, "ms") 32 | print("Total: ", t, "ms") 33 | -------------------------------------------------------------------------------- /python/bench/src/cython/build/lib.wasi-0.0.0-wasm32-cpython-311/fib.cpython-311-wasm32-wasi.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sagemathinc/cowasm/3f8f231f96f330f80140de4d1350553caa5e6960/python/bench/src/cython/build/lib.wasi-0.0.0-wasm32-cpython-311/fib.cpython-311-wasm32-wasi.so -------------------------------------------------------------------------------- /python/bench/src/cython/build/lib.wasi-0.0.0-wasm32-cpython-311/nt.cpython-311-wasm32-wasi.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sagemathinc/cowasm/3f8f231f96f330f80140de4d1350553caa5e6960/python/bench/src/cython/build/lib.wasi-0.0.0-wasm32-cpython-311/nt.cpython-311-wasm32-wasi.so -------------------------------------------------------------------------------- /python/bench/src/cython/build/lib.wasi-0.0.0-wasm32-cpython-311/numbers.cpython-311-wasm32-wasi.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sagemathinc/cowasm/3f8f231f96f330f80140de4d1350553caa5e6960/python/bench/src/cython/build/lib.wasi-0.0.0-wasm32-cpython-311/numbers.cpython-311-wasm32-wasi.so -------------------------------------------------------------------------------- /python/bench/src/cython/build/temp.wasi-0.0.0-wasm32-cpython-311/fib.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sagemathinc/cowasm/3f8f231f96f330f80140de4d1350553caa5e6960/python/bench/src/cython/build/temp.wasi-0.0.0-wasm32-cpython-311/fib.o -------------------------------------------------------------------------------- /python/bench/src/cython/build/temp.wasi-0.0.0-wasm32-cpython-311/nt.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sagemathinc/cowasm/3f8f231f96f330f80140de4d1350553caa5e6960/python/bench/src/cython/build/temp.wasi-0.0.0-wasm32-cpython-311/nt.o -------------------------------------------------------------------------------- /python/bench/src/cython/build/temp.wasi-0.0.0-wasm32-cpython-311/numbers.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sagemathinc/cowasm/3f8f231f96f330f80140de4d1350553caa5e6960/python/bench/src/cython/build/temp.wasi-0.0.0-wasm32-cpython-311/numbers.o -------------------------------------------------------------------------------- /python/bench/src/cython/fib.pyx: -------------------------------------------------------------------------------- 1 | # Various ways to compute Fibonacci numbers go here. 2 | 3 | from bench import register, all 4 | 5 | cdef inline int rfib(int n): 6 | if n == 1 or n == 0: 7 | return 1 8 | return rfib(n - 1) + rfib(n - 2) 9 | 10 | def fib(n=30): 11 | return rfib(n) 12 | 13 | register("cython: recursive fibonacci", fib) 14 | 15 | if __name__ == '__main__': 16 | all() 17 | -------------------------------------------------------------------------------- /python/bench/src/cython/nt.pxd: -------------------------------------------------------------------------------- 1 | cpdef int gcd(int a, int b) 2 | 3 | cdef int xgcd_c(int a, int b, int* cx, int* cy) 4 | 5 | cpdef int inverse_mod(int a, int N) 6 | -------------------------------------------------------------------------------- /python/bench/src/cython/setup.py: -------------------------------------------------------------------------------- 1 | # Run as: 2 | # python-wasm setup.py build 3 | 4 | from distutils.core import setup 5 | from distutils.extension import Extension 6 | from Cython.Build import cythonize 7 | 8 | ext_modules = cythonize("*.pyx") 9 | 10 | setup( 11 | name='Bench', 12 | ext_modules=ext_modules, 13 | ) 14 | -------------------------------------------------------------------------------- /python/bench/src/fib.py: -------------------------------------------------------------------------------- 1 | # Various ways to compute Fibonacci numbers go here. 2 | 3 | from bench import register, all 4 | 5 | 6 | def rfib(n=30): 7 | if n == 1 or n == 0: 8 | return 1 9 | return rfib(n - 1) + rfib(n - 2) 10 | 11 | 12 | register("recursive fibonacci", rfib) 13 | 14 | if __name__ == '__main__': 15 | all() 16 | -------------------------------------------------------------------------------- /python/bench/src/lambda_.py: -------------------------------------------------------------------------------- 1 | from bench import register, all 2 | 3 | 4 | # Test speed of lambda 5 | def speed_test(n=10**6): 6 | f = lambda a, b: a + b 7 | for i in range(n): 8 | f(2, 3) 9 | 10 | 11 | register("lambda speed test (1)", speed_test) 12 | 13 | 14 | # Test speed of lambda 15 | def speed_test_2(n=10**6): 16 | f = lambda a, b=10, **kwds: a + b 17 | for i in range(n): 18 | f(2) 19 | 20 | 21 | register("lambda speed test (2)", speed_test_2) 22 | 23 | if __name__ == '__main__': 24 | all() 25 | -------------------------------------------------------------------------------- /python/bench/src/misc.py: -------------------------------------------------------------------------------- 1 | from bench import register, all 2 | 3 | 4 | # JPython is really bad at these, since Javascript 5 | # doesn't really have a notion of generic lists. 6 | def list_times_number(n=100): 7 | for i in range(n): 8 | [0] * 100000 9 | 10 | 11 | register('list_times_number', list_times_number) 12 | 13 | 14 | def list_times_number2(n=1000000): 15 | v = [1, 2, list(range(100))] 16 | len(v * n) 17 | 18 | 19 | register('list_times_number2', list_times_number2) 20 | 21 | 22 | def list_times_number3(n=1000000): 23 | w = [0] 24 | for i in range(n): 25 | w * 3 26 | 27 | 28 | register('list_times_number3', list_times_number3) 29 | 30 | 31 | def list_to_string(n=10**5): 32 | len(str(list(range(n)))) 33 | 34 | 35 | register("list_to_string", list_to_string) 36 | 37 | if __name__ == '__main__': 38 | all() 39 | -------------------------------------------------------------------------------- /python/bench/src/parse_int.py: -------------------------------------------------------------------------------- 1 | from bench import register, all 2 | 3 | 4 | def parse_int(S: str = '1' * 5*10**5, B: int = 10) -> int: 5 | """ 6 | Parse string S as an integer in base B. This is from 7 | 8 | https://discuss.python.org/t/int-str-conversions-broken-in-latest-python-bugfix-releases/18889/14?u=williamstein 9 | 10 | which is a discussion that illustrates how some security researchers and core 11 | Python developers view computational mathematics... 12 | 13 | AUTHOR: Oscar Benjamin 14 | 15 | NOTE: with pylang this gives the answer as Javascript float, so take that benchmark with a grain of salt. 16 | """ 17 | m = len(S) 18 | l = list(map(int, S[::-1])) 19 | b, k = B, m 20 | while k > 1: 21 | last = [l[-1]] if k % 2 == 1 else [] 22 | l = [l1 + b * l2 for l1, l2 in zip(l[::2], l[1::2])] 23 | l.extend(last) 24 | b, k = b**2, (k + 1) // 2 25 | [l0] = l 26 | return l0 27 | 28 | register("parse_int", parse_int) 29 | 30 | if __name__ == '__main__': 31 | all() -------------------------------------------------------------------------------- /python/bench/src/uuid_.py: -------------------------------------------------------------------------------- 1 | # Benchmark computing uuid's 2 | 3 | # Strangely, pypy is really bad on this benchmark compared to python-native and pylang. 4 | 5 | from bench import register, all 6 | 7 | from uuid import uuid4 8 | 9 | 10 | def compute_uuids(n=10**5): 11 | for i in range(n): 12 | uuid4() 13 | 14 | 15 | register('compute_uuids', compute_uuids) 16 | 17 | if __name__ == '__main__': 18 | all() 19 | -------------------------------------------------------------------------------- /python/bench/src/zig/Makefile: -------------------------------------------------------------------------------- 1 | nt.wasm.o: nt.zig 2 | zig-fPIC0 build-lib nt.zig 3 | 4 | build: nt.wasm.o nt.pyx 5 | python-wasm setup.py build 6 | -------------------------------------------------------------------------------- /python/bench/src/zig/README.md: -------------------------------------------------------------------------------- 1 | It would be nice to use zig to write code for extension modules to python-wasm. 2 | This is *impossible* until zig can create -fPIC wasm code from *zig* code. 3 | Right now it's possible to create fPIC code from C/C++ code, but not wasm. 4 | Fixing that will involve changing the zig compiler a bit to work with the 5 | wasm32-emscripten target. It might be easy, but I don't know... 6 | 7 | Anyway, this is just a tiny bit of code to try out when figuring that out... 8 | -------------------------------------------------------------------------------- /python/bench/src/zig/nt.pyx: -------------------------------------------------------------------------------- 1 | 2 | cdef extern int gcd_impl(int a, int b); 3 | 4 | cpdef int gcd(int a, int b): 5 | return gcd_impl(a, b) -------------------------------------------------------------------------------- /python/bench/src/zig/nt.zig: -------------------------------------------------------------------------------- 1 | export fn gcd_impl(a: c_int, b: c_int) c_int { 2 | var c: c_int = undefined; 3 | var a0 = a; 4 | var b0 = b; 5 | while (b0 != 0) { 6 | c = @mod(a0, b0); 7 | a0 = b0; 8 | b0 = c; 9 | } 10 | return a0; 11 | } 12 | -------------------------------------------------------------------------------- /python/bench/src/zig/setup.py: -------------------------------------------------------------------------------- 1 | # Run as: 2 | # python-wasm setup.py build 3 | 4 | from setuptools import Extension, setup 5 | from Cython.Build import cythonize 6 | 7 | extensions = [ 8 | Extension("nt", ["nt.pyx"], libraries=["nt.wasm.o"], library_dirs=["."]), 9 | ] 10 | 11 | setup( 12 | name="Bench", 13 | ext_modules=cythonize(extensions), 14 | ) 15 | -------------------------------------------------------------------------------- /python/build: -------------------------------------------------------------------------------- 1 | ../core/build -------------------------------------------------------------------------------- /python/cpython/NOTES.md: -------------------------------------------------------------------------------- 1 | # Notes 2 | 3 | ## pylifecycle.c 4 | 5 | I just noticed that in `Python/pylifecycle.c` the function is\_valid\_fd uses `fcntl(fd, F_GETFD)` to tell if a fd is valid in case of \_\_wasm\_\_. I then read the source code of `fcntl` in wasi... and it is **FAKE** \-\- it always succeeds for any random input of fd! 6 | 7 | I'm not sure if I patch pylifecycle.c or not, since this code is only used in one spot to signal a fatal error, which happens later anyways. It's just a little weird/worrisome. 8 | -------------------------------------------------------------------------------- /python/cpython/bin/python-native: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # See https://stackoverflow.com/questions/3572030/bash-script-absolute-path-with-os-x 4 | realpath() ( 5 | OURPWD=$PWD 6 | cd "$(dirname "$1")" 7 | LINK=$(readlink "$(basename "$1")") 8 | while [ "$LINK" ]; do 9 | cd "$(dirname "$LINK")" 10 | LINK=$(readlink "$(basename "$1")") 11 | done 12 | REALPATH="$PWD/$(basename "$1")" 13 | cd "$OURPWD" 14 | echo "$REALPATH" 15 | ) 16 | 17 | SCRIPT=$(realpath "${BASH_SOURCE[0]}") 18 | SCRIPT_DIR=$( cd -- "$( dirname -- "${SCRIPT}" )" &> /dev/null && pwd ) 19 | 20 | PACKAGES="$SCRIPT_DIR"/../../ 21 | export DYLD_LIBRARY_PATH="$SCRIPT_DIR"/../dist/native/lib:"$PACKAGES"/zlib/dist/native/lib:$DYLD_LIBRARY_PATH 22 | export LD_LIBRARY_PATH="$SCRIPT_DIR"/../dist/native/lib:"$PACKAGES"/zlib/dist/native/lib:$LD_LIBRARY_PATH 23 | 24 | # This is all we really put in TERMCAP, and is pretty compatible... 25 | export TERM=xterm-256color 26 | export TERMCAP="$SCRIPT_DIR"/../src/termcap 27 | 28 | "$SCRIPT_DIR"/../dist/native/bin/python3 "$@" -------------------------------------------------------------------------------- /python/cpython/bin/python-wasm: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | export PYTHONEXECUTABLE=$(readlink -f "$0") 4 | SCRIPTDIR=$(dirname "$PYTHONEXECUTABLE") 5 | # Must adapt to where it happens to be installed: 6 | export PYTHONHOME="$SCRIPTDIR"/../dist/wasm/ 7 | "$SCRIPTDIR"/../node_modules/.bin/kernel "$SCRIPTDIR"/../dist/wasm/bin/python3.11.wasm "$@" 8 | -------------------------------------------------------------------------------- /python/cpython/index.js: -------------------------------------------------------------------------------- 1 | const { join } = require("path"); 2 | exports.path = join(__dirname, "dist", "wasm"); 3 | -------------------------------------------------------------------------------- /python/cpython/src/__pycache__/cowasm_bundler.cpython-311.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sagemathinc/cowasm/3f8f231f96f330f80140de4d1350553caa5e6960/python/cpython/src/__pycache__/cowasm_bundler.cpython-311.pyc -------------------------------------------------------------------------------- /python/cpython/src/__pycache__/cowasm_importer.cpython-311.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sagemathinc/cowasm/3f8f231f96f330f80140de4d1350553caa5e6960/python/cpython/src/__pycache__/cowasm_importer.cpython-311.pyc -------------------------------------------------------------------------------- /python/cpython/src/__pycache__/sitecustomize.cpython-311.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sagemathinc/cowasm/3f8f231f96f330f80140de4d1350553caa5e6960/python/cpython/src/__pycache__/sitecustomize.cpython-311.pyc -------------------------------------------------------------------------------- /python/cpython/src/__pycache__/zython_importer.cpython-311.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sagemathinc/cowasm/3f8f231f96f330f80140de4d1350553caa5e6960/python/cpython/src/__pycache__/zython_importer.cpython-311.pyc -------------------------------------------------------------------------------- /python/cpython/src/patches/01-main.patch: -------------------------------------------------------------------------------- 1 | --- native/Programs/python.c 2022-09-11 12:23:30.000000000 -0700 2 | +++ wasm/Programs/python.c 2022-10-19 10:26:04.000000000 -0700 3 | @@ -2,6 +2,11 @@ 4 | 5 | #include "Python.h" 6 | 7 | +// This C file, which is defined right now in the dylink nodejs module, adds 8 | +// the declaration that make everything extension modules need 9 | +// accessible from outside our "python.wasm as a shared library". 10 | +#include "libpython.c" 11 | + 12 | #ifdef MS_WINDOWS 13 | int 14 | wmain(int argc, wchar_t **argv) 15 | @@ -9,6 +14,11 @@ 16 | return Py_Main(argc, argv); 17 | } 18 | #else 19 | + 20 | +// Make the main symbol visible. We do this explicitly since our trick with #define main 21 | +// doesn't work with python, due to there being other code that uses main as a struct attribute. 22 | + 23 | +__attribute__((visibility("default"))) 24 | int 25 | main(int argc, char **argv) 26 | { 27 | -------------------------------------------------------------------------------- /python/cpython/src/patches/05-st_mode.patch: -------------------------------------------------------------------------------- 1 | --- native/Modules/posixmodule.c 2022-08-05 07:45:18.000000000 -0700 2 | +++ wasm/Modules/posixmodule.c 2022-09-07 09:53:36.000000000 -0700 3 | @@ -2391,8 +2391,12 @@ 4 | PyObject *v = PyStructSequence_New((PyTypeObject *)StatResultType); 5 | if (v == NULL) 6 | return NULL; 7 | - 8 | - PyStructSequence_SET_ITEM(v, 0, PyLong_FromLong((long)st->st_mode)); 9 | + // On WASM we modify st_mode to include u+rwx, since WASI provides nothing 10 | + // but "is it a directory or not" in st_mode, and this breaks a lot of things 11 | + // horribly, e.g., the entire zipfile module. For now the best solution is 12 | + // this patch. This will change -- see 13 | + // https://github.com/WebAssembly/wasi-filesystem/issues/34 14 | + PyStructSequence_SET_ITEM(v, 0, PyLong_FromLong((long)st->st_mode | 448)); 15 | static_assert(sizeof(unsigned long long) >= sizeof(st->st_ino), 16 | "stat.st_ino is larger than unsigned long long"); 17 | PyStructSequence_SET_ITEM(v, 1, PyLong_FromUnsignedLongLong(st->st_ino)); 18 | -------------------------------------------------------------------------------- /python/cpython/src/patches/09-set-inheritable.patch: -------------------------------------------------------------------------------- 1 | --- native/Python/fileutils.c 2022-09-11 12:23:30.000000000 -0700 2 | +++ wasm/Python/fileutils.c 2022-09-18 11:58:42.000000000 -0700 3 | @@ -1323,11 +1323,25 @@ 4 | return get_inheritable(fd, 1); 5 | } 6 | 7 | +extern int python_wasm_set_inheritable(int fd, int inheritable); 8 | 9 | /* This function MUST be kept async-signal-safe on POSIX when raise=0. */ 10 | static int 11 | set_inheritable(int fd, int inheritable, int raise, int *atomic_flag_works) 12 | { 13 | + // For python-wasm we *have* to write this ourselves, since fcntl is 14 | + // built into upstream WASI and it makes this sort of stuff a no-op, or 15 | + // at least no functions in wasi get called. Note that this has limited 16 | + // impact, e.g., it can only work in a WASI context for certain types of 17 | + // fd's, e.g., pipes. 18 | + int result = python_wasm_set_inheritable(fd, inheritable); 19 | + if (result < 0) { 20 | + if (raise) 21 | + PyErr_SetFromErrno(PyExc_OSError); 22 | + return -1; 23 | + } 24 | + return 0; 25 | + 26 | #ifdef MS_WINDOWS 27 | HANDLE handle; 28 | DWORD flags; 29 | -------------------------------------------------------------------------------- /python/cpython/src/patches/10-setuptools-c++.patch: -------------------------------------------------------------------------------- 1 | --- native/lib/python3.11/site-packages/setuptools/_distutils/unixccompiler.py 2022-09-17 12:18:23.000000000 -0700 2 | +++ wasm/lib/python3.11/site-packages/setuptools/_distutils/unixccompiler.py 2022-09-19 16:52:33.000000000 -0700 3 | @@ -245,7 +245,10 @@ 4 | building_exe = target_desc == CCompiler.EXECUTABLE 5 | linker = (self.linker_exe if building_exe else self.linker_so)[:] 6 | 7 | - if target_lang == "c++" and self.compiler_cxx: 8 | + # For python-wasm the following completely messes up our 9 | + # use of wasm-ld; just using "zig cc" turns out to work fine 10 | + # with C++ code. 11 | + if False and target_lang == "c++" and self.compiler_cxx: 12 | env, linker_ne = _split_env(linker) 13 | aix, linker_na = _split_aix(linker_ne) 14 | _, compiler_cxx_ne = _split_env(self.compiler_cxx) 15 | -------------------------------------------------------------------------------- /python/cpython/src/patches/13-socket-unmodified-headers.patch: -------------------------------------------------------------------------------- 1 | --- native/Modules/socketmodule.h 2022-09-11 12:23:30.000000000 -0700 2 | +++ wasm/Modules/socketmodule.h 2022-09-24 08:45:59.000000000 -0700 3 | @@ -2,6 +2,8 @@ 4 | 5 | /* Includes needed for the sockaddr_* symbols below */ 6 | #ifndef MS_WINDOWS 7 | + 8 | +#define __wasilibc_unmodified_upstream 1 9 | #ifdef __VMS 10 | # include 11 | # else 12 | @@ -9,6 +11,7 @@ 13 | # endif 14 | # include 15 | # include 16 | +#undef __wasilibc_unmodified_upstream 17 | 18 | #else /* MS_WINDOWS */ 19 | # include 20 | -------------------------------------------------------------------------------- /python/cpython/src/patches/14-threading-warning.patch: -------------------------------------------------------------------------------- 1 | --- native/Lib/threading.py 2022-10-24 10:35:39 2 | +++ wasm/Lib/threading.py 2022-11-15 09:41:01 3 | @@ -945,6 +945,13 @@ 4 | same thread object. 5 | 6 | """ 7 | + # CoWasm -- if somehow something tries to actually start a thread, we just 8 | + # don't. CoWasm has no support for threads, but Python packages 9 | + # such as pip just assume it does. E.g., pip's progress bar uses threading, 10 | + # and showing this message is better than crashing pip. 11 | + print("(WARNING: threading is not supported)") 12 | + return 13 | + 14 | if not self._initialized: 15 | raise RuntimeError("thread.__init__() not called") 16 | 17 | @@ -1101,6 +1108,8 @@ 18 | exception. 19 | 20 | """ 21 | + # CoWasm: we're making the thread a no-op, so it's done. 22 | + return 23 | if not self._initialized: 24 | raise RuntimeError("Thread.__init__() not called") 25 | if not self._started.is_set(): 26 | -------------------------------------------------------------------------------- /python/cpython/src/patches/15-pip-no-mmap.patch: -------------------------------------------------------------------------------- 1 | --- native/lib/python3.11/site-packages/pip/_vendor/cachecontrol/filewrapper.py 2022-11-15 00:45:19 2 | +++ wasm/lib/python3.11/site-packages/pip/_vendor/cachecontrol/filewrapper.py 2022-11-15 13:11:56 3 | @@ -70,6 +70,7 @@ 4 | # a view directly into the filesystem's memory cache, so it 5 | # doesn't result in duplicate memory use. 6 | self.__buf.seek(0, 0) 7 | + return self.__buf.read() 8 | result = memoryview( 9 | mmap.mmap(self.__buf.fileno(), 0, access=mmap.ACCESS_READ) 10 | ) 11 | -------------------------------------------------------------------------------- /python/cpython/src/patches/16-pip-no-auto-refresh-progress.patch: -------------------------------------------------------------------------------- 1 | --- native/lib/python3.11/site-packages/pip/_vendor/rich/live.py 2022-11-15 00:45:19 2 | +++ wasm/lib/python3.11/site-packages/pip/_vendor/rich/live.py 2022-11-15 13:16:15 3 | @@ -127,7 +127,8 @@ 4 | # let this be displayed in the terminal). 5 | self.stop() 6 | raise 7 | - if self.auto_refresh: 8 | + # COWASM: We hard disable this since threads are not supported yet and it used pthreads. 9 | + if False and self.auto_refresh: 10 | self._refresh_thread = _RefreshThread(self, self.refresh_per_second) 11 | self._refresh_thread.start() 12 | 13 | -------------------------------------------------------------------------------- /python/cpython/src/patches/17-fix-sysconfigdata.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | # (this gets appended; not a patch) 4 | 5 | # Make this work for building even when the install is moved. 6 | import sys 7 | prefix = build_time_vars['prefix'] 8 | for key, val in build_time_vars.items(): 9 | if isinstance(val, str): 10 | build_time_vars[key] = val.replace(prefix, sys.prefix) 11 | 12 | 13 | -------------------------------------------------------------------------------- /python/cpython/src/patches/README.md: -------------------------------------------------------------------------------- 1 | Patches... Hopefully very little, and anything here obviously we want to get rid 2 | of or upstream in python. -------------------------------------------------------------------------------- /python/cpython/src/rebuild: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # Run this inside build/wasm/ to rebuild. This is 3 | # useful if you want to modify the cpython source code to understand what 4 | # is going on. E.g., put printf's all over the place, type ./rebuild, 5 | # and in a few seconds you are using python-wasm with those changes applied! 6 | # **TODO** for some reason when make fails the build doesn't stop, so for 7 | # now you MUST carefully watch the build for errors. 8 | 9 | echo "Rebuild" 10 | set -ev 11 | SCRIPTDIR=$(dirname $(readlink -f "$0")) 12 | cd "$SCRIPTDIR"/.. 13 | rm -f `pwd`/dist/wasm/.install-cpython 14 | make `pwd`/dist/wasm/.install-cpython 15 | #make python-wasm 16 | make wasm -------------------------------------------------------------------------------- /python/cpython/src/sitecustomize.py: -------------------------------------------------------------------------------- 1 | # Install our custom import hook, which imports tar.xz bundles with so in them. 2 | try: 3 | import cowasm_importer 4 | cowasm_importer.init() 5 | except ModuleNotFoundError: 6 | # python-wasm sometimes is started during the build process before cowasm_importer 7 | # is installed. That's the one case where this is safe to silently ignore. 8 | pass 9 | 10 | # Revert strange change to Python: https://discuss.python.org/t/int-str-conversions-broken-in-latest-python-bugfix-releases/18889 11 | # This was a (potential) security issue for webservers, which isn't relevant for python-wasm. 12 | import sys 13 | 14 | sys.set_int_max_str_digits(0) 15 | 16 | # This is very convenient in the context of WASM, where security constraints are different. 17 | sys.path.append('.') 18 | -------------------------------------------------------------------------------- /python/cpython/src/xgcd.py: -------------------------------------------------------------------------------- 1 | # A standard xgcd implementation for Python copied from a random webpage. 2 | # This of course quickly overflows with Javascript "integers" = doubles' 3 | def xgcd(a, b): 4 | prevx, x = 1, 0 5 | prevy, y = 0, 1 6 | while b: 7 | q, r = divmod(a, b) 8 | x, prevx = prevx - q * x, x 9 | y, prevy = prevy - q * y, y 10 | a, b = b, r 11 | return a, prevx, prevy 12 | 13 | 14 | def bench_xgcd(n=10**6): 15 | from time import time 16 | t = time() 17 | s = 0 18 | for i in range(n): 19 | s += xgcd(92250 - i, 922350 + i)[0] 20 | print(s, time() - t) 21 | 22 | 23 | def inverse_mod(a, N): 24 | """ 25 | Compute multiplicative inverse of a modulo N. 26 | """ 27 | if a == 1 or N <= 1: # common special cases 28 | return a % N 29 | [g, s, _] = xgcd(a, N) 30 | if g != 1: 31 | raise ZeroDivisionError 32 | b = s % N 33 | if b < 0: 34 | b += N 35 | return b 36 | 37 | 38 | if __name__ == "__main__": 39 | print("inverse_mod(7,15) = ", inverse_mod(7,15)) 40 | bench_xgcd() -------------------------------------------------------------------------------- /python/libedit-native/Makefile: -------------------------------------------------------------------------------- 1 | 2 | include ../build/Makefile-vars 3 | 4 | all: native 5 | 6 | VERSION = 20210910-3.1 7 | TARBALL = ${UPSTREAM}/libedit-${VERSION}.tar.gz 8 | URL = https://www.thrysoee.dk/editline/libedit-${VERSION}.tar.gz 9 | 10 | include ../build/Makefile-rules 11 | 12 | # See https://www.thrysoee.dk/editline/ 13 | 14 | TERMCAP_NATIVE = ${PACKAGES}/termcap-native/dist/native 15 | 16 | ################## 17 | # NATIVE 18 | ################## 19 | 20 | ${DIST_NATIVE}/.built: ${BUILD_NATIVE}/.build 21 | cd ../build && make zig 22 | cd ../termcap-native && make native 23 | cd ${BUILD_NATIVE} && \ 24 | CFLAGS="-I${TERMCAP_NATIVE}/include -L${TERMCAP_NATIVE}/lib" \ 25 | CC="zig cc -Oz ${ZIG_NATIVE_CFLAGS_GNU} " \ 26 | AR="zig ar" \ 27 | ./configure --prefix=${DIST_NATIVE} 28 | cd ${BUILD_NATIVE} && make -j8 29 | cd ${BUILD_NATIVE} && make install 30 | touch ${DIST_NATIVE}/.built 31 | 32 | test: ${DIST_NATIVE}/.built 33 | echo "no test" -------------------------------------------------------------------------------- /python/lzma-native/Makefile: -------------------------------------------------------------------------------- 1 | include ../build/Makefile-vars 2 | 3 | all: native 4 | 5 | # LZMA doesn't change, but I didn't want to force git clone, so I made 6 | # a fork and a release myself. 7 | 8 | VERSION = 1.1 9 | URL = https://github.com/sagemathinc/lzma/archive/refs/tags/v${VERSION}.tar.gz 10 | TARBALL = ${UPSTREAM}/lzma-v${VERSION}.tar.gz 11 | 12 | include ../build/Makefile-rules 13 | 14 | ${DIST_NATIVE}/.built: ${BUILD_NATIVE}/.build 15 | cd ../build && make zig 16 | cd ${BUILD_NATIVE} && \ 17 | RANLIB="zig ranlib" \ 18 | AR="zig ar" \ 19 | CC="zig cc ${ZIG_NATIVE_CFLAGS}" \ 20 | CXX="zig c++ ${ZIG_NATIVE_CFLAGS}" \ 21 | ./configure \ 22 | --build=`./build-aux/config.guess` \ 23 | --host=none --prefix="${DIST_NATIVE}" 24 | cd ${BUILD_NATIVE} && make -j4 && make install 25 | touch ${DIST_NATIVE}/.built 26 | 27 | test: ${DIST_NATIVE}/.built 28 | echo "no test" -------------------------------------------------------------------------------- /python/py-cython/README.md: -------------------------------------------------------------------------------- 1 | # WebAssembly build of the Cython Python library 2 | -------------------------------------------------------------------------------- /python/py-cython/bin/cython: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # The cython.py script imports import Cython.Compiler.Main, which 4 | # imports the same script cython.py that we run below, which is not 5 | # even in the Cython module. That's really weird and backwards, in my opinion. 6 | # That's why setting PYTHONPATH is so important here, since otherwise 7 | # that second import of cython.py would fail. 8 | export SCRIPTPATH="$( cd -- "$(dirname "`readlink -f $0`")" >/dev/null 2>&1 ; pwd -P )" 9 | export PYTHONPATH="$SCRIPTPATH"/../dist/wasm/ 10 | 11 | `dirname $0`/python-wasm "$PYTHONPATH"/cython.py "$@" -------------------------------------------------------------------------------- /python/py-cython/index.js: -------------------------------------------------------------------------------- 1 | const { join } = require("path"); 2 | exports.path = join(__dirname, "dist", "wasm"); 3 | -------------------------------------------------------------------------------- /python/py-cython/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@cowasm/py-cython", 3 | "version": "1.1.0", 4 | "description": "WebAssembly build of the cython python library", 5 | "main": "index.js", 6 | "files": [ 7 | "dist/wasm/**", 8 | "README.md", 9 | "package.json", 10 | "index.js" 11 | ], 12 | "scripts": { 13 | "preinstall": "npx only-allow pnpm", 14 | "build": "make wasm", 15 | "prepublishOnly": "pnpm run build && make test", 16 | "test": "make test" 17 | }, 18 | "repository": { 19 | "type": "git", 20 | "url": "git+ssh://git@github.com/sagemathinc/cowasm.git" 21 | }, 22 | "keywords": [ 23 | "WebAssembly", 24 | "wasm" 25 | ], 26 | "author": "William Stein ", 27 | "license": "BSD-3-Clause", 28 | "bugs": { 29 | "url": "https://github.com/sagemathinc/cowasm/issues" 30 | }, 31 | "homepage": "https://github.com/sagemathinc/cowasm/tree/main/python/py-cython", 32 | "devDependencies": { 33 | "@cowasm/cpython": "workspace:*", 34 | "@cowasm/kernel": "workspace:*", 35 | "@cowasm/py-pip": "workspace:*" 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /python/py-matplotlib/Makefile: -------------------------------------------------------------------------------- 1 | ## 2 | # This does not work at all yet. 3 | ## 4 | 5 | include ../build/Makefile-vars 6 | 7 | # https://github.com/matplotlib/matplotlib/releases 8 | VERSION=3.6.2 9 | 10 | 11 | URL = https://github.com/matplotlib/matplotlib/archive/refs/tags/v${VERSION}.tar.gz 12 | 13 | TARBALL = ${UPSTREAM}/matplotlib-${VERSION}.tar.gz 14 | 15 | #all: deps wasm 16 | all: 17 | 18 | include ../build/Makefile-rules 19 | 20 | ${BUILD_WASM}/.patched: ${BUILD_WASM}/.build 21 | touch ${BUILD_WASM}/.patched 22 | 23 | ${BUILD_WASM}/.install: ${BUILD_WASM}/.patched 24 | cd ${BUILD_WASM} \ 25 | && PYTHONPATH=${PIP} pnpm-exec cpython setup.py build 26 | touch ${BUILD_WASM}/.install 27 | 28 | ${DIST_WASM}/.built: ${BUILD_WASM}/.install 29 | rm -rf ${DIST_WASM} && mkdir -p ${DIST_WASM} 30 | touch ${DIST_WASM}/.built 31 | 32 | #test: ${DIST_WASM}/.built 33 | # echo "It built!" 34 | 35 | test: 36 | echo "matplotlib not done at all" -------------------------------------------------------------------------------- /python/py-matplotlib/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@cowasm/py-matplotlib", 3 | "version": "1.0.0", 4 | "description": "WebAssembly build of the matplotlib python library", 5 | "main": "index.js", 6 | "files": [ 7 | "dist/wasm/**", 8 | "README.md", 9 | "package.json", 10 | "index.js" 11 | ], 12 | "scripts": { 13 | "preinstall": "npx only-allow pnpm", 14 | "build": "make wasm", 15 | "prepublishOnly": "pnpm run build && make test", 16 | "test": "make test" 17 | }, 18 | "repository": { 19 | "type": "git", 20 | "url": "git+ssh://git@github.com/sagemathinc/cowasm.git" 21 | }, 22 | "keywords": [ 23 | "WebAssembly", 24 | "wasm" 25 | ], 26 | "author": "William Stein ", 27 | "license": "BSD-3-Clause", 28 | "bugs": { 29 | "url": "https://github.com/sagemathinc/cowasm/issues" 30 | }, 31 | "homepage": "https://github.com/sagemathinc/cowasm/tree/main/python/py-matplotlib", 32 | "devDependencies": { 33 | "@cowasm/cpython": "workspace:*", 34 | "@cowasm/kernel": "workspace:*", 35 | "@cowasm/py-pip": "workspace:*" 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /python/py-mpmath/README.md: -------------------------------------------------------------------------------- 1 | # WebAssembly build of the mpmath python library 2 | -------------------------------------------------------------------------------- /python/py-mpmath/index.js: -------------------------------------------------------------------------------- 1 | const { join } = require("path"); 2 | exports.path = join(__dirname, "dist", "wasm"); 3 | -------------------------------------------------------------------------------- /python/py-mpmath/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@cowasm/py-mpmath", 3 | "version": "1.0.0", 4 | "description": "WebAssembly build of the mpmath python library", 5 | "main": "index.js", 6 | "files": ["dist/wasm/**", "README.md", "package.json", "index.js"], 7 | "scripts": { 8 | "preinstall": "npx only-allow pnpm", 9 | "build": "make wasm", 10 | "prepublishOnly": "pnpm run build && make test", 11 | "test": "make test" 12 | }, 13 | "repository": { 14 | "type": "git", 15 | "url": "git+ssh://git@github.com/sagemathinc/cowasm.git" 16 | }, 17 | "keywords": ["WebAssembly", "wasm"], 18 | "author": "William Stein ", 19 | "license": "BSD-3-Clause", 20 | "bugs": { 21 | "url": "https://github.com/sagemathinc/cowasm/issues" 22 | }, 23 | "homepage": "https://github.com/sagemathinc/cowasm/tree/main/python/py-mpmath", 24 | "devDependencies": { 25 | "@cowasm/cpython": "workspace:*", 26 | "@cowasm/kernel": "workspace:*", 27 | "@cowasm/py-pip": "workspace:*" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /python/py-numpy/README.md: -------------------------------------------------------------------------------- 1 | # WebAssembly build of the NumPy Python library 2 | 3 | Upstream NumPy: https://numpy.org/ 4 | 5 | This is part of CoWasm: https://cowasm.org 6 | 7 | -------------------------------------------------------------------------------- /python/py-numpy/index.js: -------------------------------------------------------------------------------- 1 | const { join } = require("path"); 2 | exports.path = join(__dirname, "dist", "wasm"); 3 | -------------------------------------------------------------------------------- /python/py-numpy/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@cowasm/py-numpy", 3 | "version": "1.1.0", 4 | "description": "WebAssembly build of the NumPy Python library", 5 | "main": "index.js", 6 | "files": [ 7 | "dist/wasm/**", 8 | "README.md", 9 | "package.json", 10 | "index.js" 11 | ], 12 | "scripts": { 13 | "preinstall": "npx only-allow pnpm", 14 | "build": "make wasm", 15 | "prepublishOnly": "pnpm run build && make test", 16 | "test": "make test" 17 | }, 18 | "repository": { 19 | "type": "git", 20 | "url": "git+ssh://git@github.com/sagemathinc/cowasm.git" 21 | }, 22 | "keywords": [ 23 | "WebAssembly", 24 | "wasm" 25 | ], 26 | "author": "William Stein ", 27 | "license": "BSD-3-Clause", 28 | "bugs": { 29 | "url": "https://github.com/sagemathinc/cowasm/issues" 30 | }, 31 | "homepage": "https://github.com/sagemathinc/cowasm/tree/main/python/py-numpy", 32 | "devDependencies": { 33 | "@cowasm/cpython": "workspace:*", 34 | "@cowasm/py-cython": "workspace:*", 35 | "@cowasm/py-pip": "workspace:*", 36 | "@cowasm/kernel": "workspace:*" 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /python/py-numpy/src/fake-bin/gcc: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | zig cc -target wasm32-wasi "$@" -------------------------------------------------------------------------------- /python/py-numpy/src/patches/02-cxx_compiler.patch: -------------------------------------------------------------------------------- 1 | --- native/numpy/distutils/command/build_ext.py 2022-09-09 06:36:30.000000000 -0700 2 | +++ wasm/numpy/distutils/command/build_ext.py 2022-09-19 20:32:04.000000000 -0700 3 | @@ -510,6 +510,11 @@ 4 | **kws) 5 | if cxx_sources: 6 | log.info("compiling C++ sources") 7 | + # python-wasm: the heuristics that numpy uses to 8 | + # convert the c compiler to a c++ compiler don't work 9 | + # for us since we use "cowasm-cc", so we manually 10 | + # make the change here: 11 | + cxx_compiler.compiler_so[1] = 'c++' 12 | c_objects += cxx_compiler.compile( 13 | cxx_sources, 14 | output_dir=output_dir, 15 | -------------------------------------------------------------------------------- /python/py-numpy/src/patches/03-disable-complex.patch: -------------------------------------------------------------------------------- 1 | --- native/numpy/core/setup.py 2022-12-25 19:52:52 2 | +++ wasm/numpy/core/setup.py 2023-02-03 08:17:04 3 | @@ -262,6 +262,7 @@ 4 | 5 | # Check for complex support 6 | st = config.check_header('complex.h') 7 | + st = False 8 | if st: 9 | priv.append(('HAVE_COMPLEX_H', 1)) 10 | pub.append(('NPY_USE_C99_COMPLEX', 1)) 11 | -------------------------------------------------------------------------------- /python/py-numpy/src/patches/05-no-backtrace.patch: -------------------------------------------------------------------------------- 1 | --- native/numpy/core/setup_common.py 2022-09-09 06:36:30.443449000 -0700 2 | +++ wasm/numpy/core/setup_common.py 2022-09-23 17:24:28.115837013 -0700 3 | @@ -131,7 +131,14 @@ 4 | 5 | OPTIONAL_LOCALE_FUNCS = ["strtold_l"] 6 | OPTIONAL_FILE_FUNCS = ["ftello", "fseeko", "fallocate"] 7 | -OPTIONAL_MISC_FUNCS = ["backtrace", "madvise"] 8 | + 9 | +# On WASM the feature detection for backtrace doesn't work properly, 10 | +# and I don't know any way to disable this via a command line flag, 11 | +# so we change code here to not even look for backtrace. This is needed 12 | +# with clang15 just to compile, since backtrace isn't declared. Of course, 13 | +# WASM can't possible provide backtraces, as that violates their security 14 | +# model, so it's best to not build C code that thinks this is available. 15 | +OPTIONAL_MISC_FUNCS = ["madvise"] # ["backtrace", "madvise"] 16 | 17 | 18 | OPTIONAL_HEADERS = [ 19 | -------------------------------------------------------------------------------- /python/py-numpy/src/patches/06-setup-setuptools.patch: -------------------------------------------------------------------------------- 1 | --- native/setup.py 2022-12-25 19:52:53 2 | +++ wasm/setup.py 2023-02-03 08:21:35 3 | @@ -1,8 +1,13 @@ 4 | #!/usr/bin/env python3 5 | """ 6 | -Numpy build options can be modified with a site.cfg file. 7 | +Numpy build options can be modified with a site.cfg file. 8 | See site.cfg.example for a template and more information. 9 | """ 10 | + 11 | +# COWASM -- we explicitly import setuptools first before anything else. There's 12 | +# a huge warning at startup if we don't do this, and then distutils gets messed up 13 | +# with weird C++ compiler issues, etc. This conflicts with the comments below... but works? 14 | +import setuptools 15 | 16 | import os 17 | from pathlib import Path 18 | -------------------------------------------------------------------------------- /python/py-pandas/README.md: -------------------------------------------------------------------------------- 1 | # WebAssembly build of the Pandas Python library 2 | 3 | Upstream Pandas: https://pandas.pydata.org/ 4 | 5 | This is part of CoWasm: https://cowasm.org 6 | 7 | **STATUS:** This is an incomplete build. It's not suitable for trusted general 8 | use yet. -------------------------------------------------------------------------------- /python/py-pandas/index.js: -------------------------------------------------------------------------------- 1 | const { join } = require("path"); 2 | exports.path = join(__dirname, "dist", "wasm"); 3 | -------------------------------------------------------------------------------- /python/py-pip/README.md: -------------------------------------------------------------------------------- 1 | # Pip python library (for webassembly python) 2 | -------------------------------------------------------------------------------- /python/py-pip/index.js: -------------------------------------------------------------------------------- 1 | const { join } = require("path"); 2 | exports.path = join(__dirname, "dist", "wasm"); 3 | -------------------------------------------------------------------------------- /python/py-pip/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@cowasm/py-pip", 3 | "version": "1.1.4", 4 | "description": "WebAssembly Python pip package", 5 | "main": "index.js", 6 | "files": ["dist/wasm/**", "README.md", "package.json", "index.js"], 7 | "scripts": { 8 | "preinstall": "npx only-allow pnpm", 9 | "build": "make wasm", 10 | "prepublishOnly": "pnpm run build && make test", 11 | "test": "make test" 12 | }, 13 | "repository": { 14 | "type": "git", 15 | "url": "git+ssh://git@github.com/sagemathinc/cowasm.git" 16 | }, 17 | "keywords": ["WebAssembly", "wasm"], 18 | "author": "William Stein ", 19 | "license": "BSD-3-Clause", 20 | "bugs": { 21 | "url": "https://github.com/sagemathinc/cowasm/issues" 22 | }, 23 | "homepage": "https://github.com/sagemathinc/cowasm/tree/main/python/py-pip", 24 | "devDependencies": { 25 | "@cowasm/cpython": "workspace:*", 26 | "@cowasm/kernel": "workspace:*", 27 | "@cowasm/py-setuptools": "workspace:*" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /python/py-pip/src/patches/01-pip-no-mmap.patch: -------------------------------------------------------------------------------- 1 | --- native/src/pip/_vendor/cachecontrol/filewrapper.py 2022-11-30 22:08:59 2 | +++ wasm/src/pip/_vendor/cachecontrol/filewrapper.py 2022-11-30 22:10:05 3 | @@ -69,6 +69,10 @@ 4 | # relying on Python's buffer API and mmap(). mmap() just gives 5 | # a view directly into the filesystem's memory cache, so it 6 | # doesn't result in duplicate memory use. 7 | + 8 | + # CoWasm: Temporary hack to avoid using mmap. 9 | + return self.__buf.read() 10 | + 11 | self.__buf.seek(0, 0) 12 | result = memoryview( 13 | mmap.mmap(self.__buf.fileno(), 0, access=mmap.ACCESS_READ) 14 | -------------------------------------------------------------------------------- /python/py-pip/src/patches/02-pip-no-auto-refresh-progress.patch: -------------------------------------------------------------------------------- 1 | --- native/src/pip/_vendor/rich/live.py 2022-11-30 22:08:59 2 | +++ wasm/src/pip/_vendor/rich/live.py 2022-11-30 22:11:29 3 | @@ -127,7 +127,8 @@ 4 | # let this be displayed in the terminal). 5 | self.stop() 6 | raise 7 | - if self.auto_refresh: 8 | + # COWASM: We hard disable this since threads are not supported yet and it used pthreads. 9 | + if False and self.auto_refresh: 10 | self._refresh_thread = _RefreshThread(self, self.refresh_per_second) 11 | self._refresh_thread.start() 12 | 13 | -------------------------------------------------------------------------------- /python/py-setuptools/README.md: -------------------------------------------------------------------------------- 1 | # Setuptools python library (for webassembly python) 2 | -------------------------------------------------------------------------------- /python/py-setuptools/index.js: -------------------------------------------------------------------------------- 1 | const { join } = require("path"); 2 | exports.path = join(__dirname, "dist", "wasm"); 3 | -------------------------------------------------------------------------------- /python/py-setuptools/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@cowasm/py-setuptools", 3 | "version": "1.2.2", 4 | "description": "WebAssembly Python setuptools package", 5 | "main": "index.js", 6 | "files": ["dist/wasm/**", "README.md", "package.json", "index.js"], 7 | "scripts": { 8 | "preinstall": "npx only-allow pnpm", 9 | "build": "make wasm", 10 | "prepublishOnly": "pnpm run build && make test", 11 | "test": "make test" 12 | }, 13 | "repository": { 14 | "type": "git", 15 | "url": "git+ssh://git@github.com/sagemathinc/cowasm.git" 16 | }, 17 | "keywords": ["WebAssembly", "wasm"], 18 | "author": "William Stein ", 19 | "license": "BSD-3-Clause", 20 | "bugs": { 21 | "url": "https://github.com/sagemathinc/cowasm/issues" 22 | }, 23 | "homepage": "https://github.com/sagemathinc/cowasm/tree/main/python/py-setuptools", 24 | "devDependencies": { 25 | "@cowasm/kernel": "workspace:*", 26 | "@cowasm/cpython": "workspace:*" 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /python/py-setuptools/src/patches/01-c++.patch: -------------------------------------------------------------------------------- 1 | --- native/setuptools/_distutils/unixccompiler.py 2022-11-30 22:02:14 2 | +++ wasm/setuptools/_distutils/unixccompiler.py 2022-11-30 22:02:54 3 | @@ -253,7 +253,10 @@ 4 | building_exe = target_desc == CCompiler.EXECUTABLE 5 | linker = (self.linker_exe if building_exe else self.linker_so)[:] 6 | 7 | - if target_lang == "c++" and self.compiler_cxx: 8 | + # For python-wasm the following completely messes up our 9 | + # use of wasm-ld; just using "zig cc" turns out to work fine 10 | + # with C++ code. 11 | + if False and target_lang == "c++" and self.compiler_cxx: 12 | env, linker_ne = _split_env(linker) 13 | aix, linker_na = _split_aix(linker_ne) 14 | _, compiler_cxx_ne = _split_env(self.compiler_cxx) 15 | -------------------------------------------------------------------------------- /python/py-sympy/README.md: -------------------------------------------------------------------------------- 1 | # WebAssembly build of the sympy python library 2 | -------------------------------------------------------------------------------- /python/py-sympy/index.js: -------------------------------------------------------------------------------- 1 | const { join } = require("path"); 2 | exports.path = join(__dirname, "dist", "wasm"); 3 | -------------------------------------------------------------------------------- /python/py-sympy/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@cowasm/py-sympy", 3 | "version": "1.0.0", 4 | "description": "WebAssembly build of the SymPy python library", 5 | "main": "index.js", 6 | "files": ["dist/wasm/**", "README.md", "package.json", "index.js"], 7 | "scripts": { 8 | "preinstall": "npx only-allow pnpm", 9 | "build": "make wasm", 10 | "prepublishOnly": "pnpm run build && make test", 11 | "test": "make test" 12 | }, 13 | "repository": { 14 | "type": "git", 15 | "url": "git+ssh://git@github.com/sagemathinc/cowasm.git" 16 | }, 17 | "keywords": ["WebAssembly", "wasm"], 18 | "author": "William Stein ", 19 | "license": "BSD-3-Clause", 20 | "bugs": { 21 | "url": "https://github.com/sagemathinc/cowasm/issues" 22 | }, 23 | "homepage": "https://github.com/sagemathinc/cowasm/tree/main/python/py-sympy", 24 | "devDependencies": { 25 | "@cowasm/cpython": "workspace:*", 26 | "@cowasm/py-mpmath": "workspace:*", 27 | "@cowasm/kernel": "workspace:*", 28 | "@cowasm/py-setuptools": "workspace:*" 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /python/py-sympy/src/__pycache__/test_basic.cpython-311.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sagemathinc/cowasm/3f8f231f96f330f80140de4d1350553caa5e6960/python/py-sympy/src/__pycache__/test_basic.cpython-311.pyc -------------------------------------------------------------------------------- /python/pylang/CONTRIBUTORS.md: -------------------------------------------------------------------------------- 1 | ## Main Developers 2 | 3 | William Stein (SageMath, Inc.) 4 | 5 | ## Other Contributors 6 | 7 | See https://github.com/sagemathinc/pylang/graphs/contributors 8 | 9 | Also, people from the past projects this was forked from: 10 | 11 | - Kovid Goyal (main developer of RapydScript-ng) 12 | - Alexander Tsepkov (main developer of the original RapydScript) 13 | - Charles Law 14 | - Tobias Weber 15 | - Salvatore Di Dio 16 | - Tuomas Laakkonen 17 | -------------------------------------------------------------------------------- /python/pylang/Makefile: -------------------------------------------------------------------------------- 1 | CWD = $(shell dirname $(realpath $(firstword $(MAKEFILE_LIST)))) 2 | DIST = ${CWD}/dist 3 | 4 | all: dist 5 | 6 | node_modules: 7 | pnpm install 8 | 9 | dist: node_modules 10 | pnpm run build 11 | 12 | .PHONY: test 13 | test: dist 14 | pnpm run test 15 | 16 | clean: 17 | rm -rf ${DIST} node_modules 18 | -------------------------------------------------------------------------------- /python/pylang/src/baselib/errors.py: -------------------------------------------------------------------------------- 1 | # vim:fileencoding=utf-8 2 | # License: BSD 3 | # Copyright: 2015, Kovid Goyal 4 | # globals: ρσ_str 5 | 6 | NameError = ReferenceError 7 | 8 | class Exception(Error): 9 | 10 | def __init__(self, message): 11 | self.message = message 12 | self.stack = Error().stack 13 | self.name = self.constructor.name 14 | 15 | def __repr__(self): 16 | return self.name + ': ' + self.message 17 | 18 | class AttributeError(Exception): 19 | pass 20 | 21 | class IndexError(Exception): 22 | pass 23 | 24 | class KeyError(Exception): 25 | pass 26 | 27 | class ValueError(Exception): 28 | pass 29 | 30 | class UnicodeDecodeError(Exception): 31 | pass 32 | 33 | class AssertionError(Exception): 34 | pass 35 | 36 | class ZeroDivisionError(Exception): 37 | pass 38 | -------------------------------------------------------------------------------- /python/pylang/src/lib/js.py: -------------------------------------------------------------------------------- 1 | # Code that is NOT written in valid Python syntax, but can 2 | # be used from valid python code to accomplish various things 3 | # that are needed. 4 | 5 | # This gives us the new operator as a Python function call: 6 | def js_new(f, *args, **kwds): 7 | return new f(*args, **kwds) 8 | 9 | def js_instanceof(obj, cls): 10 | return r"%js obj instanceof cls" -------------------------------------------------------------------------------- /python/pylang/src/lib/operator.py: -------------------------------------------------------------------------------- 1 | add = __add__ = def(x, y): return x + y 2 | sub = __sub__ = def(x, y): return x - y 3 | mul = __mul__ = def(x, y): return x * y 4 | div = __div__ = def(x, y): return x / y 5 | 6 | lt = __lt__ = def(x, y): return x < y 7 | le = __le__ = def(x, y): return x <= y 8 | eq = __eq__ = def(x, y): return x is y 9 | ne = __ne__ = def(x, y): return x is not y 10 | ge = __ge__ = def(x, y): return x >= y 11 | gt = __gt__ = def(x, y): return x > y 12 | -------------------------------------------------------------------------------- /python/pylang/src/lib/pythonize.py: -------------------------------------------------------------------------------- 1 | # vim:fileencoding=utf-8 2 | # License: BSD Copyright: 2016, Kovid Goyal 3 | # globals: ρσ_str 4 | 5 | 6 | def strings(): 7 | string_funcs = set(( 8 | 'capitalize strip lstrip rstrip islower isupper isspace lower upper swapcase' 9 | ' center count endswith startswith find rfind index rindex format join ljust rjust' 10 | ' partition rpartition replace split rsplit splitlines zfill' 11 | ).split(' ')) 12 | 13 | if not arguments.length: 14 | exclude = {'split', 'replace'} 15 | elif arguments[0]: 16 | exclude = Array.prototype.slice.call(arguments) 17 | else: 18 | exclude = None 19 | if exclude: 20 | string_funcs = string_funcs.difference(set(exclude)) 21 | for name in string_funcs: 22 | String.prototype[name] = ρσ_str.prototype[name] 23 | -------------------------------------------------------------------------------- /python/pylang/src/lib/sys.py: -------------------------------------------------------------------------------- 1 | # Placeholder for now -- nothing implemented 2 | 3 | def exit(status=None): 4 | if status is None: 5 | status = 0 6 | elif not isinstance(status, int): 7 | print(status) 8 | status = 1 9 | process.exit(status) 10 | 11 | argv = process.argv -------------------------------------------------------------------------------- /python/pylang/src/output/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sagemathinc/cowasm/3f8f231f96f330f80140de4d1350553caa5e6960/python/pylang/src/output/__init__.py -------------------------------------------------------------------------------- /python/pylang/test/_import_one.py: -------------------------------------------------------------------------------- 1 | # vim:fileencoding=utf-8 2 | nonlocal GLOBAL_SYMBOL 3 | 4 | 'Module level ds1' 5 | 6 | 7 | def toplevel_func(a): 8 | return a + 'toplevel' 9 | 10 | 11 | ''' 12 | Module level ds2 13 | line2 14 | ''' 15 | 16 | 17 | class TopLevel: 18 | def __init__(self, a): 19 | self.a = a 20 | 21 | 22 | 'Module level ds 3' 23 | 24 | 25 | class AClass(TopLevel): 26 | def __init__(self, a): 27 | self.a = a 28 | 29 | 30 | toplevel_var = 'foo' 31 | 32 | if True: 33 | true_var = 'true' 34 | else: 35 | false_var = 'false' 36 | 37 | GLOBAL_SYMBOL = 'i am global' 38 | 39 | from _import_two.other import other 40 | 41 | test_other = other 42 | -------------------------------------------------------------------------------- /python/pylang/test/_import_two/__init__.py: -------------------------------------------------------------------------------- 1 | # vim:fileencoding=utf-8 2 | 3 | 4 | def toplevel_func2(a): 5 | return a + 'toplevel2' 6 | 7 | 8 | class TopLevel2: 9 | def __init__(self, a): 10 | self.a = a 11 | 12 | 13 | toplevel_var2 = 'foo2' 14 | -------------------------------------------------------------------------------- /python/pylang/test/_import_two/level2/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sagemathinc/cowasm/3f8f231f96f330f80140de4d1350553caa5e6960/python/pylang/test/_import_two/level2/__init__.py -------------------------------------------------------------------------------- /python/pylang/test/_import_two/level2/deep.py: -------------------------------------------------------------------------------- 1 | # vim:fileencoding=utf-8 2 | # License: BSD Copyright: 2016, Kovid Goyal 3 | 4 | deep_var = 'deep' 5 | -------------------------------------------------------------------------------- /python/pylang/test/_import_two/other.py: -------------------------------------------------------------------------------- 1 | # vim:fileencoding=utf-8 2 | # License: BSD 3 | # Copyright: 2015, Kovid Goyal 4 | 5 | other = 'other' 6 | -------------------------------------------------------------------------------- /python/pylang/test/_import_two/sub.py: -------------------------------------------------------------------------------- 1 | # vim:fileencoding=utf-8 2 | # License: BSD 3 | # Copyright: 2015, Kovid Goyal 4 | 5 | sub_var = 'sub' 6 | 7 | 8 | def sub_func(): 9 | return sub_var 10 | 11 | 12 | class Sub: 13 | def __init__(self, a): 14 | self.a = a 15 | -------------------------------------------------------------------------------- /python/pylang/test/docstrings.py: -------------------------------------------------------------------------------- 1 | # vim:fileencoding=utf-8 2 | # License: BSD Copyright: 2016, Kovid Goyal 3 | # globals: ρσ_module_doc__ 4 | 5 | import _import_one 6 | 7 | def f(): 8 | " A basic docstring " 9 | pass 10 | 11 | assrt.equal(f.__doc__, 'A basic docstring') 12 | assrt.equal(_import_one.__doc__, 'Module level ds1\n\nModule level ds2\nline2\n\nModule level ds 3') 13 | 14 | def g(): 15 | ''' 16 | A more complex docstring: 17 | xxx 18 | yyyy 19 | 20 | the end 21 | ''' 22 | pass 23 | 24 | assrt.equal(g.__doc__, 'A more complex docstring:\n xxx\n yyyy\n\nthe end') 25 | 26 | class D: 27 | ' Docstring for a class ' 28 | 29 | def method(self): 30 | 'ds for a method' 31 | pass 32 | 33 | assrt.equal(D().__doc__, 'Docstring for a class') 34 | assrt.equal(D().method.__doc__, 'ds for a method') 35 | 36 | x = def(): 37 | 'xxx' 38 | 39 | assrt.equal(x.__doc__, 'xxx') 40 | -------------------------------------------------------------------------------- /python/pylang/test/generators.py: -------------------------------------------------------------------------------- 1 | # vim:fileencoding=utf-8 2 | # License: BSD 3 | # Copyright: 2015, Kovid Goyal 4 | 5 | 6 | def g1(): 7 | yield 1 8 | yield 2 9 | 10 | 11 | def g2(): 12 | for i in range(2): 13 | yield from g1() 14 | 15 | 16 | def g3(): 17 | data = yield 1 18 | yield data 19 | 20 | 21 | class A: 22 | def __init__(self): 23 | self.items = [1, 2, 3] 24 | 25 | def __iter__(self): 26 | for x in self.items: 27 | yield x 28 | 29 | 30 | assrt.deepEqual([x for x in g1()], [1, 2]) 31 | assrt.deepEqual([x for x in g2()], [1, 2, 1, 2]) 32 | assrt.deepEqual([x for x in A()], [1, 2, 3]) 33 | 34 | g = g3() 35 | assrt.equal(g.next().value, 1) 36 | assrt.equal(g.next('a').value, 'a') 37 | 38 | a = (x for x in range(3)) 39 | assrt.deepEqual(list(a), [0, 1, 2]) 40 | a = ([x, x**2] for x in range(3)) 41 | assrt.deepEqual(list(a), [[0, 0], [1, 1], [2, 4]]) 42 | assrt.deepEqual(list(x for x in range(3)), [0, 1, 2]) 43 | 44 | 45 | def t(a, b): 46 | assrt.deepEqual(list(a), list(b)) 47 | 48 | 49 | t((x for x in range(1)), (y for y in range(1))) 50 | -------------------------------------------------------------------------------- /python/pylang/test/newlines.py: -------------------------------------------------------------------------------- 1 | # Obviously do NOT run autoformatting on this! If you do, it defeats 2 | # the point of all the tests. 3 | 4 | a = 1 + \ 5 | 2 + \ 6 | 3 7 | assert a == 6 8 | 9 | a = (1 + 10 | 2 + 11 | 3 + 12 | 4) 13 | 14 | assert a == 10 15 | 16 | a = (1, 17 | 2, 18 | 3, 19 | 4) 20 | 21 | assert sum(a) == 10 22 | 23 | a = [1, 24 | 2, 25 | 3] 26 | 27 | assert sum(a) == 6 28 | 29 | a = """ 30 | abc""" 31 | 32 | assert a == '\nabc' 33 | 34 | a = ''' 35 | abc''' 36 | 37 | assert a == '\nabc' 38 | 39 | 40 | a = {'x':10, 41 | 'y':15} 42 | 43 | assert str(a) == "{'x': 10, 'y': 15}" 44 | 45 | from math import (sin, 46 | cos, 47 | pi) 48 | assert sin(0) + cos(pi) == -1.0 49 | -------------------------------------------------------------------------------- /python/pylang/test/random_lib.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sagemathinc/cowasm/3f8f231f96f330f80140de4d1350553caa5e6960/python/pylang/test/random_lib.py -------------------------------------------------------------------------------- /python/pylang/test/typing_.py: -------------------------------------------------------------------------------- 1 | # mypy 2 | # You can run this file through mypy and it passes the checks. 3 | # You can also use it in pylang. 4 | # 5 | # The way this works is as follows: 6 | # - the "typing" module is mocked by the pylang compiler so that 7 | # importing from it is a no-op (so src/parser.py), and 8 | # - function annotations are not defined, since that potentially 9 | # involves running code defined in typing at runtime, which 10 | # can't work. 11 | 12 | from typing import Iterator 13 | 14 | 15 | def fib(n: int) -> Iterator[int]: 16 | a, b = 0, 1 17 | while a < n: 18 | yield a 19 | a, b = b, a + b 20 | -------------------------------------------------------------------------------- /python/pylang/try.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import subprocess 4 | import sys 5 | import os 6 | import shutil 7 | 8 | args = sys.argv[1:] 9 | source = None 10 | 11 | cmd = ['bin/pylang'] 12 | 13 | while args: 14 | if args[0] in ('-m', '-x'): 15 | cmd.append(args.pop(0)) 16 | elif args[0] == '-f': 17 | args.pop(0) 18 | source = args[0] 19 | cmd.append(source) 20 | else: 21 | break 22 | 23 | raw = ' '.join(args).replace('\\n', '\n') 24 | 25 | if os.path.exists('dev'): 26 | shutil.rmtree('dev') 27 | shutil.copytree('release', 'dev') 28 | subprocess.check_call(cmd[:1] + ['self']) 29 | if source: 30 | p = subprocess.Popen( 31 | ['node', '--stack-trace-limit=1000'] + cmd) 32 | else: 33 | p = subprocess.Popen( 34 | ['node', '--stack-trace-limit=1000'] + cmd, stdin=subprocess.PIPE) 35 | p.stdin.write(raw.encode('utf-8')) 36 | p.stdin.close() 37 | try: 38 | raise SystemExit(p.wait()) 39 | except KeyboardInterrupt: 40 | p.kill() 41 | raise SystemExit(1) 42 | -------------------------------------------------------------------------------- /python/pylang/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "incremental": true, 4 | "target": "es5", 5 | "lib": ["es6", "es2017", "dom"], 6 | "allowJs": true, 7 | "declaration": false, 8 | "downlevelIteration": true, 9 | "esModuleInterop": true, 10 | "forceConsistentCasingInFileNames": true, 11 | "isolatedModules": true, 12 | "jsx": "react-jsx", 13 | "noImplicitThis": true, 14 | "noUnusedLocals": true, 15 | "noUnusedParameters": true, 16 | "skipLibCheck": true, 17 | "sourceMap": true, 18 | "strictNullChecks": true, 19 | "rootDir": "./", 20 | "outDir": "dist" 21 | }, 22 | "exclude": ["node_modules", "dist"], 23 | "watchOptions": { 24 | "watchFile": "useFsEvents", 25 | "watchDirectory": "useFsEvents", 26 | "fallbackPolling": "dynamicPriority", 27 | "synchronousWatchDirectory": true 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /python/python-wasm/bin/python-wasm: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | require('../dist/node-terminal'); -------------------------------------------------------------------------------- /python/python-wasm/data/README.md: -------------------------------------------------------------------------------- 1 | These are some scratch python scripts I used for developing sockets 2 | 3 | - maybe delete them later, but I don't want to delete them just yet. -------------------------------------------------------------------------------- /python/python-wasm/data/http/demo1.py: -------------------------------------------------------------------------------- 1 | import ssl 2 | ssl._create_default_https_context = ssl._create_unverified_context 3 | import http.client 4 | 5 | connection = http.client.HTTPSConnection('pypi.org') 6 | print(connection) 7 | 8 | connection.request("GET", "/simple/pip/") 9 | response = connection.getresponse() 10 | print("Status: {} and reason: {}".format(response.status, response.reason)) 11 | 12 | connection.close() -------------------------------------------------------------------------------- /python/python-wasm/data/http/wrap_socket.py: -------------------------------------------------------------------------------- 1 | import ssl 2 | import socket 3 | #context0 = ssl.SSLContext(16) 4 | #print(context0) 5 | 6 | conn = socket.create_connection(("localhost", 2000)) 7 | 8 | import ssl 9 | # this works with "import ssl" down here, but breaks 10 | # with "import ssl" at the top of this file. 11 | context = ssl.SSLContext(16) 12 | print(context) -------------------------------------------------------------------------------- /python/python-wasm/data/socket/client.py: -------------------------------------------------------------------------------- 1 | """ 2 | 3 | Run the server first, then run this via 4 | 5 | python-wasm client.py 6 | 7 | You can also run either the client or server with python-native 8 | to narrow down problems. 9 | 10 | """ 11 | 12 | import socket, time 13 | 14 | 15 | def f(): 16 | # TODO: This currently "hangs for 5 seconds" even 17 | # though the other side is ready. The problem 18 | # is that poll_oneoff or pollSocket (in posix-node) 19 | # need to be improved. 20 | conn = socket.create_connection(("localhost", 2000), timeout=5) 21 | print("connected to port 2000") 22 | #conn.settimeout(1) 23 | 24 | print("*" * 80) 25 | print("conn =", conn) 26 | print("*" * 80) 27 | 28 | t = time.time() 29 | print(conn.recv(6)) 30 | print("time = ", time.time() - t) 31 | 32 | t = time.time() 33 | print(conn.send(b"CoWasm")) 34 | print("time = ", time.time() - t) 35 | 36 | #conn.shutdown(socket.SHUT_RD) 37 | 38 | 39 | f() 40 | -------------------------------------------------------------------------------- /python/python-wasm/data/ssl/basic.py: -------------------------------------------------------------------------------- 1 | from _ssl import _SSLContext 2 | import sys 3 | import hashlib, ssl 4 | 5 | def main(): 6 | print(sys.platform) 7 | c = _SSLContext(16) 8 | print(c) 9 | return c 10 | 11 | if __name__ == '__main__': 12 | [main() for i in range(10)] 13 | 14 | -------------------------------------------------------------------------------- /python/python-wasm/index.d.ts: -------------------------------------------------------------------------------- 1 | declare module '*.wasm'; 2 | declare module '*.zip'; 3 | declare module '*.tar.xz'; 4 | -------------------------------------------------------------------------------- /python/python-wasm/src/extension/README.md: -------------------------------------------------------------------------------- 1 | A simple Python C extension, for **testing** and developing dynamic library loading functionality for Python. 2 | -------------------------------------------------------------------------------- /python/python-wasm/src/extension/hello.py: -------------------------------------------------------------------------------- 1 | import sys, time 2 | 3 | sys.path.insert(0, 'dist') 4 | import hellozig, hello 5 | 6 | print(hellozig.add389(100)) 7 | hellozig.hello('william') 8 | print(hellozig.gcd(18, 21)) 9 | t = time.time() 10 | print(sum(hellozig.gcd(12345678, n) for n in range(1,1000000))) 11 | print(time.time() - t) 12 | 13 | print("\n---\n") 14 | print(hello.add389(100)) 15 | hello.hello('william') 16 | print(hello.gcd(18, 21)) 17 | t = time.time() 18 | print(sum(hello.gcd(12345678, n) for n in range(1,1000000))) 19 | print(time.time() - t) 20 | -------------------------------------------------------------------------------- /python/python-wasm/src/extension/hello.test.ts: -------------------------------------------------------------------------------- 1 | import { syncPython } from "../node"; 2 | import { join } from "path"; 3 | 4 | // Test that it is possible to import a dynamic library 5 | test("hello extension module loads and works", async () => { 6 | const { exec, repr } = await syncPython(); 7 | const dist = join(__dirname, ".."); 8 | exec(`import sys; sys.path.insert(0,'${dist}')`); 9 | exec("import hello"); 10 | expect(parseInt(repr("hello.add389(10)"))).toBe(10 + 389); 11 | }); 12 | 13 | // Test that it is not stupidly slow, which could happen if 14 | // we are not sufficiently clever regarding how dynamic 15 | // linking works. 16 | test("not stupidly slow", async () => { 17 | const { exec, repr } = await syncPython(); 18 | const dist = join(__dirname, ".."); 19 | exec(`import sys; sys.path.insert(0,'${dist}')`); 20 | exec("import hello"); 21 | const t = new Date().valueOf(); 22 | repr("sum(hello.add389(10) for _ in range(10**5))"); 23 | expect(new Date().valueOf() - t).toBeLessThan(1000); 24 | }); 25 | -------------------------------------------------------------------------------- /python/python-wasm/src/extension/hellozigmodule.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | extern PyObject *hello(PyObject *self, PyObject *args); 5 | extern PyObject *add389(PyObject *self, PyObject *args); 6 | extern PyObject *gcd_impl(PyObject *self, PyObject *args); 7 | 8 | static PyMethodDef module_methods[] = { 9 | {"hello", _PyCFunction_CAST(hello), METH_VARARGS, "Say hello to you."}, 10 | {"add389", _PyCFunction_CAST(add389), METH_VARARGS, "Add 389 to a C long."}, 11 | {"gcd", _PyCFunction_CAST(gcd_impl), METH_VARARGS, "GCD of two C longs"}, 12 | {NULL, NULL, 0, NULL}}; 13 | 14 | static int module_clear(PyObject *module) { return 0; } 15 | 16 | static void module_free(void *module) { module_clear((PyObject *)module); } 17 | 18 | struct PyModuleDef _hellomodule = { 19 | .m_name = "hellozig", 20 | .m_methods = module_methods, 21 | .m_clear = module_clear, 22 | .m_free = module_free, 23 | }; 24 | 25 | PyMODINIT_FUNC PyInit_hellozig(void) { return PyModuleDef_Init(&_hellomodule); } -------------------------------------------------------------------------------- /python/python-wasm/src/extension/sqlite.test.ts: -------------------------------------------------------------------------------- 1 | import { syncPython } from "../node"; 2 | 3 | // TODO: note that non-in-memory sqlite currently definitely doesn't work at all... YET. 4 | // That's clear even with the standalone binary. 5 | 6 | test("use the sqlite module to do something", async () => { 7 | const { exec, repr } = await syncPython(); 8 | exec(` 9 | import sqlite3 10 | con = sqlite3.connect(":memory:") 11 | cur = con.cursor() 12 | cur.execute("CREATE TABLE movies(title, year, score)") 13 | cur.execute("INSERT INTO movies values('Red Dawn',1984,50)") 14 | cur.execute("INSERT INTO movies values('Red Dawn',2012,15)") 15 | res = cur.execute("SELECT * FROM movies") 16 | `); 17 | expect(repr("list(res)")).toBe( 18 | "[('Red Dawn', 1984, 50), ('Red Dawn', 2012, 15)]" 19 | ); 20 | }); 21 | -------------------------------------------------------------------------------- /python/python-wasm/src/packages.ts: -------------------------------------------------------------------------------- 1 | // TODO: Very preliminary! 2 | 3 | import debug from "debug"; 4 | const log = debug("python-wasm:packages"); 5 | 6 | import numpy from "./numpy.tar.xz"; 7 | import mpmath from "./mpmath.tar.xz"; 8 | import sympy from "./sympy.tar.xz"; 9 | import pandas from "./pandas.tar.xz"; 10 | import six from "./six.tar.xz"; 11 | import pytz from "./pytz.tar.xz"; 12 | import dateutil from "./dateutil.tar.xz"; 13 | 14 | export async function fetchPackages(kernel) { 15 | log("fetching demo packages in parallel: numpy, mpmath, sympy"); 16 | await Promise.all([ 17 | kernel.fetch(numpy, "/usr/lib/python3.11/numpy.tar.xz"), 18 | kernel.fetch(mpmath, "/usr/lib/python3.11/mpmath.tar.xz"), 19 | kernel.fetch(sympy, "/usr/lib/python3.11/sympy.tar.xz"), 20 | kernel.fetch(pandas, "/usr/lib/python3.11/pandas.tar.xz"), 21 | kernel.fetch(six, "/usr/lib/python3.11/six.tar.xz"), 22 | kernel.fetch(pytz, "/usr/lib/python3.11/pytz.tar.xz"), 23 | kernel.fetch(dateutil, "/usr/lib/python3.11/dateutil.tar.xz"), 24 | ]); 25 | log("fetched packages"); 26 | } 27 | -------------------------------------------------------------------------------- /python/python-wasm/src/test/default.test.ts: -------------------------------------------------------------------------------- 1 | import { asyncPython, syncPython } from "../node"; 2 | 3 | test("that the default syncPython import works", async () => { 4 | const { exec, repr } = await syncPython(); 5 | exec("a = 2+3"); 6 | expect(repr("a")).toBe("5"); 7 | }); 8 | 9 | test("that the default asyncPython import works", async () => { 10 | const { exec, repr, kernel } = await asyncPython(); 11 | await exec("a = 2+3"); 12 | expect(await repr("a")).toBe("5"); 13 | await kernel.terminate(); 14 | }); 15 | -------------------------------------------------------------------------------- /python/python-wasm/src/test/home.test.ts: -------------------------------------------------------------------------------- 1 | import { asyncPython, syncPython } from "../node"; 2 | 3 | test("that the default syncPython has the PYTHONHOME", async () => { 4 | const { exec, repr } = await syncPython(); 5 | exec("import os"); 6 | expect(repr("os.environ.get('PYTHONHOME')")).toBe("'/usr'"); 7 | }); 8 | 9 | test("that the default asyncPython has the PYTHONHOME", async () => { 10 | const { exec, repr, kernel } = await asyncPython(); 11 | await exec("import os"); 12 | expect(await repr("os.environ.get('PYTHONHOME')")).toBe("'/usr'"); 13 | await kernel.terminate(); 14 | }); 15 | 16 | test("also confirm that some interesting packages are installed", async () => { 17 | const { exec } = await syncPython(); 18 | exec("import pandas, sympy"); 19 | }, 15000); 20 | -------------------------------------------------------------------------------- /python/python-wasm/src/test/misc.test.ts: -------------------------------------------------------------------------------- 1 | import { syncPython } from "../node"; 2 | 3 | test("that creating a directory works, and can get listing on new directory", async () => { 4 | const { exec, repr } = await syncPython(); 5 | const path = `/tmp/${Math.random()}`; 6 | try { 7 | exec(`import os; os.makedirs('${path}')`); 8 | expect(repr(`os.path.exists('${path}')`)).toBe("True"); 9 | expect(repr(`os.listdir('${path}')`)).toBe("[]"); 10 | } finally { 11 | exec(`os.rmdir('${path}')`); 12 | } 13 | }); 14 | -------------------------------------------------------------------------------- /python/python-wasm/src/test/posix/netif.test.ts: -------------------------------------------------------------------------------- 1 | import { syncPython} from "../../node"; 2 | 3 | test("getting the first network interface works", async () => { 4 | const { exec, repr } = await syncPython(); 5 | exec("import socket"); 6 | const name = eval(repr("socket.if_indextoname(1)")); 7 | expect(typeof name).toBe("string"); 8 | expect(name.length).toBeGreaterThan(0); 9 | }); 10 | 11 | test("going back and forth between interface and name works", async () => { 12 | const { exec, repr } = await syncPython(); 13 | exec("import socket"); 14 | const name = eval(repr("socket.if_indextoname(1)")); 15 | expect(eval(repr(`socket.if_nametoindex('${name}')`))).toBe(1); 16 | }); 17 | 18 | test("going back and forth for all interfaces works", async () => { 19 | const { exec, repr } = await syncPython(); 20 | exec("import json, socket"); 21 | const ni = JSON.parse(eval(repr("json.dumps(socket.if_nameindex())"))); 22 | for (const [index, name] of ni) { 23 | expect(eval(repr(`socket.if_indextoname(${index})`))).toBe(name); 24 | expect(eval(repr(`socket.if_nametoindex("${name}")`))).toBe(index); 25 | } 26 | }); 27 | -------------------------------------------------------------------------------- /python/python-wasm/src/test/posix/other.test.ts: -------------------------------------------------------------------------------- 1 | import { syncPython } from "../../node"; 2 | 3 | test("test ctermid", async () => { 4 | const { exec, repr } = await syncPython(); 5 | exec("import os"); 6 | expect(typeof repr("os.ctermid()")).toBe("string"); 7 | }); 8 | 9 | test("bindtextdomain doesn't crash (it is still basically a stub)", async () => { 10 | const { exec, repr } = await syncPython(); 11 | exec("import gettext"); 12 | expect(eval(repr("gettext.bindtextdomain('foo','/bar')"))).toBe("/bar"); 13 | }); 14 | -------------------------------------------------------------------------------- /python/python-wasm/src/test/python-async.test.ts: -------------------------------------------------------------------------------- 1 | import { asyncPython } from "../node"; 2 | 3 | // TODO: I have seen this test random fail sometimes, where 4 | // it hangs. Not sure why. Hence skipping. 5 | // 6 | // Error is ENOENT: no such file or directory, uv_cwd so I suspect conflict 7 | // between node threads. 8 | 9 | 10 | test.skip("add 2+3 (async version)", async () => { 11 | const { exec, repr, kernel } = await asyncPython(); 12 | await exec("a = 2+3"); 13 | expect(await repr("a")).toBe("5"); 14 | kernel.terminate(); 15 | }); 16 | 17 | test.skip("sleeping for a quarter of a second (async version)", async () => { 18 | const { exec, kernel } = await asyncPython(); 19 | const t0 = new Date().valueOf(); 20 | await exec("import time; time.sleep(0.25)"); 21 | const t = new Date().valueOf() - t0; 22 | expect(t >= 240 && t <= 1000).toBe(true); 23 | kernel.terminate(); 24 | }); 25 | 26 | -------------------------------------------------------------------------------- /python/python-wasm/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "rootDir": "src", 5 | "outDir": "dist", 6 | "tsBuildInfoFile": "dist/tsconfig.tsbuildinfo" 7 | }, 8 | "exclude": ["node_modules", "build", "dist"], 9 | } 10 | -------------------------------------------------------------------------------- /python/termcap-native/Makefile: -------------------------------------------------------------------------------- 1 | 2 | all: native 3 | 4 | 5 | include ../build/Makefile-vars 6 | 7 | # See https://ftp.gnu.org/gnu/termcap/ 8 | # Not likely to change -- it hasn't in over 20 years! 9 | VERSION = 1.3.1 10 | TARBALL = ${UPSTREAM}/termcap-${VERSION}.tar.gz 11 | URL = https://ftp.gnu.org/gnu/termcap/termcap-${VERSION}.tar.gz 12 | 13 | 14 | include ../build/Makefile-rules 15 | 16 | ################## 17 | # NATIVE 18 | ################## 19 | 20 | ${DIST_NATIVE}/.built: ${BUILD_NATIVE}/.build 21 | cd ../build && make zig 22 | cp src/config.h ${BUILD_NATIVE} 23 | cd ${BUILD_NATIVE} && \ 24 | CC="zig cc ${ZIG_NATIVE_CFLAGS_GNU} -DHAVE_CONFIG_H=1 " AR="zig ar" ./configure --prefix=${DIST_NATIVE} && \ 25 | make -j8 && \ 26 | make install 27 | touch ${DIST_NATIVE}/.built 28 | 29 | test: ${DIST_NATIVE}/.built 30 | echo "no test" -------------------------------------------------------------------------------- /python/termcap-native/src/config.h: -------------------------------------------------------------------------------- 1 | #define STDC_HEADERS 1 2 | #include 3 | #include 4 | #include 5 | -------------------------------------------------------------------------------- /python/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "incremental": true, 4 | "target": "es2020", 5 | "module": "commonjs", 6 | "lib": ["es5", "es6", "es2017", "dom"], 7 | "allowJs": true, 8 | "declaration": true, 9 | "downlevelIteration": true, 10 | "esModuleInterop": true, 11 | "forceConsistentCasingInFileNames": true, 12 | "isolatedModules": true, 13 | "noImplicitThis": true, 14 | "noUnusedLocals": true, 15 | "noUnusedParameters": true, 16 | "skipLibCheck": true, 17 | "sourceMap": true, 18 | "strictNullChecks": true, 19 | "moduleResolution": "node" 20 | }, 21 | } 22 | -------------------------------------------------------------------------------- /python/zlib-native/Makefile: -------------------------------------------------------------------------------- 1 | include ../build/Makefile-vars 2 | 3 | # See https://github.com/sagemathinc/zlib/releases 4 | ZLIB_VERSION = 1.2.13 5 | 6 | # https://stackoverflow.com/questions/18136918/how-to-get-current-relative-directory-of-your-makefile 7 | 8 | all: native 9 | 10 | URL = https://github.com/sagemathinc/zlib/archive/refs/tags/${ZLIB_VERSION}.tar.gz 11 | TARBALL = ${UPSTREAM}/zlib-${ZLIB_VERSION}.tar.xz 12 | 13 | include ../build/Makefile-rules 14 | 15 | # NATIVE 16 | 17 | ${DIST_NATIVE}/.built: ${BUILD_NATIVE}/.build 18 | cd ../build && make zig 19 | cd ${BUILD_NATIVE} \ 20 | && AR="zig ar" \ 21 | CC="zig cc ${ZIG_NATIVE_CFLAGS_GNU} " \ 22 | ./configure --static --prefix=${DIST_NATIVE} \ 23 | && make install -j8 24 | touch ${DIST_NATIVE}/.built 25 | 26 | test: ${DIST_NATIVE}/.built 27 | echo "no test" -------------------------------------------------------------------------------- /sagemath/README.md: -------------------------------------------------------------------------------- 1 | # Sagemath Component of CoWasm 2 | 3 | The goal of the packages in this directory is a full port of 4 | https://www.sagemath.org/ to WebAssembly. 5 | 6 | This is a work in progress, which starts with copying over some packages [from here](https://github.com/sagemathinc/jsage). 7 | 8 | **WARNING: Unlike the rest of CoWasm, there is code in this directory 9 | that is licensed under the GPL. No code in the other packages (core, python, web, etc.,) depends on this code.** 10 | -------------------------------------------------------------------------------- /sagemath/build: -------------------------------------------------------------------------------- 1 | ../core/build -------------------------------------------------------------------------------- /sagemath/gmp/Makefile: -------------------------------------------------------------------------------- 1 | include ../build/Makefile-vars 2 | 3 | # See https://gmplib.org for versions. 4 | VERSION = 6.2.1 5 | URL = https://gmplib.org/download/gmp/gmp-${VERSION}.tar.bz2 6 | TARBALL = ${UPSTREAM}/gmp-${VERSION}.tar.bz2 7 | 8 | all: wasm 9 | 10 | include ../build/Makefile-rules 11 | 12 | 13 | ${DIST_WASM}/.built: ${BUILD_WASM}/.build 14 | cd ${BUILD_WASM} && \ 15 | CC="cowasm-cc" \ 16 | AR="zig ar" \ 17 | RANLIB="zig ranlib" \ 18 | ABI=standard \ 19 | CC_FOR_BUILD="zig cc ${ZIG_NATIVE_CFLAGS}" \ 20 | CFLAGS="-Oz" \ 21 | ./configure \ 22 | --build i686-pc-linux-gnu \ 23 | --host=none \ 24 | --prefix=${DIST_WASM} 25 | # Edit config.h to change '#define HAVE_OBSTACK_VPRINTF 1' to '#define HAVE_OBSTACK_VPRINTF 0' because missing in zig... 26 | cd ${BUILD_WASM} && sed -i'.original' -e 's/HAVE_OBSTACK_VPRINTF 1/HAVE_OBSTACK_VPRINTF 0/' config.h 27 | cd ${BUILD_WASM} && make -j4 install 28 | touch ${DIST_WASM}/.built 29 | 30 | test: 31 | echo "No GMP tests yet" -------------------------------------------------------------------------------- /sagemath/gmp/README.md: -------------------------------------------------------------------------------- 1 | # GMP 2 | 3 | This is 32-bit GMP compiled (fPIC) for web assembly. 4 | 5 | ## Note about 64-bit: 6 | 7 | I learned from 8 | 9 | https://github.com/torquem-ch/gmp-wasm/commit/48fec192ca77d2a8a874f973f469d4c16b21f034 10 | 11 | how to enable 64-bit limbs. In some benchmarks, this VERY significantly 12 | improves the speed (it's over twice as fast). See https://github.com/sagemathinc/JSage/tree/main/packages/gmp if you want to try this. I also found that it leads to weird random bugs in client libraries, e.g., FLINT, 13 | and is generally probably a very bad idea at present, unfortunately. 14 | 15 | Another thing I learned is that Javascript (in V8 at least) itself has native very fast BigInts these days. However, GMP is of course much more than just arithmetic. 16 | -------------------------------------------------------------------------------- /sagemath/gmp/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@cowasm/gmp", 3 | "version": "1.0.0", 4 | "description": "GNU Multiprecision Arithmetic", 5 | "exports": { "./*": "./dist/js/*.js" }, 6 | "type": "module", 7 | "files": [ 8 | "dist/js/*", 9 | "README.md", 10 | "src/*", 11 | "package.json", 12 | "tsconfig.json", 13 | "Makefile" 14 | ], 15 | "scripts": { 16 | "preinstall": "npx only-allow pnpm", 17 | "build": "make", 18 | "clean": "make clean" 19 | }, 20 | "repository": { 21 | "type": "git", 22 | "url": "git+https://github.com/sagemathinc/cowasm.git" 23 | }, 24 | "homepage": "https://github.com/sagemathinc/cowasm/tree/main/sagemath/gmp", 25 | "keywords": ["number", "theory"], 26 | "author": "William Stein", 27 | "license": "LGPL-3.0-or-later", 28 | "bugs": { 29 | "url": "https://github.com/sagemathinc/cowasm/issues" 30 | }, 31 | "homepage": "https://github.com/sagemathinc/cowasm/tree/main/sagemath/gmp", 32 | "dependencies": {}, 33 | "devDependencies": {} 34 | } 35 | -------------------------------------------------------------------------------- /sagemath/pari/TODO.md: -------------------------------------------------------------------------------- 1 | This is just a very minimal first proof of concept build. It does work though, if you type 2 | 3 | ```sh 4 | ./dist/wasm/bin/gp 5 | ``` 6 | 7 | ## [ ] Build dynamically linked 8 | 9 | The current build is statically linked, so it can't be run as part of the dash shell. 10 | 11 | ## [ ] Support Readline (via editline + compat support or hacking) 12 | 13 | My understanding is nobody has ever built pari using libedit, so this 14 | could be a little challenging. 15 | 16 | ## [ ] Support GMP 17 | 18 | WASM Pari is definitely being built without GMP right now, since we haven't 19 | even tried. This is making it MUCH MUCH slower. 20 | 21 | Here is how to tell if GMP is being used or not: 22 | 23 | ```sh 24 | ~/jsage/packages/pari$ make run-wasm