Ymir requires CMake 3.28+ and a C++20 compiler.
The repository includes several vendored dependencies as Git submodules. When cloning, make sure to include the --recurse-submodules parameter.
You can also initialize submodules with git submodule update --init --recursive after a git clone or when pulling changes.
Ymir has been successfully compiled with the following toolchains:
- Visual Studio 2022's Clang 19.1.5
- Visual Studio 2022's MSVC 19.44.35213.0
- Visual Studio 2026's Clang 20.1.8
- Visual Studio 2026's MSVC 19.50.35724.0
- Clang 15.0.7 on WSL Ubuntu 24.04.5 LTS (
clang-15/clang++-15) - Clang 18.1.3 on WSL Ubuntu 24.04.5 LTS (
clang/clang++) - Clang 19.1.1 on Ubuntu 24.04.2 LTS (
clang-19/clang++-19) - GCC 14.2.0 on Ubuntu 24.04.2 LTS (
gcc-14/g++-14) - Clang 19.1.7 on FreeBSD 14.3-RELEASE (
clang19/clang++19) - Clang 21.1.0 on FreeBSD 14.3-RELEASE (
clang21/clang++21) - Apple Clang 17 on macOS 15 Sequoia
The project has been compiled for x86_64 and ARM64 Windows, Linux, FreeBSD and macOS platforms.
Clang is the preferred compiler for its multiplatform support and excellent code generation. Ymir requires Clang 15 or later. Ninja is the preferred build system for its speed and feature support. Makefiles are also acceptable.
You can tune the build with following CMake options:
Ymir_AVX2(BOOL): Set toONto use AVX2 extensions (on x86_64 platforms only).OFFuses the platform's default instruction set, typically SSE2. ARM64 platforms will always use NEON. Disabled by default.Ymir_ENABLE_TESTS(BOOL): Includes the unit test project in the build. Enabled by default if this is the top level CMake project.Ymir_ENABLE_SANDBOX(BOOL): Includes the sandbox project in the build. Enabled by default if this is the top level CMake project.Ymir_ENABLE_YMDASM(BOOL): Includes the disassembly tool project in the build. Enabled by default if this is the top level CMake project.Ymir_ENABLE_IPO(BOOL): Enables interprocedural optimizations (also called link-time optimizations) on all projects. Enabled by default.Ymir_ENABLE_DEVLOG(BOOL): Enables logs meant to aid development. Enabled by default.Ymir_ENABLE_DEV_ASSERTIONS(BOOL): Enables development assertions, meant to mark code as incomplete or for potential bugs. Disabled by default.Ymir_ENABLE_IMGUI_DEMO(BOOL): Enables the ImGui demo window, useful as a reference when developing new UI elements. Enabled by default.Ymir_ENABLE_UPDATE_CHECKS(BOOL): Enables automatic update checks and onboarding process. Enabled by default.Ymir_EXTRA_INLINING(BOOL): Enables more aggressive inlining, which slows down the build in exchange for better runtime performance. Only applies to Clang, which handles heavy inlining much better than GCC or MSVC. Disabled by default.Ymir_PGO(STRING): PGO mode. Valid values areOFF,GENERATE,USE. Defaults toOFF.Ymir_PGO_DIR(PATH): Directory where PGO profile data is written. Defaults to${CMAKE_BINARY_DIR}/pgo-profdata.Ymir_PGO_PROFDATA(FILEPATH): Merged LLVM PGO profile data path. Defaults to${Ymir_PGO_DIR}/ymir.profdata.Ymir_LIBRARY_ONLY(BOOL): Compilesymir-coreonly, for use as a subproject in another CMake project. Defaults toONif included as subproject,OFFotherwise.
These options are used by the build workflows to tune the build output:
Ymir_DEV_BUILD(BOOL): Create a development build. This affects the versioning scheme (-devsuffix added, "(development build)" added to About window) and availability of development-friendly features (e.g. disabled automatic update checks). Enabled by default, and should probably not be disabled unless you're checking behavior of stable and nightly builds.
Ymir also supports feature flags. These are enabled by default on development and nightly builds:
Ymir_FEATUREFLAG_DEFAULT(BOOL): Enables or disables all non-overridden feature flags. Enabled by default on development builds.Ymir_FF_HOST_CD_DRIVES(BOOL): Enables support for reading discs from host CD drives (physical or virtual). Disabled by default, including development and nightly builds.
Feature flags are made available to code as macros in ymir-core's CMakeLists.txt (find ## Define feature flags macros).
If you add new feature flags, make sure to add the macro to this file too.
Depending on the target build system, you might have to specify CMAKE_BUILD_TYPE for Release builds, otherwise CMake defaults to slow Debug builds.
This option can be set to one of these values (see docs):
Debug: an unoptimized Debug build, with debug assertions and no inlining. Ideal for deep code debugging, but very slow.Release: optimized Release build without debug symbols. Best used for stable and nightly builds. Probably not useful for development.RelWithDebInfo: same asRelease, but includes debug symbols. Great for general development, but the optimizations and inlining might get in the way of debugging.MinSizeRel: a Release build that is optimized for code size. Not very useful since we're not targeting memory-constrained systems.
For a Release build, you might want to disable the devlog and ImGui demo window and enable extra inlining to maximize performance and reduce the binary size.
It is highly recommended to use Ninja as it greatly accelerates the build process, especially on machines with high CPU core counts.
To build Ymir on Windows, you will need Visual Studio 2022 Community or later and CMake 3.28+. Clang is highly recommended over MSVC as it produces much higher quality code, outperforming MSVC by 50-80%. However, MSVC tends to provide a better debugging experience.
You may also want to install the Vulkan SDK. You can do so by downloading and running the installer or with the following command:
winget install KhronosGroup.VulkanSDKVulkan is an optional dependency on Windows as Ymir always supports Direct3D 12 and 11 on this operating system.
All other dependencies are included through vcpkg and in the vendor directory, and are built together with the emulator.
The core library does not consume any vcpkg dependencies.
You can choose to generate a .sln file with CMake or open the directory directly with Visual Studio. Both methods work, but opening the directory allows Visual Studio to use Ninja for significantly faster build times. If you choose to generate the .sln file, you will need to specify the vcpkg toolchain:
cmake -DCMAKE_TOOLCHAIN_FILE=vcpkg/scripts/buildsystems/vcpkg.cmakeYmir uses custom Windows triplets to ensure all libraries are statically linked when possible. You can find the overridden triplets in the vcpkg-triplets folder.
To build Ymir on Linux, first you will need to install SDL3's required dependencies. Follow the instructions on this page to install them. You might also have to install additional packages:
autoconf autoconf-archive automake libtoolfor ALSApython3 python3-venvfor dbus
Vulkan is an optional dependency which enables GPU-accelerated VDP1/VDP2 rendering. For that reason, it is highly recommended to install the Vulkan SDK.
If compiled with support for Vulkan, your system must also provide dxc or glslc (shaderc's CLI tool) to allow Ymir to compile shaders offline. Both tools are usually included with the SDK.
DXC is preferred over shaderc due to better support for more modern features.
You can opt to install the Vulkan dependencies from your system's package manager instead of the SDK. For example, on Ubuntu: libvulkan-dev vulkan-tools vulkan-validationlayers spirv-tools-dev glslc glslang-tools.
The compiler of choice for this platform is Clang. GCC is also supported, but produces slightly slower code.
Use CMake to generate a Makefile or (preferably) a Ninja build script:
cmake -S . -B build -G Ninja -DCMAKE_TOOLCHAIN_FILE=vcpkg/scripts/buildsystems/vcpkg.cmakePass additional -D<option>=<value> parameters to tune the build. See the Build configuration section above for details.
CMAKE_BUILD_TYPE defaults to Debug. Use -DCMAKE_BUILD_TYPE=RelWithDebInfo for a Release build with debug symbols.
You can use CMake to build the project, regardless of generator:
cmake --build build --parallelInstall required packages:
pkg install cmake evdev-proto git gmake libX11 libXcursor libXext libXfixes libXi \
libXrandr libXrender libXScrnSaver libXtst libglvnd libinotify llvm19 ninja patchelf \
pkgconf python3 vulkan-loader zip glslang shaderc vulkan-headersNotes:
- A default FreeBSD installation provides a stripped-down LLVM toolchain which lacks
the required
clang-scan-depsbinary. Therefore it is necessary to install a complete LLVM toolchain package, e.g.llvm19. - The usage of CMake's "Precompile Headers" feature triggers a compiler bug in LLVM
prior to version 21 for ARM64 builds on FreeBSD. Therefore it is necessary to install
and use at least
llvm21for ARM64.
Configure build:
CXX=clang++19 \
CC=clang19 \
cmake -S . -B build -G Ninja -DCMAKE_TOOLCHAIN_FILE=vcpkg/scripts/buildsystems/vcpkg.cmakeNotes:
- By default vcpkg and CMake will use the stripped-down LLVM toolchain instead of
the previously installed complete toolchain. Therefore it is necessary to set
the
CXXandCCenvironment variables to the correct compilers.
Pass additional -D<option>=<value> parameters to tune the build. See the Build configuration section above for details.
Build:
cmake --build build --parallelYmir uses SDL3's Dialog API. This requires an installed dialog driver in order for the file dialogs to work in Ymir. Install Zenity:
pkg install zenityUse CMake to generate a Makefile or (preferably) a Ninja build script:
cmake -S . -B build -G Ninja -DCMAKE_TOOLCHAIN_FILE=vcpkg/scripts/buildsystems/vcpkg.cmakePass additional -D<option>=<value> parameters to tune the build. See the Build configuration section above for details.
CMAKE_BUILD_TYPE defaults to Debug. Use -DCMAKE_BUILD_TYPE=RelWithDebInfo for a Release build with debug symbols.
You can use CMake to build the project, regardless of generator:
cmake --build build --parallelAfter building, you will find the .app bundle at:
build/apps/ymir-sdl3/ymir-sdl3.appPGO is supported for Clang/AppleClang and GCC (MSVC PGO may be added in future releases). Use a two-phase build: first generate profile data, then rebuild using that data.
With the project opened as a folder:
- Select the Full x86-64 [arch] Clang Release/Dist (PGO Generate) target.
- Build and run a representative workload. This will produce a
.profrawfile inout\pgo-profdata\windows\x86_64-[arch]. - In the Solution Explorer view, switch to the CMake Targets view. You can also find it in the View menu.
- Build the
ymir-pgo-mergeutility target. This will combine the.profrawfiles intoymir.profdata. - Select the Full x86-64 [arch] Clang Release/Dist (PGO Use) target.
- Build and run. This build will use profile-guided optimization with the profiling data you acquired from the previous run.
-
Launch the x64 Native Tools Command Prompt for VS 2022/2026.
-
Generate an instrumented build:
cmake -S . -B build-pgo-gen -G Ninja ^ -DCMAKE_BUILD_TYPE=Release ^ -DCMAKE_TOOLCHAIN_FILE=vcpkg/scripts/buildsystems/vcpkg.cmake ^ -DYmir_PGO=GENERATE cmake --build build-pgo-gen --parallel
-
Run a representative workload and emit
.profrawinto the PGO directory:set LLVM_PROFILE_FILE="%CD%\build-pgo-gen\pgo-profdata\ymir_%p.profraw" .\build-pgo-gen\apps\ymir-sdl3\ymir-sdl3
-
Merge the raw profiles using the CMake target:
cmake --build build-pgo-gen --target ymir-pgo-merge
Or manually with
llvm-profdata:llvm-profdata merge ^ -o "%CD%\build-pgo-gen\pgo-profdata\ymir.profdata" ^ "%CD%\build-pgo-gen\pgo-profdata"\*.profraw
-
Build using the merged profile:
cmake -S . -B build-pgo-use -G Ninja -DCMAKE_BUILD_TYPE=Release ^ -DYmir_PGO=USE ^ -DYmir_PGO_PROFDATA="%CD%\build-pgo-gen\pgo-profdata\ymir.profdata" cmake --build build-pgo-use --parallel
-
Generate an instrumented build:
Linux
cmake -S . -B build-pgo-gen -G Ninja \ -DCMAKE_BUILD_TYPE=Release \ -DCMAKE_TOOLCHAIN_FILE=vcpkg/scripts/buildsystems/vcpkg.cmake \ -DYmir_PGO=GENERATE cmake --build build-pgo-gen --parallelmacOS
cmake -S . -B build-pgo-gen -G Ninja \ -DCMAKE_BUILD_TYPE=Release \ -DCMAKE_TOOLCHAIN_FILE="$PWD/vcpkg/scripts/buildsystems/vcpkg.cmake" \ -DYmir_PGO=GENERATE cmake --build build-pgo-gen --parallel
-
Run a representative workload and emit
.profrawinto the PGO directory:export LLVM_PROFILE_FILE="$PWD/build-pgo-gen/pgo-profdata/ymir_%p.profraw" ./build-pgo-gen/apps/ymir-sdl3/ymir-sdl3
-
Merge the raw profiles using the CMake target:
cmake --build build-pgo-gen --target ymir-pgo-merge
Or manually with
llvm-profdata:llvm-profdata merge \ -o "$PWD/build-pgo-gen/pgo-profdata/ymir.profdata" \ "$PWD/build-pgo-gen/pgo-profdata"/*.profraw
-
Build using the merged profile:
Linux
cmake -S . -B build-pgo-use -G Ninja -DCMAKE_BUILD_TYPE=Release \ -DYmir_PGO=USE \ -DYmir_PGO_PROFDATA="$PWD/build-pgo-gen/pgo-profdata/ymir.profdata" cmake --build build-pgo-use --parallel
macOS
cmake -S . -B build-pgo-use -G Ninja -DCMAKE_BUILD_TYPE=Release \ -DCMAKE_TOOLCHAIN_FILE="$PWD/vcpkg/scripts/buildsystems/vcpkg.cmake" \ -DYmir_PGO=USE \ -DYmir_PGO_PROFDATA="$PWD/build-pgo-gen/pgo-profdata/ymir.profdata" cmake --build build-pgo-use --parallel
-
Generate an instrumented build:
cmake -S . -B build-pgo-gen -DCMAKE_BUILD_TYPE=Release -DYmir_PGO=GENERATE cmake --build build-pgo-gen --parallel -
Run a representative workload to emit
.gcdadata intobuild-pgo-gen/pgo-profdata/gcc:./build-pgo-gen/apps/ymir-sdl3/ymir-sdl3
Profiles will appear in the subdirectory tree, not flat.
-
Build using the generated profiles (point the use build at the generate build directory):
cmake -S . -B build-pgo-use -DCMAKE_BUILD_TYPE=Release \ -DYmir_PGO=USE \ -DYmir_PGO_DIR="$PWD/build-pgo-gen/pgo-profdata" cmake --build build-pgo-use --parallel
When Ymir is included as a subproject inside another CMake project, it automatically sets Ymir_LIBRARY_ONLY=ON, which
reconfigures the project to only build the ymir::ymir-core static library target without using vcpkg.
The easiest ways to use Ymir as a library are to include it as a Git submodule or by using CMake's FetchContent.
Whatever method is used, be patient -- Ymir includes several large Git submodules that can take some time to download.
Important
Before v0.3.2, Ymir did not offer the option to build the core library alone and required vcpkg to work. You will not be able to use older versions of the emulator as a library in this manner without a ton of headaches due to the combined use of vcpkg integration and Git submodules as dependencies.
Version 0.3.2 fixes this by offering the Ymir_LIBRARY_ONLY option explained above.
It is recommended to keep your vendored dependencies in a subdirectory of your repository, usually called vendor or
third_party. Inside it, run these commands:
git submodule add https://github.com/StrikerX3/Ymir.git
git submodule update --init --recursiveOnce that is done, adding Ymir to your project is as simple as adding these instructions to your CMakeLists.txt:
add_subdirectory(vendor/Ymir)
target_link_libraries(your-target PRIVATE ymir-core)With this method, you can easily keep your dependency up-to-date by git pulling the latest commit from within the
Ymir subdirectory. This method also lets you tinker with the emulator's source code at any time.
With FetchContent, the Git cloning process is automated by CMake. Add these instructions to your CMakeLists.txt:
include(FetchContent)
FetchContent_Declare(
ymir
GIT_REPOSITORY https://github.com/StrikerX3/Ymir
GIT_TAG v0.3.2 # ideally, a specific tag or commit, but `main` also works
)
FetchContent_MakeAvailable(ymir)To link your target against Ymir:
add_subdirectory(vendor/Ymir)
target_link_libraries(your-target PRIVATE ymir-core)With this option, you cannot modify Ymir's source code. Additionally, the dependency is recursively cloned for each build configuration you use, which could waste disk space.