diff --git a/.github/workflows/rake.yml b/.github/workflows/rake.yml index 6921bed1..59555a1f 100644 --- a/.github/workflows/rake.yml +++ b/.github/workflows/rake.yml @@ -7,7 +7,7 @@ on: push: branches: [ main ] tags: [ v* ] - pull_request: + # pull_request: jobs: rake: @@ -19,5 +19,7 @@ jobs: mkdir -p .bundle 2>&1 || true echo "---" > .bundle/config 2>&1 || true echo 'BUNDLE_BUILD__LIBXML___RUBY: "--with-xml2-dir=C:/vcpkg/installed/x64-windows --with-xml2-include=C:/vcpkg/installed/x64-windows/include/libxml2 --with-xml2-lib=C:/vcpkg/installed/x64-windows/lib"' >> .bundle/config 2>&1 || true + after-setup-ruby: | + bundle exec ruby debug.rb 2>&1 || true secrets: pat_token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml new file mode 100644 index 00000000..f65931cc --- /dev/null +++ b/.github/workflows/windows.yml @@ -0,0 +1,209 @@ +name: windows + +on: + push: + branches: [ main ] + pull_request: + workflow_dispatch: + +jobs: + test-windows-scripts: + name: Test Windows Setup Scripts + runs-on: windows-latest + strategy: + fail-fast: false + matrix: + ruby: ['3.2'] + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Setup Ruby + uses: ruby/setup-ruby@v1 + with: + ruby-version: ${{ matrix.ruby }} + bundler-cache: false + + - name: Verify MSYS2 Installation + shell: pwsh + run: | + if (Test-Path "C:\msys64") { + Write-Host "✓ MSYS2 found at C:\msys64" + } else { + Write-Host "✗ MSYS2 not found" + exit 1 + } + + - name: Install libxml2 via MSYS2 + shell: cmd + run: | + # C:\msys64\usr\bin\pacman.exe -S --needed --noconfirm mingw-w64-x86_64-libxml2 mingw-w64-x86_64-libiconv mingw-w64-x86_64-zlib + + C:\msys64\usr\bin\pacman.exe -S --needed --noconfirm mingw-w64-ucrt-x86_64-libxml2 mingw-w64-ucrt-x86_64-libiconv mingw-w64-ucrt-x86_64-zlib + + - name: Set Environment Variables + shell: pwsh + run: | + $rubyPlatform = ruby -e "puts RUBY_PLATFORM" + Write-Host "Ruby platform: $rubyPlatform" + + # $envPath = "C:\msys64\mingw64" + $envPath = "C:\msys64\ucrt64" + + echo "ICONV_INCLUDE=$envPath\include" >> $env:GITHUB_ENV + echo "WINDOWS_XML2_INCLUDE=$envPath\include\libxml2" >> $env:GITHUB_ENV + echo "WINDOWS_XML2_LIB=$envPath\lib" >> $env:GITHUB_ENV + echo "MSYS2_PATH=$envPath" >> $env:GITHUB_ENV + + # Set PATH to include MSYS2 bin directory for DLL resolution + $rubyBin = ruby -e "puts RbConfig::CONFIG['bindir']" + Write-Host "Ruby bin directory: $rubyBin" + Write-Host "PATH environment variable: $env:Path" + $env:Path += ";$envPath;$envPath\lib;$envPath\include;$envPath\include\libxml2;$rubyBin" + echo "PATH=$env:Path" >> $env:GITHUB_ENV + Write-Host "PATH environment variable: $env:Path" + + Write-Host "Environment variables set:" + Write-Host " ICONV_INCLUDE=$envPath\include" + Write-Host " WINDOWS_XML2_INCLUDE=$envPath\include\libxml2" + Write-Host " WINDOWS_XML2_LIB=$envPath\lib" + Write-Host " PATH=$env:Path" + + - name: Install libxml-ruby + shell: pwsh + run: | + Write-Host "ICONV_INCLUDE=$env:ICONV_INCLUDE" + Write-Host "WINDOWS_XML2_INCLUDE=$env:WINDOWS_XML2_INCLUDE" + Write-Host "WINDOWS_XML2_LIB=$env:WINDOWS_XML2_LIB" + Write-Host "MSYS2_PATH=$env:MSYS2_PATH" + + Write-Host "Files in $env:ICONV_INCLUDE are" + dir -Path $env:ICONV_INCLUDE | ForEach-Object { + Write-Host $_.Name + } + + Write-Host "Files in $env:WINDOWS_XML2_INCLUDE are" + dir -Path $env:WINDOWS_XML2_INCLUDE | ForEach-Object { + Write-Host $_.Name + } + + Write-Host "Files in $env:WINDOWS_XML2_LIB are" + dir -Path $env:WINDOWS_XML2_LIB | ForEach-Object { + Write-Host $_.Name + } + + Write-Host "Files in $env:MSYS2_PATH are" + dir -Path $env:MSYS2_PATH | ForEach-Object { + Write-Host $_.Name + } + + $rubyPlatform = ruby -e "puts RUBY_PLATFORM" + Write-Host "Installing libxml-ruby for $rubyPlatform..." + + gem install libxml-ruby --version 5.0.3 -- --with-xml2-include=$env:WINDOWS_XML2_INCLUDE --with-xml2-lib=$env:WINDOWS_XML2_LIB --with-xml2-dir=$env:MSYS2_PATH --with-iconv-include=$env:ICONV_INCLUDE + + if ($LASTEXITCODE -eq 0) { + Write-Host "✓ libxml-ruby installed successfully" + } else { + Write-Host "✗ Failed to install libxml-ruby" + exit 1 + } + + - name: Copy Required DLLs + shell: pwsh + run: | + $msys2Path = $env:MSYS2_PATH + $rubyBin = ruby -e "puts RbConfig::CONFIG['bindir']" + + $libxmlrubyfilepath = gem which libxml-ruby + $libxmlrubyfolder = Split-Path -Path $libxmlrubyfilepath -Parent + Write-Host "Folder of libxml-ruby is $libxmlrubyfolder" + + $sourcedir = "$msys2Path\bin" + Write-Host "Files in $sourcedir are:" + dir -Path $sourcedir -File | ForEach-Object { + Write-Host $_.Name + } + + Write-Host "Copying DLLs from $msys2Path\bin to $rubyBin..." + $dlls = @("libxml2-16.dll", "libiconv-2.dll", "zlib1.dll") + foreach ($dll in $dlls) { + $source = "$msys2Path\bin\$dll" + $dest = "$rubyBin\$dll" + $dest2 = "$libxmlrubyfolder\$dll" + + if (Test-Path $source) { + Copy-Item $source $dest -Force + Copy-Item $source $dest2 -Force + Write-Host "✓ Copied $dll" + } else { + Write-Host "✗ $dll not found at $source" + } + } + + Write-Host "Files in $libxmlrubyfolder\${{ matrix.ruby }} are" + dir -Path "$libxmlrubyfolder\${{ matrix.ruby }}" | ForEach-Object { + Write-Host $_.Name + } + Write-Host "Copying SO from $libxmlrubyfolder\${{ matrix.ruby }} to $rubyBin..." + $source = "$libxmlrubyfolder\${{ matrix.ruby }}\libxml_ruby.so" + $dest = "$rubyBin\libxml_ruby.so" + + if (Test-Path $source) { + Copy-Item $source $dest -Force + Copy-Item $source "$libxmlrubyfolder\libxml_ruby.so" -Force + Write-Host "✓ Copied libxml_ruby.so" + } else { + Write-Host "✗ libxml_ruby.so not found at $source" + } + + - name: Test libxml-ruby Installation + shell: pwsh + run: | + Write-Host "Inspec PATH environment variable: $env:Path" + + ruby -e @" + require 'libxml' + puts "libxml-ruby version: #{LibXML::XML::VERSION}" + puts "libxml2 version: #{LibXML::XML::LIBXML_VERSION}" + + # Test basic parsing + doc = LibXML::XML::Document.string('') + puts "Root element: #{doc.root.name}" + puts "Child element: #{doc.root.child.name}" + puts "Attribute value: #{doc.root.child['attr']}" + puts "" + puts "✓ libxml-ruby is working correctly!" + "@ + + - name: Test Moxml with LibXML Adapter + shell: pwsh + run: | + bundle install + + ruby -e @" + require 'moxml' + + # Configure to use LibXML adapter + Moxml.configure do |config| + config.adapter = :libxml + end + + # Create a document + doc = Moxml.new.create_document + root = doc.create_element('root') + doc.add_child(root) + + child = doc.create_element('child') + child['attr'] = 'value' + child.text = 'Hello from Windows!' + root.add_child(child) + + puts "Document created with LibXML adapter:" + puts doc.to_xml(indent: 2) + puts "" + puts "✓ Moxml with LibXML adapter is working on Windows!" + "@ + + bundle exec rake diff --git a/Gemfile b/Gemfile index 8964baf0..e8aa50b2 100644 --- a/Gemfile +++ b/Gemfile @@ -7,18 +7,26 @@ gemspec gem "byebug" gem "get_process_mem" -gem "libxml-ruby", "~> 5.0" gem "nokogiri", "~> 1.18" gem "oga", "~> 3.4" gem "ox", "~> 2.14" gem "rake" gem "rexml" gem "rspec" -gem "simplecov", require: false gem "rubocop" +gem "rubocop-performance" +gem "rubocop-rake" +gem "rubocop-rspec" +gem "simplecov", require: false gem "tempfile" # Provides iteration per second benchmarking for Ruby gem "benchmark-ips" # Needed by get_process_mem on Windows gem "sys-proctable" if Gem.win_platform? + +if Gem.win_platform? + gem "libxml-ruby", "5.0.4" +else + gem "libxml-ruby" +end diff --git a/debug.rb b/debug.rb new file mode 100644 index 00000000..5b98274f --- /dev/null +++ b/debug.rb @@ -0,0 +1,39 @@ +#!/usr/bin/env ruby + +require "rubygems" +# spec = Gem::Specification.find_by_name("libxml-ruby") +spec = Gem::Specification.find_by_name("moxml") +puts spec.full_gem_path + +# all_files = Dir.glob("#{spec.full_gem_path}/**/*").select { |f| File.file?(f) } + +# all_files.each do |file| +# puts file +# end + +# check PATH +puts ENV.fetch("PATH", nil) + +# patch lib/libxml-ruby.rb +# filepath = "a.txt" +filepath = File.expand_path("#{spec.full_gem_path}/dlls") +ENV["PATH"] = "#{ENV.fetch("PATH", nil)};#{filepath}" + +puts "Patched PATH:" +puts ENV.fetch("PATH", nil) + +# original_content = File.read(filepath) + +# line_to_add = "ENV['PATH'] = ENV['PATH'] + ';' + File.expand_path(File.dirname(__FILE__))\nputs 'Patched PATH: ' + ENV['PATH']" + +# # Combine the new line with the original content +# new_content = line_to_add + "\n" + original_content + +# # Overwrite the file with the new content +# File.write(filepath, new_content) + +# puts "new_content================" +# puts new_content +# puts "===========================" + +# LD_LIBRARY_PATH diff --git a/dlls/libiconv-2.dll b/dlls/libiconv-2.dll new file mode 100644 index 00000000..94fb8c7a Binary files /dev/null and b/dlls/libiconv-2.dll differ diff --git a/dlls/libxml2-2.dll b/dlls/libxml2-2.dll new file mode 100644 index 00000000..041d9a90 Binary files /dev/null and b/dlls/libxml2-2.dll differ diff --git a/dlls/zlib1.dll b/dlls/zlib1.dll new file mode 100644 index 00000000..5ac41bb7 Binary files /dev/null and b/dlls/zlib1.dll differ diff --git a/windows/setup-libxml-windows.bat b/windows/setup-libxml-windows.bat new file mode 100644 index 00000000..336ba394 --- /dev/null +++ b/windows/setup-libxml-windows.bat @@ -0,0 +1,234 @@ +@echo off +REM Setup script for building libxml-ruby on Windows +REM This batch file provides a simpler alternative to the PowerShell script + +echo ======================================== +echo libxml-ruby Windows Setup +echo ======================================== +echo. + +REM Check for Ruby +ruby -v >nul 2>&1 +if errorlevel 1 ( + echo ERROR: Ruby is not installed or not in PATH + echo Please install Ruby from https://rubyinstaller.org/ + exit /b 1 +) + +echo Found Ruby: +ruby -v +echo. + +REM Detect Ruby platform and set appropriate environment +for /f "tokens=*" %%a in ('ruby -e "puts RUBY_PLATFORM"') do set RUBY_PLATFORM=%%a +echo Ruby platform: %RUBY_PLATFORM% + +if "%RUBY_PLATFORM%"=="x64-mingw-ucrt" ( + echo Detected UCRT64 environment (Ruby 3.1+) + set MSYS2_ENV=ucrt64 + set PKG_PREFIX=mingw-w64-ucrt-x86_64 + set MSYS2_LIB_PATH=C:\msys64\ucrt64 +) else if "%RUBY_PLATFORM%"=="x64-mingw32" ( + echo Detected MinGW64 environment + set MSYS2_ENV=mingw64 + set PKG_PREFIX=mingw-w64-x86_64 + set MSYS2_LIB_PATH=C:\msys64\mingw64 +) else if "%RUBY_PLATFORM%"=="i386-mingw32" ( + echo Detected MinGW32 environment + set MSYS2_ENV=mingw32 + set PKG_PREFIX=mingw-w64-i686 + set MSYS2_LIB_PATH=C:\msys64\mingw32 +) else ( + echo Unknown platform: %RUBY_PLATFORM% + echo Assuming UCRT64 (Ruby 3.1+) + set MSYS2_ENV=ucrt64 + set PKG_PREFIX=mingw-w64-ucrt-x86_64 + set MSYS2_LIB_PATH=C:\msys64\ucrt64 +) + +echo. +echo MSYS2 Environment: %MSYS2_ENV% +echo Package Prefix: %PKG_PREFIX% +echo. + +REM Check MSYS2 installation +if not exist C:\msys64 ( + echo ERROR: MSYS2 not found at C:\msys64 + echo Please install MSYS2 or modify this script with the correct path + exit /b 1 +) + +echo Found MSYS2 at C:\msys64 +echo. + +REM Set environment variables +set WINDOWS_XML2_INCLUDE=%MSYS2_LIB_PATH%\include\libxml2 +set WINDOWS_XML2_LIB=%MSYS2_LIB_PATH%\lib + +echo Environment variables set: +echo WINDOWS_XML2_INCLUDE=%WINDOWS_XML2_INCLUDE% +echo WINDOWS_XML2_LIB=%WINDOWS_XML2_LIB% +echo. + +REM Menu +echo Choose installation method: +echo 1. Install pre-built gem (easiest, recommended) +echo 2. Install MSYS2 dependencies only +echo 3. Set environment variables only +echo 4. Verify installation +echo 5. Show help +echo. + +set /p choice="Enter choice [1-5]: " + +if "%choice%"=="1" goto install_prebuilt +if "%choice%"=="2" goto install_deps +if "%choice%"=="3" goto set_env +if "%choice%"=="4" goto verify +if "%choice%"=="5" goto help + +echo Invalid choice +goto end + +:install_prebuilt +echo. +echo Installing pre-built gem... + +if "%MSYS2_ENV%"=="ucrt64" ( + gem install libxml-ruby-x64-mingw-ucrt +) else ( + gem install libxml-ruby-x64-mingw32 +) + +if errorlevel 1 ( + echo. + echo ERROR: Installation failed + echo Try building from source or check your Ruby version +) else ( + echo. + echo SUCCESS: Pre-built gem installed + echo. + echo Don't forget to copy DLLs from %MSYS2_LIB_PATH%\bin to your Ruby bin directory: + echo - libxml2-2.dll + echo - libiconv-2.dll + echo - zlib1.dll +) +goto end + +:install_deps +echo. +echo Installing MSYS2 dependencies... +echo This may take several minutes... +echo. + +C:\msys64\usr\bin\pacman.exe -S --needed --noconfirm %PKG_PREFIX%-libxml2 +C:\msys64\usr\bin\pacman.exe -S --needed --noconfirm %PKG_PREFIX%-libiconv +C:\msys64\usr\bin\pacman.exe -S --needed --noconfirm %PKG_PREFIX%-zlib +C:\msys64\usr\bin\pacman.exe -S --needed --noconfirm %PKG_PREFIX%-gcc +C:\msys64\usr\bin\pacman.exe -S --needed --noconfirm %PKG_PREFIX%-make + +echo. +echo Dependencies installed +echo. +echo NOTE: This script did not set permanent environment variables. +echo Run option 3 or set them manually in System Properties. +goto end + +:set_env +echo. +echo Setting environment variables... +echo. +echo Current session: +echo WINDOWS_XML2_INCLUDE=%WINDOWS_XML2_INCLUDE% +echo WINDOWS_XML2_LIB=%WINDOWS_XML2_LIB% +echo. +echo To set these permanently, run these commands as Administrator: +echo. +echo setx WINDOWS_XML2_INCLUDE "%WINDOWS_XML2_INCLUDE%" /M +echo setx WINDOWS_XML2_LIB "%WINDOWS_XML2_LIB%" /M +echo. +echo Or use Windows System Properties - +echo Advanced - +e Environment Variables +goto end + +:verify +echo. +echo Verifying installation... +echo. + +echo Checking include path: +if exist "%WINDOWS_XML2_INCLUDE%\libxml\parser.h" ( + echo [OK] libxml/parser.h found +) else ( + echo [MISSING] libxml/parser.h not found +) + +if exist "%WINDOWS_XML2_INCLUDE%\libxml\tree.h" ( + echo [OK] libxml/tree.h found +) else ( + echo [MISSING] libxml/tree.h not found +) + +echo. +echo Checking library path: +if exist "%WINDOWS_XML2_LIB%" ( + echo [OK] Library path exists +) else ( + echo [MISSING] Library path not found +) + +echo. +echo Testing libxml-ruby: +ruby -e "require 'libxml'; puts 'libxml-ruby version: ' + LibXML::XML::VERSION" 2>nul +if errorlevel 1 ( + echo [NOT INSTALLED] libxml-ruby gem not found + echo Install it first using option 1 +) else ( + echo [OK] libxml-ruby is installed +) + +goto end + +:help +echo. +echo BUILD_LIBXML_WINDOWS.bat - Setup libxml-ruby on Windows +echo. +echo This script helps you install libxml-ruby on Windows by: +echo - Detecting your Ruby platform (UCRT64 or MinGW) +echo - Installing MSYS2 dependencies (libxml2, libiconv, zlib) +echo - Setting required environment variables +echo - Installing the pre-built gem +echo. +echo PREREQUISITES: +echo - Ruby 3.0+ with DevKit installed from rubyinstaller.org +echo - MSYS2 (included with Ruby+Devkit) +echo - Internet connection for downloading packages +echo. +echo OPTIONS: +echo 1. Install pre-built gem - Quickest method, downloads pre-compiled gem +echo 2. Install MSYS2 deps - Only installs required MSYS2 packages +echo 3. Set environment vars - Shows how to set permanent env vars +echo 4. Verify installation - Checks if everything is set up correctly +echo 5. Show this help - Displays this help message +echo. +echo TROUBLESHOOTING: +echo - If installation fails, ensure MSYS2 is in your PATH +echo - Run 'ridk install' after installing Ruby if MSYS2 is not configured +echo - Check BUILD_LIBXML_WINDOWS.md for detailed instructions +echo. +echo DLL FILES: +echo After installation, copy these DLLs from %MSYS2_LIB_PATH%\bin to your Ruby bin: +echo - libxml2-2.dll +echo - libiconv-2.dll +echo - zlib1.dll +echo. +echo Or use the DLLs already provided in the dlls/ folder of this project. +goto end + +:end +echo. +echo ======================================== +echo Setup complete +echo ======================================== +pause diff --git a/windows/setup-libxml-windows.ps1 b/windows/setup-libxml-windows.ps1 new file mode 100644 index 00000000..048f234a --- /dev/null +++ b/windows/setup-libxml-windows.ps1 @@ -0,0 +1,314 @@ +#Requires -Version 5.1 +<# +.SYNOPSIS + Setup script for building libxml-ruby on Windows + +.DESCRIPTION + This script automates the setup and installation of libxml-ruby on Windows. + It installs MSYS2 dependencies, sets environment variables, and builds the gem. + +.PARAMETER RubyVersion + The Ruby version being used (e.g., "3.1", "3.2", "3.3") + +.PARAMETER Msys2Path + Path to MSYS2 installation (default: C:\msys64) + +.PARAMETER SkipMsys2Install + Skip MSYS2 package installation (if already done) + +.EXAMPLE + .\setup-libxml-windows.ps1 -RubyVersion "3.3" + +.EXAMPLE + .\setup-libxml-windows.ps1 -RubyVersion "3.1" -Msys2Path "D:\msys64" +#> + +param( + [Parameter(Mandatory=$false)] + [string]$RubyVersion = "3.3", + + [Parameter(Mandatory=$false)] + [string]$Msys2Path = "C:\msys64", + + [Parameter(Mandatory=$false)] + [switch]$SkipMsys2Install +) + +# Error handling +$ErrorActionPreference = "Stop" + +function Write-Header { + param([string]$Message) + Write-Host "`n========================================" -ForegroundColor Cyan + Write-Host $Message -ForegroundColor Cyan + Write-Host "========================================`n" -ForegroundColor Cyan +} + +function Write-Success { + param([string]$Message) + Write-Host "✓ $Message" -ForegroundColor Green +} + +function Write-Error { + param([string]$Message) + Write-Host "✗ $Message" -ForegroundColor Red +} + +function Test-Command { + param([string]$Command) + $null -ne (Get-Command $Command -ErrorAction SilentlyContinue) +} + +# Determine MSYS2 environment based on Ruby version +function Get-Msys2Environment { + param([string]$Version) + + $major = [int]($Version.Split('.')[0]) + $minor = [int]($Version.Split('.')[1]) + + if ($major -gt 3 -or ($major -eq 3 -and $minor -ge 1)) { + return @{ + Name = "ucrt64" + PackagePrefix = "mingw-w64-ucrt-x86_64" + Path = "$Msys2Path\ucrt64" + } + } else { + return @{ + Name = "mingw64" + PackagePrefix = "mingw-w64-x86_64" + Path = "$Msys2Path\mingw64" + } + } +} + +Write-Header "libxml-ruby Windows Setup Script" + +# Check prerequisites +Write-Host "Checking prerequisites..." + +if (-not (Test-Command "ruby")) { + Write-Error "Ruby is not installed or not in PATH" + Write-Host "Please install Ruby from https://rubyinstaller.org/" + exit 1 +} + +$rubyVer = ruby -v +Write-Success "Found Ruby: $rubyVer" + +if (-not (Test-Command "gem")) { + Write-Error "Gem command not found" + exit 1 +} + +if (-not (Test-Path $Msys2Path)) { + Write-Error "MSYS2 not found at $Msys2Path" + Write-Host "Please install MSYS2 or specify the correct path with -Msys2Path" + exit 1 +} + +Write-Success "Found MSYS2 at $Msys2Path" + +# Determine environment +$envInfo = Get-Msys2Environment -Version $RubyVersion +Write-Host "Using MSYS2 environment: $($envInfo.Name)" +Write-Host "Package prefix: $($envInfo.PackagePrefix)" + +# Install MSYS2 packages +if (-not $SkipMsys2Install) { + Write-Header "Installing MSYS2 Packages" + + $packages = @( + "$($envInfo.PackagePrefix)-libxml2" + "$($envInfo.PackagePrefix)-libiconv" + "$($envInfo.PackagePrefix)-zlib" + "$($envInfo.PackagePrefix)-gcc" + "$($envInfo.PackagePrefix)-make" + ) + + foreach ($package in $packages) { + Write-Host "Installing $package..." + & "$Msys2Path\usr\bin\pacman.exe" -S --needed --noconfirm $package + if ($LASTEXITCODE -eq 0) { + Write-Success "Installed $package" + } else { + Write-Error "Failed to install $package" + } + } +} else { + Write-Host "Skipping MSYS2 package installation (--SkipMsys2Install specified)" +} + +# Set environment variables +Write-Header "Setting Environment Variables" + +$env:WINDOWS_XML2_INCLUDE = "$($envInfo.Path)\include\libxml2" +$env:WINDOWS_XML2_LIB = "$($envInfo.Path)\lib" + +# Add to system environment variables (requires admin) +$setSystemEnv = Read-Host "Set environment variables system-wide? (requires admin) [y/N]" +if ($setSystemEnv -eq 'y' -or $setSystemEnv -eq 'Y') { + try { + [Environment]::SetEnvironmentVariable("WINDOWS_XML2_INCLUDE", $env:WINDOWS_XML2_INCLUDE, "Machine") + [Environment]::SetEnvironmentVariable("WINDOWS_XML2_LIB", $env:WINDOWS_XML2_LIB, "Machine") + + # Add to PATH if not already there + $currentPath = [Environment]::GetEnvironmentVariable("PATH", "Machine") + $binPath = "$($envInfo.Path)\bin" + if (-not $currentPath.Contains($binPath)) { + [Environment]::SetEnvironmentVariable("PATH", "$currentPath;$binPath", "Machine") + } + Write-Success "Environment variables set system-wide" + } catch { + Write-Error "Failed to set system environment variables (run as Administrator)" + Write-Host "You can set them manually:" + Write-Host " WINDOWS_XML2_INCLUDE = $($env:WINDOWS_XML2_INCLUDE)" + Write-Host " WINDOWS_XML2_LIB = $($env:WINDOWS_XML2_LIB)" + } +} + +# Verify installation +Write-Header "Verifying Installation" + +$includePath = $env:WINDOWS_XML2_INCLUDE +if (Test-Path $includePath) { + Write-Success "Include path exists: $includePath" + + # Check for key header files + $requiredHeaders = @("libxml/parser.h", "libxml/tree.h", "libxml/xmlversion.h") + foreach ($header in $requiredHeaders) { + $headerPath = Join-Path $includePath $header + if (Test-Path $headerPath) { + Write-Success "Found $header" + } else { + Write-Error "Missing $header" + } + } +} else { + Write-Error "Include path not found: $includePath" +} + +$libPath = $env:WINDOWS_XML2_LIB +if (Test-Path $libPath) { + Write-Success "Library path exists: $libPath" +} else { + Write-Error "Library path not found: $libPath" +} + +# Build options +Write-Header "Build Options" + +$buildChoice = Read-Host @" +Choose installation method: +1. Install pre-built gem (easiest, recommended) +2. Build from source +3. Configure Bundler only + +Enter choice [1-3] +"@ + +switch ($buildChoice) { + "1" { + Write-Host "Installing pre-built gem..." + + if ($envInfo.Name -eq "ucrt64") { + gem install libxml-ruby-x64-mingw-ucrt + } else { + gem install libxml-ruby-x64-mingw32 + } + + if ($LASTEXITCODE -eq 0) { + Write-Success "Pre-built gem installed successfully" + } else { + Write-Error "Failed to install pre-built gem" + } + } + + "2" { + Write-Host "Building from source..." + + # Clone repository + $cloneDir = "..\libxml-ruby-src" + if (-not (Test-Path $cloneDir)) { + git clone https://github.com/xml4r/libxml-ruby.git $cloneDir + } + + Push-Location $cloneDir + + # Install dependencies + bundle install + + # Compile + rake compile + + if ($LASTEXITCODE -eq 0) { + Write-Success "Compilation successful" + + # Run tests + rake test + + # Build gem + rake build + + # Install + $gemFile = Get-ChildItem "pkg\libxml-ruby-*.gem" | Select-Object -First 1 + if ($gemFile) { + gem install $gemFile.FullName + Write-Success "Gem installed from source" + } + } else { + Write-Error "Compilation failed" + } + + Pop-Location + } + + "3" { + Write-Host "Configuring Bundler..." + Write-Host "Run the following command in your project directory:" + Write-Host "" + Write-Host " bundle config build.libxml-ruby --with-xml2-include=$includePath --with-xml2-lib=$libPath" + Write-Host "" + Write-Host "Then run:" + Write-Host "" + Write-Host " bundle install" + Write-Host "" + } + + default { + Write-Host "Invalid choice. Please run the script again." + } +} + +# Final verification +Write-Header "Final Verification" + +$testScript = @" +require 'libxml' +puts "libxml-ruby version: #{LibXML::XML::VERSION}" +puts "libxml2 version: #{LibXML::XML::LIBXML_VERSION}" +doc = LibXML::XML::Document.string('') +puts "Test parse successful: #{doc.root.name == 'root'}" +"@ + +try { + $result = $testScript | ruby 2>&1 + Write-Success "libxml-ruby is working correctly" + Write-Host $result +} catch { + Write-Error "Verification failed" + Write-Host $result +} + +Write-Header "Setup Complete" +Write-Host @" + +Next steps: +1. If you installed the pre-built gem or built from source, you're ready to use libxml-ruby +2. If you chose Bundler configuration, run the bundle commands shown above +3. Copy DLLs from $($envInfo.Path)\bin to your Ruby bin directory or project dlls/ folder: + - libxml2-2.dll + - libiconv-2.dll + - zlib1.dll + +For troubleshooting, see BUILD_LIBXML_WINDOWS.md +"@