Building JaiScript into a Host
JaiScript has no dependencies and compiles with your program: add its sources, its include folder and a few compiler settings. This page gives each route in full: CMake, Visual Studio's MSBuild, Xcode and an installed package. The quickstart has the short version.
What every build needs
| Setting | Value | Why |
|---|---|---|
| Sources | source/jaiscript.cpp, or every .cpp under source/implementation/ (never both) | One file or per file |
| Include path | include/ | headers are included as <jaiscript/...> |
| Language standard | C++20 | |
| Exceptions and RTTI | required, in the library and in every file that includes its headers. Both are every compiler's default; a project built with -fno-exceptions, -fno-rtti or /GR- cannot host JaiScript. | errors reach the host as exceptions, and bound classes are matched by type |
| MSVC | /bigobj, in your files that bind classes as well as the library's; /EHsc and /permissive- (a new project's defaults) | the binder's templates overflow the default object-file section limit |
| MinGW GCC | -Wa,-mbig-obj | the COFF counterpart of /bigobj |
| GCC and Clang | -ffp-contract=off | stops a*b+c fusing into one instruction, so floating-point results match on every platform |
| Windows libraries | ws2_32 and bcrypt | the debugger's sockets and the random source behind crypto::. MSVC and clang-cl pick them up from the source; a GNU linker needs them named. |
Define JAISCRIPT_ENABLE_DEBUGGER | optional; for every file or none | compiles in the debugger's socket transport (below) |
Define JAISCRIPT_INTERPRETER | optional; for every file or none | adds the tree-walking interpreter (below) |
Compile JaiScript's files with the same settings as yours: the same runtime library, the same
NDEBUG, the same defines. NDEBUG and the diagnostic builds
(JAISCRIPT_DIAG_ATOMIC_RC, JAISCRIPT_DIAG_XTHREAD_RC, JAISCRIPT_VM_COVERAGE) change
class layouts, so a mismatch fails to link: MSVC reports LNK2038: mismatch detected for
'jaiscript_build_config', and GCC and Clang an undefined
jai::detail::build_config_debug1_atomic_rc0_xthread_rc0_coverage0 (or the like) naming the configuration
the library was not built with.
The debugger define
JAISCRIPT_ENABLE_DEBUGGER compiles the debugger's TCP listener. Compiled
in, it still opens no socket until the host calls jai::debug::listen.
| Build | Default | To change it |
|---|---|---|
| CMake | on: the option JAISCRIPT_ENABLE_DEBUGGER defaults to ON and defines the macro for the library and for every target that links it | -DJAISCRIPT_ENABLE_DEBUGGER=OFF for shipping and mobile builds: no socket code is compiled, and constructing a connector is a link error |
| MSBuild, Xcode, your own build | off: nothing defines it | add the define to every file, in development configurations only |
Platforms
The library is verified with MSVC 19.51 (Visual Studio 18), Clang 20 and GCC 16. Its continuous integration builds and runs the full test suite, the differential fuzzer and the example hash gates, in Debug and Release, on:
| Platform | Compiler |
|---|---|
| Windows x64 (Visual Studio 2026 image) | MSVC, and clang-cl against the MSVC standard library |
| Linux x64 (Ubuntu 24.04) | GCC 14, and Clang (also under ASan and UBSan) |
| macOS 15, Apple silicon | AppleClang; a second job builds with the Xcode generator and runs the VM suite |
Two more targets are checked by gates in tools/ci/gates.sh that run where their SDK is installed, not in
CI: android cross-compiles the library and its suites with the NDK for arm64-v8a and 32-bit armeabi-v7a
(libc++), and wasm builds the engine with Emscripten (a 32-bit target) and runs the example games under
Node to the native builds' hashes.
One file or per file
source/jaiscript.cppincludes every implementation file: one file adds the whole library, which compiles once and stays built. The default when you use JaiScript unchanged.source/implementation/**/*.cppis the same library as about fifty units. Use it, with parallel compilation on (MSBuild's/MP; Ninja and Xcode by default), when you work on JaiScript itself: an edit rebuilds one file.
CMake
The library is the target JaiScript::jaiscript; linking it brings every setting above. Put the JaiScript
folder inside your project (a copy elsewhere takes a binary directory too:
add_subdirectory(path/to/JaiScript jaiscript)). As a subproject only the library builds, and its MSVC
runtime follows yours.
cmake_minimum_required(VERSION 3.20)
project(my_game CXX)
add_subdirectory(JaiScript)
add_executable(my_game main.cpp)
target_link_libraries(my_game PRIVATE JaiScript::jaiscript)Or fetch it at configure time:
include(FetchContent)
FetchContent_Declare(jaiscript GIT_REPOSITORY https://github.com/Devacor/jaiscript.git GIT_TAG v0.5.2)
FetchContent_MakeAvailable(jaiscript)
target_link_libraries(my_game PRIVATE JaiScript::jaiscript)Options, set before add_subdirectory or FetchContent_MakeAvailable, or with -D:
| Option | Standalone / subproject | Builds |
|---|---|---|
JAISCRIPT_BUILD_RUNNER, JAISCRIPT_BUILD_TESTS, JAISCRIPT_BUILD_EXAMPLES, JAISCRIPT_BUILD_LSP, JAISCRIPT_BUILD_SPIDER | on / off | the runner, the test suite, the examples, the language server, jai_spider |
JAISCRIPT_INTERPRETER | on / off | the jaiscript_interpreter target |
JAISCRIPT_INSTALL | on / off | the install rules and the CMake package |
JAISCRIPT_LTCG | on / off | MSVC whole-program optimization for Release (/GL, /LTCG) |
JAISCRIPT_ENABLE_DEBUGGER | on / on | the debugger's socket transport |
Visual Studio (MSBuild)
New to Visual Studio? Visual Studio, Step by Step goes from a fresh install to a running program, with the errors a missed step gives.
In the IDE. Add JaiScript\source\jaiscript.cpp to the project. In its Properties, for All
Configurations, under C/C++:
| Property | Value |
|---|---|
| General → Additional Include Directories | $(SolutionDir)JaiScript\include |
| Language → C++ Language Standard | ISO C++20 (/std:c++20); Conformance mode Yes (/permissive-) |
| Command Line → Additional Options | /bigobj |
| Code Generation → Enable C++ Exceptions | Yes (/EHsc), the default |
| Preprocessor → Preprocessor Definitions | JAISCRIPT_ENABLE_DEBUGGER, for VS Code attach |
For the per-file route add the .cpp files under JaiScript\source\implementation instead and
set General → Multi-processor Compilation to Yes.
In a property sheet. The same settings in one file a project imports. Save it beside your project as
jaiscript.props:
<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<JaiScriptDir Condition="'$(JaiScriptDir)'==''">$(MSBuildThisFileDirectory)JaiScript\</JaiScriptDir>
<JaiScriptPerFile Condition="'$(JaiScriptPerFile)'==''">false</JaiScriptPerFile>
</PropertyGroup>
<ItemDefinitionGroup>
<ClCompile>
<AdditionalIncludeDirectories>$(JaiScriptDir)include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<LanguageStandard>stdcpp20</LanguageStandard>
<ConformanceMode>true</ConformanceMode>
<ExceptionHandling>Sync</ExceptionHandling>
<AdditionalOptions>/bigobj %(AdditionalOptions)</AdditionalOptions>
<PreprocessorDefinitions>JAISCRIPT_ENABLE_DEBUGGER;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
</ItemDefinitionGroup>
<ItemGroup Condition="'$(JaiScriptPerFile)'!='true'">
<ClCompile Include="$(JaiScriptDir)source\jaiscript.cpp" />
</ItemGroup>
<ItemGroup Condition="'$(JaiScriptPerFile)'=='true'">
<ClCompile Include="$(JaiScriptDir)source\implementation\**\*.cpp" />
</ItemGroup>
</Project>This sheet defines JAISCRIPT_ENABLE_DEBUGGER in every configuration; remove that line, or put a
configuration condition on it, for a shipping build. Import the sheet in the .vcxproj after
Microsoft.Cpp.props:
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<Import Project="jaiscript.props" />A Directory.Build.props can carry the ItemDefinitionGroup for every project in a folder;
keep the ClCompile items in the one project that compiles the library.
/p:JaiScriptPerFile=true /p:MultiProcessorCompilation=true on the msbuild command line selects
the per-file route.
Xcode
Add JaiScript/source/jaiscript.cpp to your target (or the files under
source/implementation/), then set in its Build Settings:
Build setting (.xcconfig name) | Value |
|---|---|
Header Search Paths (HEADER_SEARCH_PATHS) | $(SRCROOT)/JaiScript/include |
C++ Language Dialect (CLANG_CXX_LANGUAGE_STANDARD) | C++20 (c++20) |
C++ Standard Library (CLANG_CXX_LIBRARY) | libc++ (the default) |
Enable C++ Exceptions (GCC_ENABLE_CPP_EXCEPTIONS) | Yes (the default) |
Enable C++ Runtime Types (GCC_ENABLE_CPP_RTTI) | Yes (the default) |
Other C++ Flags (OTHER_CPLUSPLUSFLAGS) | $(inherited) -ffp-contract=off |
Preprocessor Macros (GCC_PREPROCESSOR_DEFINITIONS) | Release: NDEBUG=1. Add JAISCRIPT_ENABLE_DEBUGGER=1 to a desktop development build only. |
Xcode's Release configuration does not define NDEBUG. Add it to every target that
compiles JaiScript or includes its headers. Left out of all of them, the library's assertions stay on and cost speed;
left out of some, the link fails with the configuration mismatch above.
Debug and Release
- A Debug build checks the library's invariants with assertions and runs script many times slower. Measure Release
builds, which define
NDEBUG(automatic in CMake and Visual Studio). - MSVC whole-program optimization speeds the VM up a few percent and makes every Release link much slower.
- Deeply recursive scripts need native stack. The engine raises a catchable error instead of crashing when the stack runs low; a host thread that runs such scripts wants a larger stack than the platform default.
An installed package
Build and install once per configuration (Debug and Release share a prefix; the Debug library is
jaiscriptd):
cmake -S JaiScript -B build-jai -G Ninja -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/opt/jaiscript -DJAISCRIPT_LTCG=OFF -DJAISCRIPT_BUILD_TESTS=OFF -DJAISCRIPT_BUILD_EXAMPLES=OFF -DJAISCRIPT_BUILD_RUNNER=OFF -DJAISCRIPT_BUILD_SPIDER=OFF -DJAISCRIPT_BUILD_LSP=OFF
cmake --build build-jai
cmake --install build-jaicmake_minimum_required(VERSION 3.20)
project(my_game CXX)
find_package(JaiScript 0.5 CONFIG REQUIRED) # configure with -DCMAKE_PREFIX_PATH=/opt/jaiscript
add_executable(my_game main.cpp)
target_link_libraries(my_game PRIVATE JaiScript::jaiscript)
set_property(TARGET my_game PROPERTY MSVC_RUNTIME_LIBRARY "${JaiScript_MSVC_RUNTIME_LIBRARY}")- The last line matters on MSVC. A standalone JaiScript build uses the static runtime
(
/MT,/MTd) unless you passCMAKE_MSVC_RUNTIME_LIBRARY, and a CMake project defaults to the DLL runtime. The package records its runtime inJaiScript_MSVC_RUNTIME_LIBRARY; without the line the link fails withLNK2038: mismatch detected for 'RuntimeLibrary'. - The version must share its minor.
find_package(JaiScript 0.5)accepts any installed 0.5.z and refuses 0.6 (Stability). - From another build system, compile your files with the definitions the library was built with: its
runtime,
NDEBUGfor a Release library, andJAISCRIPT_ENABLE_DEBUGGERunless it was configured off.
The interpreter, for checking parity
The tree-walking interpreter (Backends) is the reference the VM is checked against.
Nothing a host runs needs it, so the library compiles the VM alone, and
set_backend(jai::backend_type::interpreter) throws set_backend(interpreter) is unsupported: this
build has no interpreter (link jaiscript_interpreter). A program that compares the backends adds it:
- CMake: link
JaiScript::jaiscript_interpreterinstead ofJaiScript::jaiscript. A standalone build's test suite, fuzzer, runner andjai_spiderlink it. - Other build systems: define
JAISCRIPT_INTERPRETERand add the files undersource/interpreter/, or define it forsource/jaiscript.cpp, which then includes them.
The runner, for trying scripts
cmake -S JaiScript -B build -G Ninja -DCMAKE_BUILD_TYPE=Release
cmake --build build --target jaiscript_runner
build/bin/jaiscript hello.jai # run a file; no argument starts a REPL
build/bin/jaiscript --backend=interp --warnings hello.jaiThe runner registers the standard library plus file and console functions, runs on the VM, and lifts the execution
budget (--budget=N puts one back).
The headers a host includes
#include <jaiscript/core/engine.hpp> // engine, script_value, the error types
#include <jaiscript/core/dynamic_binder.hpp> // dynamic_binder, convert_script_function
#include <jaiscript/stdlib/stdlib.hpp> // jai::stdlib::register_all
#include <jaiscript/serialization/convenience.hpp> // jai::to_json / from_json / to_binary / from_binary
#include <jaiscript/core/engine_time.hpp> // eng->time(): the clock scripts read
#include <jaiscript/debug/connector.hpp> // jai::debug::listen (VS Code attach)<jaiscript/jaiscript.hpp> pulls the core, the binder and the archives in one include (not the
standard library).