Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

emscripten PoC #224

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 70 additions & 2 deletions build.zig
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,26 @@ pub fn build(b: *std.Build) void {
}
ensureGitLfsContent("/libs/zgpu/libs/dawn/x86_64-windows-gnu/dawn.lib") catch return;

// hacky emscripten override, just for PoC, do not ship!
const target = (std.zig.system.NativeTargetInfo.detect(options.target) catch unreachable).target;
if (target.os.tag == .emscripten) {
zsdl_pkg = zsdl.Package.build(b, .{});
zopengl_pkg = zopengl.Package.build(b, .{});

{ // minimal sdl
// Workaround zig std lib not compiling for emscripten: see https://github.com/ziglang/zig/issues/10836
var options_override = options;
options_override.target.os_tag = .freestanding;

const exe = minimal_sdl.build(b, options_override);
exe.addModule("zsdl", zsdl_pkg.zsdl);
exe.addModule("zopengl", zopengl_pkg.zopengl);
zsdl_pkg.link(exe, target);
installDemoEmsc(b, exe, "minimal_sdl");
}
return;
}

//
// Packages
//
Expand Down Expand Up @@ -159,7 +179,7 @@ fn samplesCrossPlatform(b: *std.Build, options: Options) void {
const exe = minimal_sdl.build(b, options);
exe.addModule("zsdl", zsdl_pkg.zsdl);
exe.addModule("zopengl", zopengl_pkg.zopengl);
zsdl_pkg.link(exe);
zsdl_pkg.link(exe, null);
installDemo(b, exe, "minimal_sdl");
}
{ // triangle wgpu
Expand Down Expand Up @@ -644,6 +664,52 @@ fn installDemo(b: *std.Build, exe: *std.Build.CompileStep, comptime name: []cons
b.getInstallStep().dependOn(install);
}

fn installDemoEmsc(b: *std.Build, exe: *std.Build.CompileStep, comptime name: []const u8) void {
comptime var desc_name: [256]u8 = [_]u8{0} ** 256;
comptime _ = std.mem.replace(u8, name, "_", " ", desc_name[0..]);
comptime var desc_size = std.mem.indexOf(u8, &desc_name, "\x00").?;

const install = b.step(name, "Build '" ++ desc_name[0..desc_size] ++ "' demo");
install.dependOn(&b.addInstallArtifact(exe).step);

{ // "borrowed" & modifed version of https://github.com/floooh/pacman.zig/blob/main/build.zig
const emcc_path = std.fs.path.join(b.allocator, &.{ b.sysroot.?, "../../emcc" }) catch unreachable;
defer b.allocator.free(emcc_path);
const emrun_path = std.fs.path.join(b.allocator, &.{ b.sysroot.?, "../../emrun" }) catch unreachable;
defer b.allocator.free(emrun_path);

std.fs.cwd().makePath("zig-out/web") catch unreachable;
const emcc = b.addSystemCommand(&.{
emcc_path,
"-Os",
"--closure",
"1",
"emscripten/entry.c",
"-ozig-out/web/test.html",
"--shell-file",
"emscripten/shell.html",
"-Lzig-out/lib/",
"-l" ++ name,
"-sNO_FILESYSTEM=1",
"-sMALLOC='emmalloc'",
"-sASSERTIONS=0",
"-sEXPORTED_FUNCTIONS=['_main']",
"-sUSE_SDL=2",
});
emcc.step.dependOn(&exe.install_step.?.step);

// get the emcc step to run on 'zig build'
b.getInstallStep().dependOn(&emcc.step);

// a seperate run step using emrun
const emrun = b.addSystemCommand(&.{ emrun_path, "zig-out/web/test.html" });
emrun.step.dependOn(&emcc.step);
b.step(name ++ "-run", "Run '" ++ desc_name[0..desc_size] ++ "' demo (emscripten)").dependOn(&emrun.step);
}

b.getInstallStep().dependOn(install);
}

fn ensureZigVersion() !void {
var installed_ver = @import("builtin").zig_version;
installed_ver.build = null;
Expand Down Expand Up @@ -682,13 +748,14 @@ fn ensureTarget(cross: std.zig.CrossTarget) !void {
if (target.os.version_range.semver.min.order(min_available) == .lt) break :blk false;
break :blk true;
},
.emscripten => target.cpu.arch.isWasm(),
else => false,
};
if (!supported) {
std.log.err("\n" ++
\\---------------------------------------------------------------------------
\\
\\Unsupported build target. Dawn/WebGPU binary for this target is not available.
\\Unsupported build target.
\\
\\Following targets are supported:
\\
Expand All @@ -697,6 +764,7 @@ fn ensureTarget(cross: std.zig.CrossTarget) !void {
\\x86_64-macos.12-none
\\aarch64-linux-gnu
\\aarch64-macos.12-none
\\wasm32-emscripten
\\
\\---------------------------------------------------------------------------
\\
Expand Down
27 changes: 27 additions & 0 deletions emscripten/emsdk/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
Copyright (c) 2018 Emscripten authors (see AUTHORS in Emscripten)

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

----------------------------------------------------------------------------

This is the MIT/Expat Licence. For more information see:

1. http://www.opensource.org/licenses/mit-license.php

2. http://en.wikipedia.org/wiki/MIT_License
258 changes: 258 additions & 0 deletions emscripten/emsdk/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,258 @@
Emscripten SDK
==============

[![CircleCI](https://circleci.com/gh/emscripten-core/emsdk/tree/main.svg?style=svg)](https://circleci.com/gh/emscripten-core/emsdk/tree/main)

The Emscripten toolchain is distributed as a standalone Emscripten SDK. The SDK
provides all the required tools, such as Clang, Python and Node.js along with an
update mechanism that enables migrating to newer Emscripten versions as they are
released.

You can also set up Emscripten from source, without the pre-built SDK, see
"Installing from Source" below.

## Downloads / How do I get the latest Emscripten build?

To get started with Emscripten development, see the [Emscripten website
documentation](https://emscripten.org/docs/getting_started/downloads.html).

That explains how to use the emsdk to get the latest binary builds (without
compiling from source). Basically, that amounts to

```
./emsdk install latest
./emsdk activate latest
```

## SDK Concepts

The Emscripten SDK is effectively a small package manager for tools that are
used in conjunction with Emscripten. The following glossary highlights the
important concepts to help understanding the internals of the SDK:

* **Tool**: The basic unit of software bundled in the SDK. A Tool has a name and
a version. For example, 'clang-3.2-32bit' is a Tool that contains the 32-bit
version of the Clang v3.2 compiler.
* **SDK**: A set of tools. For example, 'sdk-1.5.6-32bit' is an SDK consisting
of the tools `clang-3.2-32bit`, `node-0.10.17-32bit`, `python-2.7.5.1-32bit`
and `emscripten-1.5.6`.
* **Active Tool/SDK**: Emscripten stores compiler configuration in a
user-specific file **~/.emscripten**. This file points to paths for
Emscripten, Python, Clang and so on. If the file ~/.emscripten is configured
to point to a Tool in a specific directory, then that tool is denoted as being
**active**. The Emscripten Command Prompt always gives access to the currently
active Tools. This mechanism allows switching between different installed SDK
versions easily.
* **emsdk**: This is the name of the manager script that Emscripten SDK is
accessed through. Most operations are of the form `emsdk command`. To access
the emsdk script, launch the Emscripten Command Prompt.

## System Requirements

Using the emsdk pre-compiled packages requires only the minimal set of
dependenencies lists below. When building from source a wider set of tools
include git, cmake, and a host compiler are required. See:
https://emscripten.org/docs/building_from_source/toolchain_what_is_needed.html.

### Mac OS X

- For Intel-based Macs, macOS 10.13 or newer. For ARM64 M1 based Macs, macOS
11.0 or newer.
- `java`: For running closure compiler (optional). After installing emscripten
via emsdk, typing 'emcc --help' should pop up a OS X dialog "Java is not
installed. To open java, you need a Java SE 6 runtime. Would you like to
install one now?" that will automatically download a Java runtime to the
system.

### Linux

- `python`: Version 2.7.0 or above.
- `java`: For running closure compiler (optional)

The emsdk pre-compiled binaries are built aginst Ubuntu/Xenial 16.04 LTS and
therefore depend on system libraries compatiable with versions of `glibc` and
`libstdc++` present in that release. If your linux distribution is very old
you may not be able to use the pre-compiled binaries packages.

### Windows

- `java`: For running closure compiler (optional)

## Uninstalling the Emscripten SDK

To remove the Emscripten SDK, simply delete the emsdk directory.

## SDK Maintenance

The following tasks are common with the Emscripten SDK:

### How do I work the emsdk utility?

Run `emsdk help` or just `emsdk` to get information about all available commands.

### How do I check the installation status and version of the SDK and tools?

To get a list of all currently installed tools and SDK versions, and all
available tools, run `emsdk list`.
* A line will be printed for each tool/SDK that is available for installation.
* The text `INSTALLED` will be shown for each tool that has already been
installed.
* If a tool/SDK is currently active, a star * will be shown next to it.
* If a tool/SDK is currently active, but the terminal your are calling emsdk
from does not have `PATH` and environment set up to utilize that tool, a star
in parentheses (\*) will be shown next to it. Run `emsdk_env.bat` (Windows) or
`source ./emsdk_env.sh` (Linux and OS X) to set up the environment for the
calling terminal.

### How do I install a tool/SDK version?

Run the command `emsdk install <tool/sdk name>` to download and install a new
tool or an SDK version.

### How do I remove a tool or an SDK?

Run the command `emsdk uninstall <tool/sdk name>` to delete the given tool or
SDK from the local hard drive completely.

### How do I check for updates to the Emscripten SDK?

`emsdk update` will fetch package information for all the new tools and
SDK versions. After that, run `emsdk install <tool/sdk name>` to install a new
version.

### How do I install an old Emscripten compiler version?

Emsdk contains a history of old compiler versions that you can use to maintain
your migration path. Type `emsdk list --old` to get a list of archived tool and
SDK versions, and `emsdk install <name_of_tool>` to install it.

### I want to build from source!

Some Emsdk Tool and SDK targets refer to packages that are precompiled, and
no compilation is needed when installing them. Other Emsdk Tools and SDK
targets come "from source", meaning that they will fetch the source repositories
using git, and compile the package on demand.

When you run `emsdk list`, it will group the Tools and SDKs under these two
categories.

To obtain and build latest wasm SDK from source, run

```
emsdk install sdk-main-64bit
emsdk activate sdk-main-64bit
```

You can use this target for example to bootstrap developing patches to LLVM,
Binaryen or Emscripten. (After initial installation, use `git remote add`
in the cloned tree to add your own fork to push changes as patches)

If you only intend to contribute to Emscripten repository, and not to LLVM
or Binaryen, you can also use precompiled versions of them, and only git
clone the Emscripten repository. For more details, see

https://emscripten.org/docs/contributing/developers_guide.html?highlight=developer#setting-up

### When working on git branches compiled from source, how do I update to a newer compiler version?

Unlike tags and precompiled versions, a few of the SDK packages are based on
"moving" git branches and compiled from source (e.g. sdk-main,
sdk-main, emscripten-main, binaryen-main). Because of that, the
compiled versions will eventually go out of date as new commits are introduced
to the development branches. To update an old compiled installation of one of
this branches, simply reissue the "emsdk install" command on that tool/SDK. This
will `git pull` the latest changes to the branch and issue an incremental
recompilation of the target in question. This way you can keep calling `emsdk
install` to keep an Emscripten installation up to date with a given git branch.

Note though that if the previously compiled branch is very old, sometimes CMake
gets confused and is unable to properly rebuild a project. This has happened in
the past e.g. when LLVM migrated to requiring a newer CMake version. In cases of
any odd compilation errors, it is advised to try deleting the intermediate build
directory to clear the build (e.g. "emsdk/clang/fastcomp/build_xxx/") before
reissuing `emsdk install`.

### How do I change the currently active SDK version?

You can toggle between different tools and SDK versions by running `emsdk
activate <tool/sdk name>`. Activating a tool will set up `~/.emscripten` to
point to that particular tool. On Windows, you can pass the option `--permanent` to
the `activate` command to register the environment permanently for the current user. Use `--system` to do this for all users.

### How do I build multiple projects with different SDK versions in parallel?

By default, Emscripten locates all configuration files in the home directory of
the user. This may be a problem if you need to simultaneously build with
multiple Emscripten compiler versions, since the user home directory can only be
configured to point to one compiler at a time. This can be overcome by
specifying the '--embedded' option as a parameter to 'emsdk activate', which
will signal emsdk to generate the compiler configuration files inside the emsdk
root directory instead of the user home directory. Use this option also when it
is desirable to run emsdk in a fully portable mode that does not touch any files
outside the emsdk directory.

### How do I track the latest Emscripten development with the SDK?

A common and supported use case of the Emscripten SDK is to enable the workflow
where you directly interact with the github repositories. This allows you to
obtain new features and latest fixes immediately as they are pushed to the
github repository, without having to wait for release to be tagged. You do not
need a github account or a fork of Emscripten to do this. To switch to using the
latest git development branch `main`, run the following:

emsdk install git-1.9.4 # Install git. Skip if the system already has it.
emsdk install sdk-main-64bit # Clone+pull the latest emscripten-core/emscripten/main.
emsdk activate sdk-main-64bit # Set the main SDK as the currently active one.

### How do I use my own Emscripten github fork with the SDK?

It is also possible to use your own fork of the Emscripten repository via the
SDK. This is achieved with standard git machinery, so there if you are already
acquainted with working on multiple remotes in a git clone, these steps should
be familiar to you. This is useful in the case when you want to make your own
modifications to the Emscripten toolchain, but still keep using the SDK
environment and tools. To set up your own fork as the currently active
Emscripten toolchain, first install the `sdk-main` SDK like shown in the
previous section, and then run the following commands in the emsdk directory:

cd emscripten/main
# Add a git remote link to your own repository.
git remote add myremote https://github.com/mygituseraccount/emscripten.git
# Obtain the changes in your link.
git fetch myremote
# Switch the emscripten-main tool to use your fork.
git checkout -b mymain --track myremote/main

In this way you can utilize the Emscripten SDK tools while using your own git
fork. You can switch back and forth between remotes via the `git checkout`
command as usual.

### How do I use Emscripten SDK with a custom version of python, java, node.js or some other tool?

The provided Emscripten SDK targets are metapackages that refer to a specific
set of tools that have been tested to work together. For example,
`sdk-1.35.0-64bit` is an alias to the individual packages `clang-e1.35.0-64bit`,
`node-4.1.1-64bit`, `python-2.7.5.3-64bit` and `emscripten-1.35.0`. This means
that if you install this version of the SDK, both python and node.js will be
installed inside emsdk as well. If you want to use your own/system python or
node.js instead, you can opt to install emsdk by specifying the individual set
of packages that you want to use. For example, `emsdk install
clang-e1.35.0-64bit emscripten-1.35.0` will only install the Emscripten
LLVM/Clang compiler and the Emscripten frontend without supplying python and
node.js.

### My installation fails with "fatal error: ld terminated with signal 9 [Killed]"?

This may happen if the system runs out of memory. If you are attempting to build
one of the packages from source and are running in a virtual OS or may have
relatively little RAM and disk space available, then the build might fail. Try
feeding your computer more memory. Another thing to try is to force emsdk
install to build in a singlethreaded mode, which will require less RAM
simultaneously. To do this, pass the `-j1` flag to the `emsdk install` command.

### How do I run Emscripten on 32-bit systems or non-x86-64 systems?

Emscripten SDK releases are no longer packaged or maintained for 32-bit systems.
If you want to run Emscripten on a 32-bit system, you can try manually building
the compiler. Follow the steps in the above section "Building an Emscripten tag
or branch from source" to get started.
Loading