Skip to content

Commit

Permalink
Use Cygwin to build libiconv on Windows CI (#14999)
Browse files Browse the repository at this point in the history
This uses the official releases and build instructions.

To compile code with this patch using a Windows Crystal compiler without this patch, either the new library files (`lib\iconv.lib`, `lib\iconv-dynamic.lib`, `iconv-2.dll`) shall be copied to that existing Crystal installation, or `CRYSTAL_LIBRARY_PATH` shall include the new `lib` directory so that the `@[Link]` annotation will pick up the new `iconv-2.dll` on program builds. Otherwise, compiled programs will continue to look for the old `libiconv.dll`, and silently break if it is not in `%PATH%` (which is hopefully rare since most of the time Crystal itself is also in `%PATH%`).

Cygwin's location is currently hardcoded to `C:\cygwin64`, the default installation location for 64-bit Cygwin.

Cygwin itself doesn't have native ARM64 support, but cross-compilation should be possible by simply using the x64-to-ARM64 cross tools MSVC developer prompt on an ARM64 machine.
  • Loading branch information
HertzDevil committed Sep 17, 2024
1 parent 9134f9f commit 5c18900
Show file tree
Hide file tree
Showing 5 changed files with 66 additions and 42 deletions.
20 changes: 17 additions & 3 deletions .github/workflows/win.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,13 @@ jobs:
- name: Enable Developer Command Prompt
uses: ilammy/msvc-dev-cmd@0b201ec74fa43914dc39ae48a89fd1d8cb592756 # v1.13.0

- name: Set up Cygwin
uses: cygwin/cygwin-install-action@006ad0b0946ca6d0a3ea2d4437677fa767392401 # v4
with:
packages: make
install-dir: C:\cygwin64
add-to-path: false

- name: Download Crystal source
uses: actions/checkout@v4

Expand Down Expand Up @@ -50,7 +57,7 @@ jobs:
run: .\etc\win-ci\build-pcre2.ps1 -BuildTree deps\pcre2 -Version 10.43
- name: Build libiconv
if: steps.cache-libs.outputs.cache-hit != 'true'
run: .\etc\win-ci\build-iconv.ps1 -BuildTree deps\iconv
run: .\etc\win-ci\build-iconv.ps1 -BuildTree deps\iconv -Version 1.17
- name: Build libffi
if: steps.cache-libs.outputs.cache-hit != 'true'
run: .\etc\win-ci\build-ffi.ps1 -BuildTree deps\ffi -Version 3.3
Expand Down Expand Up @@ -93,6 +100,13 @@ jobs:
- name: Enable Developer Command Prompt
uses: ilammy/msvc-dev-cmd@0b201ec74fa43914dc39ae48a89fd1d8cb592756 # v1.13.0

- name: Set up Cygwin
uses: cygwin/cygwin-install-action@006ad0b0946ca6d0a3ea2d4437677fa767392401 # v4
with:
packages: make
install-dir: C:\cygwin64
add-to-path: false

- name: Download Crystal source
uses: actions/checkout@v4

Expand All @@ -112,7 +126,7 @@ jobs:
libs/xml2-dynamic.lib
dlls/pcre.dll
dlls/pcre2-8.dll
dlls/libiconv.dll
dlls/iconv-2.dll
dlls/gc.dll
dlls/libffi.dll
dlls/zlib1.dll
Expand All @@ -131,7 +145,7 @@ jobs:
run: .\etc\win-ci\build-pcre2.ps1 -BuildTree deps\pcre2 -Version 10.43 -Dynamic
- name: Build libiconv
if: steps.cache-dlls.outputs.cache-hit != 'true'
run: .\etc\win-ci\build-iconv.ps1 -BuildTree deps\iconv -Dynamic
run: .\etc\win-ci\build-iconv.ps1 -BuildTree deps\iconv -Version 1.17 -Dynamic
- name: Build libffi
if: steps.cache-dlls.outputs.cache-hit != 'true'
run: .\etc\win-ci\build-ffi.ps1 -BuildTree deps\ffi -Version 3.3 -Dynamic
Expand Down
7 changes: 6 additions & 1 deletion .github/workflows/win_build_portable.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ jobs:

- name: Install Crystal
uses: crystal-lang/install-crystal@v1
id: install-crystal
with:
crystal: "1.13.2"

Expand Down Expand Up @@ -68,7 +69,7 @@ jobs:
libs/xml2-dynamic.lib
dlls/pcre.dll
dlls/pcre2-8.dll
dlls/libiconv.dll
dlls/iconv-2.dll
dlls/gc.dll
dlls/libffi.dll
dlls/zlib1.dll
Expand Down Expand Up @@ -107,6 +108,10 @@ jobs:
run: |
echo "CRYSTAL_LIBRARY_PATH=$(pwd)\libs" >> ${env:GITHUB_ENV}
echo "LLVM_CONFIG=$(pwd)\llvm\bin\llvm-config.exe" >> ${env:GITHUB_ENV}
# NOTE: the name of the libiconv DLL has changed, so we manually copy
# the new one to the existing Crystal installation; remove after
# updating the base compiler to 1.14
cp dlls/iconv-2.dll ${{ steps.install-crystal.outputs.path }}
- name: Build LLVM extensions
run: make -f Makefile.win deps
Expand Down
47 changes: 10 additions & 37 deletions etc/win-ci/build-iconv.ps1
Original file line number Diff line number Diff line change
@@ -1,56 +1,29 @@
param(
[Parameter(Mandatory)] [string] $BuildTree,
[Parameter(Mandatory)] [string] $Version,
[switch] $Dynamic
)

. "$(Split-Path -Parent $MyInvocation.MyCommand.Path)\setup.ps1"

[void](New-Item -Name (Split-Path -Parent $BuildTree) -ItemType Directory -Force)
Setup-Git -Path $BuildTree -Url https://github.com/pffang/libiconv-for-Windows.git -Ref 1353455a6c4e15c9db6865fd9c2bf7203b59c0ec # master@{2022-10-11}
Invoke-WebRequest "https://ftp.gnu.org/pub/gnu/libiconv/libiconv-${Version}.tar.gz" -OutFile libiconv.tar.gz
tar -xzf libiconv.tar.gz
mv libiconv-* $BuildTree
rm libiconv.tar.gz

Run-InDirectory $BuildTree {
Replace-Text libiconv\include\iconv.h '__declspec (dllimport) ' ''

echo '<Project>
<PropertyGroup>
<ForceImportAfterCppTargets>$(MsbuildThisFileDirectory)\Override.props</ForceImportAfterCppTargets>
</PropertyGroup>
</Project>' > 'Directory.Build.props'

echo "<Project>
<PropertyGroup>
<WholeProgramOptimization>false</WholeProgramOptimization>
</PropertyGroup>
<ItemDefinitionGroup>
<ClCompile>
<DebugInformationFormat>None</DebugInformationFormat>
<WholeProgramOptimization>false</WholeProgramOptimization>
</ClCompile>
<Link>
<GenerateDebugInformation>false</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition=`"'`$(Configuration)'=='Release'`">
<ClCompile>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
</ClCompile>
</ItemDefinitionGroup>
</Project>" > 'Override.props'

if ($Dynamic) {
MSBuild.exe /p:Platform=x64 /p:Configuration=Release libiconv.vcxproj
} else {
MSBuild.exe /p:Platform=x64 /p:Configuration=ReleaseStatic libiconv.vcxproj
}
$env:CHERE_INVOKING = 1
& 'C:\cygwin64\bin\bash.exe' --login "$PSScriptRoot\cygwin-build-iconv.sh" "$Version" "$(if ($Dynamic) { 1 })"
if (-not $?) {
Write-Host "Error: Failed to build libiconv" -ForegroundColor Red
Exit 1
}
}

if ($Dynamic) {
mv -Force $BuildTree\output\x64\Release\libiconv.lib libs\iconv-dynamic.lib
mv -Force $BuildTree\output\x64\Release\libiconv.dll dlls\
mv -Force $BuildTree\iconv\lib\iconv.dll.lib libs\iconv-dynamic.lib
mv -Force $BuildTree\iconv\bin\iconv-2.dll dlls\
} else {
mv -Force $BuildTree\output\x64\ReleaseStatic\libiconvStatic.lib libs\iconv.lib
mv -Force $BuildTree\iconv\lib\iconv.lib libs\
}
32 changes: 32 additions & 0 deletions etc/win-ci/cygwin-build-iconv.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
#!/bin/sh

set -eo pipefail

Version=$1
Dynamic=$2

export PATH="$(pwd)/build-aux:$PATH"
export CC="$(pwd)/build-aux/compile cl -nologo"
export CXX="$(pwd)/build-aux/compile cl -nologo"
export AR="$(pwd)/build-aux/ar-lib lib"
export LD="link"
export NM="dumpbin -symbols"
export STRIP=":"
export RANLIB=":"
if [ -n "$Dynamic" ]; then
export CFLAGS="-MD"
export CXXFLAGS="-MD"
enable_shared=yes
enable_static=no
else
export CFLAGS="-MT"
export CXXFLAGS="-MT"
enable_shared=no
enable_static=yes
fi
export CPPFLAGS="-D_WIN32_WINNT=_WIN32_WINNT_WIN7 -I$(pwd)/iconv/include"
export LDFLAGS="-L$(pwd)/iconv/lib"

./configure --host=x86_64-w64-mingw32 --prefix="$(pwd)/iconv" --enable-shared="${enable_shared}" --enable-static="${enable_static}"
make
make install
2 changes: 1 addition & 1 deletion src/crystal/lib_iconv.cr
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ require "c/stddef"

@[Link("iconv")]
{% if compare_versions(Crystal::VERSION, "1.11.0-dev") >= 0 %}
@[Link(dll: "libiconv.dll")]
@[Link(dll: "iconv-2.dll")]
{% end %}
lib LibIconv
type IconvT = Void*
Expand Down

0 comments on commit 5c18900

Please sign in to comment.