From 33fd145da865f849e773eda2b39f0e123f8b5bc4 Mon Sep 17 00:00:00 2001 From: Michele Locati Date: Sun, 22 Sep 2024 18:43:29 +0200 Subject: [PATCH] Remove unneeded built DLLs, add MinGW DLLs automatically --- .github/workflows/build-exe-create-output | 45 +---- .github/workflows/build-exe-dependencies.ps1 | 188 +++++++++++++++++++ .github/workflows/build-exe-setup.ps1 | 5 +- .github/workflows/build.yml | 14 +- 4 files changed, 204 insertions(+), 48 deletions(-) create mode 100644 .github/workflows/build-exe-dependencies.ps1 diff --git a/.github/workflows/build-exe-create-output b/.github/workflows/build-exe-create-output index d55abb4..6ae3d6d 100755 --- a/.github/workflows/build-exe-create-output +++ b/.github/workflows/build-exe-create-output @@ -30,7 +30,7 @@ copyFile () { mkdir -p "$(dirname "$destinationPath")" case "$fileType" in binary) - strip --strip-unneeded "$sourcePath" -o "$destinationPath" + "$MINGW_HOST-strip" --strip-unneeded "$sourcePath" -o "$destinationPath" ;; text) perl -pe 's/\r\n|\n|\r/\r\n/g' <"$sourcePath" >"$destinationPath" @@ -61,32 +61,11 @@ if [ ! -d "$DESTINATION" ]; then printf 'Destination directory (%s) not found\n' "$DESTINATION" exit 1 fi -LINK="${3:-}" -case "$LINK" in - shared | static) - ;; - '') - echo 'Missing 3rd argument (link)' - exit 1 - ;; - *) - printf 'Missing/wrong link (%s)\n' "$LINK" - exit 1 - ;; -esac -BITS="${4:-}" -case "$BITS" in - 32 | 64) - ;; - '') - echo 'Missing 4rd argument (bits)' - exit 1 - ;; - *) - printf 'Missing/wrong bits (%s)\n' "$BITS" - exit 1 - ;; -esac +MINGW_HOST="${3:-}" +if [ -z "$MINGW_HOST" ]; then + echo 'Missing 3nd argument (MinGW host)' + exit 1 +fi mkdir -p "$DESTINATION/share/gettext" @@ -108,15 +87,3 @@ cp -r "$SOURCE/share/gettext/styles" "$DESTINATION/share/gettext/" cp -r $SOURCE/share/gettext-*/its "$DESTINATION/share/gettext" copyFile "$SOURCE/share/gettext/msgunfmt.tcl" copyFile "$SOURCE/cldr-plurals.xml" '' lib/gettext/common/supplemental/plurals.xml -case "$LINK$BITS" in - shared32) - copyFile /usr/i686-w64-mingw32/sys-root/mingw/bin/libgcc_s_sjlj-1.dll '' bin/libgcc_s_sjlj-1.dll - copyFile /usr/i686-w64-mingw32/sys-root/mingw/bin/libstdc++-6.dll '' bin/libstdc++-6.dll - copyFile /usr/i686-w64-mingw32/sys-root/mingw/bin/libwinpthread-1.dll '' bin/libwinpthread-1.dll - ;; - shared64) - copyFile /usr/x86_64-w64-mingw32/sys-root/mingw/bin/libwinpthread-1.dll '' bin/libwinpthread-1.dll - copyFile /usr/x86_64-w64-mingw32/sys-root/mingw/bin/libstdc++-6.dll '' bin/libstdc++-6.dll - copyFile /usr/x86_64-w64-mingw32/sys-root/mingw/bin/libgcc_s_seh-1.dll '' bin/libgcc_s_seh-1.dll - ;; -esac diff --git a/.github/workflows/build-exe-dependencies.ps1 b/.github/workflows/build-exe-dependencies.ps1 new file mode 100644 index 0000000..6e426de --- /dev/null +++ b/.github/workflows/build-exe-dependencies.ps1 @@ -0,0 +1,188 @@ +<# +$Env:PATH += ";C:\Program Files (x86)\Microsoft Visual Studio\Installer" +#> + +param ( + [Parameter(Mandatory = $true)] + [ValidateSet(32, 64)] + [int] $bits, + [Parameter(Mandatory = $true)] + [ValidateSet('shared', 'static')] + [string] $link, + [Parameter(Mandatory = $true)] + [ValidateLength(1, [int]::MaxValue)] + [ValidateScript({Test-Path -LiteralPath $_ -PathType Container})] + [string] $outputPath, + [Parameter(Mandatory = $true)] + [ValidateLength(1, [int]::MaxValue)] + [ValidateScript({Test-Path -LiteralPath $_ -PathType Container})] + [string] $mingwPath +) + +function Find-Dumpbin +{ + [OutputType([string])] + $vsPath = & vswhere.exe -latest -products * -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -property installationPath + if (-not($?)) { + throw "vswhere failed" + } + $vcToolsVersion = Get-Content -LiteralPath "$vsPath\VC\Auxiliary\Build\Microsoft.VCToolsVersion.default.txt" -TotalCount 1 + switch ($bits) { + 32 { + $result = "$vsPath\VC\Tools\MSVC\$vcToolsVersion\bin\Hostx86\x86\dumpbin.exe" + } + 64 { + $result = "$vsPath\VC\Tools\MSVC\$vcToolsVersion\bin\HostX64\x64\dumpbin.exe" + } + } + if (-not(Test-Path -LiteralPath $result -PathType Leaf)) { + throw "$result`ndoes not exist" + } + $result +} + +function Get-Dependencies() +{ + [OutputType([string[]])] + param( + [Parameter(Mandatory = $true)] + [ValidateLength(1, [int]::MaxValue)] + [ValidateScript({Test-Path -LiteralPath $_ -PathType Leaf})] + [string] $path + ) + + $dumpbinResult = & "$dumpbin" /NOLOGO /DEPENDENTS "$path" + if (-not($?)) { + throw "dumpbin failed to analyze the file $($path)" + } + [string[]]$dependencies = @() + $started = $false + foreach ($line in $dumpbinResult) { + $line = $line.Trim() + if (-not($line)) { + continue; + } + if ($started) { + if ($line -eq 'Summary') { + break + } + $dependencies += $line.ToLowerInvariant() + } elseif ($line -eq 'Image has the following dependencies:') { + $started = $true + } + } + $dependencies +} + +class Binary +{ + [System.IO.FileInfo] $File + [string[]] $Dependencies + Binary([System.IO.FileInfo]$file) + { + $this.File = $file + $this.Dependencies = Get-Dependencies $this.File.FullName + } +} + +class Binaries +{ + [bool] $MinGWFilesAdded = $false + + [Binary[]] $Items + + Binaries() + { + $this.Items = @() + } + + [void] Add([Binary]$binary) + { + if ($this.GetBinaryByName($binary.File.Name)) { + throw "Duplicated binary name $($binary.File.Name)" + } + $this.Items += $binary + } + + [Binary] GetBinaryByName([string] $name) + { + foreach ($item in $this.Items) { + if ($item.File.Name -eq $name) { + return $item + } + } + return $null + } + + [void] RemoveUnusedDlls() + { + do { + $repeat = $false + foreach ($binary in $this.Items) { + if ($binary.File.Extension -ne '.dll') { + continue + } + $name = $binary.File.Name.ToLowerInvariant() + $unused = $true + foreach ($other in $this.Items) { + if ($other -ne $binary -and $other.Dependencies -contains $name) { + $unused = $false + break + } + } + if ($unused) { + Write-Host "$($binary.File.Name) is never used: deleting it" + $binary.File.Delete() + $this.Items = $this.Items | Where-Object { $_ -ne $binary } + $repeat = $true + break + } + } + } while ($repeat) + } + + [void] AddMingwDlls([string] $mingwBinPath) + { + $checkedDeps = @() + for ($index = 0; $index -lt $this.Items.Count; $index++) { + $binary = $this.Items[$index] + foreach ($dependency in $binary.Dependencies) { + if ($checkedDeps -contains $dependency) { + continue + } + $checkedDeps += $dependency + if ($this.GetBinaryByName($dependency)) { + continue + } + $mingwDllPath = Join-Path -Path $mingwBinPath -ChildPath $dependency + if (-not(Test-Path -LiteralPath $mingwDllPath -PathType Leaf)) { + continue + } + Write-Host -Object "Adding MinGW DLL $dependency" + Copy-Item -LiteralPath $mingwDllPath -Destination $binary.File.Directory + $newFilePath = Join-Path -Path $binary.File.Directory -ChildPath $dependency + $newFile = Get-ChildItem -LiteralPath $newFilePath -File + $newBinary = [Binary]::new($newFile) + $this.Add($newBinary) + $this.MinGWFilesAdded = $true + } + } + } +} + +$dumpbin = Find-Dumpbin +$mingwBinPath = Join-Path -Path $mingwPath -ChildPath 'sys-root\mingw\bin' +$outputBinPath = Join-Path -Path $outputPath -ChildPath 'bin' +$binaries = [Binaries]::new() +foreach ($file in Get-ChildItem -LiteralPath $outputBinPath -Recurse -File) { + if ($file.Extension -eq '.exe' -or $file.Extension -eq '.dll') { + $binary = [Binary]::new($file) + $binaries.Add($binary) + } +} + +$binaries.RemoveUnusedDlls() +$binaries.AddMingwDlls($mingwBinPath) +if ($binaries.MinGWFilesAdded) { + # todo +} diff --git a/.github/workflows/build-exe-setup.ps1 b/.github/workflows/build-exe-setup.ps1 index 04e2fc9..a1df1bc 100644 --- a/.github/workflows/build-exe-setup.ps1 +++ b/.github/workflows/build-exe-setup.ps1 @@ -16,12 +16,10 @@ $gettextIgnoreTestsC = 'gettext-tools/gnulib-tests/test-asyncsafe-spin2.c gettex switch ($bits) { 32 { $cygwinPackages = "$cygwinPackages,mingw64-i686-gcc-core,mingw64-i686-gcc-g++,mingw64-i686-headers,mingw64-i686-runtime" - $mingwPath = '/usr/i686-w64-mingw32' $mingwHost = 'i686-w64-mingw32' } 64 { $cygwinPackages = "$cygwinPackages,mingw64-x86_64-gcc-core,mingw64-x86_64-gcc-g++,mingw64-x86_64-headers,mingw64-x86_64-runtime" - $mingwPath = '/usr/x86_64-w64-mingw32' $mingwHost = 'x86_64-w64-mingw32' } } @@ -36,8 +34,7 @@ switch ($link) { } } "cygwin-packages=$cygwinPackages" | Out-File -FilePath $env:GITHUB_OUTPUT -Append -Encoding utf8 -"cygwin-path=/installed/bin:$mingwPath/bin:$mingwPath/sys-root/mingw/bin:/usr/sbin:/usr/bin:/sbin:/bin:/cygdrive/c/Windows/system32:/cygdrive/c/Windows" | Out-File -FilePath $env:GITHUB_OUTPUT -Append -Encoding utf8 -"mingw-path=$mingwPath" | Out-File -FilePath $env:GITHUB_OUTPUT -Append -Encoding utf8 +"cygwin-path=/installed/bin:/usr/$mingwHost/bin:/usr/$mingwHost/sys-root/mingw/bin:/usr/sbin:/usr/bin:/sbin:/bin:/cygdrive/c/Windows/system32:/cygdrive/c/Windows" | Out-File -FilePath $env:GITHUB_OUTPUT -Append -Encoding utf8 "mingw-host=$mingwHost" | Out-File -FilePath $env:GITHUB_OUTPUT -Append -Encoding utf8 "configure-options=$configureOptions" | Out-File -FilePath $env:GITHUB_OUTPUT -Append -Encoding utf8 "gettext-cppflags=$gettextCppFlags" | Out-File -FilePath $env:GITHUB_OUTPUT -Append -Encoding utf8 diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index c993917..ab5f893 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -127,8 +127,8 @@ jobs: CC='${{ steps.setup.outputs.mingw-host }}-gcc' CXX='${{ steps.setup.outputs.mingw-host }}-g++' LD='${{ steps.setup.outputs.mingw-host }}-ld' - CPPFLAGS='-I${{ steps.setup.outputs.mingw-path }}/sys-root/mingw/include -D__USE_MINGW_ANSI_STDIO=0 -g0 -O2' - LDFLAGS='-L${{ steps.setup.outputs.mingw-path }}/sys-root/mingw/lib' + CPPFLAGS='-I/usr/${{ steps.setup.outputs.mingw-host }}/sys-root/mingw/include -D__USE_MINGW_ANSI_STDIO=0 -g0 -O2' + LDFLAGS='-L/usr/${{ steps.setup.outputs.mingw-host }}/sys-root/mingw/lib' ac_cv_func__set_invalid_parameter_handler=no gl_cv_header_working_stdint_h=no --host=${{ steps.setup.outputs.mingw-host }} @@ -180,8 +180,8 @@ jobs: CC='${{ steps.setup.outputs.mingw-host }}-gcc' CXX='${{ steps.setup.outputs.mingw-host }}-g++' LD='${{ steps.setup.outputs.mingw-host }}-ld' - CPPFLAGS='-I/installed/include -I${{ steps.setup.outputs.mingw-path }}/sys-root/mingw/include -D__USE_MINGW_ANSI_STDIO=0 -g0 -O2 ${{ steps.setup.outputs.gettext-cppflags }}' - LDFLAGS='-L/installed/lib -L${{ steps.setup.outputs.mingw-path }}/sys-root/mingw/lib' + CPPFLAGS='-I/installed/include -I/usr/${{ steps.setup.outputs.mingw-host }}/sys-root/mingw/include -D__USE_MINGW_ANSI_STDIO=0 -g0 -O2 ${{ steps.setup.outputs.gettext-cppflags }}' + LDFLAGS='-L/installed/lib -L/usr/${{ steps.setup.outputs.mingw-host }}/sys-root/mingw/lib' ac_cv_func__set_invalid_parameter_handler=no gl_cv_header_working_stdint_h=no --host=${{ steps.setup.outputs.mingw-host }} @@ -222,7 +222,11 @@ jobs: run: make install && cp ../COPYING /installed/gettext-license.txt - name: Copy built assets - run: ./.github/workflows/build-exe-create-output /installed /output ${{ matrix.link }} ${{ matrix.bits}} + run: ./.github/workflows/build-exe-create-output /installed /output '${{ steps.setup.outputs.mingw-host }}' + - + name: Check dependencies + shell: pwsh + run: ./.github/workflows/build-exe-dependencies.ps1 ${{ matrix.bits }} ${{ matrix.link }} C:\cygwin\output C:\cygwin\usr\${{ steps.setup.outputs.mingw-host }} - name: Upload artifact uses: actions/upload-artifact@v4