Files
stockfish/src/Makefile
T
f4bcd40409 Update nnue architecture to SFNNv16 and net nn-89cb98a217f7.nnue
Failed STC (https://tests.stockfishchess.org/tests/view/6a4f36355529b8472df7ff7e):
LLR: -2.94 (-2.94,2.94) <0.00,2.00>
Total: 144768 W: 38003 L: 38051 D: 68714
Ptnml(0-2): 521, 17154, 37050, 17170, 489

Passed LTC (https://tests.stockfishchess.org/tests/view/6a501dad5529b8472df80103):
LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 189888 W: 49613 L: 48984 D: 91291
Ptnml(0-2): 122, 20406, 53256, 21041, 119

Passed VLTC (https://tests.stockfishchess.org/tests/view/6a52892c5529b8472df80481):
LLR: 2.94 (-2.94,2.94) <0.00,2.00>
Total: 46124 W: 12156 L: 11865 D: 22103
Ptnml(0-2): 12, 4523, 13696, 4824, 7

Passed VVLTC (https://tests.stockfishchess.org/tests/view/6a566a285529b8472df80b84):
LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 44698 W: 11805 L: 11507 D: 21386
Ptnml(0-2): 9, 3819, 14395, 4117, 9

This PR adds pawn pair features, a new set of features that is indexed by pairs of pawns occupying the same or adjacent files (hence "3-wide"). Because these are a superset of pawn–pawn interactions in threat inputs (including the recently added pawn-pusher inputs), those are removed. HalfKA features remain unchanged.

Pawn-pair features were invented by Jonathan for Pawnocchio, based on his observation that in a net trained on *all* pairs of pawns, the most important pawn pairs were those differing by at most one file.

sscg13 made the necessary changes to the trainer (https://github.com/official-stockfish/nnue-pytorch/pull/502) and initial changes to inference. The slowdown was originally far too large (some 10%); following major optimizations from Jonathan and a bit from me, the slowdown is small enough for a comfortable LTC pass; on my machine I get a 3.5% slowdown overall. I expect there are further "easy" speedups in the new code, so this gap should narrow a bit.

Nettest PR: https://github.com/vondele/nettest/pull/359

closes https://github.com/official-stockfish/Stockfish/pull/6982

Bench: 2718396

Co-Authored-By: anematode <timothy.herchen@gmail.com>
Co-Authored-By: Jonathan Hallström <lmj.hallstrom@gmail.com>
2026-07-20 11:06:41 +02:00

1534 lines
45 KiB
Makefile

# Stockfish, a UCI chess playing engine derived from Glaurung 2.1
# Copyright (C) 2004-2026 The Stockfish developers (see AUTHORS file)
#
# Stockfish is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Stockfish is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
### ==========================================================================
### Section 1. General Configuration
### ==========================================================================
### Establish the operating system name
KERNEL := $(shell uname -s)
ifeq ($(KERNEL),Linux)
OS := $(shell uname -o)
endif
### Target operating system (may differ from KERNEL when cross-compiling)
TARGET_KERNEL := $(KERNEL)
ifeq ($(COMP),ndk)
TARGET_KERNEL := Linux
OS := Android
endif
### Command prefix to run the built executable (e.g. wine, sde, qemu)
### Backward compatible alias: WINE_PATH (deprecated)
ifneq ($(strip $(WINE_PATH)),)
ifeq ($(strip $(RUN_PREFIX)),)
RUN_PREFIX := $(WINE_PATH)
endif
ifeq ($(MAKELEVEL),0)
ifneq ($(strip $(RUN_PREFIX)),$(strip $(WINE_PATH)))
$(warning *** Both RUN_PREFIX and WINE_PATH are set; ignoring WINE_PATH. ***)
else
$(warning *** WINE_PATH is deprecated; use RUN_PREFIX instead. ***)
endif
endif
endif
### Target Windows OS
ifeq ($(OS),Windows_NT)
ifneq ($(COMP),ndk)
target_windows = yes
endif
else ifeq ($(COMP),mingw)
target_windows = yes
ifeq ($(RUN_PREFIX),)
RUN_PREFIX := $(shell which wine)
endif
endif
### Executable name
ifeq ($(target_windows),yes)
EXE = stockfish.exe
else ifneq (,$(findstring wasm,$(ARCH)))
EXE = stockfish.js
else
EXE = stockfish
endif
### Installation dir definitions
PREFIX = /usr/local
BINDIR = $(PREFIX)/bin
### Built-in benchmark for pgo-builds
PGOBENCH = $(RUN_PREFIX) ./$(EXE) bench
### Source and object files
SRCS = attacks.cpp benchmark.cpp bitboard.cpp evaluate.cpp main.cpp \
misc.cpp movegen.cpp movepick.cpp position.cpp \
search.cpp thread.cpp timeman.cpp tt.cpp uci.cpp ucioption.cpp tune.cpp syzygy/tbprobe.cpp \
nnue/nnue_accumulator.cpp nnue/nnue_misc.cpp nnue/network.cpp \
nnue/features/half_ka_v2_hm.cpp nnue/features/full_threats.cpp nnue/features/pp_3wide.cpp \
engine.cpp score.cpp memory.cpp
OTHER_SRCS = universal/entry_x86.cpp universal/entry_arm64.cpp universal/entry_riscv64.cpp universal/nnue_embed.cpp
HEADERS = attacks.h benchmark.h bitboard.h evaluate.h misc.h movegen.h movepick.h history.h \
nnue/nnue_misc.h nnue/features/half_ka_v2_hm.h nnue/features/full_threats.h \
nnue/features/pp_3wide.h nnue/layers/affine_transform.h nnue/layers/affine_transform_sparse_input.h \
nnue/layers/clipped_relu.h nnue/layers/sqr_clipped_relu.h nnue/nnue_accumulator.h \
nnue/nnue_architecture.h nnue/nnue_common.h nnue/nnue_feature_transformer.h nnue/simd.h \
nnue/nnz_helper.h position.h search.h syzygy/tbprobe.h thread.h thread_native.h timeman.h \
tt.h tune.h types.h uci.h ucioption.h perft.h nnue/network.h engine.h score.h numa.h memory.h shm.h shm_linux.h
OBJS = $(notdir $(SRCS:.cpp=.o))
VPATH = syzygy:nnue:nnue/features
### ==========================================================================
### Section 2. High-level Configuration
### ==========================================================================
#
# flag --- Comp switch --- Description
# ----------------------------------------------------------------------------
#
# debug = yes/no --- -DNDEBUG --- Enable/Disable debug mode
# sanitize = none/<sanitizer> ... (-fsanitize )
# --- ( undefined ) --- enable undefined behavior checks
# --- ( thread ) --- enable threading error checks
# --- ( address ) --- enable memory access checks
# --- ...etc... --- see compiler documentation for supported sanitizers
# optimize = yes/no --- (-O3/-fast etc.) --- Enable/Disable optimizations
# arch = (name) --- (-arch) --- Target architecture
# bits = 64/32 --- -DIS_64BIT --- 64-/32-bit operating system
# prefetch = yes/no --- -DUSE_PREFETCH --- Use prefetch asm-instruction
# popcnt = yes/no --- -DUSE_POPCNT --- Use popcnt asm-instruction
# pext = yes/no --- -DUSE_PEXT --- Use pext x86_64 asm-instruction
# sse = yes/no --- -msse --- Use Intel Streaming SIMD Extensions
# mmx = yes/no --- -mmmx --- Use Intel MMX instructions
# sse2 = yes/no --- -msse2 --- Use Intel Streaming SIMD Extensions 2
# ssse3 = yes/no --- -mssse3 --- Use Intel Supplemental Streaming SIMD Extensions 3
# sse41 = yes/no --- -msse4.1 --- Use Intel Streaming SIMD Extensions 4.1
# avx2 = yes/no --- -mavx2 --- Use Intel Advanced Vector Extensions 2
# avxvnni = yes/no --- -mavxvnni --- Use Intel Vector Neural Network Instructions AVX
# avx512 = yes/no --- -mavx512bw --- Use Intel Advanced Vector Extensions 512
# vnni512 = yes/no --- -mavx512vnni --- Use Intel Vector Neural Network Instructions 512
# avx512icl = yes/no --- ... multiple ... --- Use All AVX-512 features available on both Intel Ice Lake and AMD Zen 4
# altivec = yes/no --- -maltivec --- Use PowerPC Altivec SIMD extension
# vsx = yes/no --- -mvsx --- Use POWER VSX SIMD extension
# neon = yes/no --- -DUSE_NEON --- Use ARM SIMD architecture
# dotprod = yes/no --- -DUSE_NEON_DOTPROD --- Use ARM advanced SIMD Int8 dot product instructions
# lsx = yes/no --- -mlsx --- Use Loongson SIMD eXtension
# lasx = yes/no --- -mlasx --- Use Loongson Advanced SIMD eXtension
# relaxedsimd = y/n --- -mrelaxed-simd --- Use WebAssembly relaxed SIMD extension
# syzygy = yes/no --- -DNO_TABLEBASES --- Support Syzygy tablebase probing
#
# Note that Makefile is space sensitive, so when adding new architectures
# or modifying existing flags, you have to make sure there are no extra spaces
# at the end of the line for flag values.
#
# Example of use for these flags:
# make build ARCH=x86-64-avx512 debug=yes sanitize="address undefined"
### 2.1. General and architecture defaults
ifeq ($(ARCH),)
ARCH = native
endif
ifeq ($(ARCH), native)
override ARCH := $(shell $(SHELL) ../scripts/get_native_properties.sh | cut -d " " -f 1)
endif
# explicitly check for the list of supported architectures (as listed with make help),
# the user can override with `make ARCH=x86-64-avx512icl SUPPORTED_ARCH=true`
ifeq ($(ARCH), $(filter $(ARCH), \
x86-64-universal x86-64-avx512icl x86-64-vnni512 x86-64-avx512 x86-64-avxvnni \
x86-64-bmi2 x86-64-avx2 x86-64-sse41-popcnt x86-64-modern x86-64-ssse3 x86-64-sse3-popcnt \
x86-64 x86-32-sse41-popcnt x86-32-sse2 x86-32 ppc-64 ppc-64-altivec ppc-64-vsx ppc-32 e2k \
armv7 armv7-neon armv8 armv8-dotprod arm64-universal apple-silicon general-64 general-32 riscv64 \
riscv64-rva23 riscv64-universal loongarch64 loongarch64-lsx loongarch64-lasx wasm32 wasm32-relaxed-simd))
SUPPORTED_ARCH=true
else
SUPPORTED_ARCH=false
endif
ifneq (,$(filter $(ARCH),x86-64-universal arm64-universal riscv64-universal))
UNIVERSAL_BUILD=true
else
UNIVERSAL_BUILD=false
endif
optimize = yes
debug = no
sanitize = none
bits = 64
prefetch = no
popcnt = no
pext = no
sse = no
mmx = no
sse2 = no
ssse3 = no
sse41 = no
avx2 = no
avxvnni = no
avx512 = no
vnni512 = no
avx512icl = no
altivec = no
vsx = no
neon = no
dotprod = no
arm_version = 0
rva23 = no
lsx = no
lasx = no
relaxedsimd = no
syzygy = yes
STRIP = strip
ifneq ($(shell which clang-format-20 2> /dev/null),)
CLANG-FORMAT = clang-format-20
else
CLANG-FORMAT = clang-format
endif
### 2.2 Architecture specific
ifeq ($(findstring x86,$(ARCH)),x86)
# x86-32/64
ifeq ($(findstring x86-32,$(ARCH)),x86-32)
arch = i386
bits = 32
sse = no
mmx = yes
else
arch = x86_64
sse = yes
sse2 = yes
endif
ifeq ($(findstring -sse,$(ARCH)),-sse)
sse = yes
endif
ifeq ($(findstring -popcnt,$(ARCH)),-popcnt)
popcnt = yes
endif
ifeq ($(findstring -mmx,$(ARCH)),-mmx)
mmx = yes
endif
ifeq ($(findstring -sse2,$(ARCH)),-sse2)
sse = yes
sse2 = yes
endif
ifeq ($(findstring -ssse3,$(ARCH)),-ssse3)
sse = yes
sse2 = yes
ssse3 = yes
endif
ifeq ($(findstring -sse41,$(ARCH)),-sse41)
sse = yes
sse2 = yes
ssse3 = yes
sse41 = yes
endif
ifeq ($(findstring -modern,$(ARCH)),-modern)
$(warning *** ARCH=$(ARCH) is deprecated, defaulting to ARCH=x86-64-sse41-popcnt. Execute `make help` for a list of available architectures. ***)
$(shell sleep 5)
popcnt = yes
sse = yes
sse2 = yes
ssse3 = yes
sse41 = yes
endif
ifeq ($(findstring -avx2,$(ARCH)),-avx2)
popcnt = yes
sse = yes
sse2 = yes
ssse3 = yes
sse41 = yes
avx2 = yes
endif
ifeq ($(findstring -avxvnni,$(ARCH)),-avxvnni)
popcnt = yes
sse = yes
sse2 = yes
ssse3 = yes
sse41 = yes
avx2 = yes
avxvnni = yes
pext = yes
endif
ifeq ($(findstring -bmi2,$(ARCH)),-bmi2)
popcnt = yes
sse = yes
sse2 = yes
ssse3 = yes
sse41 = yes
avx2 = yes
pext = yes
endif
ifeq ($(findstring -avx512,$(ARCH)),-avx512)
popcnt = yes
sse = yes
sse2 = yes
ssse3 = yes
sse41 = yes
avx2 = yes
pext = yes
avx512 = yes
endif
ifeq ($(findstring -vnni512,$(ARCH)),-vnni512)
popcnt = yes
sse = yes
sse2 = yes
ssse3 = yes
sse41 = yes
avx2 = yes
pext = yes
avx512 = yes
vnni512 = yes
endif
ifeq ($(findstring -avx512icl,$(ARCH)),-avx512icl)
popcnt = yes
sse = yes
sse2 = yes
ssse3 = yes
sse41 = yes
avx2 = yes
pext = yes
avx512 = yes
vnni512 = yes
avx512icl = yes
endif
ifeq ($(sse),yes)
prefetch = yes
endif
# 64-bit pext is not available on x86-32
ifeq ($(bits),32)
pext = no
endif
else
# all other architectures
ifeq ($(ARCH),general-32)
arch = any
bits = 32
endif
ifeq ($(ARCH),general-64)
arch = any
endif
ifeq ($(ARCH),armv7)
arch = armv7
prefetch = yes
bits = 32
arm_version = 7
endif
ifeq ($(ARCH),armv7-neon)
arch = armv7
prefetch = yes
popcnt = yes
neon = yes
bits = 32
arm_version = 7
endif
ifeq ($(ARCH),armv8)
arch = armv8
prefetch = yes
popcnt = yes
neon = yes
arm_version = 8
endif
ifeq ($(ARCH),armv8-dotprod)
arch = armv8
prefetch = yes
popcnt = yes
neon = yes
dotprod = yes
arm_version = 8
endif
ifeq ($(ARCH),arm64-universal)
arch = armv8
prefetch = yes
popcnt = yes
neon = yes
arm_version = 8
endif
ifeq ($(ARCH),apple-silicon)
arch = arm64
prefetch = yes
popcnt = yes
neon = yes
dotprod = yes
arm_version = 8
endif
# WASM is largely compiled using emcc's x86 compatibility layer, with occasional
# WASM-specific intrinsics
ifeq ($(ARCH),wasm32)
arch = wasm32
sse = yes
sse2 = yes
ssse3 = yes
sse41 = yes
syzygy = no
endif
ifeq ($(ARCH),wasm32-relaxed-simd)
arch = wasm32
sse = yes
sse2 = yes
ssse3 = yes
sse41 = yes
relaxedsimd = yes
syzygy = no
endif
ifeq ($(ARCH),ppc-32)
arch = ppc
bits = 32
endif
ifeq ($(ARCH),ppc-64)
arch = ppc64
popcnt = yes
prefetch = yes
endif
ifeq ($(ARCH),ppc-64-altivec)
arch = ppc64
popcnt = yes
prefetch = yes
altivec = yes
endif
ifeq ($(ARCH),ppc-64-vsx)
arch = ppc64
popcnt = yes
prefetch = yes
vsx = yes
endif
ifeq ($(findstring e2k,$(ARCH)),e2k)
arch = e2k
mmx = yes
bits = 64
sse = yes
sse2 = yes
ssse3 = yes
sse41 = yes
popcnt = yes
endif
ifeq ($(findstring riscv64,$(ARCH)),riscv64)
arch = riscv64
endif
ifeq ($(ARCH),riscv64-rva23)
rva23 = yes
popcnt = yes
prefetch = yes
endif
ifeq ($(findstring loongarch64,$(ARCH)),loongarch64)
arch = loongarch64
prefetch = yes
ifeq ($(findstring -lasx,$(ARCH)),-lasx)
lsx = yes
lasx = yes
endif
ifeq ($(findstring -lsx,$(ARCH)),-lsx)
lsx = yes
endif
endif
endif
### ==========================================================================
### Section 3. Low-level Configuration
### ==========================================================================
### 3.1 Selecting compiler (default = gcc)
ifeq ($(MAKELEVEL),0)
export ENV_CXXFLAGS := $(CXXFLAGS)
export ENV_DEPENDFLAGS := $(DEPENDFLAGS)
export ENV_LDFLAGS := $(LDFLAGS)
endif
CXXFLAGS = $(ENV_CXXFLAGS) -Wall -Wcast-qual -fno-exceptions -std=c++17 $(EXTRACXXFLAGS)
DEPENDFLAGS = $(ENV_DEPENDFLAGS) -std=c++17
LDFLAGS = $(ENV_LDFLAGS) $(EXTRALDFLAGS)
ifeq ($(COMP),)
COMP=gcc
endif
ifeq ($(COMP),gcc)
comp=gcc
CXX=g++
CXXFLAGS += -pedantic -Wextra -Wshadow -Wmissing-declarations
ifeq ($(arch),$(filter $(arch),armv7 armv8 riscv64))
ifeq ($(OS),Android)
CXXFLAGS += -m$(bits)
LDFLAGS += -m$(bits)
endif
else ifeq ($(arch),loongarch64)
CXXFLAGS += -latomic
else ifneq ($(arch),wasm32)
CXXFLAGS += -m$(bits)
LDFLAGS += -m$(bits)
endif
ifeq ($(arch),$(filter $(arch),armv7))
LDFLAGS += -latomic
endif
ifneq ($(TARGET_KERNEL),Darwin)
ifneq ($(arch),wasm32)
LDFLAGS += -Wl,--no-as-needed
endif
endif
endif
ifeq ($(target_windows),yes)
LDFLAGS += -static
endif
ifeq ($(COMP),mingw)
comp=mingw
ifeq ($(bits),64)
ifeq ($(shell which x86_64-w64-mingw32-c++-posix 2> /dev/null),)
CXX=x86_64-w64-mingw32-c++
else
CXX=x86_64-w64-mingw32-c++-posix
endif
else
ifeq ($(shell which i686-w64-mingw32-c++-posix 2> /dev/null),)
CXX=i686-w64-mingw32-c++
else
CXX=i686-w64-mingw32-c++-posix
endif
endif
CXXFLAGS += -pedantic -Wextra -Wshadow -Wmissing-declarations -fconstexpr-ops-limit=500000000
endif
ifeq ($(COMP),icx)
comp=icx
CXX=icpx
CXXFLAGS += --intel -pedantic -Wextra -Wshadow -Wmissing-prototypes \
-Wconditional-uninitialized -Wabi -Wdeprecated -fconstexpr-steps=500000000
endif
ifeq ($(COMP),clang)
comp=clang
CXX=clang++
ifeq ($(target_windows),yes)
CXX=x86_64-w64-mingw32-clang++
endif
CXXFLAGS += -pedantic -Wextra -Wshadow -Wmissing-prototypes \
-Wconditional-uninitialized -flax-vector-conversions=none -fconstexpr-steps=500000000
ifeq ($(filter $(TARGET_KERNEL),Darwin OpenBSD FreeBSD),)
ifeq ($(target_windows),)
ifneq ($(RTLIB),compiler-rt)
LDFLAGS += -latomic
endif
endif
endif
ifeq ($(arch),$(filter $(arch),armv7 armv8 riscv64))
ifeq ($(OS),Android)
CXXFLAGS += -m$(bits)
LDFLAGS += -m$(bits)
endif
else ifeq ($(arch),loongarch64)
CXXFLAGS += -latomic
else
CXXFLAGS += -m$(bits)
LDFLAGS += -m$(bits)
endif
endif
ifeq ($(TARGET_KERNEL),Darwin)
mac_target_flags := -mmacosx-version-min=10.15
ifneq ($(arch),any)
mac_target_flags += -arch $(arch)
endif
CXXFLAGS += $(mac_target_flags)
LDFLAGS += $(mac_target_flags)
XCRUN = xcrun
endif
# To cross-compile for Android, use NDK version r27c or later.
ifeq ($(COMP),ndk)
CXXFLAGS += -stdlib=libc++
comp=clang
ifeq ($(arch),armv7)
CXX=armv7a-linux-androideabi29-clang++
CXXFLAGS += -mthumb -march=armv7-a -mfloat-abi=softfp -mfpu=neon
ifneq ($(shell which arm-linux-androideabi-strip 2>/dev/null),)
STRIP=arm-linux-androideabi-strip
else
STRIP=llvm-strip
endif
endif
ifeq ($(arch),armv8)
CXX=aarch64-linux-android29-clang++
ifneq ($(shell which aarch64-linux-android-strip 2>/dev/null),)
STRIP=aarch64-linux-android-strip
else
STRIP=llvm-strip
endif
endif
ifeq ($(arch),x86_64)
CXX=x86_64-linux-android29-clang++
ifneq ($(shell which x86_64-linux-android-strip 2>/dev/null),)
STRIP=x86_64-linux-android-strip
else
STRIP=llvm-strip
endif
endif
OBJCOPY=llvm-objcopy
LDFLAGS += -static-libstdc++
endif
### Allow overwriting CXX from command line
ifdef COMPCXX
CXX=$(COMPCXX)
endif
# llvm-profdata must be version compatible with the specified CXX (be it clang, or the gcc alias)
# make -j profile-build CXX=clang++-20 COMP=clang
# Locate the version in the same directory as the compiler used,
# with fallback to a generic one if it can't be located
LLVM_PROFDATA := $(dir $(realpath $(shell which $(CXX) 2> /dev/null)))llvm-profdata
# for icx
ifeq ($(wildcard $(LLVM_PROFDATA)),)
LLVM_PROFDATA := $(dir $(realpath $(shell which $(CXX) 2> /dev/null)))/compiler/llvm-profdata
endif
ifeq ($(wildcard $(LLVM_PROFDATA)),)
LLVM_PROFDATA := llvm-profdata
endif
ifeq ($(comp),icx)
profile_make = icx-profile-make
profile_use = icx-profile-use
else ifeq ($(comp),clang)
profile_make = clang-profile-make
profile_use = clang-profile-use
else
profile_make = gcc-profile-make
profile_use = gcc-profile-use
ifeq ($(TARGET_KERNEL),Darwin)
EXTRAPROFILEFLAGS = -fvisibility=hidden
endif
endif
### Sometimes gcc is really clang
ifeq ($(COMP),gcc)
gccversion := $(shell $(CXX) --version 2>/dev/null)
gccisclang := $(findstring clang,$(gccversion))
ifneq ($(gccisclang),)
profile_make = clang-profile-make
profile_use = clang-profile-use
CXXFLAGS += -fconstexpr-steps=500000000
else
CXXFLAGS += -Wstack-usage=128000 -fno-ipa-cp-clone -fconstexpr-ops-limit=500000000
endif
else ifeq ($(COMP),mingw)
CXXFLAGS += -fno-ipa-cp-clone
endif
# On Android Bionic's C library comes with its own pthread implementation bundled in
ifneq ($(OS),Android)
# Haiku has pthreads in its libroot, so only link it in on other platforms
ifneq ($(KERNEL),Haiku)
ifneq ($(COMP),ndk)
ifneq ($(arch),wasm32)
LDFLAGS += -lpthread
add_lrt = yes
ifeq ($(target_windows),yes)
add_lrt = no
endif
ifeq ($(TARGET_KERNEL),Darwin)
add_lrt = no
endif
ifeq ($(add_lrt),yes)
LDFLAGS += -lrt
endif
endif
endif
endif
endif
### 3.2.1 Debugging
ifeq ($(debug),no)
CXXFLAGS += -DNDEBUG
else
CXXFLAGS += -g
CXXFLAGS += -D_GLIBCXX_ASSERTIONS -D_GLIBCXX_DEBUG
endif
### 3.2.2 Debugging with undefined behavior sanitizers
ifneq ($(sanitize),none)
CXXFLAGS += -g3 $(addprefix -fsanitize=,$(sanitize))
LDFLAGS += $(addprefix -fsanitize=,$(sanitize))
endif
### 3.3 Optimization
ifeq ($(optimize),yes)
CXXFLAGS += -O3 -funroll-loops
ifeq ($(comp),gcc)
ifeq ($(OS), Android)
CXXFLAGS += -fno-gcse -mthumb -march=armv7-a -mfloat-abi=softfp
endif
endif
ifeq ($(TARGET_KERNEL),Darwin)
ifeq ($(comp),$(filter $(comp),clang icx))
CXXFLAGS += -mdynamic-no-pic
endif
ifeq ($(comp),gcc)
ifneq ($(arch),arm64)
CXXFLAGS += -mdynamic-no-pic
endif
endif
endif
ifeq ($(comp),clang)
clangmajorversion := $(shell $(CXX) -dumpversion 2>/dev/null | cut -f1 -d.)
ifeq ($(shell expr $(clangmajorversion) \< 16),1)
CXXFLAGS += -fexperimental-new-pass-manager
endif
endif
endif
### 3.4 Bits
ifeq ($(bits),64)
CXXFLAGS += -DIS_64BIT
endif
### 3.5 prefetch and popcount
ifeq ($(prefetch),yes)
ifeq ($(sse),yes)
CXXFLAGS += -msse
endif
else
CXXFLAGS += -DNO_PREFETCH
endif
ifeq ($(popcnt),yes)
ifeq ($(arch),$(filter $(arch),ppc64 ppc64-altivec ppc64-vsx armv7 armv8 arm64 riscv64))
CXXFLAGS += -DUSE_POPCNT
else
CXXFLAGS += -msse3 -mpopcnt -DUSE_POPCNT
endif
endif
### 3.6 SIMD architectures
ifeq ($(avx2),yes)
CXXFLAGS += -DUSE_AVX2
ifeq ($(comp),$(filter $(comp),gcc clang mingw icx))
CXXFLAGS += -mavx2 -mbmi
endif
endif
ifeq ($(avxvnni),yes)
CXXFLAGS += -DUSE_VNNI -DUSE_AVXVNNI
ifeq ($(comp),$(filter $(comp),gcc clang mingw icx))
CXXFLAGS += -mavxvnni
endif
endif
ifeq ($(avx512),yes)
CXXFLAGS += -DUSE_AVX512
ifeq ($(comp),$(filter $(comp),gcc clang mingw icx))
CXXFLAGS += -mavx512f -mavx512bw -mavx512dq -mavx512vl
endif
endif
ifeq ($(vnni512),yes)
CXXFLAGS += -DUSE_VNNI
ifeq ($(comp),$(filter $(comp),gcc clang mingw icx))
CXXFLAGS += -mavx512f -mavx512bw -mavx512vnni -mavx512dq -mavx512vl
endif
endif
ifeq ($(avx512icl),yes)
CXXFLAGS += -DUSE_AVX512 -DUSE_VNNI -DUSE_AVX512ICL
ifeq ($(comp),$(filter $(comp),gcc clang mingw icx))
CXXFLAGS += -mavx512f -mavx512cd -mavx512vl -mavx512dq -mavx512bw -mavx512ifma -mavx512vbmi -mavx512vbmi2 -mavx512vpopcntdq -mavx512bitalg -mavx512vnni -mvpclmulqdq -mgfni -mvaes
endif
endif
ifeq ($(sse41),yes)
CXXFLAGS += -DUSE_SSE41
ifeq ($(comp),$(filter $(comp),gcc clang mingw icx))
CXXFLAGS += -msse4.1
endif
endif
ifeq ($(ssse3),yes)
CXXFLAGS += -DUSE_SSSE3
ifeq ($(comp),$(filter $(comp),gcc clang mingw icx))
CXXFLAGS += -mssse3
endif
endif
ifeq ($(sse2),yes)
CXXFLAGS += -DUSE_SSE2
ifeq ($(comp),$(filter $(comp),gcc clang mingw icx))
CXXFLAGS += -msse2
endif
endif
ifeq ($(mmx),yes)
ifeq ($(comp),$(filter $(comp),gcc clang mingw icx))
CXXFLAGS += -mmmx
endif
endif
ifeq ($(altivec),yes)
CXXFLAGS += -maltivec
ifeq ($(COMP),gcc)
CXXFLAGS += -mabi=altivec
endif
endif
ifeq ($(vsx),yes)
CXXFLAGS += -mvsx
ifeq ($(COMP),gcc)
CXXFLAGS += -DNO_WARN_X86_INTRINSICS -DUSE_SSE2
endif
endif
ifeq ($(neon),yes)
CXXFLAGS += -DUSE_NEON=$(arm_version)
ifeq ($(TARGET_KERNEL),Linux)
ifneq ($(COMP),ndk)
ifneq ($(arch),armv8)
CXXFLAGS += -mfpu=neon
endif
endif
endif
endif
ifeq ($(dotprod),yes)
CXXFLAGS += -march=armv8.2-a+dotprod -DUSE_NEON_DOTPROD
endif
ifeq ($(rva23),yes)
CXXFLAGS += -march=rv64gcv1p0_zba_zbb_zbs_zicbop_zicond -DUSE_RVV
endif
ifeq ($(lasx),yes)
CXXFLAGS += -DUSE_LASX
ifeq ($(comp),$(filter $(comp),gcc clang mingw icx))
CXXFLAGS += -mlasx
endif
endif
ifeq ($(lsx),yes)
CXXFLAGS += -DUSE_LSX
ifeq ($(comp),$(filter $(comp),gcc clang mingw icx))
CXXFLAGS += -mlsx
endif
endif
ifeq ($(arch),wasm32)
CXXFLAGS += -pthread -msimd128 -DUSE_POPCNT -DNNUE_EMBEDDING_OFF -DUSE_SLOPPY_ATOMICS
LDFLAGS += -pthread -sINITIAL_MEMORY=64MB -sALLOW_MEMORY_GROWTH -sSTACK_SIZE=3MB
ifeq ($(relaxedsimd),yes)
CXXFLAGS += -mrelaxed-simd
endif
endif
### 3.7 pext
ifeq ($(pext),yes)
CXXFLAGS += -DUSE_PEXT
ifeq ($(comp),$(filter $(comp),gcc clang mingw icx))
CXXFLAGS += -mbmi2
endif
endif
### Syzygy tablebases
ifeq ($(syzygy),no)
CXXFLAGS += -DNO_TABLEBASES
endif
### 3.8.1 Try to include git info for versioning and avoid recompiles if nothing changes
BUILD_SHA_FILE := .build_sha.txt
BUILD_DATE_FILE := .build_date.txt
BUILD_DIFFINDEX_FILE := .build_diffindex.txt
GIT_SHA := $(shell git rev-parse HEAD 2>/dev/null | cut -c 1-8 || true)
GIT_DATE := $(shell git show -s --date=format:%Y%m%d --format=%cd HEAD 2>/dev/null || true)
GIT_DIFFINDEX := $(shell git diff-index --quiet HEAD -- 2>/dev/null; [ $$? -eq 1 ] && echo 1 || true)
COMPILER_DATE := $(shell date +%Y%m%d 2>/dev/null)
BUILD_DATE := $(if $(GIT_DATE),$(GIT_DATE),$(COMPILER_DATE))
define cache_file_contents
$(shell \
if [ ! -f "$(1)" ] || [ "$$(cat "$(1)" 2>/dev/null)" != "$(2)" ]; then \
printf '%s\n' "$(2)" > "$(1)"; \
fi)
endef
ifneq ($(filter $(MAKECMDGOALS),help strip install clean net objclean profileclean format config-sanity),$(MAKECMDGOALS))
_ := $(call cache_file_contents,$(BUILD_SHA_FILE),$(GIT_SHA))
_ := $(call cache_file_contents,$(BUILD_DATE_FILE),$(BUILD_DATE))
_ := $(call cache_file_contents,$(BUILD_DIFFINDEX_FILE),$(BUILD_DIFFINDEX))
endif
### 3.8.2 Try to include architecture
ifneq ($(ARCH), )
CXXFLAGS += -DARCH=$(ARCH)
endif
### 3.9 Link Time Optimization
### This is a mix of compile and link time options because the lto link phase
### needs access to the optimization flags.
ifeq ($(optimize),yes)
ifeq ($(debug),no)
ifeq ($(arch),wasm32)
else ifneq ($(TARGET_KERNEL),Darwin)
LLD_BIN := $(shell command -v ld.lld 2>/dev/null)
ifeq ($(LLD_BIN),)
LLD_BIN := $(shell command -v lld 2>/dev/null)
endif
ifneq ($(LLD_BIN),)
ifeq ($(comp),clang)
LDFLAGS += -fuse-ld=lld
else ifeq ($(comp),gcc)
ifneq ($(gccisclang),)
LDFLAGS += -fuse-ld=lld
endif
endif
endif
endif
ifeq ($(comp),$(filter $(comp),clang icx))
CXXFLAGS += -flto=full
ifeq ($(comp),icx)
CXXFLAGS += -fwhole-program-vtables
endif
LDFLAGS += $(CXXFLAGS)
# GCC and CLANG use different methods for parallelizing LTO and CLANG pretends to be
# GCC on some systems.
else ifeq ($(comp),gcc)
ifeq ($(gccisclang),)
CXXFLAGS += -flto -flto-partition=one
LDFLAGS += $(CXXFLAGS) -flto=jobserver
else
CXXFLAGS += -flto=full
LDFLAGS += $(CXXFLAGS)
endif
# To use LTO and static linking on Windows,
# the tool chain requires gcc version 10.1 or later.
else ifeq ($(comp),mingw)
CXXFLAGS += -flto -flto-partition=one
LDFLAGS += $(CXXFLAGS) -save-temps
endif
endif
endif
### 3.10 Android 5 can only run position independent executables. Note that this
### breaks Android 4.0 and earlier.
ifeq ($(OS), Android)
CXXFLAGS += -fPIE
LDFLAGS += -fPIE -pie
endif
### 3.11 Inline settings
ifeq ($(optimize), yes)
ifeq ($(comp), clang)
CXXFLAGS += -Xclang -mllvm -Xclang -inline-threshold=500
endif
endif
### ==========================================================================
### Section 4. Public Targets
### ==========================================================================
help:
@echo "" && \
echo "To compile stockfish, type: " && \
echo "" && \
echo "make -j target [ARCH=arch] [COMP=compiler] [COMPCXX=cxx]" && \
echo "" && \
echo "Supported targets:" && \
echo "" && \
echo "help > Display architecture details" && \
echo "profile-build > standard build with profile-guided optimization" && \
echo "build > skip profile-guided optimization" && \
echo "macos-lipo > macOS x86-64 + Apple silicon universal binary" && \
echo "net > Download the default nnue nets" && \
echo "strip > Strip executable" && \
echo "install > Install executable" && \
echo "clean > Clean up" && \
echo "" && \
echo "Supported archs:" && \
echo "" && \
echo "native > select the best architecture for the host processor (default)" && \
echo "x86-64-universal > x86 64-bit with automatic runtime selection of the best architecture" && \
echo "x86-64-avx512icl > x86 64-bit with minimum avx512 support of Intel Ice Lake or AMD Zen 4" && \
echo "x86-64-vnni512 > x86 64-bit with vnni 512bit support" && \
echo "x86-64-avx512 > x86 64-bit with avx512 support" && \
echo "x86-64-avxvnni > x86 64-bit with vnni 256bit support" && \
echo "x86-64-bmi2 > x86 64-bit with bmi2 support" && \
echo "x86-64-avx2 > x86 64-bit with avx2 support" && \
echo "x86-64-sse41-popcnt > x86 64-bit with sse41 and popcnt support" && \
echo "x86-64-modern > deprecated, currently x86-64-sse41-popcnt" && \
echo "x86-64-ssse3 > x86 64-bit with ssse3 support" && \
echo "x86-64-sse3-popcnt > x86 64-bit with sse3 compile and popcnt support" && \
echo "x86-64 > x86 64-bit generic (with sse2 support)" && \
echo "x86-32-sse41-popcnt > x86 32-bit with sse41 and popcnt support" && \
echo "x86-32-sse2 > x86 32-bit with sse2 support" && \
echo "x86-32 > x86 32-bit generic (with mmx compile support)" && \
echo "ppc-64 > PPC 64-bit" && \
echo "ppc-64-altivec > PPC 64-bit with altivec support" && \
echo "ppc-64-vsx > PPC 64-bit with vsx support" && \
echo "ppc-32 > PPC 32-bit" && \
echo "armv7 > ARMv7 32-bit" && \
echo "armv7-neon > ARMv7 32-bit with popcnt and neon" && \
echo "arm64-universal > ARMv8 64-bit with automatic runtime selection of the best architecture" && \
echo "armv8 > ARMv8 64-bit with popcnt and neon" && \
echo "armv8-dotprod > ARMv8 64-bit with popcnt, neon and dot product support" && \
echo "e2k > Elbrus 2000" && \
echo "apple-silicon > Apple silicon ARM64" && \
echo "general-64 > unspecified 64-bit" && \
echo "general-32 > unspecified 32-bit" && \
echo "riscv64 > RISC-V 64-bit" && \
echo "riscv64-rva23 > RISC-V 64-bit RVA23 profile" && \
echo "riscv64-universal > RISC-V 64-bit with automatic runtime selection of the best architecture" && \
echo "loongarch64 > LoongArch 64-bit" && \
echo "loongarch64-lsx > LoongArch 64-bit with SIMD eXtension" && \
echo "loongarch64-lasx > LoongArch 64-bit with Advanced SIMD eXtension" && \
echo "" && \
echo "Supported compilers:" && \
echo "" && \
echo "gcc > GNU compiler (default)" && \
echo "mingw > GNU compiler with MinGW under Windows" && \
echo "clang > LLVM Clang compiler" && \
echo "icx > Intel oneAPI DPC++/C++ Compiler" && \
echo "ndk > Google NDK to cross-compile for Android" && \
echo "" && \
echo "Simple examples. If you don't know what to do, you likely want to run one of: " && \
echo "" && \
echo "make -j profile-build ARCH=native # a fast compile for local use" && \
echo "make -j profile-build ARCH=x86-64-avx2 # A portable compile for most x86-64 systems " && \
echo "make -j profile-build ARCH=x86-64 # A portable compile for x86-64 systems " && \
echo "" && \
echo "Advanced examples, for experienced users: " && \
echo "" && \
echo "make -j profile-build ARCH=x86-64-avxvnni" && \
echo "make -j profile-build ARCH=x86-64-avxvnni COMP=gcc CXX=g++-12.0" && \
echo 'make -j profile-build ARCH=x86-64-universal RUN_PREFIX="/path/to/sde -future --" CXX=g++-15' && \
echo "make -j build ARCH=x86-64-ssse3 COMP=clang" && \
echo ""
ifneq ($(SUPPORTED_ARCH), true)
@echo "Specify a supported architecture with the ARCH option for more details"
@echo ""
endif
.PHONY: help analyze build profile-build macos-lipo strip install clean net \
objclean profileclean config-sanity \
icx-profile-use icx-profile-make \
gcc-profile-use gcc-profile-make \
clang-profile-use clang-profile-make FORCE \
format analyze
analyze: net config-sanity objclean
$(MAKE) -k ARCH=$(ARCH) COMP=$(COMP) $(OBJS)
ifeq ($(UNIVERSAL_BUILD),false)
build: net config-sanity
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) all
profile-build: net config-sanity objclean profileclean
@echo ""
@echo "Step 1/4. Building instrumented executable ..."
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) $(profile_make)
@echo ""
@echo "Step 2/4. Running benchmark for pgo-build ..."
$(PGOBENCH) > PGOBENCH.out 2>&1
tail -n 4 PGOBENCH.out
@echo ""
@echo "Step 3/4. Building optimized executable ..."
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) objclean
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) $(profile_use)
@echo ""
@echo "Step 4/4. Deleting profile data ..."
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) profileclean
endif
# Default network filename, read from evaluate.h's EvalFileDefaultName.
macos-lipo: NNUE_NET = $(shell grep -oE 'nn-[0-9a-f]+\.nnue' $(CURDIR)/evaluate.h | head -1)
macos-lipo:
@echo ""
@echo "Step 1/4. Building x86-64 slice (network shared from Apple-silicon slice) ..."
CXXFLAGS="-arch x86_64" $(MAKE) build ARCH=x86-64-universal COMP=$(COMP) MACOS_X86_SLICE=1
mv $(EXE) $(EXE)-x86_64
@echo ""
@echo "Step 2/4. Building Apple silicon slice ..."
$(MAKE) profile-build ARCH=apple-silicon COMP=$(COMP)
mv $(EXE) $(EXE)-arm64
@echo ""
@echo "Step 3/4. Combining slices and locating the embedded network ..."
lipo -create $(EXE)-x86_64 $(EXE)-arm64 -output $(EXE)
$(SHELL) universal/patch_x86_slice.sh $(EXE) $(EXE)-x86_64 $(NNUE_NET)
@echo ""
@echo "Step 4/4. Re-combining slices with the patched x86-64 slice ..."
lipo -create $(EXE)-x86_64 $(EXE)-arm64 -output $(EXE)
@rm -f $(EXE)-x86_64 $(EXE)-arm64
@echo "Universal macOS binary built: $(EXE)"
ifeq ($(TARGET_KERNEL),Darwin)
# Apple uses ld64 which doesn't have --save-temps
LTO_OBJ_SUFFIX := .lto.o
SAVE_TEMPS := -Wl,-object_path_lto,stockfish.lto.o
else ifeq ($(comp), clang)
LTO_OBJ_SUFFIX := .lto.o
ifeq ($(target_windows),yes)
SAVE_TEMPS := -Wl,--lto-emit-asm # ld.lld doesn't have a save temps functionality
use_lto_emit_asm := yes
else
SAVE_TEMPS := -Wl,--save-temps
endif
else
LTO_OBJ_SUFFIX := .ltrans0.ltrans.o
SAVE_TEMPS := -save-temps
endif
ifeq ($(arch),armv8)
ASM_FLAGS := -mcpu=neoverse-v2
endif
MODNAME := $(subst -,_,$(notdir $(CURDIR)))
universal-object-pgo: objclean profileclean universalclean
@echo ""
@echo "Step 1/4. Building instrumented executable ..."
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) ENV_LDFLAGS='$(ENV_LDFLAGS) $(NNUE_EMBED_OBJ)' $(profile_make)
@echo ""
@echo "Step 2/4. Running benchmark for pgo-build ..."
$(PGOBENCH) > PGOBENCH.out 2>&1
tail -n 4 PGOBENCH.out
@echo ""
@echo "Step 3/4. Building optimized object files ..."
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) objclean
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) ENV_LDFLAGS='$(SAVE_TEMPS) $(NNUE_EMBED_OBJ)' $(profile_use)
@echo ""
ifeq ($(use_lto_emit_asm),yes)
@echo "Step 4/4. Renaming ctors and extracting LTO-optimized relocatable object ..."
awk -v MODNAME=$(MODNAME) -f ../../universal/rewrite_asm_sections.awk *.lto.s > renamed.s
# -mcpu=neoverse-v2 (or another CPU supporting dotprod) is required for clang
# to not complain when assembling
$(CXX) -c renamed.s -o stockfish.o $(ASM_FLAGS)
else
@echo "Step 4/4. Extracting LTO-optimized relocatable object ..."
cp "$(basename $(EXE))$(LTO_OBJ_SUFFIX)" stockfish.o
endif
universal-object-nopgo: objclean universalclean
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) ENV_LDFLAGS='$(SAVE_TEMPS) $(NNUE_EMBED_OBJ)' all
ifeq ($(use_lto_emit_asm),yes)
awk -v MODNAME=$(MODNAME) -f ../../universal/rewrite_asm_sections.awk *.lto.s > renamed.s
$(CXX) -c renamed.s -o stockfish.o $(ASM_FLAGS)
else
cp "$(basename $(EXE))$(LTO_OBJ_SUFFIX)" stockfish.o
endif
strip:
$(STRIP) $(EXE)
install:
-mkdir -p -m 755 $(BINDIR)
-cp $(EXE) $(BINDIR)
$(STRIP) $(BINDIR)/$(EXE)
# clean all
clean: objclean profileclean universalclean
@rm -f .depend *~ core
# clean binaries and objects
objclean:
@rm -f stockfish stockfish.exe *.o ./syzygy/*.o ./nnue/*.o ./nnue/features/*.o $(BUILD_SHA_FILE) $(BUILD_DATE_FILE) $(BUILD_DIFFINDEX_FILE)
# clean auxiliary profiling files
profileclean:
@rm -rf profdir
@rm -f bench.txt *.gcda *.gcno ./syzygy/*.gcda ./nnue/*.gcda ./nnue/features/*.gcda *.s PGOBENCH.out
@rm -f stockfish.profdata *.profraw
@rm -f stockfish.*args*
@rm -f stockfish.*lt*
@rm -f stockfish.res
@rm -f ./-lstdc++.res
universalclean:
@rm -rf $(TEMP_DIR)
@rm -f universal/network_dump.inc
# evaluation network (nnue)
net:
@$(SHELL) ../scripts/net.sh
format:
$(CLANG-FORMAT) -i $(SRCS) $(OTHER_SRCS) $(HEADERS) -style=file
### ==========================================================================
### Section 5. Private Targets
### ==========================================================================
all: $(EXE) .depend
config-sanity: net
@echo ""
@echo "Config:" && \
echo "debug: '$(debug)'" && \
echo "sanitize: '$(sanitize)'" && \
echo "optimize: '$(optimize)'" && \
echo "arch: '$(arch)'" && \
echo "bits: '$(bits)'" && \
echo "kernel: '$(KERNEL)'" && \
echo "os: '$(OS)'" && \
echo "prefetch: '$(prefetch)'" && \
echo "popcnt: '$(popcnt)'" && \
echo "pext: '$(pext)'" && \
echo "sse: '$(sse)'" && \
echo "mmx: '$(mmx)'" && \
echo "sse2: '$(sse2)'" && \
echo "ssse3: '$(ssse3)'" && \
echo "sse41: '$(sse41)'" && \
echo "avx2: '$(avx2)'" && \
echo "avxvnni: '$(avxvnni)'" && \
echo "avx512: '$(avx512)'" && \
echo "vnni512: '$(vnni512)'" && \
echo "avx512icl: '$(avx512icl)'" && \
echo "altivec: '$(altivec)'" && \
echo "vsx: '$(vsx)'" && \
echo "neon: '$(neon)'" && \
echo "dotprod: '$(dotprod)'" && \
echo "arm_version: '$(arm_version)'" && \
echo "lsx: '$(lsx)'" && \
echo "lasx: '$(lasx)'" && \
echo "syzygy: '$(syzygy)'" && \
echo "target_windows: '$(target_windows)'" && \
echo "" && \
echo "Flags:" && \
echo "CXX: $(CXX)" && \
echo "CXXFLAGS: $(CXXFLAGS)" && \
echo "LDFLAGS: $(LDFLAGS)" && \
echo "" && \
echo "Testing config sanity. If this fails, try 'make help' ..." && \
echo "" && \
(test "$(debug)" = "yes" || test "$(debug)" = "no") && \
(test "$(optimize)" = "yes" || test "$(optimize)" = "no") && \
(test "$(SUPPORTED_ARCH)" = "true") && \
(test "$(arch)" = "any" || test "$(arch)" = "x86_64" || test "$(arch)" = "i386" || \
test "$(arch)" = "ppc64" || test "$(arch)" = "ppc" || test "$(arch)" = "e2k" || \
test "$(arch)" = "armv7" || test "$(arch)" = "armv8" || test "$(arch)" = "arm64" || \
test "$(arch)" = "riscv64" || test "$(arch)" = "loongarch64" || \
test "$(arch)" = "wasm32") && \
(test "$(bits)" = "32" || test "$(bits)" = "64") && \
(test "$(prefetch)" = "yes" || test "$(prefetch)" = "no") && \
(test "$(popcnt)" = "yes" || test "$(popcnt)" = "no") && \
(test "$(pext)" = "yes" || test "$(pext)" = "no") && \
(test "$(sse)" = "yes" || test "$(sse)" = "no") && \
(test "$(mmx)" = "yes" || test "$(mmx)" = "no") && \
(test "$(sse2)" = "yes" || test "$(sse2)" = "no") && \
(test "$(ssse3)" = "yes" || test "$(ssse3)" = "no") && \
(test "$(sse41)" = "yes" || test "$(sse41)" = "no") && \
(test "$(avx2)" = "yes" || test "$(avx2)" = "no") && \
(test "$(avx512)" = "yes" || test "$(avx512)" = "no") && \
(test "$(vnni512)" = "yes" || test "$(vnni512)" = "no") && \
(test "$(avx512icl)" = "yes" || test "$(avx512icl)" = "no") && \
(test "$(altivec)" = "yes" || test "$(altivec)" = "no") && \
(test "$(vsx)" = "yes" || test "$(vsx)" = "no") && \
(test "$(neon)" = "yes" || test "$(neon)" = "no") && \
(test "$(lsx)" = "yes" || test "$(lsx)" = "no") && \
(test "$(lasx)" = "yes" || test "$(lasx)" = "no") && \
(test "$(syzygy)" = "yes" || test "$(syzygy)" = "no") && \
(test "$(comp)" = "gcc" || test "$(comp)" = "icx" || test "$(comp)" = "mingw" || \
test "$(comp)" = "clang" || test "$(comp)" = "armv7a-linux-androideabi16-clang" || \
test "$(comp)" = "aarch64-linux-android21-clang")
$(EXE): $(OBJS)
+$(CXX) -o $@ $(OBJS) $(LDFLAGS)
%.o: %.cpp
$(strip $(CXX) $(CPPFLAGS) $(CXXFLAGS)) -c -o $@ $<
misc.o: misc.cpp $(BUILD_SHA_FILE) $(BUILD_DATE_FILE) $(BUILD_DIFFINDEX_FILE)
$(strip $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(if $(GIT_SHA),-DGIT_SHA=$(GIT_SHA)) $(if $(GIT_DATE),-DGIT_DATE=$(GIT_DATE))) $(if $(GIT_DIFFINDEX),-DGIT_DIFFINDEX=$(GIT_DIFFINDEX)) -c -o $@ $<
clang-profile-make:
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) \
EXTRACXXFLAGS='-fprofile-generate ' \
EXTRALDFLAGS=' -fprofile-generate' \
all
clang-profile-use:
$(XCRUN) $(LLVM_PROFDATA) merge -output=stockfish.profdata *.profraw
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) \
EXTRACXXFLAGS='-fprofile-use=stockfish.profdata' \
EXTRALDFLAGS='-fprofile-use ' \
all
gcc-profile-make:
@mkdir -p profdir
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) \
EXTRACXXFLAGS='-fprofile-generate=profdir' \
EXTRACXXFLAGS+=$(EXTRAPROFILEFLAGS) \
EXTRALDFLAGS='-lgcov' \
all
gcc-profile-use:
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) \
EXTRACXXFLAGS='-fprofile-use=profdir -fno-peel-loops -fno-tracer' \
EXTRACXXFLAGS+=$(EXTRAPROFILEFLAGS) \
EXTRALDFLAGS='-lgcov' \
all
icx-profile-make:
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) \
EXTRACXXFLAGS='-fprofile-instr-generate ' \
EXTRALDFLAGS=' -fprofile-instr-generate' \
all
icx-profile-use:
$(XCRUN) $(LLVM_PROFDATA) merge -output=stockfish.profdata *.profraw
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) \
EXTRACXXFLAGS='-fprofile-instr-use=stockfish.profdata' \
EXTRALDFLAGS='-fprofile-use ' \
all
.depend: $(SRCS)
-@$(CXX) $(DEPENDFLAGS) -MM $(SRCS) > $@ 2> /dev/null
ifeq (, $(filter $(MAKECMDGOALS), help strip install clean net objclean profileclean format config-sanity))
ifeq ($(UNIVERSAL_BUILD),false)
-include .depend
endif
endif
### ==========================================================================
### Section 6. Universal binary driver
### ==========================================================================
#
# Usage:
# make -j ARCH=x86-64-universal build # non-PGO
# make -j ARCH=x86-64-universal profile-build # PGO (use RUN_PREFIX for intel SDE)
# make -j ARCH=arm64-universal build
TEMP_DIR := $(CURDIR)/temp_builds
UNIVERSAL_EXE := $(CURDIR)/$(EXE)
ifeq ($(UNIVERSAL_BUILD),true)
UNIVERSAL_SRC_DIR := $(CURDIR)/universal
NNUE_EMBED_OBJ := $(TEMP_DIR)/nnue_embed.o
NET_SENTINEL := $(TEMP_DIR)/.net-done
ifeq ($(arch),x86_64)
UNIVERSAL_ARCHES := x86-64 x86-64-sse41-popcnt x86-64-avx2 x86-64-bmi2 \
x86-64-avxvnni x86-64-avx512 x86-64-vnni512 x86-64-avx512icl
UNIVERSAL_ENTRY_OBJ := $(TEMP_DIR)/entry_x86.o
UNIVERSAL_ENTRY_SRC := $(UNIVERSAL_SRC_DIR)/entry_x86.cpp
BASELINE_ARCH := x86-64
else ifeq ($(arch),riscv64)
UNIVERSAL_ARCHES := riscv64 riscv64-rva23
UNIVERSAL_ENTRY_OBJ := $(TEMP_DIR)/entry_riscv64.o
UNIVERSAL_ENTRY_SRC := $(UNIVERSAL_SRC_DIR)/entry_riscv64.cpp
BASELINE_ARCH := riscv64
else
UNIVERSAL_ARCHES := armv8 armv8-dotprod
UNIVERSAL_ENTRY_OBJ := $(TEMP_DIR)/entry_arm64.o
UNIVERSAL_ENTRY_SRC := $(UNIVERSAL_SRC_DIR)/entry_arm64.cpp
BASELINE_ARCH := armv8
endif
# Top-level tracked items in src/ (directories and files)
TRACKED_TOP := $(sort $(foreach f,$(SRCS) $(HEADERS) Makefile incbin,$(firstword $(subst /, ,$(f)))))
# Baseline build must come first in the final link (Windows --allow-multiple-definition
# uses the first copy of inline duplicates)
ARCH_OBJS := $(TEMP_DIR)/$(BASELINE_ARCH)/stockfish.o \
$(patsubst %,$(TEMP_DIR)/%/stockfish.o,$(filter-out $(BASELINE_ARCH),$(UNIVERSAL_ARCHES)))
UNIVERSAL_FINAL_FLAGS := -fno-exceptions -Os \
-Wno-c++26-extensions -Wno-c23-extensions # suppress #embed warnings
ifeq ($(TARGET_KERNEL),Darwin)
UNIVERSAL_FINAL_FLAGS += $(mac_target_flags)
else ifeq ($(TARGET_KERNEL),Linux)
UNIVERSAL_FINAL_FLAGS += -static-libstdc++ -static-libgcc
ifeq ($(COMP),ndk)
UNIVERSAL_FINAL_FLAGS += -static
else
UNIVERSAL_FINAL_FLAGS += -lrt -lpthread
endif
else # windows
UNIVERSAL_FINAL_FLAGS += -Wl,--allow-multiple-definition -static
ifeq ($(COMP),clang)
UNIVERSAL_FINAL_FLAGS += -lpthread
endif
endif
# $(call arch-namespace,x86-64-avx2) => Stockfish_x86_64_avx2
arch-suffix = $(subst -,_,$(1))
arch-namespace = Stockfish_$(call arch-suffix,$(1))
# Itanium ABI mangled name for Stockfish_<suffix>::main(int, char**)
arch-mangled = _ZN$(shell printf %s '$(call arch-namespace,$(1))' | wc -c | tr -d ' ')$(call arch-namespace,$(1))4mainEiPPc
# Mach-O initializer section name: strip "x86-64" or "x86-64-" and prefix with "_i_"
# (Mach-O section names are restricted to <=16 chars, hence this naming scheme)
arch-mac-section = _i_$(subst -,_,$(patsubst x86-64,,$(patsubst x86-64-%,%,$(1))))
ifeq ($(TARGET_KERNEL),Darwin)
arch-defmain = -Wl,-alias,_$(call arch-mangled,$(1)),_main
# lld-link, used on Windows+clang, doesn't accept --defsym, so
# we define main directly in main.cpp instead and delete it later.
else ifeq ($(target_windows)+$(COMP),yes+clang)
arch-defmain = -DUNIVERSAL_NEEDS_MAIN_SHIM
else
arch-defmain = -Wl,--defsym=main=$(call arch-mangled,$(1))
endif
EMBED_DIR_SUPPORTED := $(shell echo 'int main(){}' | $(CXX) -x c++ --embed-dir=. -o /dev/null -c - 2>/dev/null && echo 1 || echo 0)
ifeq ($(EMBED_DIR_SUPPORTED),1)
EMBED_DIR = --embed-dir=$(CURDIR)
endif
# macos-lipo sets MACOS_X86_SLICE=1 when building the x86-64 slice so that the
# slice reads the network out of the Apple-silicon slice instead of embedding
# its own copy (see universal/nnue_embed.cpp and universal/patch_x86_slice.sh).
ifeq ($(MACOS_X86_SLICE),1)
SLICE_DEF := -DUNIVERSAL_BINARY_MACOS_X86_SLICE
endif
arch-cxxflags = $(EMBED_DIR) -DStockfish=$(call arch-namespace,$(1)) -DUNIVERSAL_BINARY $(SLICE_DEF) \
$(call arch-defmain,$(1)) -Wno-c++26-extensions -Wno-c23-extensions
UOBJ_TGT ?= universal-object-pgo
ifeq ($(COMP),clang)
OBJCOPY ?= llvm-objcopy
else
OBJCOPY ?= objcopy
endif
.PHONY: build profile-build universal-clean
build: UOBJ_TGT := universal-object-nopgo
build: $(UNIVERSAL_EXE)
profile-build: UOBJ_TGT := universal-object-pgo
profile-build: $(UNIVERSAL_EXE)
$(TEMP_DIR):
@mkdir -p $@
# Download nnue files once in src/ (reused by every sub-arch via --embed-dir).
$(NET_SENTINEL): | $(TEMP_DIR)
@cd $(CURDIR) && $(SHELL) ../scripts/net.sh $(EMBED_DIR_SUPPORTED)
@touch $@
$(NNUE_EMBED_OBJ): $(UNIVERSAL_SRC_DIR)/nnue_embed.cpp $(NET_SENTINEL) | $(TEMP_DIR)
$(CXX) -O2 -std=c++20 -Wno-c++26-extensions $(SLICE_DEF) $(mac_target_flags) $(EXTRACXXFLAGS) $(EMBED_DIR) -c $< -o $@
$(UNIVERSAL_ENTRY_OBJ): $(UNIVERSAL_ENTRY_SRC) | $(TEMP_DIR)
$(CXX) -O2 -std=c++20 $(mac_target_flags) $(EXTRACXXFLAGS) -c $< -o $@
# Symlink tracked top-level items from src/ into temp_builds/<arch>/.
$(TEMP_DIR)/%/.setup: | $(TEMP_DIR)
@rm -rf $(TEMP_DIR)/$*
@mkdir -p $(TEMP_DIR)/$*
@$(foreach f,$(TRACKED_TOP),ln -s $(CURDIR)/$(f) $(TEMP_DIR)/$*/$(f);)
@touch $@
# Per-arch stockfish.o
.SECONDARY: $(patsubst %,$(TEMP_DIR)/%/.setup,$(UNIVERSAL_ARCHES))
$(TEMP_DIR)/%/stockfish.o: $(TEMP_DIR)/%/.setup $(NNUE_EMBED_OBJ) $(NET_SENTINEL)
+ENV_CXXFLAGS='$(ENV_CXXFLAGS) $(call arch-cxxflags,$*)' \
$(MAKE) -C $(TEMP_DIR)/$* $(UOBJ_TGT) \
ARCH=$* CXX=$(CXX) COMP=$(COMP) \
NNUE_EMBED_OBJ=$(NNUE_EMBED_OBJ)
ifeq ($(TARGET_KERNEL),Darwin)
# Rename the initializer section
ld -r -rename_section __DATA __mod_init_func __DATA $(call arch-mac-section,$*) $@ -o $@.tmp
mv $@.tmp $@
else
# Drop COMDAT groups; clang LTO leaves them around internalized LOCAL
# template instantiations which causes problems at the final link
$(OBJCOPY) -R .group $@
ifeq ($(use_lto_emit_asm),yes)
# Delete per-arch main shim
$(OBJCOPY) -N main $@
else
# Rename .init_array (Linux) or .ctors (Windows) so we can manually invoke them
$(OBJCOPY) --rename-section .init_array=$(call arch-suffix,$*)_init $@
$(OBJCOPY) --rename-section .ctors=$(call arch-suffix,$*)_init $@
# Make the array inert
$(OBJCOPY) --set-section-flags $(call arch-suffix,$*)_init=alloc,data $@
endif
endif
$(UNIVERSAL_EXE): $(UNIVERSAL_ENTRY_OBJ) $(NNUE_EMBED_OBJ) $(ARCH_OBJS)
$(CXX) -o $@ $(UNIVERSAL_ENTRY_OBJ) $(NNUE_EMBED_OBJ) $(ARCH_OBJS) $(UNIVERSAL_FINAL_FLAGS) $(EXTRALDFLAGS)
@echo "Universal binary built: $@"
endif # UNIVERSAL_BUILD