Open-source project
HaxeFoundation/hashlink avatar
HaxeFoundation/hashlink

HashLink: building the Haxe virtual machine from source

A virtual machine for Haxe

908 stars204 forksCMIT

At a glance

What is it?
HashLink is the virtual machine that executes Haxe bytecode, written in C and released under the MIT licence. It ships as a core runtime plus loadable .hdll modules, and building it yourself means pulling in SDL3, mbedTLS, OpenAL and a static PCRE2.
Who is it for?
HashLink suits engineers who need to run Haxe output on a machine they control, or who need a runtime tailored to their own desktop, audio and database dependencies. It is a poor fit for teams expecting a one command install, since the build path requires system development packages and, for SDL3, a manual source compile.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 1 day ago.
What is it written in?
Mainly C, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.

Editorial analysis

HashLink executes Haxe bytecode, it does not compile Haxe

HashLink is a virtual machine for Haxe. The primary language of the repository is C, and the licence field on the repository says MIT, so the code can be inspected, patched and redistributed under normal MIT terms. That is the whole scope of the project: it is a runtime, not a compiler. The Haxe compiler produces bytecode, and HashLink is the piece that loads that bytecode, manages its memory, resolves calls into the standard library, and hands work to the operating system underneath.

The practical audience is narrow and specific. If you write Haxe and want the result to run as a native binary rather than as JavaScript on a browser, HashLink is the execution layer you need. Teams that want their own desktop application, their own tool, or their own server process with predictable startup and native library access tend to land here. The project pages point at https://hashlink.haxe.org/ for general information, and the documentation itself lives in the repository wiki rather than in the README, which is a reasonable hint about where the detail actually is.

One thing to keep in mind before going further. The repository does not present a package manager route for most platforms. What it presents is a source build, and a Makefile whose behaviour is the deciding factor in most of the sections below.

The Makefile splits HashLink into a core library and loadable .hdll modules

Understanding the layout saves time later. The Makefile compiles a library called libhl, and then a set of optional features that are each emitted as a separate .hdll module. The module list is fixed in the Makefile:

code
LIBS = $(addsuffix .hdll,fmt sdl ssl openal ui uv mysql sqlite heaps)

So a build produces modules for image formats, SDL, TLS, OpenAL, a UI layer, libuv, MySQL, SQLite and the heap module. The runtime link line for the core library is small, with only the math and threading libraries attached:

code
LIBHL_LDLIBS = -lm -lpthread

That separation is the important design fact. Optional capabilities are not compiled into the core runtime unconditionally, they are separate shared objects, which means a deployment only needs the modules for the features an application touches. The README also says that you can manually disable the libraries you want to compile in the Makefile, so a headless server build can drop SDL, OpenAL and the UI module instead of dragging in a full desktop graphics stack.

The C compilation itself uses a conservative, modern baseline:

code
CFLAGS = -Wall -O3 -std=c11 -fvisibility=hidden -MMD -MP

Note the hidden default visibility. Symbols that are not meant to be part of the public surface stay internal to the library, and the explicit export list lives elsewhere in the project rather than being inferred by the compiler.

Linux and macOS builds start with a dependency list that decides your feature set

On Linux and macOS the build is a Makefile flow, and everything before `make` is dependency installation. The project groups the libraries by the feature they enable, and the Ubuntu example installs them all at once:

code
sudo apt-get install libpng-dev libturbojpeg-dev libvorbis-dev libopenal-dev libsdl3-dev libglu1-mesa-dev libmbedtls-dev libuv1-dev libsqlite3-dev

The Fedora path uses the equivalent package names in a different packaging system:

code
sudo dnf install libpng-devel turbojpeg-devel libvorbis-devel openal-soft-devel SDL3-devel mesa-libGLU-devel mbedtls-devel libuv-devel  sqlite-devel

On macOS the project points at a Brewfile committed to the repository and installs the list with a single command:

code
brew bundle

Once the dependencies are present, the build itself is short:

code
make

Install targets follow the same pattern, and the default prefix is the usual Unix one, which the Makefile states directly:

code
PREFIX ?= /usr/local

The two install commands are separate from the build, and the macOS codesign step is a distinct third one, which is worth reading carefully. The README says that to use the hashlink binary with the debugger you can call:

code
sudo make codesign_osx

That step exists because debugging needs the binary to carry a signature the system will accept. If you skip it, the debugger integration described below is not going to behave as intended on macOS.

SDL3 has to be compiled from source on Linux, which is the rough edge of the build

This is the part of the build that most often turns into an afternoon. The dependency list includes libsdl3-dev, and the README states plainly that this package is not released yet, so a build from source is needed, with a link to the SDL wiki for the Linux notes. The documented sequence is:

code
wget https://github.com/libsdl-org/SDL/releases/download/release-3.4.10/SDL3-3.4.10.tar.gz
tar -xzvf SDL3-3.4.10.tar.gz
cd SDL3-3.4.10/
mkdir build
cd build
cmake ..
make
sudo make install

Two consequences follow. First, any machine without network access to that release archive cannot reproduce the documented setup without sourcing the archive by hand. Second, the sdl module is the reason the graphics dependency set exists at all, and the graphics set in turn drags in mesa, X11, pulse audio and a long tail of dev packages listed in the build snippet, including libgl1-mesa-dev, libegl1-mesa-dev, libibus-1.0-dev and libthai-dev. The full toolchain line is:

code
sudo apt-get install build-essential git make pkg-config cmake ninja-build gnome-desktop-testing libasound2-dev libpulse-dev libaudio-dev libfribidi-dev libjack-dev libsndio-dev libx11-dev libxext-dev libxrandr-dev libxcursor-dev libxfixes-dev libxi-dev libxss-dev libxtst-dev libxkbcommon-dev libdrm-dev libgbm-dev libgl1-mesa-dev libgles2-mesa-dev libegl1-mesa-dev libdbus-1-dev libibus-1.0-dev libudev-dev libthai-dev libusb-1.0-0-dev

For older systems the README points to a separate note, including a specific issue for 16.04 users. The honest conclusion: HashLink is straightforward to build once the dependencies exist, and genuinely awkward to bootstrap from a bare Linux image.

Windows developers work inside hl.sln in Visual Studio C++

The Windows path abandons the Makefile entirely. The repository root contains hl.sln together with hl.vcxproj, libhl.vcxproj and the matching filters files, and the README says to open hl.sln using Visual Studio C++ and compile.

Building the full set of libraries requires more than the solution file provides. The README says each library has its own README under hashlink/libs/xxx/README.md with additional information, and summarises what is probably required. Two downloads are named with exact versions, the SDL3 3.4.10 Visual C++ package at https://github.com/libsdl-org/SDL/releases/download/release-3.4.10/SDL3-devel-3.4.10-VC.zip and the openal-soft 1.23.1 binary archive at https://github.com/kcat/openal-soft/releases/download/1.23.1/openal-soft-1.23.1-bin.zip. The SDL3 package is extracted to the include/sdl folder in the hashlink tree and the openal-soft archive to include/openal. The destination folders matter because the build looks for those include trees, so unpacking them somewhere else produces a project that configures but fails to link. Unlike the Unix path, there is no documented per library toggle in the Visual Studio projects, so trimming the build to a subset of modules is easier on Linux and macOS than on Windows.

WITH_SYSTEM_PCRE2 trades the bundled regex engine for the platform one

The Makefile carries an internal decision that has real consequences for distributions, and it is the one genuine alternative approach visible in the build. Regular expression support is provided by PCRE2, and the Makefile can either compile a copy bundled in the repository or link the one already present on the system:

code
PCRE_CPPFLAGS = -D PCRE2_CODE_UNIT_WIDTH=16
code
ifdef WITH_SYSTEM_PCRE2
LIBHL_LDLIBS += -lpcre2-16

Without the flag, the build compiles the bundled sources under include/pcre with PCRE2_STATIC defined, roughly two dozen object files. With the flag, the runtime links against the system library and the bundled tree is not compiled at all. The 16 bit code unit width is fixed in either case.

For teams that ship HashLink inside a managed Linux distribution, the system route removes a chunk of vendored source from the build and lets the platform maintain the regex engine. The bundled route removes the dependency on a matching PCRE2 being present. Either is defensible, but you have to pick one deliberately, and the default is the static bundled build.

No competing Haxe runtime is named in the repository, so the comparison available here is a build level one rather than a feature level one. Any claim that a different runtime is faster or easier to integrate cannot be traced to this project.

Debugging runs through the HaxeFoundation.haxe-hl Visual Studio Code extension

Debugging a Haxe program on HashLink is handled by an editor extension rather than by a debugger built into the project. The README points at the Visual Studio Code Debugger, the marketplace item HaxeFoundation.haxe-hl.

That division of labour is worth understanding before you adopt HashLink. The runtime provides the hooks, the extension provides the user interface, and on macOS the binary has to be signed first with the codesign target shown earlier, otherwise the debugger cannot attach to it. The project also maintains a wiki for the documentation, and that wiki rather than the README is where the deeper guidance is expected to live.

If your workflow depends on stepping through code in a familiar editor, this is a working path. If your workflow depends on remote attaching, on a specific debugger, or on profiling instrumentation, the project does not describe those workflows, and you would be extending the build yourself.

Nightly builds sit ahead of the tagged releases, and the last push was on 2026-10-16

The repository is not archived, and the last push was on 2026-10-22, so the project is receiving commits. The release list shows a rolling channel alongside numbered versions: a HashLink Nightly Build dated 2026-10-14, then HashLink 1.16 dated 2026-08-03, then HashLink 1.15 dated 2025-03-23.

That ordering tells you how to pick a download. The numbered releases are the ones with a stable name attached, while the nightly build is what the master branch produces continuously, and the gap between the nightly date and the last push date shows the nightly is generated close to the tip of the branch rather than months behind it. Whether the nightly or the tagged release suits you depends on whether you can tolerate a moving target.

The version distance between 1.15 and 1.16 is about a year and a half, with a nightly published after it, which tells you the project is not on a frequent release cadence. For a runtime that sits underneath an application, that is a reasonable trade, but it does mean you are picking between a well identified tag and a frequently changing build. Neither the README nor the repository listing documents a rollback procedure for the runtime, so treat the tagged release as the safe reference point when you need a reproducible build.

Editorial conclusion

HashLink suits engineers who need to run Haxe output on a machine they control, or who need a runtime tailored to their own desktop, audio and database dependencies. It is a poor fit for teams expecting a one command install, since the build path requires system development packages and, for SDL3, a manual source compile. Before adopting it, verify that your target platform can satisfy the dependency list, that the module set in the Makefile matches the features your application actually calls, and that the release tag you pick still matches the Haxe compiler version you build against.

Frequently asked questions

What is HashLink and what language is it written in?

HashLink is a virtual machine for Haxe, and it is written in C. The licence field on the repository says MIT, so it can be used, modified and redistributed under those terms.

How do I build HashLink on Linux or macOS?

Install the listed development dependencies first, then run make in the repository. On macOS the dependency list is installed with brew bundle, and the README notes that libsdl3-dev is not released yet, so SDL3 has to be built from source.

Which optional features does HashLink provide as separate modules?

The Makefile builds fmt, sdl, ssl, openal, ui, uv, mysql, sqlite and heaps as separate .hdll modules. The README also says you can manually disable the libraries you do not want to compile.

Can I use the system PCRE2 instead of the bundled one?

Yes, by defining WITH_SYSTEM_PCRE2, which adds -lpcre2-16 to the library link line and stops the bundled sources under include/pcre from being compiled. The code unit width stays fixed at 16 bits.

How do I debug a Haxe program running on HashLink?

The README points at the Visual Studio Code Debugger extension, HaxeFoundation.haxe-hl. On macOS the hashlink binary has to be signed first using the codesign_osx make target for the debugger to work with it.

Official sources

  1. HaxeFoundation/hashlink on GitHub
  2. License: MIT
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/haxefoundation-hashlink.svg)](https://hysenlabs.com/projects/haxefoundation-hashlink)

Was this useful?