diff --git a/.github/workflows/python-app.yml b/.github/workflows/python-app.yml index 35675ea..b08ccde 100644 --- a/.github/workflows/python-app.yml +++ b/.github/workflows/python-app.yml @@ -19,19 +19,6 @@ jobs: - name: Check-out repository uses: actions/checkout@v4 - # Install audio library dependencies - - name: Install Audio Dependencies (Ubuntu) - if: runner.os == 'Linux' - run: | - sudo apt-get update - sudo apt-get install -y \ - build-essential \ - pkg-config \ - portaudio19-dev \ - libsndfile1-dev \ - libsamplerate0-dev \ - ccache - - name: Install Audio Dependencies (macOS) if: runner.os == 'macOS' run: | diff --git a/libs/audio/Makefile b/libs/audio/Makefile index af18c67..3049eb2 100644 --- a/libs/audio/Makefile +++ b/libs/audio/Makefile @@ -1,121 +1,167 @@ -# Makefile for audio library with full static linking +# Makefile for audio library with intelligent dependency detection CC = gcc CFLAGS = -Wall -Wextra -O3 -fPIC -std=c99 LDFLAGS = -shared -Wl,--export-dynamic -LIBS = -lportaudio -lsndfile -lsamplerate -lpthread -lm UNAME_S := $(shell uname -s 2>/dev/null || echo Windows) -# MSYS2/MinGW-w64 with full static linking +# Function to check if a library exists +define check_lib +$(shell pkg-config --exists $(1) 2>/dev/null && echo "yes" || echo "no") +endef + +# Function to check if a static library file exists +define check_static_lib +$(shell find /usr/lib /usr/local/lib /lib -name "lib$(1).a" 2>/dev/null | head -1) +endef + +# MSYS2/MinGW-w64 with intelligent static linking ifneq (,$(findstring MINGW,$(UNAME_S))) CC = x86_64-w64-mingw32-gcc LIBNAME = libaudio.dll CFLAGS = -Wall -Wextra -O3 -fPIC -std=c99 -I/mingw64/include -m64 + LDFLAGS = -shared -Wl,--export-all-symbols -static-libgcc -static-libstdc++ -L/mingw64/lib -m64 - # Full static linking flags - LDFLAGS = -shared \ - -Wl,--export-all-symbols \ - -Wl,--whole-archive \ - -static-libgcc \ - -static-libstdc++ \ - -static \ - -L/mingw64/lib \ - -m64 + # Core libraries (try static first, fall back to dynamic) + CORE_LIBS = + ifneq (,$(wildcard /mingw64/lib/libportaudio.a)) + CORE_LIBS += /mingw64/lib/libportaudio.a + else + CORE_LIBS += -lportaudio + endif - # Static libraries in correct order (dependencies matter!) - LIBS = -Wl,--start-group \ - -lportaudio \ - -lsndfile \ - -lsamplerate \ - -lFLAC \ - -lvorbisenc \ - -lvorbisfile \ - -lvorbis \ - -logg \ - -lopus \ - -lwinmm \ - -lole32 \ - -luuid \ - -lksuser \ - -lsetupapi \ - -lws2_32 \ - -ladvapi32 \ - -luser32 \ - -lgdi32 \ - -lkernel32 \ - -Wl,--end-group \ - -Wl,--no-whole-archive + ifneq (,$(wildcard /mingw64/lib/libsndfile.a)) + CORE_LIBS += /mingw64/lib/libsndfile.a + else + CORE_LIBS += -lsndfile + endif + ifneq (,$(wildcard /mingw64/lib/libsamplerate.a)) + CORE_LIBS += /mingw64/lib/libsamplerate.a + else + CORE_LIBS += -lsamplerate + endif + + # Optional codec libraries + CODEC_LIBS = + ifneq (,$(wildcard /mingw64/lib/libFLAC.a)) + CODEC_LIBS += /mingw64/lib/libFLAC.a + endif + ifneq (,$(wildcard /mingw64/lib/libvorbisenc.a)) + CODEC_LIBS += /mingw64/lib/libvorbisenc.a /mingw64/lib/libvorbisfile.a /mingw64/lib/libvorbis.a + endif + ifneq (,$(wildcard /mingw64/lib/libogg.a)) + CODEC_LIBS += /mingw64/lib/libogg.a + endif + + # System libraries + SYSTEM_LIBS = -lwinmm -lole32 -luuid -lksuser -lsetupapi -lws2_32 + + LIBS = $(CORE_LIBS) $(CODEC_LIBS) $(SYSTEM_LIBS) OBJ_EXT = .o -else ifneq (,$(findstring Windows,$(UNAME_S))) - # Windows with MSVC (alternative approach) - CC = cl - LIBNAME = libaudio.dll - CFLAGS = /O2 /W3 /MD /TC /DSTATIC_LINK - LDFLAGS = /DLL /NODEFAULTLIB:MSVCRT - LIBS = portaudio_static.lib libsndfile_static.lib libsamplerate_static.lib \ - winmm.lib ole32.lib uuid.lib setupapi.lib ws2_32.lib - OBJ_EXT = .obj - else ifeq ($(UNAME_S),Darwin) - # macOS with static linking + # macOS LIBNAME = libaudio.dylib CFLAGS += -I/usr/local/include -I/opt/homebrew/include - LDFLAGS = -shared -undefined dynamic_lookup - LDFLAGS += -L/usr/local/lib -L/opt/homebrew/lib - # Try static first, fall back to dynamic - LIBS = -Wl,-search_paths_first \ - /usr/local/lib/libportaudio.a \ - /usr/local/lib/libsndfile.a \ - /usr/local/lib/libsamplerate.a \ - -framework CoreAudio -framework AudioToolbox -framework AudioUnit \ - -framework CoreFoundation -framework CoreServices + LDFLAGS = -shared -undefined dynamic_lookup -L/usr/local/lib -L/opt/homebrew/lib + + # Core libraries + LIBS = -lportaudio -lsndfile -lsamplerate + + # macOS frameworks + LIBS += -framework CoreAudio -framework AudioToolbox -framework AudioUnit + LIBS += -framework CoreFoundation -framework CoreServices OBJ_EXT = .o else ifeq ($(UNAME_S),Linux) - # Linux with static linking + # Linux with intelligent library detection LIBNAME = libaudio.so - LDFLAGS = -shared -static-libgcc - # Static link audio libraries, dynamic link system libraries - LIBS = -Wl,-Bstatic \ - -lportaudio \ - -lsndfile \ - -lsamplerate \ - -lFLAC \ - -lvorbisenc \ - -lvorbisfile \ - -lvorbis \ - -logg \ - -Wl,-Bdynamic \ - -lasound \ - -ljack \ - -lpulse \ - -lpulse-simple \ - -pthread \ - -lm \ - -ldl + + # Check for pkg-config availability + PKG_CONFIG := $(shell command -v pkg-config 2> /dev/null) + + # Core audio libraries (required) + CORE_LIBS = -lportaudio -lsndfile + + # Check for libsamplerate + ifeq ($(call check_lib,samplerate),yes) + CORE_LIBS += -lsamplerate + CFLAGS += -DHAVE_SAMPLERATE + else + $(warning libsamplerate not found - building without sample rate conversion) + endif + + # Audio backend libraries (optional) + BACKEND_LIBS = + + # Check for ALSA + ifeq ($(call check_lib,alsa),yes) + BACKEND_LIBS += -lasound + CFLAGS += -DHAVE_ALSA + endif + + # Check for PulseAudio + ifeq ($(call check_lib,libpulse),yes) + BACKEND_LIBS += -lpulse + CFLAGS += -DHAVE_PULSE + endif + + ifeq ($(call check_lib,libpulse-simple),yes) + BACKEND_LIBS += -lpulse-simple + CFLAGS += -DHAVE_PULSE_SIMPLE + endif + + # Check for JACK (optional) + ifeq ($(call check_lib,jack),yes) + BACKEND_LIBS += -ljack + CFLAGS += -DHAVE_JACK + endif + + # Codec libraries (optional) + CODEC_LIBS = + ifeq ($(call check_lib,flac),yes) + CODEC_LIBS += -lFLAC + CFLAGS += -DHAVE_FLAC + endif + + ifeq ($(call check_lib,vorbisenc),yes) + CODEC_LIBS += -lvorbisenc -lvorbisfile -lvorbis + CFLAGS += -DHAVE_VORBIS + endif + + ifeq ($(call check_lib,ogg),yes) + CODEC_LIBS += -logg + CFLAGS += -DHAVE_OGG + endif + + # System libraries + SYSTEM_LIBS = -lpthread -lm -ldl + + # Combine all libraries + LIBS = $(CORE_LIBS) $(BACKEND_LIBS) $(CODEC_LIBS) $(SYSTEM_LIBS) OBJ_EXT = .o else - # Generic Unix fallback + # Generic Unix fallback - minimal dependencies LIBNAME = libaudio.so + LIBS = -lportaudio -lsndfile -lpthread -lm OBJ_EXT = .o endif SOURCES = $(wildcard *.c) -# Object files with correct extension +# Object files ifneq (,$(findstring Windows,$(UNAME_S))) OBJECTS = $(SOURCES:.c=.obj) else OBJECTS = $(SOURCES:.c=.o) endif -.PHONY: all clean install debug check-deps static +.PHONY: all clean install debug check-deps list-libs minimal -all: $(LIBNAME) +all: check-deps $(LIBNAME) -# Main build targets +# Build targets ifneq (,$(findstring Windows,$(UNAME_S))) $(LIBNAME): $(OBJECTS) link $(LDFLAGS) /OUT:$@ $^ $(LIBS) @@ -126,10 +172,6 @@ $(LIBNAME): $(OBJECTS) clean: -del /Q *.obj $(LIBNAME) 2>nul || rm -f $(OBJECTS) $(LIBNAME) -check-deps: - @echo "Checking for static libraries on Windows..." - @if exist "$(VCPKG_INSTALLATION_ROOT)\installed\x64-windows-static\lib\portaudio.lib" (echo Static PortAudio found!) else (echo Static PortAudio not found!) - else # Unix/Linux/macOS build rules $(LIBNAME): $(OBJECTS) @@ -144,46 +186,74 @@ clean: install: $(LIBNAME) sudo cp $(LIBNAME) /usr/local/lib/ sudo ldconfig 2>/dev/null || true - -check-deps: - @echo "Checking for static libraries..." - @pkg-config --exists --static portaudio-2.0 || echo "Static PortAudio not found" - @pkg-config --exists --static sndfile || echo "Static libsndfile not found" - @find /usr/local/lib /usr/lib -name "libportaudio.a" 2>/dev/null || echo "No static portaudio found" - @find /usr/local/lib /usr/lib -name "libsndfile.a" 2>/dev/null || echo "No static sndfile found" - endif -# Development target with debug symbols -debug: CFLAGS += $(if $(findstring Windows,$(UNAME_S)),/Zi,-g -DDEBUG) -debug: $(LIBNAME) +# Check dependencies and show what will be used +check-deps: + @echo "=== Dependency Check ===" + @echo "Target system: $(UNAME_S)" + @echo "Library name: $(LIBNAME)" + @echo "Compiler: $(CC)" +ifneq (,$(findstring MINGW,$(UNAME_S))) + @echo "=== MinGW Libraries ===" + @echo "Available static libraries:" + @ls /mingw64/lib/lib{portaudio,sndfile,samplerate,FLAC,vorbis*,ogg}.a 2>/dev/null || echo "None found" + @echo "Libraries to link: $(LIBS)" +else ifeq ($(UNAME_S),Linux) + @echo "=== Linux Package Check ===" +ifdef PKG_CONFIG + @echo "pkg-config available: yes" + @echo -n "PortAudio: "; pkg-config --exists portaudio-2.0 && echo "✓" || echo "✗" + @echo -n "libsndfile: "; pkg-config --exists sndfile && echo "✓" || echo "✗" + @echo -n "libsamplerate: "; pkg-config --exists samplerate && echo "✓" || echo "✗" + @echo -n "ALSA: "; pkg-config --exists alsa && echo "✓" || echo "✗" + @echo -n "PulseAudio: "; pkg-config --exists libpulse && echo "✓" || echo "✗" + @echo -n "JACK: "; pkg-config --exists jack && echo "✓" || echo "✗" +else + @echo "pkg-config not available" +endif + @echo "Libraries to link: $(LIBS)" +else + @echo "Libraries to link: $(LIBS)" +endif -# Target to build with maximum static linking -static: LDFLAGS += $(if $(findstring MINGW,$(UNAME_S)),-static,) -static: $(LIBNAME) +# Show detected libraries +list-libs: + @echo "Core libraries: $(CORE_LIBS)" + @echo "Backend libraries: $(BACKEND_LIBS)" + @echo "Codec libraries: $(CODEC_LIBS)" + @echo "System libraries: $(SYSTEM_LIBS)" + @echo "All libraries: $(LIBS)" + +# Build with only essential libraries (fallback) +minimal: override LIBS = -lportaudio -lsndfile -lpthread -lm +minimal: $(LIBNAME) + @echo "Built minimal version with basic dependencies only" + +# Development target +debug: CFLAGS += -g -DDEBUG +debug: $(LIBNAME) # Verification target verify: $(LIBNAME) @echo "=== Library Information ===" - @if [ "$(findstring MINGW,$(UNAME_S))" ]; then \ - file $(LIBNAME); \ - echo "=== Dependencies ==="; \ - objdump -p $(LIBNAME) | grep "DLL Name:" || echo "No DLL dependencies (fully static)"; \ - elif [ "$(UNAME_S)" = "Linux" ]; then \ - file $(LIBNAME); \ - echo "=== Dependencies ==="; \ - ldd $(LIBNAME) 2>/dev/null || echo "No shared library dependencies"; \ - else \ - file $(LIBNAME); \ - fi + @file $(LIBNAME) +ifneq (,$(findstring MINGW,$(UNAME_S))) + @echo "=== Dependencies ===" + @objdump -p $(LIBNAME) | grep "DLL Name:" | head -10 || echo "No dependencies found" +else ifeq ($(UNAME_S),Linux) + @echo "=== Dependencies ===" + @ldd $(LIBNAME) 2>/dev/null | head -10 || echo "Static build or no dependencies" +endif help: @echo "Available targets:" @echo " all - Build the audio library (default)" - @echo " static - Build with maximum static linking" + @echo " minimal - Build with minimal dependencies" @echo " clean - Remove build artifacts" @echo " install - Install library (Unix/Linux/macOS only)" @echo " debug - Build with debug symbols" @echo " check-deps- Check for required dependencies" + @echo " list-libs - Show detected library configuration" @echo " verify - Verify built library and show dependencies" @echo " help - Show this help message"