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..270d19a 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,101 @@ 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='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';"; + 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/buildscripts b/buildscripts index 2dae539..252bb27 160000 --- a/buildscripts +++ b/buildscripts @@ -1 +1 @@ -Subproject commit 2dae539a2b7bf49bec07aa63a2c529a7406c5aa5 +Subproject commit 252bb27265b77a649b2d0c38e625f56b1f653a87 diff --git a/ffmpeg.windows-arm64.config b/ffmpeg.windows-arm64.config new file mode 100644 index 0000000..81f6147 --- /dev/null +++ b/ffmpeg.windows-arm64.config @@ -0,0 +1,14 @@ +######################################################################################################################## +### Toolchain Options +######################################################################################################################## +--arch=aarch64 +--extra-cflags='-DHAVE_UNISTD_H=0' +--extra-ldflags=-static +--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..5d08464 100644 --- a/ffmpeg.windows-x64.config +++ b/ffmpeg.windows-x64.config @@ -2,7 +2,8 @@ ### Toolchain Options ######################################################################################################################## --arch=x86_64 ---extra-cflags="-DHAVE_UNISTD_H=0" +--extra-cflags='-DHAVE_UNISTD_H=0' +--extra-ldflags=-static --target-os=mingw32 ########################################################################################################################