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
87 changes: 67 additions & 20 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,6 @@ on:
permissions:
contents: read

env:
# Pin the required compiler so release artifacts moving with V development
# cannot destabilize the supported lane.
V_VERSION: 0.5.2
V3_COMMIT: efae23e85b3772a28e62884d554c1e88f91f52f4
V3_VC_COMMIT: 2cbaf6bc2367937cd5f0b4ef923d1ef9aad613b3
V3_TCC_COMMIT: d6e7ac1b1bcc98aed734a6ecbfa8509f24606c74
VULKAN_REF: v3.2.2
GLFW_REF: v2.0.1

concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
Expand All @@ -30,25 +21,33 @@ jobs:
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
- name: Validate and resolve tested compatibility
id: compat
shell: bash
working-directory: ${{ github.workspace }}
run: |
python ./scripts/test_compatibility.py
python ./scripts/test_doctor.py
python ./scripts/compatibility.py --github-output "$GITHUB_OUTPUT"
- name: Check out pinned Vulkan module
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
with:
repository: antono2/vulkan
ref: ${{ env.VULKAN_REF }}
ref: ${{ steps.compat.outputs.module_vulkan }}
path: .ci-modules/vulkan
- name: Check out pinned GLFW module
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
with:
repository: antono2/glfw
ref: ${{ env.GLFW_REF }}
ref: ${{ steps.compat.outputs.module_glfw }}
path: .ci-modules/glfw
- name: Validate generator provenance marker
run: |
generator_commit=$(cat GENERATOR_COMMIT)
[[ "$generator_commit" =~ ^[0-9a-f]{40}$ ]]
- uses: prantlf/setup-v-action@92f20bea50d2c9931a28c96bb4997a3c7357baf0 # v4
with:
version: ${{ env.V_VERSION }}
version: ${{ steps.compat.outputs.v_release }}
- name: Install native dependencies
run: |
sudo apt-get update
Expand All @@ -61,8 +60,8 @@ jobs:
install -m 0644 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 "$HOME/.vmodules/antono2/opencl/"
install -d "$HOME/.vmodules/antono2/opencl/include/CL"
install -m 0644 include/CL/opencl.h "$HOME/.vmodules/antono2/opencl/include/CL/opencl.h"
test "$(git -C .ci-modules/vulkan describe --tags --exact-match)" = "$VULKAN_REF"
test "$(git -C .ci-modules/glfw describe --tags --exact-match)" = "$GLFW_REF"
test "$(git -C .ci-modules/vulkan describe --tags --exact-match)" = '${{ steps.compat.outputs.module_vulkan }}'
test "$(git -C .ci-modules/glfw describe --tags --exact-match)" = '${{ steps.compat.outputs.module_glfw }}'
install -d "$HOME/.vmodules/antono2/vulkan" "$HOME/.vmodules/antono2/glfw"
cp -a .ci-modules/vulkan/. "$HOME/.vmodules/antono2/vulkan/"
cp -a .ci-modules/glfw/. "$HOME/.vmodules/antono2/glfw/"
Expand Down Expand Up @@ -98,9 +97,17 @@ jobs:
runs-on: macos-14
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
- name: Validate and resolve tested compatibility
id: compat
shell: bash
working-directory: ${{ github.workspace }}
run: |
python ./scripts/test_compatibility.py
python ./scripts/test_doctor.py
python ./scripts/compatibility.py --github-output "$GITHUB_OUTPUT"
- uses: prantlf/setup-v-action@92f20bea50d2c9931a28c96bb4997a3c7357baf0 # v4
with:
version: ${{ env.V_VERSION }}
version: ${{ steps.compat.outputs.v_release }}
- name: Assemble namespaced module
run: |
install -d "$HOME/.vmodules/antono2/opencl"
Expand All @@ -119,6 +126,14 @@ jobs:
# V master currently builds a separate v1_fallback executable for tool
# commands such as `v test`. Keep the complete source build together;
# setup-v-action@v4's reduced cache bundle omits that executable.
- name: Validate and resolve tested compatibility
id: compat
shell: bash
working-directory: ${{ github.workspace }}
run: |
python ./scripts/test_compatibility.py
python ./scripts/test_doctor.py
python ./scripts/compatibility.py --github-output "$GITHUB_OUTPUT"
- name: Check out V master
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
id: checkout_v_master
Expand Down Expand Up @@ -162,25 +177,33 @@ jobs:
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
- name: Validate and resolve tested compatibility
id: compat
shell: bash
working-directory: ${{ github.workspace }}
run: |
python ./scripts/test_compatibility.py
python ./scripts/test_doctor.py
python ./scripts/compatibility.py --github-output "$GITHUB_OUTPUT"
- name: Check out pinned V3 compiler
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
with:
repository: vlang/v
ref: ${{ env.V3_COMMIT }}
ref: ${{ steps.compat.outputs.v3_v }}
path: .ci-v3
fetch-depth: 1
- name: Check out matching V3 bootstrap source
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
with:
repository: vlang/vc
ref: ${{ env.V3_VC_COMMIT }}
ref: ${{ steps.compat.outputs.v3_vc }}
path: .ci-v3/vc
fetch-depth: 1
- name: Check out matching V3 TinyCC runtime
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
with:
repository: vlang/tccbin
ref: ${{ env.V3_TCC_COMMIT }}
ref: ${{ steps.compat.outputs.v3_tcc }}
path: .ci-v3/thirdparty/tcc
fetch-depth: 1
- name: Build pinned V3 compiler
Expand Down Expand Up @@ -211,9 +234,17 @@ jobs:
runs-on: windows-2022
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
- name: Validate and resolve tested compatibility
id: compat
shell: bash
working-directory: ${{ github.workspace }}
run: |
python ./scripts/test_compatibility.py
python ./scripts/test_doctor.py
python ./scripts/compatibility.py --github-output "$GITHUB_OUTPUT"
- uses: prantlf/setup-v-action@92f20bea50d2c9931a28c96bb4997a3c7357baf0 # v4
with:
version: ${{ env.V_VERSION }}
version: ${{ steps.compat.outputs.v_release }}
- name: Install OpenCL SDK
run: vcpkg install opencl:x64-windows
- name: Assemble namespaced module and compile ABI probe
Expand Down Expand Up @@ -242,6 +273,14 @@ jobs:
GLFW_LIB: /usr/lib/x86_64-linux-gnu
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
- name: Validate and resolve tested compatibility
id: compat
shell: bash
working-directory: ${{ github.workspace }}
run: |
python ./scripts/test_compatibility.py
python ./scripts/test_doctor.py
python ./scripts/compatibility.py --github-output "$GITHUB_OUTPUT"
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
with:
repository: antono2/vulkan
Expand All @@ -254,7 +293,7 @@ jobs:
path: .ci-modules/glfw
- uses: prantlf/setup-v-action@92f20bea50d2c9931a28c96bb4997a3c7357baf0 # v4
with:
version: ${{ env.V_VERSION }}
version: ${{ steps.compat.outputs.v_release }}
- name: Install native dependencies
run: sudo apt-get update && sudo apt-get install -y ocl-icd-opencl-dev pocl-opencl-icd libvulkan-dev libvulkan-volk-dev libglfw3-dev
- name: Assemble modules and compile particles
Expand Down Expand Up @@ -295,6 +334,14 @@ jobs:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
with:
fetch-depth: 0
- name: Validate and resolve tested compatibility
id: compat
shell: bash
working-directory: ${{ github.workspace }}
run: |
python ./scripts/test_compatibility.py
python ./scripts/test_doctor.py
python ./scripts/compatibility.py --github-output "$GITHUB_OUTPUT"
- name: Validate release version and generator provenance
run: |
set -euo pipefail
Expand Down
10 changes: 8 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ OpenCL bindings for the [V programming language](https://vlang.io/), with the
complete OpenCL 1.0 through 3.0 core API, selected Khronos extensions and
optional helpers for device discovery and explicit resource ownership.

[Available on VPM](https://vpm.vlang.io/packages/antono2.opencl) ·
[Release notes](https://github.com/antono2/opencl/releases) ·
[Available on VPM](https://vpm.vlang.io/packages/antono2.opencl) ·
[Release notes](https://github.com/antono2/opencl/releases) ·
[Project portfolio](https://oreskin.de/projects_en.php)

## Install and setup
Expand Down Expand Up @@ -326,3 +326,9 @@ Handwritten discovery, ownership, event, image and interoperability files have
purpose comments describing their role. Make shared source and example changes
in that repository, then run its publisher; direct edits here can be overwritten.
Keep vendored OpenCL headers and their upstream license notices intact.


## Compatibility and diagnostics

See [tested profiles and read-only diagnostics](docs/compatibility.md) for
compiler/dependency versions, setup recovery actions and upgrade checks.
15 changes: 15 additions & 0 deletions compatibility.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"schema_version": 1,
"v_release": "0.5.2",
"v3_v": "efae23e85b3772a28e62884d554c1e88f91f52f4",
"v3_vc": "2cbaf6bc2367937cd5f0b4ef923d1ef9aad613b3",
"v3_tcc": "d6e7ac1b1bcc98aed734a6ecbfa8509f24606c74",
"modules": {
"vulkan": "v3.2.2",
"glfw": "v2.0.1"
},
"build_tools": [
"git",
"cmake"
]
}
23 changes: 23 additions & 0 deletions docs/compatibility.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Tested compatibility and diagnostics

`compatibility.json` records the existing tested compiler, bootstrap, native and
module versions. CI resolves these values before dependency checkout and rejects
disagreement with `v.mod`. Advisory upstream-master lanes remain advisory.
Registry/version files owned by binding generators remain authoritative for
generated API contents; upstream update workflows deliberately select candidates
separately from the tested compiler profiles.

Upgrade the manifest and affected VPM declarations together. Run
`python scripts/test_compatibility.py` and the full project CI. Consumer application
compilation/runtime checks are also required before publishing a dependency upgrade.
The resolver's `--modules PATH` option verifies installed Git tags without fetching.

Run `python scripts/doctor.py --v PATH_TO_V --modules PATH_TO_MODULES` for read-only
compiler/tool/dependency diagnostics. Add `--json` for a support report and
`--runtime` for Vulkan device enumeration when Vulkan tools are available. Missing
or mismatched prerequisites include a recovery action; diagnostics never repair
caches or change the environment. Enumeration alone does not prove hardware video
decoding or OpenCL interoperability. Python 3.9 or newer is required for these tools.

Choose `--profile v3` for the pinned V3 compiler or `--profile release` for
the released compiler when the project defines multiple profiles.
65 changes: 65 additions & 0 deletions scripts/compatibility.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
#!/usr/bin/env python3
"""Resolve tested compiler/native/module profiles and validate VPM declarations."""
import argparse
import json
from pathlib import Path
import re
import subprocess


def resolve(root, profile='stable'):
pins = json.loads((root / 'compatibility.json').read_text())
if pins.get('schema_version') != 1:
raise ValueError('Unsupported compatibility schema_version')
if 'v_release' in pins and not re.fullmatch(r'[0-9]+\.[0-9]+\.[0-9]+', pins['v_release']):
raise ValueError('v_release must be a released compiler version')
upstream = root / 'third_party/upstream.json'
if upstream.is_file() and pins.get('glfw') != json.loads(upstream.read_text())['version']:
raise ValueError('Native GLFW version and compatibility.json disagree')
for key, value in pins.items():
if key in ['v', 'vc', 'tcc', 'volk', 'generator'] or key.endswith(('_v', '_vc', '_tcc')):
if not re.fullmatch('[0-9a-f]{40}', value):
raise ValueError(f'{key} must be an immutable Git commit')
declared = dict(re.findall(r"'antono2\.([a-z0-9_]+)@([^']+)'", (root / 'v.mod').read_text()))
for name, tag in declared.items():
if pins.get('modules', {}).get(name) != tag:
raise ValueError(f'v.mod and compatibility.json disagree for {name}')
outputs = {key: value for key, value in pins.items() if isinstance(value, str)}
for name, tag in pins.get('modules', {}).items():
if not re.fullmatch('[a-z0-9_]+', name) or not re.fullmatch(r'v[0-9]+\.[0-9]+\.[0-9]+(?:-standard)?', tag):
raise ValueError(f'Invalid module pin: {name}={tag}')
outputs['module_' + name] = tag
outputs['selected_v'] = 'master' if profile == 'master' else (pins['v3_v'] if profile == 'v3' else pins.get('v', pins.get('v_release', '')))
for key, value in outputs.items():
if not re.fullmatch('[a-z0-9_]+', key) or '\n' in value or '\r' in value:
raise ValueError(f'Unsafe compatibility output: {key}')
return outputs


def main():
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument('--root', type=Path, default=Path(__file__).resolve().parents[1])
parser.add_argument('--profile', choices=['stable', 'v3', 'master'], default='stable')
parser.add_argument('--github-output', type=Path)
parser.add_argument('--get')
parser.add_argument('--modules', type=Path)
args = parser.parse_args()
outputs = resolve(args.root, args.profile)
if args.modules:
for key, tag in outputs.items():
if not key.startswith('module_'):
continue
checkout = args.modules / 'antono2' / key[len('module_'):]
def revision(ref):
return subprocess.check_output(['git', '-C', str(checkout), 'rev-parse', '--verify', ref], text=True).strip()
if revision('HEAD') != revision(f'refs/tags/{tag}^{{commit}}'):
raise ValueError(f'Installed module does not match {tag}: {checkout}')
if args.github_output:
with args.github_output.open('a', encoding='utf-8') as output:
for key, value in outputs.items():
output.write(f'{key}={value}\n')
print(outputs[args.get] if args.get else json.dumps(outputs, indent=2))


if __name__ == '__main__':
main()
Loading
Loading