diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 7848e9b..8bf3e66 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -432,35 +432,134 @@ jobs: Remove-Item Env:CMAKE_GENERATOR_PLATFORM -ErrorAction SilentlyContinue Remove-Item Env:CMAKE_ARGS -ErrorAction SilentlyContinue - if (-not (Get-Command gfortran.exe -ErrorAction SilentlyContinue)) { - Write-Host "gfortran not found on PATH, installing MinGW fallback" - choco install mingw -y --no-progress + if ("${{ matrix.arch }}" -eq "arm64") { + # The arm64 runner ships with arm64-native LLVM (clang/flang) at + # C:\Program Files\LLVM. We just need VsDevCmd to put mt.exe and + # the Windows SDK linker libraries on PATH so flang can link. + $vswhere = Join-Path ${env:ProgramFiles(x86)} "Microsoft Visual Studio\Installer\vswhere.exe" + if (-not (Test-Path $vswhere)) { throw "vswhere.exe not found" } + $vsInstallPath = & $vswhere -latest -products * ` + -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 ` + -property installationPath + if (-not $vsInstallPath) { throw "Could not locate a Visual Studio installation" } + $vsDevCmd = Join-Path $vsInstallPath "Common7\Tools\VsDevCmd.bat" + if (-not (Test-Path $vsDevCmd)) { throw "VsDevCmd.bat not found" } + + $envDump = & cmd.exe /s /c "`"$vsDevCmd`" -no_logo -host_arch=arm64 -arch=arm64 && set" + foreach ($line in $envDump) { + if ($line -match '^(.*?)=(.*)$') { + Set-Item -Path ("Env:" + $matches[1]) -Value $matches[2] + } + } + if ($env:VCToolsInstallDir) { + "VCToolsInstallDir=$env:VCToolsInstallDir" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append + } + + # Use the pre-installed arm64 LLVM toolchain with Ninja. The clang-cl + # driver matches the MSVC-style flags emitted by dependency CMake files. + # VsDevCmd may have set a VS generator; override back to Ninja. + $env:CMAKE_GENERATOR = "Ninja" + Remove-Item Env:CMAKE_GENERATOR_PLATFORM -ErrorAction SilentlyContinue + $llvmArm64Bin = Join-Path $vsInstallPath "VC\Tools\Llvm\ARM64\bin" + if (-not (Test-Path "$llvmArm64Bin\clang-cl.exe")) { throw "ARM64 clang-cl not found at $llvmArm64Bin" } + + if (Test-Path "$llvmArm64Bin\flang.exe") { + $fortranCompiler = Join-Path $llvmArm64Bin "flang.exe" + } elseif (Test-Path "C:\Program Files\LLVM\bin\flang.exe") { + # Fallback to standalone LLVM flang and force an ARM64 target triple. + $fortranCompiler = "C:\Program Files\LLVM\bin\flang.exe" + $env:FFLAGS = "--target=aarch64-pc-windows-msvc" + } else { + throw "No flang.exe found for Windows arm64 build" + } + + "$llvmArm64Bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append + $env:Path = "$llvmArm64Bin;$env:Path" + + $env:CC = (Join-Path $llvmArm64Bin "clang-cl.exe") + $env:CXX = (Join-Path $llvmArm64Bin "clang-cl.exe") + $env:FC = $fortranCompiler + + # Disable OpenMP on Windows arm64 to avoid wrong-arch libomp runtime issues. + $env:CMAKE_ARGS = "-DPYGEOPACK_GEOPACK_USE_OPENMP=OFF" + + if (-not (Get-Command $env:CC -ErrorAction SilentlyContinue)) { throw "clang-cl not found" } + if (-not (Get-Command $env:FC -ErrorAction SilentlyContinue)) { throw "flang not found" } + if (-not (Get-Command ninja.exe -ErrorAction SilentlyContinue)) { throw "ninja not found" } + } else { + # x64: prefer any pre-installed gfortran; fall back to Chocolatey MinGW. + if (-not (Get-Command gfortran.exe -ErrorAction SilentlyContinue)) { + Write-Host "gfortran not found on PATH, installing MinGW fallback" + choco install mingw -y --no-progress + } + + if (-not (Get-Command ninja.exe -ErrorAction SilentlyContinue)) { + Write-Host "ninja not found on PATH, installing Ninja" + choco install ninja -y --no-progress + } + + $mingwBinCandidates = @( + "C:\ProgramData\chocolatey\lib\mingw\tools\install\mingw64\bin", + "C:\tools\mingw64\bin", + "C:\mingw64\bin" + ) + $mingwBin = $mingwBinCandidates | Where-Object { Test-Path $_ } | Select-Object -First 1 + if ($mingwBin) { + "$mingwBin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append + $env:Path = "$mingwBin;$env:Path" + } + + $env:CC = "gcc" + $env:CXX = "g++" + $env:FC = "gfortran" + + if (-not (Get-Command gcc.exe -ErrorAction SilentlyContinue)) { throw "gcc not found" } + if (-not (Get-Command gfortran.exe -ErrorAction SilentlyContinue)) { throw "gfortran not found" } + if (-not (Get-Command ninja.exe -ErrorAction SilentlyContinue)) { throw "ninja not found" } } - if (-not (Get-Command ninja.exe -ErrorAction SilentlyContinue)) { - Write-Host "ninja not found on PATH, installing Ninja" - choco install ninja -y --no-progress - } + & $pythonExe -m build --wheel -o dist - $mingwBinCandidates = @( - "C:\ProgramData\chocolatey\lib\mingw\tools\install\mingw64\bin", - "C:\tools\mingw64\bin" - ) - $mingwBin = $mingwBinCandidates | Where-Object { Test-Path $_ } | Select-Object -First 1 - if ($mingwBin) { - "$mingwBin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append - $env:Path = "$mingwBin;$env:Path" + - name: Verify DLL machine type (arm64) + if: matrix.arch == 'arm64' + shell: pwsh + run: | + .\env\Scripts\Activate.ps1 + $wheel = Get-ChildItem -Path dist -Filter *.whl | Select-Object -First 1 + if (-not $wheel) { throw "No wheel found in dist/" } + $tmp = Join-Path $env:RUNNER_TEMP "wheel_unpack" + if (Test-Path $tmp) { Remove-Item -Path $tmp -Recurse -Force } + New-Item -ItemType Directory -Path $tmp | Out-Null + python -m zipfile -e $wheel.FullName $tmp + $dll = Get-ChildItem -Path $tmp -Recurse -Filter geopack.dll | Select-Object -First 1 + if (-not $dll) { throw "geopack.dll not found inside wheel" } + + $vcToolsInstallDir = $env:VCToolsInstallDir + if (-not $vcToolsInstallDir) { + $vswhere = Join-Path ${env:ProgramFiles(x86)} "Microsoft Visual Studio\Installer\vswhere.exe" + if (-not (Test-Path $vswhere)) { throw "vswhere.exe not found" } + $vsInstallPath = & $vswhere -latest -products * ` + -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 ` + -property installationPath + if (-not $vsInstallPath) { throw "Could not locate a Visual Studio installation" } + $vcToolsRoot = Join-Path $vsInstallPath "VC\Tools\MSVC" + $vcToolsInstallDir = Get-ChildItem -Path $vcToolsRoot -Directory | + Sort-Object Name -Descending | + Select-Object -First 1 -ExpandProperty FullName + if (-not $vcToolsInstallDir) { throw "Could not locate VC tools directory" } } - $env:CC = "gcc" - $env:CXX = "g++" - $env:FC = "gfortran" - - if (-not (Get-Command gcc.exe -ErrorAction SilentlyContinue)) { throw "gcc not found" } - if (-not (Get-Command gfortran.exe -ErrorAction SilentlyContinue)) { throw "gfortran not found" } - if (-not (Get-Command ninja.exe -ErrorAction SilentlyContinue)) { throw "ninja not found" } + $dumpbin = Join-Path $vcToolsInstallDir "bin\HostARM64\arm64\dumpbin.exe" + if (-not (Test-Path $dumpbin)) { + $dumpbin = Join-Path $vcToolsInstallDir "bin\Hostx64\arm64\dumpbin.exe" + } + if (-not (Test-Path $dumpbin)) { throw "dumpbin.exe not found" } - & $pythonExe -m build --wheel -o dist + $headers = & $dumpbin /headers $dll.FullName + $headers | Out-String | Write-Host + if (-not ($headers -match "machine \(ARM64\)")) { + throw "geopack.dll is not ARM64" + } - name: Install wheel shell: pwsh diff --git a/CMakeLists.txt b/CMakeLists.txt index 2173afb..c922e6b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -19,9 +19,12 @@ elseif(UNIX) set(_pygeopack_library_glob "*.so*") endif() +option(PYGEOPACK_GEOPACK_USE_OPENMP "Enable OpenMP in geopack dependency" ON) + set(_pygeopack_cmake_args -DGEOPACK_BUILD_TESTS=OFF -DGEOPACK_BUILD_SHARED=ON + -DGEOPACK_USE_OPENMP=${PYGEOPACK_GEOPACK_USE_OPENMP} -DCMAKE_BUILD_TYPE=Release ) diff --git a/PyGeopack/_CheckFirstImport.py b/PyGeopack/_CheckFirstImport.py index e6f7168..efb0fa5 100644 --- a/PyGeopack/_CheckFirstImport.py +++ b/PyGeopack/_CheckFirstImport.py @@ -22,21 +22,24 @@ def getLibFilename(isShort=False): Filename of the source library """ - if(isShort): - libFilename = "libgeopack." - else: - libFilename = os.path.dirname(__file__) + "/__data/geopack/lib/libgeopack." - systype = platform.system() if systype == 'Linux': + libName = "libgeopack" extension = "so" elif systype == 'Windows': + libName = "geopack" extension = "dll" elif systype == 'Darwin': + libName = "libgeopack" extension = 'dylib' else: raise Exception("The Operating System is not supported") - + + if(isShort): + libFilename = libName + "." + else: + libFilename = os.path.dirname(__file__) + "/__data/geopack/lib/" + libName + "." + return libFilename + extension diff --git a/PyGeopack/__data/geopack b/PyGeopack/__data/geopack index 4c54686..2f1ca24 160000 --- a/PyGeopack/__data/geopack +++ b/PyGeopack/__data/geopack @@ -1 +1 @@ -Subproject commit 4c546866232e60776bc8d7adbda514ef301df209 +Subproject commit 2f1ca24f4f8ac7c6c0862bb056df252f61bd672b diff --git a/pyproject.toml b/pyproject.toml index 3b79a35..d8ac965 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -33,10 +33,6 @@ wheel.packages = ["PyGeopack"] wheel.install-dir = "PyGeopack/__data/geopack/lib" install.components = ["python"] -[tool.scikit-build.cmake.define] -GEOPACK_BUILD_TESTS = false -GEOPACK_BUILD_SHARED = true - [tool.scikit-build.metadata.version] provider = "scikit_build_core.metadata.regex" -input = "PyGeopack/__init__.py" \ No newline at end of file +input = "PyGeopack/__init__.py"