This describes the native shared library built from src/ffishdll.cpp. It exposes a C ABI, making it easy to consume from C, C++, Rust, Python (ctypes), C#, etc., on both Linux and Windows (MinGW).
- Move generation and legality checking for all variants enabled by Fairy-Stockfish.
- FEN parsing/validation, SAN conversion, result detection, pockets/hand pieces, variant metadata.
- Uses the same variant definitions as the engine (
variants.inican be loaded at runtime). - No Emscripten; pure native GCC/Clang/MinGW build.
From src/:
# Linux / macOS (produces libffish.so)
make -f Makefile_dll
# Windows with MinGW (produces ffish.dll)
make -f Makefile_dll EXE=ffish.dll
Notes:
- The makefile adds
-DNNUE_EMBEDDING_OFFso it does not embed an NNUE file. If you want NNUE embedded, remove that flag and ensure the .nnue is available. - It builds with
-DLARGEBOARDS -DPRECOMPUTED_MAGICS -DALLVARSto enable all variants and large boards.
g++ example_dll_usage.cpp -L/path/to/src -lffish -Wl,-rpath,/path/to/src -std=c++17 -O2 -o example
Ensure libffish.so is on your runtime path (use rpath as above or set LD_LIBRARY_PATH).
# after building ffish.dll and libffish.dll.a in src/
g++ example_dll_usage.cpp -Lpath\\to\\src -lffish -std=c++17 -O2 -o example.exe
Ensure ffish.dll is beside the executable or on PATH. Link against the import library libffish.dll.a generated by Makefile_dll.
Key exported functions (see src/ffishdll.cpp):
- Initialization:
fsf_init() - Board lifecycle:
fsf_new_board(variant, fen, is960),fsf_free_board - Moves:
fsf_legal_moves,fsf_legal_moves_san,fsf_number_legal_moves,fsf_push,fsf_push_san,fsf_pop - FEN/SAN:
fsf_fen,fsf_san_move,fsf_variation_san - State:
fsf_is_game_over,fsf_result,fsf_turn,fsf_fullmove_number,fsf_halfmove_clock,fsf_game_ply - Material/hand:
fsf_has_insufficient_material,fsf_is_insufficient_material,fsf_checked_pieces,fsf_is_check,fsf_is_capture,fsf_pocket - Variant/meta:
fsf_available_variants,fsf_starting_fen,fsf_captures_to_hand,fsf_validate_fen,fsf_board_variant - Options/engine info:
fsf_info,fsf_set_option_str/int/bool - Memory release for returned strings:
fsf_free
All returned const char* strings are heap-allocated; free them with fsf_free.
fsf_init();
fsf_board b = fsf_new_board("chess", nullptr, false);
const char* moves = fsf_legal_moves(b);
printf("Legal moves: %s\n", moves);
fsf_free(moves);
fsf_push(b, "e2e4");
const char* fen = fsf_fen(b, false, 0);
printf("FEN: %s\n", fen);
fsf_free(fen);
fsf_free_board(b);Read your variants.ini content into a string and call:
fsf_load_variant_config(iniContent);This reconfigures the variant list (mirrors the behavior in ffish.js).
fsf_init() is protected with std::call_once, but board operations themselves are not internally synchronized. Use separate boards per thread or provide your own locking if sharing.
Variant initialization/configuration touches global engine state. In particular, board creation (fsf_new_board) and fsf_load_variant_config are serialized internally; do not assume independent per-thread variant state.
#include <cstdio>
extern "C" {
typedef void* fsf_board;
void fsf_init();
fsf_board fsf_new_board(const char* variant, const char* fen, bool is960);
void fsf_free_board(fsf_board);
const char* fsf_legal_moves(fsf_board);
const char* fsf_fen(fsf_board, bool showPromoted, int countStarted);
bool fsf_push(fsf_board, const char* uciMove);
void fsf_pop(fsf_board);
int fsf_validate_fen(const char* fen, const char* variant, bool is960);
const char* fsf_available_variants();
const char* fsf_starting_fen(const char* variant);
void fsf_free(const char* p);
}
int main() {
fsf_init();
const char* variants = fsf_available_variants();
std::printf("Variants: %s\n", variants);
fsf_free(variants);
const char* start = fsf_starting_fen("chess");
fsf_board b = fsf_new_board("chess", start, false);
fsf_free(start);
const char* moves = fsf_legal_moves(b);
std::printf("Legal (UCI): %s\n", moves);
fsf_free(moves);
fsf_push(b, "e2e4");
const char* fen = fsf_fen(b, false, 0);
std::printf("After e2e4: %s\n", fen);
fsf_free(fen);
fsf_pop(b);
fen = fsf_fen(b, false, 0);
std::printf("After undo: %s\n", fen);
fsf_free(fen);
int ok = fsf_validate_fen("8/8/8/8/8/8/8/8 w - - 0 1", "chess", false);
std::printf("Validate empty-board FEN (expect error): %d\n", ok);
fsf_free_board(b);
return 0;
}Build:
- Linux:
g++ demo.cpp -L/path/to/src -lffish -Wl,-rpath,/path/to/src -std=c++17 -O2 -o demo - Windows (MinGW):
g++ demo.cpp -Lpath\\to\\src -lffish -std=c++17 -O2 -o demo.exe(ensureffish.dllis next to the exe or onPATH)