Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 12 additions & 2 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ jobs:
run: |
sudo apt-get update
sudo apt-get install --yes ocl-icd-opencl-dev pocl-opencl-icd libvulkan-dev libvulkan-volk-dev libglfw3-dev mesa-vulkan-drivers vulkan-validationlayers xauth xvfb
- name: Verify the public setup diagnostics
run: v run setup.vsh --check
- name: Assemble namespaced module and install example modules
run: |
install -d "$HOME/.vmodules/antono2/opencl"
Expand Down Expand Up @@ -98,7 +100,9 @@ jobs:
install -d "$HOME/.vmodules/antono2/opencl/include/CL"
install -m 0644 include/CL/opencl.h "$HOME/.vmodules/antono2/opencl/include/CL/opencl.h"
- name: Compile macOS ABI probe
run: v -cc clang -o /tmp/opencl-abi-probe abi/main.c.v
run: |
v run setup.vsh --check
v -cc clang -o /tmp/opencl-abi-probe abi/main.c.v

linux-v-master:
runs-on: ubuntu-24.04
Expand Down Expand Up @@ -162,7 +166,13 @@ jobs:
Copy-Item opencl.v, convenience.v, ownership.v, program.v, event.v, image.v, svm.v, capabilities.v, external_interop.v, v.mod, VERSION, LICENSE, GENERATOR_COMMIT -Destination $module
$include = Join-Path $env:VCPKG_INSTALLATION_ROOT 'installed/x64-windows/include'
$lib = Join-Path $env:VCPKG_INSTALLATION_ROOT 'installed/x64-windows/lib'
v -cc msvc -cflags "/I$include" -ldflags "/LIBPATH:$lib" -o "$env:TEMP/opencl-abi-probe.exe" abi/main.c.v
New-Item -ItemType Directory -Force (Join-Path $module 'include') | Out-Null
Copy-Item -Recurse (Join-Path $include 'CL') -Destination (Join-Path $module 'include')
New-Item -ItemType Directory -Force (Join-Path $module 'lib') | Out-Null
Copy-Item (Join-Path $lib 'OpenCL.lib') -Destination (Join-Path $module 'lib')
$env:OPENCL_SDK = Join-Path $env:VCPKG_INSTALLATION_ROOT 'installed/x64-windows'
v run setup.vsh --check
v -cc msvc -o "$env:TEMP/opencl-abi-probe.exe" abi/main.c.v

required-checks:
name: required-checks
Expand Down
1 change: 1 addition & 0 deletions DISTRIBUTION_FILES
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ include/CL/opencl.h
opencl.v
ownership.v
program.v
setup.vsh
svm.v
test/pointer_abi_shim.c
test/pointer_abi_test.v
Expand Down
2 changes: 1 addition & 1 deletion GENERATOR_COMMIT
Original file line number Diff line number Diff line change
@@ -1 +1 @@
672b9a1dd1d38693829296568a832b656f86c866
3abe0dabc477c2302e68a4fcb46ce493659fdeb9
15 changes: 11 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,21 @@ The bindings are generated from Khronos' canonical OpenCL XML registry by
for this release. `GENERATOR_COMMIT` identifies the exact canonical generator
revision from which the published module was synchronized.

Applications must have an OpenCL ICD loader and OpenCL development headers.
On Debian or Ubuntu, a CPU implementation suitable for development and testing
can be installed with:
## One-command setup

Install the native OpenCL development prerequisites and this V module:

```sh
sudo apt install ocl-icd-opencl-dev pocl-opencl-icd
v run setup.vsh
```

When running from an installed module, use
`v run ~/.vmodules/antono2/opencl/setup.vsh`. Ubuntu and Debian, Fedora, Arch,
openSUSE, macOS, and Windows are supported. `v run setup.vsh --check` performs
a read-only diagnostic pass. On Windows, the script installs the Khronos loader
and headers through vcpkg; the current GPU vendor driver still supplies the
actual OpenCL implementation. macOS uses its built-in OpenCL framework.

## Supported toolchains

| Platform | V compiler | C compiler | Validation level |
Expand Down
2 changes: 2 additions & 0 deletions opencl.v
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ module opencl

#flag linux -lOpenCL
#flag windows -lOpenCL
#flag windows -I@VMODROOT/include
#flag windows -L@VMODROOT/lib
#flag darwin -framework OpenCL
#flag darwin -I@VMODROOT/include
#include <CL/opencl.h>
Expand Down
231 changes: 231 additions & 0 deletions setup.vsh
Original file line number Diff line number Diff line change
@@ -0,0 +1,231 @@
#!/usr/bin/env -S v run

// Installs and verifies the native prerequisites used by antono2.opencl.
// Running without arguments performs the installation. Use --check for a
// read-only diagnostic pass suitable for support requests and CI.

import os

const usage = 'Usage: v run setup.vsh [--install|--check]\n\n' + ' --install Install the OpenCL loader, headers, a development runtime, and this V module (default).\n' + ' --check Only report whether the compiler, headers, loader, and an OpenCL platform work.\n'

fn command_exists(name string) bool {
os.find_abs_path_of_executable(name) or { return false }
return true
}

fn run(command string) ! {
println('\n> ${command}')
result := os.execute(command)
if result.output.trim_space() != '' {
println(result.output.trim_right('\r\n'))
}
if result.exit_code != 0 {
return error('command failed with exit code ${result.exit_code}')
}
}

fn install_linux() ! {
if command_exists('apt-get') {
run('sudo apt-get update')!
run('sudo apt-get install -y build-essential clinfo ocl-icd-opencl-dev pocl-opencl-icd')!
return
}
if command_exists('dnf') {
run('sudo dnf install -y gcc gcc-c++ clinfo ocl-icd-devel opencl-headers pocl')!
return
}
if command_exists('pacman') {
run('sudo pacman -S --needed --noconfirm base-devel clinfo ocl-icd opencl-headers pocl')!
return
}
if command_exists('zypper') {
run('sudo zypper --non-interactive install -y gcc gcc-c++ clinfo ocl-icd-devel opencl-headers pocl')!
return
}
return error('unsupported Linux package manager; install OpenCL headers, an ICD loader, clinfo, and an ICD such as PoCL, then rerun with --check')
}

fn install_macos() ! {
if !command_exists('xcode-select') || os.execute('xcode-select -p').exit_code != 0 {
return error('Apple Command Line Tools are required; run `xcode-select --install`, then retry')
}
println('The OpenCL headers, loader, and implementation are provided by the macOS OpenCL framework.')
}

fn copy_windows_sdk_files(module_root string) ! {
sdk_root := os.getenv('OPENCL_SDK')
source := os.join_path(sdk_root, 'lib', 'OpenCL.lib')
if !os.is_file(source) {
return error('OpenCL import library was not installed at ${source}')
}
os.mkdir_all(os.join_path(module_root, 'lib'))!
os.cp(source, os.join_path(module_root, 'lib', 'OpenCL.lib'))!
os.cp_all(os.join_path(sdk_root, 'include'), os.join_path(module_root, 'include'), true)!
}

fn install_windows() ! {
if !command_exists('winget') {
return error('winget is required for automatic Windows setup; install Microsoft App Installer, then try again')
}
if !command_exists('git') {
run('winget install --id Git.Git --exact --accept-package-agreements --accept-source-agreements')!
}
if !command_exists('cmake') {
run('winget install --id Kitware.CMake --exact --accept-package-agreements --accept-source-agreements')!
}
path_result := os.execute('powershell -NoProfile -Command "[Environment]::GetEnvironmentVariable(\'Path\',\'Machine\') + \';\' + [Environment]::GetEnvironmentVariable(\'Path\',\'User\')"')
if path_result.exit_code == 0 && path_result.output.trim_space() != '' {
os.setenv('PATH', path_result.output.trim_space(), true)
}
cache_root := os.join_path(os.cache_dir(), 'antono2', 'opencl')
vcpkg_root := os.join_path(cache_root, 'vcpkg')
if !os.is_dir(vcpkg_root) {
os.mkdir_all(cache_root)!
run('git clone --depth 1 https://github.com/microsoft/vcpkg.git ${os.quoted_path(vcpkg_root)}')!
}
bootstrap := os.join_path(vcpkg_root, 'bootstrap-vcpkg.bat')
vcpkg := os.join_path(vcpkg_root, 'vcpkg.exe')
if !os.is_file(vcpkg) {
run(os.quoted_path(bootstrap))!
}
run('${os.quoted_path(vcpkg)} install opencl:x64-windows')!
sdk_root := os.join_path(vcpkg_root, 'installed', 'x64-windows')
os.setenv('OPENCL_SDK', sdk_root, true)
copy_windows_sdk_files(os.dir(os.real_path(@FILE)))!
// Persist the development location for new terminals. The current process
// is also updated above so verification can continue without a restart.
run('setx OPENCL_SDK ${os.quoted_path(sdk_root)}')!
println('\nThe Khronos loader is installed for development. Install the current GPU vendor driver to provide an OpenCL implementation.')
}

fn install_native() ! {
$if linux {
install_linux()!
} $else $if macos {
install_macos()!
} $else $if windows {
install_windows()!
} $else {
return error('automatic setup is not supported on this operating system')
}
}

fn find_opencl_header() string {
mut roots := []string{}
if sdk := os.getenv_opt('OPENCL_SDK') {
roots << sdk
}
$if macos {
framework := '/System/Library/Frameworks/OpenCL.framework'
if os.is_dir(framework) {
return framework
}
} $else $if !windows {
roots << ['/usr', '/usr/local', '/opt/homebrew']
}
for root in roots {
for relative in ['include/CL/opencl.h', 'Headers/opencl.h'] {
candidate := os.join_path(root, relative)
if os.is_file(candidate) {
return candidate
}
}
}
return ''
}

fn report_command(name string, required bool) bool {
if path := os.find_abs_path_of_executable(name) {
println('[ok] ${name}: ${path}')
return true
}
label := if required { 'missing' } else { 'optional' }
println('[${label}] ${name}')
return !required
}

fn check() bool {
println('\nOpenCL setup check')
println('------------------')
mut ok := true
ok = report_command('v', true) && ok
$if windows {
report_command('cl', false)
} $else {
ok = report_command('cc', true) && ok
}
header := find_opencl_header()
$if macos {
if header == '' {
println('[missing] macOS OpenCL framework headers')
ok = false
} else {
println('[ok] OpenCL framework header: ${header}')
}
} $else {
if header == '' {
println('[missing] OpenCL development headers')
ok = false
} else {
println('[ok] OpenCL header: ${header}')
}
}
if command_exists('clinfo') {
result := os.execute('clinfo -l')
if result.exit_code == 0 && result.output.contains('Platform') {
println('[ok] OpenCL loader enumerated a platform')
} else {
println('[warning] the loader is installed, but no OpenCL platform was found')
println(' Install the GPU vendor driver or a CPU implementation such as PoCL.')
}
} else {
$if windows {
if os.exists(os.join_path(os.getenv('WINDIR'), 'System32', 'OpenCL.dll')) {
println('[ok] OpenCL.dll is installed')
} else {
println('[warning] OpenCL.dll was not found; install the current GPU vendor driver')
}
} $else $if macos {
println('[ok] macOS OpenCL framework is available')
} $else {
println('[warning] clinfo is unavailable; OpenCL runtime verification was skipped')
}
}
return ok
}

fn main() {
if os.args.len > 2 || (os.args.len == 2 && os.args[1] !in ['--install', '--check', '-h', '--help']) {
eprintln(usage)
exit(2)
}
if os.args.len == 2 && os.args[1] in ['-h', '--help'] {
println(usage)
return
}
install := os.args.len == 1 || os.args[1] == '--install'
if install {
install_native() or {
eprintln('Setup failed: ${err}')
exit(1)
}
if command_exists('v') {
run('v install antono2.opencl') or {
eprintln('Could not install the V module: ${err}')
exit(1)
}
$if windows {
installed_module := os.join_path(os.vmodules_dir(), 'antono2', 'opencl')
copy_windows_sdk_files(installed_module) or {
eprintln('Could not configure the installed V module: ${err}')
exit(1)
}
}
}
}
if !check() {
eprintln('\nSetup is incomplete. Resolve the missing items above and rerun with --check.')
exit(1)
}
println('\nOpenCL development prerequisites are ready.')
}
Loading