From bc02927077322dc291bf0c6e1d7837de69bbf700 Mon Sep 17 00:00:00 2001 From: Dean Ellis Date: Tue, 17 Feb 2026 22:08:59 +0000 Subject: [PATCH 1/7] Add Support for Windows Arm64 --- buildscripts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/buildscripts b/buildscripts index 2dae539..b7baf1d 160000 --- a/buildscripts +++ b/buildscripts @@ -1 +1 @@ -Subproject commit 2dae539a2b7bf49bec07aa63a2c529a7406c5aa5 +Subproject commit b7baf1d21b5bc76ff2f4658b318f35edd91937f2 From adf40970c3ed845f4fa0de24136f1279611e313f Mon Sep 17 00:00:00 2001 From: Dean Ellis Date: Tue, 17 Feb 2026 22:18:04 +0000 Subject: [PATCH 2/7] Initial code changes for windows arm64 support --- .github/workflows/main.yml | 13 ++++ build/BuildWIndowsTask.cs | 114 +++++++++++++++++++++++++++++++++--- ffmpeg.windows-arm64.config | 13 ++++ ffmpeg.windows-x64.config | 2 +- 4 files changed, 132 insertions(+), 10 deletions(-) create mode 100644 ffmpeg.windows-arm64.config diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index e46fde8..3632fa4 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -29,6 +29,19 @@ jobs: shell: bash run: | C:\\msys64\\usr\\bin\\bash.exe -c 'export PATH="/usr/bin:/mingw64/bin:$PATH"; pacman -S --needed --noconfirm mingw-w64-x86_64-toolchain mingw-w64-x86_64-mpg123 mingw-w64-x86_64-gtk2 mingw-w64-x86_64-libogg mingw-w64-x86_64-libvorbis mingw-w64-x86_64-lame mingw-w64-x86_64-pkg-config nasm yasm make base-devel autoconf automake libtool' + + - name: Install llvm-mingw for ARM64 cross-compilation + if: runner.os == 'Windows' + shell: pwsh + run: | + $llvmMingwVersion = "20250114" + $url = "https://github.com/mstorsjo/llvm-mingw/releases/download/$llvmMingwVersion/llvm-mingw-$llvmMingwVersion-ucrt-x86_64.zip" + Invoke-WebRequest -Uri $url -OutFile "$env:TEMP\llvm-mingw.zip" + Expand-Archive -Path "$env:TEMP\llvm-mingw.zip" -DestinationPath "C:\llvm-mingw-extract" + if (Test-Path "C:\llvm-mingw") { Remove-Item -Path "C:\llvm-mingw" -Recurse -Force } + Move-Item -Path "C:\llvm-mingw-extract\llvm-mingw-$llvmMingwVersion-ucrt-x86_64" -Destination "C:\llvm-mingw" + Write-Host "llvm-mingw installed to C:\llvm-mingw" + - name: Clone repository uses: actions/checkout@v4 with: diff --git a/build/BuildWIndowsTask.cs b/build/BuildWIndowsTask.cs index 7b8f6d6..4817965 100644 --- a/build/BuildWIndowsTask.cs +++ b/build/BuildWIndowsTask.cs @@ -8,9 +8,15 @@ public sealed class BuildWindowsTask : FrostingTask public override bool ShouldRun(BuildContext context) => context.IsRunningOnWindows(); public override void Run(BuildContext context) + { + Buildx64(context); + Buildarm64(context); + } + + private void Buildx64(BuildContext context) { // Absolute path to the artifact directory is needed for flags since they don't allow relative path - var artifactDir = context.MakeAbsolute(new DirectoryPath(context.ArtifactsDir)); + var artifactDir = context.MakeAbsolute(new DirectoryPath(System.IO.Path.Combine(context.ArtifactsDir, "windows-x64"))); // The directory that all dependencies that are built manually are output too. Originally this was output to the // artifacts directory but that started causing issues on the github runners, so it was moved back to the @@ -21,12 +27,13 @@ public override void Run(BuildContext context) // since they would be set for the Windows side of things and not the mingw environment that everything is // running in. Instead, we'll build an export statement that can be used at the start of every process call to // ensure the correct environment variables are set for each command executed. - var cFlagsExport = "export CFLAGS=\"-w\";"; - var ccFlagsExport = "export CCFLAGS=\"x86_64-w64-mingw32-gcc\";"; - var ldFlagsExport = "export LDFLAGS=\"--static\";"; - var pathExport = "export PATH=\"/usr/bin:/mingw64/bin:$PATH\";"; - var pkgConfigExport = $"export PKG_CONFIG_PATH=\"/mingw64/lib/pkgconfig:$PKG_CONFIG_PATH\";"; - var exports = $"{pathExport}{cFlagsExport}{ccFlagsExport}{ldFlagsExport}{pkgConfigExport}"; + var cFlagsExport = "export CFLAGS='-w' -Wno-error=incompatible-pointer-types';"; + var ccFlagsExport = "export CC='x86_64-w64-mingw32-gcc';"; + var cxxFlagsExport = "export CXX='x86_64-w64-mingw32-g++';"; + var ldFlagsExport = "export LDFLAGS='--static';"; + var pathExport = "export PATH='/usr/bin:/mingw64/bin:$PATH';"; + var pkgConfigExport = $"export PKG_CONFIG_PATH='/mingw64/lib/pkgconfig:$PKG_CONFIG_PATH';"; + var exports = $"{pathExport}{cFlagsExport}{ccFlagsExport}{cxxFlagsExport}{ldFlagsExport}{pkgConfigExport}"; // The --prefix flag used for all ./configure commands to ensure that build dependencies are output to the // dependency directory specified @@ -94,11 +101,100 @@ public override void Run(BuildContext context) context.StartProcess(shellCommandPath, processSettings); } - private static string GetFFMpegConfigureFlags(BuildContext context) + private void Buildarm64(BuildContext context) + { + // Absolute path to the artifact directory is needed for flags since they don't allow relative path + var artifactDir = context.MakeAbsolute(new DirectoryPath(System.IO.Path.Combine(context.ArtifactsDir, "windows-arm64"))); + + // The directory that all dependencies that are built manually are output too. Originally this was output to the + // artifacts directory but that started causing issues on the github runners, so it was moved back to the + // project root directory. + var dependencyDir = context.MakeAbsolute(new DirectoryPath($"{context.ArtifactsDir}/../dependencies-windows-arm64")); + + // For Windows build, since we're using mingw environment, we can't set environment variables as normal + // since they would be set for the Windows side of things and not the mingw environment that everything is + // running in. Instead, we'll build an export statement that can be used at the start of every process call to + // ensure the correct environment variables are set for each command executed. + var depPathUnix = dependencyDir.FullPath.Replace("\\", "/").Replace("C:", "/c"); + var cFlagsExport = $"export CFLAGS='-w -Wno-error=incompatible-pointer-types -I{depPathUnix}/include';"; + var ccFlagsExport = $"export CC='x86_64-w64-mingw32-gcc;"; + var cxxFlagsExport = $"export CXX='x86_64-w64-mingw32-g++;"; + var ldFlagsExport = $"export LDFLAGS='--static -L{depPathUnix}/lib';"; + var pathExport = "export PATH='/c/llvm-mingw/bin:/usr/bin:/mingw64/bin:$PATH';"; + var pkgConfigExport = $"export PKG_CONFIG_PATH='{depPathUnix}/lib/pkgconfig';"; + var exports = $"{pathExport}{cFlagsExport}{ccFlagsExport}{cxxFlagsExport}{ldFlagsExport}{pkgConfigExport}"; + + // The --prefix flag used for all ./configure commands to ensure that build dependencies are output to the + // dependency directory specified + var prefixFlag = $"--prefix='{depPathUnix}'"; + + // The --bindir flag used in the final ffmpeg build so that the binary is output to the artifacts directory. + var binDirFlag = $"--bindir='{artifactDir}'"; + + // Get the FFmpeg ./configure flags specific for this windows build + var configureFlags = GetFFMpegConfigureFlags(context, "windows-arm64"); + + // The command to execute in order to run the shell environment (mingw) needed for this build. + var shellCommandPath = @"C:\msys64\usr\bin\bash.exe"; + + // Reusuable process settings instance. As each dependency is built, we'll adjust the working directory and + // arguments of this instance for each command. + var processSettings = new ProcessSettings(); + + // Build libogg + processSettings.WorkingDirectory = "./ogg"; + processSettings.Arguments = $"-c \"{exports} make distclean\""; + context.StartProcess(shellCommandPath, processSettings); + processSettings.Arguments = $"-c \"{exports} ./autogen.sh\""; + context.StartProcess(shellCommandPath, processSettings); + processSettings.Arguments = $"-c \"{exports} ./configure --host=aarch64-w64-mingw32 --disable-shared {prefixFlag}\""; + context.StartProcess(shellCommandPath, processSettings); + processSettings.Arguments = $"-c \"{exports} make -j{Environment.ProcessorCount}\""; + context.StartProcess(shellCommandPath, processSettings); + processSettings.Arguments = $"-c \"{exports} make install\""; + context.StartProcess(shellCommandPath, processSettings); + + // build libvorbis + processSettings.WorkingDirectory = "./vorbis"; + processSettings.Arguments = $"-c \"{exports} make distclean\""; + context.StartProcess(shellCommandPath, processSettings); + processSettings.Arguments = $"-c \"{exports} ./autogen.sh\""; + context.StartProcess(shellCommandPath, processSettings); + processSettings.Arguments = $"-c \"{exports} ./configure --host=aarch64-w64-mingw32 --disable-examples --disable-docs --disable-shared {prefixFlag}\""; + context.StartProcess(shellCommandPath, processSettings); + processSettings.Arguments = $"-c \"{exports} make -j{Environment.ProcessorCount}\""; + context.StartProcess(shellCommandPath, processSettings); + processSettings.Arguments = $"-c \"{exports} make install\""; + context.StartProcess(shellCommandPath, processSettings); + + // build lame + processSettings.WorkingDirectory = "./lame"; + processSettings.Arguments = $"-c \"{exports} make distclean\""; + context.StartProcess(shellCommandPath, processSettings); + processSettings.Arguments = $"-c \"{exports} ./configure --host=aarch64-w64-mingw32 --disable-frontend --disable-decoder --disable-shared {prefixFlag}\""; + context.StartProcess(shellCommandPath, processSettings); + processSettings.Arguments = $"-c \"{exports} make -j{Environment.ProcessorCount}\""; + context.StartProcess(shellCommandPath, processSettings); + processSettings.Arguments = $"-c \"{exports} make install\""; + context.StartProcess(shellCommandPath, processSettings); + + // Build ffmpeg + processSettings.WorkingDirectory = "./ffmpeg"; + processSettings.Arguments = $"-c \"{exports} make distclean\""; + context.StartProcess(shellCommandPath, processSettings); + processSettings.Arguments = $"-c \"{exports} ./configure --cc=aarch64-w64-mingw32-clang --cxx=aarch64-w64-mingw32-clang++ --cross-prefix=aarch64-w64-mingw32- --pkg-config=pkg-config {binDirFlag} {configureFlags}\""; + context.StartProcess(shellCommandPath, processSettings); + processSettings.Arguments = $"-c \"{exports} make -j{Environment.ProcessorCount}\""; + context.StartProcess(shellCommandPath, processSettings); + processSettings.Arguments = $"-c \"{exports} make install\""; + context.StartProcess(shellCommandPath, processSettings); + } + + private static string GetFFMpegConfigureFlags(BuildContext context, string rid = "windows-x64") { var ignoreCommentsAndNewLines = (string line) => !string.IsNullOrWhiteSpace(line) && !line.StartsWith('#'); var configureFlags = context.FileReadLines("ffmpeg.config").Where(ignoreCommentsAndNewLines); - var osConfigureFlags = context.FileReadLines($"ffmpeg.windows-x64.config").Where(ignoreCommentsAndNewLines); + var osConfigureFlags = context.FileReadLines($"ffmpeg.{rid}.config").Where(ignoreCommentsAndNewLines); return string.Join(' ', configureFlags) + " " + string.Join(' ', osConfigureFlags); } } diff --git a/ffmpeg.windows-arm64.config b/ffmpeg.windows-arm64.config new file mode 100644 index 0000000..c17afcb --- /dev/null +++ b/ffmpeg.windows-arm64.config @@ -0,0 +1,13 @@ +######################################################################################################################## +### Toolchain Options +######################################################################################################################## +--arch=aarch64 +--extra-cflags='-DHAVE_UNISTD_H=0' +--target-os=mingw32 + +######################################################################################################################## +### Optimization Options +######################################################################################################################## +--enable-asm +--disable-x86asm +--enable-neon diff --git a/ffmpeg.windows-x64.config b/ffmpeg.windows-x64.config index 7b5779f..4d27408 100644 --- a/ffmpeg.windows-x64.config +++ b/ffmpeg.windows-x64.config @@ -2,7 +2,7 @@ ### Toolchain Options ######################################################################################################################## --arch=x86_64 ---extra-cflags="-DHAVE_UNISTD_H=0" +--extra-cflags='-DHAVE_UNISTD_H=0' --target-os=mingw32 ######################################################################################################################## From a2d78f63aaf758cb13df95cbbeb2027193f85eb5 Mon Sep 17 00:00:00 2001 From: Dean Ellis Date: Tue, 17 Feb 2026 23:19:06 +0000 Subject: [PATCH 3/7] Fix a few typo's --- build/BuildWIndowsTask.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/build/BuildWIndowsTask.cs b/build/BuildWIndowsTask.cs index 4817965..e2cc903 100644 --- a/build/BuildWIndowsTask.cs +++ b/build/BuildWIndowsTask.cs @@ -27,7 +27,7 @@ private void Buildx64(BuildContext context) // since they would be set for the Windows side of things and not the mingw environment that everything is // running in. Instead, we'll build an export statement that can be used at the start of every process call to // ensure the correct environment variables are set for each command executed. - var cFlagsExport = "export CFLAGS='-w' -Wno-error=incompatible-pointer-types';"; + var cFlagsExport = "export CFLAGS='-w -Wno-error=incompatible-pointer-types';"; var ccFlagsExport = "export CC='x86_64-w64-mingw32-gcc';"; var cxxFlagsExport = "export CXX='x86_64-w64-mingw32-g++';"; var ldFlagsExport = "export LDFLAGS='--static';"; @@ -117,8 +117,8 @@ private void Buildarm64(BuildContext context) // ensure the correct environment variables are set for each command executed. var depPathUnix = dependencyDir.FullPath.Replace("\\", "/").Replace("C:", "/c"); var cFlagsExport = $"export CFLAGS='-w -Wno-error=incompatible-pointer-types -I{depPathUnix}/include';"; - var ccFlagsExport = $"export CC='x86_64-w64-mingw32-gcc;"; - var cxxFlagsExport = $"export CXX='x86_64-w64-mingw32-g++;"; + var ccFlagsExport = $"export CC='aarch64-w64-mingw32-clang;"; + var cxxFlagsExport = $"export CXX='aarch64-w64-mingw32-clang++';"; var ldFlagsExport = $"export LDFLAGS='--static -L{depPathUnix}/lib';"; var pathExport = "export PATH='/c/llvm-mingw/bin:/usr/bin:/mingw64/bin:$PATH';"; var pkgConfigExport = $"export PKG_CONFIG_PATH='{depPathUnix}/lib/pkgconfig';"; From 94636d83adc4a55dd849b7635ab97cb3387fb1fe Mon Sep 17 00:00:00 2001 From: Dean Ellis Date: Tue, 17 Feb 2026 23:23:31 +0000 Subject: [PATCH 4/7] Bump buildscripts --- buildscripts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/buildscripts b/buildscripts index b7baf1d..a6e447a 160000 --- a/buildscripts +++ b/buildscripts @@ -1 +1 @@ -Subproject commit b7baf1d21b5bc76ff2f4658b318f35edd91937f2 +Subproject commit a6e447a15ad9a1812c72a8fd7c45c746652881a9 From 48330ae66be4f4b05fb4b3d272c48904a98cc9ec Mon Sep 17 00:00:00 2001 From: Dean Ellis Date: Tue, 17 Feb 2026 23:54:53 +0000 Subject: [PATCH 5/7] Final typo --- build/BuildWIndowsTask.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/build/BuildWIndowsTask.cs b/build/BuildWIndowsTask.cs index e2cc903..270d19a 100644 --- a/build/BuildWIndowsTask.cs +++ b/build/BuildWIndowsTask.cs @@ -117,8 +117,8 @@ private void Buildarm64(BuildContext context) // ensure the correct environment variables are set for each command executed. var depPathUnix = dependencyDir.FullPath.Replace("\\", "/").Replace("C:", "/c"); var cFlagsExport = $"export CFLAGS='-w -Wno-error=incompatible-pointer-types -I{depPathUnix}/include';"; - var ccFlagsExport = $"export CC='aarch64-w64-mingw32-clang;"; - var cxxFlagsExport = $"export CXX='aarch64-w64-mingw32-clang++';"; + var ccFlagsExport = "export CC='aarch64-w64-mingw32-clang';"; + var cxxFlagsExport = "export CXX='aarch64-w64-mingw32-clang++';"; var ldFlagsExport = $"export LDFLAGS='--static -L{depPathUnix}/lib';"; var pathExport = "export PATH='/c/llvm-mingw/bin:/usr/bin:/mingw64/bin:$PATH';"; var pkgConfigExport = $"export PKG_CONFIG_PATH='{depPathUnix}/lib/pkgconfig';"; @@ -198,3 +198,4 @@ private static string GetFFMpegConfigureFlags(BuildContext context, string rid = return string.Join(' ', configureFlags) + " " + string.Join(' ', osConfigureFlags); } } + From 602bbb7358e7207e5f04654c2c0d1636e915163d Mon Sep 17 00:00:00 2001 From: Dean Ellis Date: Wed, 18 Feb 2026 00:25:17 +0000 Subject: [PATCH 6/7] try to force static linking --- ffmpeg.windows-arm64.config | 1 + ffmpeg.windows-x64.config | 1 + 2 files changed, 2 insertions(+) diff --git a/ffmpeg.windows-arm64.config b/ffmpeg.windows-arm64.config index c17afcb..81f6147 100644 --- a/ffmpeg.windows-arm64.config +++ b/ffmpeg.windows-arm64.config @@ -3,6 +3,7 @@ ######################################################################################################################## --arch=aarch64 --extra-cflags='-DHAVE_UNISTD_H=0' +--extra-ldflags=-static --target-os=mingw32 ######################################################################################################################## diff --git a/ffmpeg.windows-x64.config b/ffmpeg.windows-x64.config index 4d27408..5d08464 100644 --- a/ffmpeg.windows-x64.config +++ b/ffmpeg.windows-x64.config @@ -3,6 +3,7 @@ ######################################################################################################################## --arch=x86_64 --extra-cflags='-DHAVE_UNISTD_H=0' +--extra-ldflags=-static --target-os=mingw32 ######################################################################################################################## From fb80fc2ab068fa0c88bf9c992292fe8a9787b1f3 Mon Sep 17 00:00:00 2001 From: Dean Ellis Date: Wed, 18 Feb 2026 08:49:38 +0000 Subject: [PATCH 7/7] Bump buildscripts to make UCRT dependencies for amr64 valid --- buildscripts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/buildscripts b/buildscripts index a6e447a..252bb27 160000 --- a/buildscripts +++ b/buildscripts @@ -1 +1 @@ -Subproject commit a6e447a15ad9a1812c72a8fd7c45c746652881a9 +Subproject commit 252bb27265b77a649b2d0c38e625f56b1f653a87