FFTW emits '#warning Only SSE and SSE2 are available' when cross-compiling with a generic x86_64 target: the configure test for AVX intrinsics fails without an explicit -mavx flag, so FFTW silently falls back to SSE2. Fix: pass CFLAGS="-march=haswell" to configure, which enables SSE2/AVX/AVX2/FMA. Add --enable-avx2 alongside existing --enable-avx. FFTW_MARCH is overridable for older CPU targets: make -f Makefile.windows FFTW_MARCH=-march=sandybridge # AVX only, 2011+ make -f Makefile.windows FFTW_MARCH=-march=core2 # SSSE3, 2007+ Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
295 lines
13 KiB
Makefile
295 lines
13 KiB
Makefile
#
|
||
# Makefile.windows — кросс-компиляция WDSP для 64-bit Windows на Linux (MinGW-w64)
|
||
#
|
||
# Использование:
|
||
# make -f Makefile.windows # DLL + статическая библиотека
|
||
# make -f Makefile.windows dll # только DLL
|
||
# make -f Makefile.windows static # только статическая библиотека
|
||
# make -f Makefile.windows clean # удалить артефакты сборки
|
||
# make -f Makefile.windows distclean # + удалить собранный и скачанный FFTW
|
||
#
|
||
# Зависимости (установить до запуска):
|
||
# Arch: sudo pacman -S mingw-w64-gcc (тянет mingw-w64-headers автоматически)
|
||
# Debian: sudo apt install mingw-w64 (мета-пакет: компилятор + заголовки + CRT)
|
||
# Fedora: sudo dnf install mingw64-gcc (тянет mingw64-headers автоматически)
|
||
# + wget или curl, tar
|
||
#
|
||
|
||
MINGW_PREFIX ?= x86_64-w64-mingw32
|
||
|
||
CC := $(MINGW_PREFIX)-gcc
|
||
AR := $(MINGW_PREFIX)-ar
|
||
RANLIB := $(MINGW_PREFIX)-ranlib
|
||
|
||
CFLAGS ?= -O3 -Wno-parentheses -Wno-incompatible-pointer-types
|
||
LDFLAGS ?=
|
||
|
||
# ── FFTW: сборка из исходников ────────────────────────────────────────────────
|
||
|
||
FFTW_VERSION := 3.3.11
|
||
FFTW_TAR := fftw-$(FFTW_VERSION).tar.gz
|
||
FFTW_URL := https://fftw.org/pub/fftw/$(FFTW_TAR)
|
||
|
||
# Абсолютные пути — нужны для configure --prefix и sub-make -C
|
||
FFTW_SRC := $(CURDIR)/third_party/fftw-$(FFTW_VERSION)
|
||
FFTW_INST := $(CURDIR)/third_party/fftw-win64
|
||
|
||
# Раздельные build-директории для double и float precision
|
||
FFTW_BUILD_D := $(FFTW_INST)/build-double
|
||
FFTW_BUILD_F := $(FFTW_INST)/build-float
|
||
|
||
# FFTW_MARCH задаёт минимальный набор инструкций для Windows-бинарника.
|
||
# haswell (2013+) гарантирует AVX2+FMA — оптимальный выбор для SDR на современном ПК.
|
||
# Для совместимости со старыми машинами замените на -march=sandybridge (AVX, 2011+)
|
||
# или -march=core2 (SSSE3, 2007+).
|
||
FFTW_MARCH ?= -march=haswell
|
||
|
||
FFTW_CONF_COMMON = \
|
||
--host=$(MINGW_PREFIX) \
|
||
CC=$(CC) \
|
||
CFLAGS="$(FFTW_MARCH)" \
|
||
--prefix=$(FFTW_INST) \
|
||
--enable-shared \
|
||
--disable-static \
|
||
--with-our-malloc \
|
||
--enable-sse2 \
|
||
--enable-avx \
|
||
--enable-avx2 \
|
||
--disable-fortran \
|
||
--quiet
|
||
|
||
# Sentinel-файлы для отслеживания готовности FFTW
|
||
FFTW_HEADER := $(FFTW_INST)/include/fftw3.h
|
||
FFTW_LIB_D := $(FFTW_INST)/lib/libfftw3.dll.a
|
||
FFTW_LIB_F := $(FFTW_INST)/lib/libfftw3f.dll.a
|
||
FFTW_DLL_D := $(FFTW_INST)/bin/libfftw3-3.dll
|
||
FFTW_DLL_F := $(FFTW_INST)/bin/libfftw3f-3.dll
|
||
|
||
# ── Выходные директории и файлы ───────────────────────────────────────────────
|
||
|
||
OBJDIR := obj_win
|
||
OUTDIR := lib_win
|
||
|
||
DLL := $(OUTDIR)/libwdsp.dll
|
||
IMPLIB := $(OUTDIR)/libwdsp.dll.a
|
||
STATIC_LIB := $(OUTDIR)/libwdsp.a
|
||
|
||
# ── Исходники (копия из основного Makefile) ───────────────────────────────────
|
||
|
||
SOURCES = \
|
||
amd.c ammod.c amsq.c analyzer.c anf.c anr.c apfshadow.c \
|
||
bandpass.c calcc.c calculus.c cblock.c cfcomp.c cfir.c \
|
||
channel.c cmath.c compress.c delay.c dexp.c div.c doublepole.c \
|
||
eer.c emnr.c emph.c eq.c fcurve.c FDnoiseIQ.c fir.c firmin.c \
|
||
fmd.c fmmod.c fmsq.c gain.c gaussian.c gen.c icfir.c iir.c \
|
||
impulse_cache.c iobuffs.c iqc.c linux_port.c lmath.c main.c \
|
||
matchedCW.c meter.c meterlog10.c nbp.c nob.c nobII.c osctrl.c \
|
||
patchpanel.c resample.c rmatch.c rnnr.c RXA.c sbnr.c sender.c \
|
||
shift.c siphon.c slew.c snb.c ssql.c syncbuffs.c TXA.c \
|
||
utilities.c varsamp.c version.c wcpAGC.c wisdom.c zetaHat.c
|
||
|
||
OBJS := $(addprefix $(OBJDIR)/, $(SOURCES:.c=.o))
|
||
|
||
# ── NR3/NR4: исходники third-party ────────────────────────────────────────────
|
||
#
|
||
# Компилируем rnnoise и libspecbleach напрямую в obj_win/, минуя их sub-make.
|
||
# Это исключает конфликт с Linux-сборкой: third_party/*.a содержат ELF-объекты,
|
||
# и если они "свежее" исходников, sub-make считает их up-to-date и не пересобирает.
|
||
|
||
RNNOISE_DIR := third_party/rnnoise
|
||
SPECBLEACH_DIR := third_party/libspecbleach
|
||
|
||
RNNOISE_SRCS := \
|
||
src/denoise.c src/celt_lpc.c src/kiss_fft.c src/nnet.c \
|
||
src/nnet_default.c src/parse_lpcnet_weights.c src/pitch.c \
|
||
src/rnn.c src/rnnoise_data.c \
|
||
src/rnnoise_data_1.c src/rnnoise_data_2.c src/rnnoise_data_3.c \
|
||
src/rnnoise_data_4.c src/rnnoise_data_5.c src/rnnoise_data_6.c \
|
||
src/rnnoise_tables.c
|
||
|
||
SPECBLEACH_SRCS := \
|
||
src/processors/specbleach_adenoiser.c \
|
||
src/processors/specbleach_denoiser.c \
|
||
src/processors/adaptivedenoiser/adaptive_denoiser.c \
|
||
src/shared/gain_estimation/gain_estimators.c \
|
||
src/shared/noise_estimation/adaptive_noise_estimator.c \
|
||
src/shared/pre_estimation/absolute_hearing_thresholds.c \
|
||
src/shared/pre_estimation/critical_bands.c \
|
||
src/shared/pre_estimation/masking_estimator.c \
|
||
src/shared/pre_estimation/noise_scaling_criterias.c \
|
||
src/shared/pre_estimation/spectral_smoother.c \
|
||
src/shared/pre_estimation/transient_detector.c \
|
||
src/shared/post_estimation/noise_floor_manager.c \
|
||
src/shared/post_estimation/postfilter.c \
|
||
src/shared/post_estimation/spectral_whitening.c \
|
||
src/shared/utils/denoise_mixer.c \
|
||
src/shared/utils/general_utils.c \
|
||
src/shared/utils/spectral_features.c \
|
||
src/shared/utils/spectral_utils.c \
|
||
src/shared/stft/stft_processor.c \
|
||
src/shared/stft/fft_transform.c \
|
||
src/shared/stft/stft_buffer.c \
|
||
src/shared/stft/stft_windows.c
|
||
|
||
RNNOISE_OBJS := $(addprefix $(OBJDIR)/rnnoise/, $(RNNOISE_SRCS:.c=.o))
|
||
SPECBLEACH_OBJS := $(addprefix $(OBJDIR)/specbleach/, $(SPECBLEACH_SRCS:.c=.o))
|
||
|
||
RNNOISE_LIB := $(OUTDIR)/librnnoise.a
|
||
SPECBLEACH_LIB := $(OUTDIR)/libspecbleach.a
|
||
|
||
# ── Флаги компиляции ──────────────────────────────────────────────────────────
|
||
|
||
NR34_INC := -I$(RNNOISE_DIR)/include -I$(SPECBLEACH_DIR)/include
|
||
FFTW_INC := -I$(FFTW_INST)/include
|
||
|
||
COMPILE := $(CC) $(CFLAGS) $(FFTW_INC) $(NR34_INC)
|
||
|
||
NR34_DEPS := $(RNNOISE_LIB) $(SPECBLEACH_LIB)
|
||
|
||
# avrt нужен т.к. comm.h включает <avrt.h> под _WIN32
|
||
LINK_LIBS := $(NR34_DEPS) \
|
||
-L$(FFTW_INST)/lib -lfftw3 -lfftw3f \
|
||
-lavrt -lm
|
||
|
||
# ── Цели ──────────────────────────────────────────────────────────────────────
|
||
|
||
.PHONY: all dll static fftw fftw-double fftw-float third-party check-tools clean distclean
|
||
|
||
all: dll static
|
||
|
||
dll: check-tools fftw third-party $(DLL)
|
||
static: check-tools fftw third-party $(STATIC_LIB)
|
||
|
||
# ── Проверка инструментов ─────────────────────────────────────────────────────
|
||
|
||
check-tools:
|
||
@command -v $(CC) >/dev/null 2>&1 || { \
|
||
echo ""; \
|
||
echo "ОШИБКА: $(CC) не найден. Установите mingw-w64:"; \
|
||
echo " Arch: sudo pacman -S mingw-w64-gcc"; \
|
||
echo " Debian: sudo apt install mingw-w64"; \
|
||
echo " Fedora: sudo dnf install mingw64-gcc"; \
|
||
echo ""; exit 1; }
|
||
@echo '#include <windows.h>' | $(CC) -x c - -fsyntax-only -Wno-pragma-once-outside-header 2>/dev/null || { \
|
||
echo ""; \
|
||
echo "ОШИБКА: Windows API заголовки не найдены."; \
|
||
echo "Установите пакет с заголовками MinGW-w64:"; \
|
||
echo " Arch: sudo pacman -S mingw-w64-headers"; \
|
||
echo " Debian: sudo apt install mingw-w64 # не gcc-mingw-w64-x86-64!"; \
|
||
echo " Fedora: sudo dnf install mingw64-headers"; \
|
||
echo ""; exit 1; }
|
||
@(command -v wget >/dev/null 2>&1 || command -v curl >/dev/null 2>&1) || { \
|
||
echo "ОШИБКА: требуется wget или curl"; exit 1; }
|
||
|
||
# ── FFTW: скачать исходники → собрать double → собрать float ──────────────────
|
||
|
||
fftw: fftw-double fftw-float
|
||
|
||
# Шаг 1: скачать tarball
|
||
third_party/$(FFTW_TAR):
|
||
mkdir -p third_party
|
||
@echo ">>> Скачиваем FFTW $(FFTW_VERSION)..."
|
||
@if command -v wget >/dev/null 2>&1; then \
|
||
wget -q --show-progress -O $@ "$(FFTW_URL)"; \
|
||
else \
|
||
curl -L --progress-bar -o $@ "$(FFTW_URL)"; \
|
||
fi
|
||
|
||
# Шаг 2: распаковать
|
||
$(FFTW_SRC)/configure: third_party/$(FFTW_TAR)
|
||
@echo ">>> Распаковываем FFTW..."
|
||
tar xf $< -C third_party/
|
||
@touch $@
|
||
|
||
# Шаг 3a: configure для double precision
|
||
$(FFTW_BUILD_D)/Makefile: $(FFTW_SRC)/configure
|
||
mkdir -p $(FFTW_BUILD_D)
|
||
@echo ">>> Конфигурируем FFTW (double)..."
|
||
cd $(FFTW_BUILD_D) && $(FFTW_SRC)/configure $(FFTW_CONF_COMMON)
|
||
|
||
# Шаг 4a: сборка и установка double precision
|
||
fftw-double: $(FFTW_LIB_D)
|
||
$(FFTW_LIB_D): $(FFTW_BUILD_D)/Makefile
|
||
@echo ">>> Собираем FFTW (double)..."
|
||
$(MAKE) -C $(FFTW_BUILD_D) install
|
||
|
||
# Шаг 3b: configure для float precision (--enable-float)
|
||
$(FFTW_BUILD_F)/Makefile: $(FFTW_SRC)/configure
|
||
mkdir -p $(FFTW_BUILD_F)
|
||
@echo ">>> Конфигурируем FFTW (float)..."
|
||
cd $(FFTW_BUILD_F) && $(FFTW_SRC)/configure $(FFTW_CONF_COMMON) --enable-float
|
||
|
||
# Шаг 4b: сборка и установка float precision
|
||
# Зависит от fftw-double чтобы install-шаги не конкурировали за prefix
|
||
fftw-float: $(FFTW_LIB_F)
|
||
$(FFTW_LIB_F): $(FFTW_BUILD_F)/Makefile $(FFTW_LIB_D)
|
||
@echo ">>> Собираем FFTW (float)..."
|
||
$(MAKE) -C $(FFTW_BUILD_F) install
|
||
|
||
# ── Third-party библиотеки (кросс-компиляция) ─────────────────────────────────
|
||
|
||
third-party: $(NR34_DEPS)
|
||
|
||
$(RNNOISE_LIB): $(RNNOISE_OBJS) | $(OUTDIR)
|
||
$(AR) rv $@ $^
|
||
$(RANLIB) $@
|
||
|
||
$(SPECBLEACH_LIB): $(SPECBLEACH_OBJS) | $(OUTDIR)
|
||
$(AR) rv $@ $^
|
||
$(RANLIB) $@
|
||
|
||
# % в GNU make совпадает через '/', поэтому паттерн покрывает вложенные пути
|
||
$(OBJDIR)/rnnoise/%.o: $(RNNOISE_DIR)/%.c
|
||
@mkdir -p $(@D)
|
||
$(CC) $(CFLAGS) -I$(RNNOISE_DIR)/include -I$(RNNOISE_DIR)/src -c -o $@ $<
|
||
|
||
$(OBJDIR)/specbleach/%.o: $(SPECBLEACH_DIR)/%.c | $(FFTW_LIB_D)
|
||
@mkdir -p $(@D)
|
||
$(CC) $(CFLAGS) -I$(FFTW_INST)/include \
|
||
-I$(SPECBLEACH_DIR)/include -I$(SPECBLEACH_DIR)/src -I$(SPECBLEACH_DIR)/src/shared \
|
||
-c -o $@ $<
|
||
|
||
# ── Основная библиотека ───────────────────────────────────────────────────────
|
||
|
||
$(OUTDIR) $(OBJDIR):
|
||
mkdir -p $@
|
||
|
||
$(DLL): $(OBJS) $(NR34_DEPS) $(FFTW_LIB_D) $(FFTW_LIB_F) | $(OUTDIR)
|
||
@echo ">>> Линкуем $@..."
|
||
$(CC) -shared \
|
||
-Wl,--out-implib,$(IMPLIB) \
|
||
$(LDFLAGS) \
|
||
-o $@ \
|
||
$(OBJS) $(LINK_LIBS)
|
||
@cp $(FFTW_DLL_D) $(FFTW_DLL_F) $(OUTDIR)/
|
||
@echo ""
|
||
@echo "=== Готово ==="
|
||
@echo " DLL: $(DLL)"
|
||
@echo " Import lib: $(IMPLIB)"
|
||
@echo " Заголовок: wdsp.h"
|
||
@echo ""
|
||
@echo " FFTW DLL скопированы в $(OUTDIR)/ — включите их в дистрибутив"
|
||
@echo " рядом с libwdsp.dll."
|
||
|
||
$(STATIC_LIB): $(OBJS) | $(OUTDIR)
|
||
$(AR) rv $@ $(OBJS)
|
||
$(RANLIB) $@
|
||
@echo ""
|
||
@echo "=== Готово ==="
|
||
@echo " Статическая: $(STATIC_LIB)"
|
||
@echo " Линкуйте приложение с:"
|
||
@echo " $(STATIC_LIB) $(NR34_DEPS)"
|
||
@echo " -L$(FFTW_INST)/lib -lfftw3 -lfftw3f -lavrt -lm"
|
||
|
||
$(OBJDIR)/%.o: %.c | $(OBJDIR) $(FFTW_LIB_D)
|
||
$(COMPILE) -c -o $@ $<
|
||
|
||
# ── Очистка ───────────────────────────────────────────────────────────────────
|
||
|
||
clean:
|
||
-rm -rf $(OBJDIR) $(OUTDIR)
|
||
|
||
# distclean удаляет собранный и скачанный FFTW — при следующем запуске пересоберётся
|
||
distclean: clean
|
||
-rm -rf $(FFTW_INST) $(FFTW_SRC) third_party/$(FFTW_TAR)
|