diff --git a/.github/workflows/python-app.yml b/.github/workflows/python-app.yml index 030d51c..35675ea 100644 --- a/.github/workflows/python-app.yml +++ b/.github/workflows/python-app.yml @@ -38,7 +38,6 @@ jobs: brew update brew install portaudio libsndfile libsamplerate pkg-config - # Use MSYS2 for Windows audio library build - name: Set up MSYS2 (Windows) if: runner.os == 'Windows' uses: msys2/setup-msys2@v2 @@ -50,94 +49,72 @@ jobs: mingw-w64-x86_64-portaudio mingw-w64-x86_64-libsndfile mingw-w64-x86_64-libsamplerate + mingw-w64-x86_64-flac + mingw-w64-x86_64-libvorbis + mingw-w64-x86_64-libogg + mingw-w64-x86_64-opus - - name: Build audio library (DLL) (Windows) + - name: Build static audio library (Windows) if: runner.os == 'Windows' shell: msys2 {0} working-directory: libs/audio run: | + # Clean previous builds make clean - make all - - name: List build outputs (Windows) - if: runner.os == 'Windows' - shell: msys2 {0} - working-directory: libs/audio - run: | - ls -l + # Build with static linking + make static - - name: Copy DLL to build directory (Windows) + # Verify the build + make verify + + # Show final library info + echo "=== Final library verification ===" + ls -la libaudio.dll + file libaudio.dll + + # Check dependencies - should be minimal + echo "=== DLL Dependencies (should be minimal) ===" + objdump -p libaudio.dll | grep "DLL Name:" || echo "No external DLL dependencies found!" + + - name: Copy static DLL (Windows) if: runner.os == 'Windows' run: | mkdir -p build/lib cp libs/audio/libaudio.dll build/lib/ + + # No need to copy other DLLs since everything is statically linked! + echo "Static build complete - single DLL created" + ls -la build/lib/ shell: bash - - name: Copy DLL dependencies (Windows) - if: runner.os == 'Windows' - shell: msys2 {0} + # For Unix systems, also try static builds + - name: Install static development libraries (Ubuntu) + if: runner.os == 'Linux' run: | - # Get the actual workspace path - WORKSPACE_PATH=$(cygpath -m "$GITHUB_WORKSPACE") - echo "Workspace path: $WORKSPACE_PATH" + sudo apt-get update + sudo apt-get install -y \ + build-essential \ + pkg-config \ + libportaudio2 \ + portaudio19-dev \ + libsndfile1-dev \ + libsamplerate0-dev \ + libflac-dev \ + libvorbis-dev \ + libogg-dev \ + ccache - # Create build directory - mkdir -p "$WORKSPACE_PATH/build/lib" - - # Copy our built library first - cp libs/audio/libaudio.dll "$WORKSPACE_PATH/build/lib/" - - # Copy MinGW runtime dependencies - cp /mingw64/bin/libgcc_s_seh-1.dll "$WORKSPACE_PATH/build/lib/" - cp /mingw64/bin/libwinpthread-1.dll "$WORKSPACE_PATH/build/lib/" - cp /mingw64/bin/libstdc++-6.dll "$WORKSPACE_PATH/build/lib/" || echo "libstdc++-6.dll not found" - - # Copy audio library dependencies - cp /mingw64/bin/libportaudio.dll "$WORKSPACE_PATH/build/lib/" - cp /mingw64/bin/libsndfile-1.dll "$WORKSPACE_PATH/build/lib/" - cp /mingw64/bin/libsamplerate-0.dll "$WORKSPACE_PATH/build/lib/" - - # Copy other potential dependencies (with error handling) - cp /mingw64/bin/libFLAC.dll "$WORKSPACE_PATH/build/lib/" || echo "libFLAC.dll not found" - cp /mingw64/bin/libvorbis-0.dll "$WORKSPACE_PATH/build/lib/" || echo "libvorbis-0.dll not found" - cp /mingw64/bin/libvorbisenc-2.dll "$WORKSPACE_PATH/build/lib/" || echo "libvorbisenc-2.dll not found" - cp /mingw64/bin/libogg-0.dll "$WORKSPACE_PATH/build/lib/" || echo "libogg-0.dll not found" - - # Also copy DLLs directly to libs/audio for the release step - cp /mingw64/bin/libgcc_s_seh-1.dll libs/audio/ - cp /mingw64/bin/libwinpthread-1.dll libs/audio/ - cp /mingw64/bin/libstdc++-6.dll libs/audio/ || echo "libstdc++-6.dll not found" - cp /mingw64/bin/libportaudio.dll libs/audio/ - cp /mingw64/bin/libsndfile-1.dll libs/audio/ - cp /mingw64/bin/libsamplerate-0.dll libs/audio/ - cp /mingw64/bin/libFLAC.dll libs/audio/ || echo "libFLAC.dll not found" - cp /mingw64/bin/libvorbis-0.dll libs/audio/ || echo "libvorbis-0.dll not found" - cp /mingw64/bin/libvorbisenc-2.dll libs/audio/ || echo "libvorbisenc-2.dll not found" - cp /mingw64/bin/libogg-0.dll libs/audio/ || echo "libogg-0.dll not found" - - # List what we have - echo "Contents of build/lib/:" - ls -la "$WORKSPACE_PATH/build/lib/" - echo "Contents of libs/audio/:" - ls -la libs/audio/ - - # Compile the audio library (Unix) - - name: Check Audio Library Dependencies - run: | - cd libs/audio - make check-deps - shell: bash - continue-on-error: true - - - name: Compile Audio Library (Unix) + - name: Build static audio library (Unix) if: runner.os != 'Windows' run: | cd libs/audio make clean - make all + make static || make all # Fallback to regular build if static fails + make verify shell: bash - - name: Install Audio Library (Unix) + - name: Install static audio library (Unix) if: runner.os != 'Windows' run: | cd libs/audio diff --git a/.gitignore b/.gitignore index d85c758..c983ff0 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1,7 @@ -Songs2 __pycache__ .venv scores.db cache -full.csv dev-config.toml .env +libaudio.so diff --git a/libs/audio/Makefile b/libs/audio/Makefile index d45b09e..af18c67 100644 --- a/libs/audio/Makefile +++ b/libs/audio/Makefile @@ -1,41 +1,99 @@ -# Makefile for audio library -# Default compiler and flags for Unix-like systems +# Makefile for audio library with full static linking 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 detection +# MSYS2/MinGW-w64 with full 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 - LDFLAGS = -shared -Wl,--export-all-symbols -L/mingw64/lib - LIBS = -lportaudio -lsndfile -lsamplerate -lpthread -lm + CFLAGS = -Wall -Wextra -O3 -fPIC -std=c99 -I/mingw64/include -m64 + + # Full static linking flags + LDFLAGS = -shared \ + -Wl,--export-all-symbols \ + -Wl,--whole-archive \ + -static-libgcc \ + -static-libstdc++ \ + -static \ + -L/mingw64/lib \ + -m64 + + # 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 + OBJ_EXT = .o else ifneq (,$(findstring Windows,$(UNAME_S))) - # Windows with MSVC + # Windows with MSVC (alternative approach) CC = cl LIBNAME = libaudio.dll - CFLAGS = /O2 /W3 /MD /TC - LDFLAGS = /DLL - LIBS = portaudio.lib libsndfile.lib libsamplerate.lib + 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 + # macOS with static linking 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 OBJ_EXT = .o else ifeq ($(UNAME_S),Linux) - # Linux + # Linux with static linking 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 OBJ_EXT = .o else @@ -53,11 +111,11 @@ else OBJECTS = $(SOURCES:.c=.o) endif -.PHONY: all clean install debug check-deps +.PHONY: all clean install debug check-deps static all: $(LIBNAME) -# Windows-specific build rule +# Main build targets ifneq (,$(findstring Windows,$(UNAME_S))) $(LIBNAME): $(OBJECTS) link $(LDFLAGS) /OUT:$@ $^ $(LIBS) @@ -68,16 +126,9 @@ $(LIBNAME): $(OBJECTS) clean: -del /Q *.obj $(LIBNAME) 2>nul || rm -f $(OBJECTS) $(LIBNAME) -install: - @echo "Install not implemented for Windows. Copy $(LIBNAME) to your application directory." - check-deps: - @echo "Checking dependencies on Windows..." - @echo "Assuming vcpkg dependencies are installed..." - @if exist "$(VCPKG_INSTALLATION_ROOT)\installed\x64-windows\include\portaudio.h" (echo PortAudio found!) else (echo PortAudio not found! && exit 1) - @if exist "$(VCPKG_INSTALLATION_ROOT)\installed\x64-windows\include\sndfile.h" (echo libsndfile found!) else (echo libsndfile not found! && exit 1) - @if exist "$(VCPKG_INSTALLATION_ROOT)\installed\x64-windows\include\samplerate.h" (echo libsamplerate found!) else (echo libsamplerate not found! && exit 1) - @echo "All dependencies found!" + @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 @@ -95,23 +146,44 @@ install: $(LIBNAME) sudo ldconfig 2>/dev/null || true check-deps: - @echo "Checking dependencies..." - @pkg-config --exists portaudio-2.0 || (echo "PortAudio not found!" && false) - @pkg-config --exists sndfile || (echo "libsndfile not found!" && false) - @echo "All dependencies found!" + @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 (cross-platform) +# Development target with debug symbols debug: CFLAGS += $(if $(findstring Windows,$(UNAME_S)),/Zi,-g -DDEBUG) debug: $(LIBNAME) -# Help target +# Target to build with maximum static linking +static: LDFLAGS += $(if $(findstring MINGW,$(UNAME_S)),-static,) +static: $(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 + help: @echo "Available targets:" @echo " all - Build the audio library (default)" + @echo " static - Build with maximum static linking" @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 " verify - Verify built library and show dependencies" @echo " help - Show this help message"