tensoracle 0.5.1__tar.gz → 1.0.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (85) hide show
  1. {tensoracle-0.5.1 → tensoracle-1.0.0}/PKG-INFO +17 -4
  2. {tensoracle-0.5.1 → tensoracle-1.0.0}/README.md +15 -3
  3. {tensoracle-0.5.1 → tensoracle-1.0.0}/cpp/cmake/TensoracleCubinPlugin.cmake +5 -1
  4. tensoracle-1.0.0/docs/cpp-python-repositories.md +199 -0
  5. {tensoracle-0.5.1 → tensoracle-1.0.0}/docs/index.md +4 -2
  6. {tensoracle-0.5.1 → tensoracle-1.0.0}/docs/precision.md +1 -1
  7. {tensoracle-0.5.1 → tensoracle-1.0.0}/docs/tensorrt-sdk.md +88 -1
  8. {tensoracle-0.5.1 → tensoracle-1.0.0}/mkdocs.yml +1 -0
  9. {tensoracle-0.5.1 → tensoracle-1.0.0}/pyproject.toml +1 -0
  10. {tensoracle-0.5.1 → tensoracle-1.0.0}/src/tensoracle/_version.py +2 -2
  11. {tensoracle-0.5.1 → tensoracle-1.0.0}/src/tensoracle/bundle.py +18 -6
  12. {tensoracle-0.5.1 → tensoracle-1.0.0}/tests/cubin_io/check.cpp +4 -0
  13. {tensoracle-0.5.1 → tensoracle-1.0.0}/tests/example_runtime.py +3 -3
  14. tensoracle-1.0.0/tests/native/CMakeLists.txt +44 -0
  15. tensoracle-1.0.0/tests/native/export.h +7 -0
  16. tensoracle-1.0.0/tests/native_build.py +68 -0
  17. {tensoracle-0.5.1 → tensoracle-1.0.0}/tests/test_bundle.py +67 -22
  18. {tensoracle-0.5.1 → tensoracle-1.0.0}/tests/test_cache.py +9 -13
  19. tensoracle-1.0.0/tests/test_cmake_plugin.py +56 -0
  20. {tensoracle-0.5.1 → tensoracle-1.0.0}/tests/test_cpp_core.py +7 -19
  21. {tensoracle-0.5.1 → tensoracle-1.0.0}/tests/test_distribution.py +9 -5
  22. {tensoracle-0.5.1 → tensoracle-1.0.0}/tests/test_example_plugin.py +33 -8
  23. {tensoracle-0.5.1 → tensoracle-1.0.0}/tests/test_plugin_io.py +11 -49
  24. {tensoracle-0.5.1 → tensoracle-1.0.0}/tests/test_plugins.py +26 -18
  25. {tensoracle-0.5.1 → tensoracle-1.0.0}/.gitignore +0 -0
  26. {tensoracle-0.5.1 → tensoracle-1.0.0}/LICENSE +0 -0
  27. {tensoracle-0.5.1 → tensoracle-1.0.0}/build_backend.py +0 -0
  28. {tensoracle-0.5.1 → tensoracle-1.0.0}/cpp/CMakeLists.txt +0 -0
  29. {tensoracle-0.5.1 → tensoracle-1.0.0}/cpp/include/tensoracle/cubin_plugin.hpp +0 -0
  30. {tensoracle-0.5.1 → tensoracle-1.0.0}/cpp/src/cubin_plugin.cpp +0 -0
  31. {tensoracle-0.5.1 → tensoracle-1.0.0}/cpp/tests/core.cpp +0 -0
  32. {tensoracle-0.5.1 → tensoracle-1.0.0}/docs/api/bundle.md +0 -0
  33. {tensoracle-0.5.1 → tensoracle-1.0.0}/docs/api/index.md +0 -0
  34. {tensoracle-0.5.1 → tensoracle-1.0.0}/docs/api/producer.md +0 -0
  35. {tensoracle-0.5.1 → tensoracle-1.0.0}/docs/optimization.md +0 -0
  36. {tensoracle-0.5.1 → tensoracle-1.0.0}/examples/cubin_plugin/CMakeLists.txt +0 -0
  37. {tensoracle-0.5.1 → tensoracle-1.0.0}/examples/cubin_plugin/README.md +0 -0
  38. {tensoracle-0.5.1 → tensoracle-1.0.0}/examples/cubin_plugin/bundle/bundle.cpp +0 -0
  39. {tensoracle-0.5.1 → tensoracle-1.0.0}/examples/cubin_plugin/bundle/bundle.json +0 -0
  40. {tensoracle-0.5.1 → tensoracle-1.0.0}/examples/cubin_plugin/bundle/cubins/sm120/bias.cubin +0 -0
  41. {tensoracle-0.5.1 → tensoracle-1.0.0}/examples/cubin_plugin/bundle/cubins/sm120/dot.specialized.cubin +0 -0
  42. {tensoracle-0.5.1 → tensoracle-1.0.0}/examples/cubin_plugin/bundle/cubins/sm120/dot.tf32-control.cubin +0 -0
  43. {tensoracle-0.5.1 → tensoracle-1.0.0}/examples/cubin_plugin/bundle/cubins/sm120/dot.unspecialized.cubin +0 -0
  44. {tensoracle-0.5.1 → tensoracle-1.0.0}/examples/cubin_plugin/bundle/cubins/sm120/scale.cubin +0 -0
  45. {tensoracle-0.5.1 → tensoracle-1.0.0}/examples/cubin_plugin/bundle/cubins/sm86/bias.cubin +0 -0
  46. {tensoracle-0.5.1 → tensoracle-1.0.0}/examples/cubin_plugin/bundle/cubins/sm86/dot.specialized.cubin +0 -0
  47. {tensoracle-0.5.1 → tensoracle-1.0.0}/examples/cubin_plugin/bundle/cubins/sm86/dot.tf32-control.cubin +0 -0
  48. {tensoracle-0.5.1 → tensoracle-1.0.0}/examples/cubin_plugin/bundle/cubins/sm86/dot.unspecialized.cubin +0 -0
  49. {tensoracle-0.5.1 → tensoracle-1.0.0}/examples/cubin_plugin/bundle/cubins/sm86/scale.cubin +0 -0
  50. {tensoracle-0.5.1 → tensoracle-1.0.0}/examples/cubin_plugin/bundle/cubins/sm89/bias.cubin +0 -0
  51. {tensoracle-0.5.1 → tensoracle-1.0.0}/examples/cubin_plugin/bundle/cubins/sm89/dot.specialized.cubin +0 -0
  52. {tensoracle-0.5.1 → tensoracle-1.0.0}/examples/cubin_plugin/bundle/cubins/sm89/dot.tf32-control.cubin +0 -0
  53. {tensoracle-0.5.1 → tensoracle-1.0.0}/examples/cubin_plugin/bundle/cubins/sm89/dot.unspecialized.cubin +0 -0
  54. {tensoracle-0.5.1 → tensoracle-1.0.0}/examples/cubin_plugin/bundle/cubins/sm89/scale.cubin +0 -0
  55. {tensoracle-0.5.1 → tensoracle-1.0.0}/examples/cubin_plugin/example_cubin_plugin/__init__.py +0 -0
  56. {tensoracle-0.5.1 → tensoracle-1.0.0}/examples/cubin_plugin/example_cubin_plugin/weights.safetensors +0 -0
  57. {tensoracle-0.5.1 → tensoracle-1.0.0}/examples/cubin_plugin/kernels.py +0 -0
  58. {tensoracle-0.5.1 → tensoracle-1.0.0}/examples/cubin_plugin/plugin.cpp +0 -0
  59. {tensoracle-0.5.1 → tensoracle-1.0.0}/examples/cubin_plugin/pyproject.toml +0 -0
  60. {tensoracle-0.5.1 → tensoracle-1.0.0}/src/tensoracle/__init__.py +0 -0
  61. {tensoracle-0.5.1 → tensoracle-1.0.0}/src/tensoracle/_build.py +0 -0
  62. {tensoracle-0.5.1 → tensoracle-1.0.0}/src/tensoracle/_cache.py +0 -0
  63. {tensoracle-0.5.1 → tensoracle-1.0.0}/src/tensoracle/_comparison.py +0 -0
  64. {tensoracle-0.5.1 → tensoracle-1.0.0}/src/tensoracle/_execution.py +0 -0
  65. {tensoracle-0.5.1 → tensoracle-1.0.0}/src/tensoracle/_memory.py +0 -0
  66. {tensoracle-0.5.1 → tensoracle-1.0.0}/src/tensoracle/_plugins.py +0 -0
  67. {tensoracle-0.5.1 → tensoracle-1.0.0}/src/tensoracle/convert.py +0 -0
  68. {tensoracle-0.5.1 → tensoracle-1.0.0}/src/tensoracle/producer.py +0 -0
  69. {tensoracle-0.5.1 → tensoracle-1.0.0}/tests/build_memory_runtime.py +0 -0
  70. {tensoracle-0.5.1 → tensoracle-1.0.0}/tests/cubin_io/kernels.cu +0 -0
  71. {tensoracle-0.5.1 → tensoracle-1.0.0}/tests/cubin_io/plugin.cpp +0 -0
  72. {tensoracle-0.5.1 → tensoracle-1.0.0}/tests/plugin_io_runtime.py +0 -0
  73. {tensoracle-0.5.1 → tensoracle-1.0.0}/tests/precision_runtime.py +0 -0
  74. {tensoracle-0.5.1 → tensoracle-1.0.0}/tests/test_build.py +0 -0
  75. {tensoracle-0.5.1 → tensoracle-1.0.0}/tests/test_build_memory.py +0 -0
  76. {tensoracle-0.5.1 → tensoracle-1.0.0}/tests/test_comparison.py +0 -0
  77. {tensoracle-0.5.1 → tensoracle-1.0.0}/tests/test_convert.py +0 -0
  78. {tensoracle-0.5.1 → tensoracle-1.0.0}/tests/test_engine_io.py +0 -0
  79. {tensoracle-0.5.1 → tensoracle-1.0.0}/tests/test_execution.py +0 -0
  80. {tensoracle-0.5.1 → tensoracle-1.0.0}/tests/test_gpu_cache.py +0 -0
  81. {tensoracle-0.5.1 → tensoracle-1.0.0}/tests/test_precision.py +0 -0
  82. {tensoracle-0.5.1 → tensoracle-1.0.0}/tests/test_producer.py +0 -0
  83. {tensoracle-0.5.1 → tensoracle-1.0.0}/tests/test_shape_tensor_outputs.py +0 -0
  84. {tensoracle-0.5.1 → tensoracle-1.0.0}/tests/test_weight_hash.py +0 -0
  85. {tensoracle-0.5.1 → tensoracle-1.0.0}/uv.lock +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: tensoracle
3
- Version: 0.5.1
3
+ Version: 1.0.0
4
4
  Summary: Build, save, reuse, and execute TensorRT engines from safetensors weights
5
5
  Project-URL: documentation, https://sync-dev-org.github.io/tensoracle/
6
6
  Project-URL: repository, https://github.com/sync-dev-org/tensoracle
@@ -12,6 +12,7 @@ Classifier: Development Status :: 4 - Beta
12
12
  Classifier: Environment :: GPU :: NVIDIA CUDA :: 13
13
13
  Classifier: Intended Audience :: Developers
14
14
  Classifier: License :: OSI Approved :: MIT License
15
+ Classifier: Operating System :: Microsoft :: Windows
15
16
  Classifier: Operating System :: POSIX :: Linux
16
17
  Classifier: Programming Language :: Python :: 3.12
17
18
  Classifier: Programming Language :: Python :: 3.13
@@ -57,10 +58,12 @@ Choose the path that matches your work:
57
58
  | TensorRT 11 SDK | Not needed | Not needed | Native plugin build |
58
59
  | CMake 3.20 or later and C++17 compiler | Not needed | Not needed | Native plugin build |
59
60
 
60
- The supported targets are Linux x86_64 (including WSL2), TensorRT 11, and GPU generations sm86, sm89, and sm120. The producer and native build tools are separate from the `tensoracle` runtime dependencies. Engine building, engine reuse, output comparison, and cubin production do not require torch. Converting `.pth` checkpoints requires the `convert` extra described below.
61
+ The supported targets are Linux x86_64 (including WSL2) and Windows x86_64, TensorRT 11, and GPU generations sm86, sm89, and sm120. The same `py3-none-any` wheel installs on both operating systems. Cubin production with `tensoracle[producer]` runs on Linux; cubins do not depend on the OS, so a plugin DLL built on Windows can embed cubins produced on Linux. The producer and native build tools are separate from the `tensoracle` runtime dependencies. Engine building, engine reuse, output comparison, and cubin production do not require torch. Converting `.pth` checkpoints requires the `convert` extra described below.
61
62
 
62
63
  Follow the [four-stage optimization workflow](https://github.com/sync-dev-org/tensoracle/blob/main/docs/optimization.md) to establish output quality, evaluate lower precision and plugins, and measure speed.
63
64
 
65
+ Follow [Build a C++ and Python repository](https://sync-dev-org.github.io/tensoracle/cpp-python-repositories/) for source layout, development environments, bindings, and Linux wheel packaging.
66
+
64
67
  ## Convert a PyTorch checkpoint
65
68
 
66
69
  Install the conversion extra in the environment where you prepare weights:
@@ -139,7 +142,7 @@ handle = open_engine(
139
142
  engine = handle.engine # Keep handle.runtime alive while using the engine.
140
143
  ```
141
144
 
142
- Saved files live in the `tensoracle` directory under `XDG_CACHE_HOME`, or under `~/.cache` when that variable is unset. The cache identity includes the contents of all declared safetensors weight files and optional `plugins` files, the engine name, graph version, input shapes, builder settings, GPU product name, OS, CPU architecture, and TensorRT version. Raise `graph_version` when graph code changes; without a version change, the previous engine is reused. Use a different `name` or `graph_version` for engines with different tensor types, such as fp32 and fp16. Include in `graph_version` any other caller value that changes the engine contents but is not part of the cache identity, such as a plugin manifest or a build recipe. Pass `force_rebuild=True` to replace a cached engine even when it is intact.
145
+ Saved files live in the `tensoracle` directory under `XDG_CACHE_HOME`, or under the home directory's `.cache` when that variable is unset. The same rule applies on every OS; on Windows the home directory is `%USERPROFILE%`, so the default is `%USERPROFILE%\.cache\tensoracle`. The cache identity includes the contents of all declared safetensors weight files and optional `plugins` files, the engine name, graph version, input shapes, builder settings, GPU product name, OS, CPU architecture, and TensorRT version. Raise `graph_version` when graph code changes; without a version change, the previous engine is reused. Use a different `name` or `graph_version` for engines with different tensor types, such as fp32 and fp16. Include in `graph_version` any other caller value that changes the engine contents but is not part of the cache identity, such as a plugin manifest or a build recipe. Pass `force_rebuild=True` to replace a cached engine even when it is intact. tensoracle closes a saved engine file after reading it, so another process using an opened engine does not block replacement. On Windows, a process that keeps the saved file itself open prevents replacement or removal with `PermissionError`; after that process closes the file, a file left empty by the failed rebuild is rejected as `CorruptEngineError` and can be rebuilt with `force_rebuild=True`.
143
146
 
144
147
  `plugins` names native TensorRT plugin libraries. Both `open_engine` and `build_serialized_engine` accept it. Each function checks that every library exports `getCreators`, loads it through TensorRT's registry, and retains it for the process before building the graph or deserializing an engine. Repeating the same library does not register it twice. `open_engine` also hashes the loaded library bytes into the engine identity; a changed library selects a different saved engine in a new process. A missing, unreadable, or incompatible library, or a library changed after loading in the same process, raises `PluginLibraryError` before a cached plan is opened. Keep the library and its cubin bundle together in the caller's wheel.
145
148
 
@@ -319,7 +322,17 @@ The example was also built with an older compiler and CUDA toolkit:
319
322
  | --- | --- | --- | --- |
320
323
  | gcc 13.3.0 / CMake 4.2.3 / CUDA toolkit 12.9.86 / TensorRT SDK 11.2.1.2 | `build` and a separate-process `reuse` with TensorRT runtime 11.2.1.2 on sm86 succeeded with zero outputs outside tolerance and both variants launched | 3.13.7 | WSL2 / glibc 2.39 |
321
324
 
322
- Each GPU subprocess had a 50-second limit. Speed was not measured. Native Linux, other kernels, and TensorRT 11 versions not listed here have not been tested.
325
+ Each GPU subprocess had a 50-second limit. Speed was not measured.
326
+
327
+ On 2026-10-18, the test suite and a native plugin build were run on Windows:
328
+
329
+ | GPU | Result | Python | OS / NVIDIA driver / build tools / TensorRT |
330
+ | --- | --- | --- | --- |
331
+ | NVIDIA RTX 6000 Ada Generation (sm89) | `pytest`: 246 passed, 20 skipped (Linux-only memory checks and optional `convert` and `producer` dependencies) | 3.12.11 | Windows 11 Pro x64 build 26200 / 596.72 / Visual Studio 2022 (MSVC 19.44), CMake 3.31.6, Ninja, CUDA toolkit 12.8.93 / runtime and SDK 11.4.0.106 |
332
+
333
+ On Windows, the standalone `cpp/` build and CTest passed, the CMake helper built the example plugin DLL against `nvinfer_11.lib`, and the plugin engine was built and reused in a separate process. The `py3-none-any` wheel built on Linux was installed unchanged on Windows. With `PATH` reduced to the Windows system directories and no CUDA or TensorRT SDK paths, the driver's `nvcuda.dll` and the pip-installed TensorRT runtime were sufficient to build and reuse engines.
334
+
335
+ Native Linux, other kernels, Windows with sm86 or sm120, and TensorRT 11 versions not listed here have not been tested.
323
336
 
324
337
  ## Compare output arrays
325
338
 
@@ -27,10 +27,12 @@ Choose the path that matches your work:
27
27
  | TensorRT 11 SDK | Not needed | Not needed | Native plugin build |
28
28
  | CMake 3.20 or later and C++17 compiler | Not needed | Not needed | Native plugin build |
29
29
 
30
- The supported targets are Linux x86_64 (including WSL2), TensorRT 11, and GPU generations sm86, sm89, and sm120. The producer and native build tools are separate from the `tensoracle` runtime dependencies. Engine building, engine reuse, output comparison, and cubin production do not require torch. Converting `.pth` checkpoints requires the `convert` extra described below.
30
+ The supported targets are Linux x86_64 (including WSL2) and Windows x86_64, TensorRT 11, and GPU generations sm86, sm89, and sm120. The same `py3-none-any` wheel installs on both operating systems. Cubin production with `tensoracle[producer]` runs on Linux; cubins do not depend on the OS, so a plugin DLL built on Windows can embed cubins produced on Linux. The producer and native build tools are separate from the `tensoracle` runtime dependencies. Engine building, engine reuse, output comparison, and cubin production do not require torch. Converting `.pth` checkpoints requires the `convert` extra described below.
31
31
 
32
32
  Follow the [four-stage optimization workflow](https://github.com/sync-dev-org/tensoracle/blob/main/docs/optimization.md) to establish output quality, evaluate lower precision and plugins, and measure speed.
33
33
 
34
+ Follow [Build a C++ and Python repository](https://sync-dev-org.github.io/tensoracle/cpp-python-repositories/) for source layout, development environments, bindings, and Linux wheel packaging.
35
+
34
36
  ## Convert a PyTorch checkpoint
35
37
 
36
38
  Install the conversion extra in the environment where you prepare weights:
@@ -109,7 +111,7 @@ handle = open_engine(
109
111
  engine = handle.engine # Keep handle.runtime alive while using the engine.
110
112
  ```
111
113
 
112
- Saved files live in the `tensoracle` directory under `XDG_CACHE_HOME`, or under `~/.cache` when that variable is unset. The cache identity includes the contents of all declared safetensors weight files and optional `plugins` files, the engine name, graph version, input shapes, builder settings, GPU product name, OS, CPU architecture, and TensorRT version. Raise `graph_version` when graph code changes; without a version change, the previous engine is reused. Use a different `name` or `graph_version` for engines with different tensor types, such as fp32 and fp16. Include in `graph_version` any other caller value that changes the engine contents but is not part of the cache identity, such as a plugin manifest or a build recipe. Pass `force_rebuild=True` to replace a cached engine even when it is intact.
114
+ Saved files live in the `tensoracle` directory under `XDG_CACHE_HOME`, or under the home directory's `.cache` when that variable is unset. The same rule applies on every OS; on Windows the home directory is `%USERPROFILE%`, so the default is `%USERPROFILE%\.cache\tensoracle`. The cache identity includes the contents of all declared safetensors weight files and optional `plugins` files, the engine name, graph version, input shapes, builder settings, GPU product name, OS, CPU architecture, and TensorRT version. Raise `graph_version` when graph code changes; without a version change, the previous engine is reused. Use a different `name` or `graph_version` for engines with different tensor types, such as fp32 and fp16. Include in `graph_version` any other caller value that changes the engine contents but is not part of the cache identity, such as a plugin manifest or a build recipe. Pass `force_rebuild=True` to replace a cached engine even when it is intact. tensoracle closes a saved engine file after reading it, so another process using an opened engine does not block replacement. On Windows, a process that keeps the saved file itself open prevents replacement or removal with `PermissionError`; after that process closes the file, a file left empty by the failed rebuild is rejected as `CorruptEngineError` and can be rebuilt with `force_rebuild=True`.
113
115
 
114
116
  `plugins` names native TensorRT plugin libraries. Both `open_engine` and `build_serialized_engine` accept it. Each function checks that every library exports `getCreators`, loads it through TensorRT's registry, and retains it for the process before building the graph or deserializing an engine. Repeating the same library does not register it twice. `open_engine` also hashes the loaded library bytes into the engine identity; a changed library selects a different saved engine in a new process. A missing, unreadable, or incompatible library, or a library changed after loading in the same process, raises `PluginLibraryError` before a cached plan is opened. Keep the library and its cubin bundle together in the caller's wheel.
115
117
 
@@ -289,7 +291,17 @@ The example was also built with an older compiler and CUDA toolkit:
289
291
  | --- | --- | --- | --- |
290
292
  | gcc 13.3.0 / CMake 4.2.3 / CUDA toolkit 12.9.86 / TensorRT SDK 11.2.1.2 | `build` and a separate-process `reuse` with TensorRT runtime 11.2.1.2 on sm86 succeeded with zero outputs outside tolerance and both variants launched | 3.13.7 | WSL2 / glibc 2.39 |
291
293
 
292
- Each GPU subprocess had a 50-second limit. Speed was not measured. Native Linux, other kernels, and TensorRT 11 versions not listed here have not been tested.
294
+ Each GPU subprocess had a 50-second limit. Speed was not measured.
295
+
296
+ On 2026-10-18, the test suite and a native plugin build were run on Windows:
297
+
298
+ | GPU | Result | Python | OS / NVIDIA driver / build tools / TensorRT |
299
+ | --- | --- | --- | --- |
300
+ | NVIDIA RTX 6000 Ada Generation (sm89) | `pytest`: 246 passed, 20 skipped (Linux-only memory checks and optional `convert` and `producer` dependencies) | 3.12.11 | Windows 11 Pro x64 build 26200 / 596.72 / Visual Studio 2022 (MSVC 19.44), CMake 3.31.6, Ninja, CUDA toolkit 12.8.93 / runtime and SDK 11.4.0.106 |
301
+
302
+ On Windows, the standalone `cpp/` build and CTest passed, the CMake helper built the example plugin DLL against `nvinfer_11.lib`, and the plugin engine was built and reused in a separate process. The `py3-none-any` wheel built on Linux was installed unchanged on Windows. With `PATH` reduced to the Windows system directories and no CUDA or TensorRT SDK paths, the driver's `nvcuda.dll` and the pip-installed TensorRT runtime were sufficient to build and reuse engines.
303
+
304
+ Native Linux, other kernels, Windows with sm86 or sm120, and TensorRT 11 versions not listed here have not been tested.
293
305
 
294
306
  ## Compare output arrays
295
307
 
@@ -10,7 +10,11 @@ function(tensoracle_add_cubin_plugin)
10
10
  find_package(CUDAToolkit REQUIRED)
11
11
  find_path(TENSORACLE_NVINFER_INCLUDE NvInfer.h
12
12
  PATHS "${ARG_TENSORRT_ROOT}/include" NO_DEFAULT_PATH REQUIRED)
13
- find_library(TENSORACLE_NVINFER_LIBRARY NAMES nvinfer
13
+ set(_tensoracle_nvinfer_names nvinfer)
14
+ if(WIN32)
15
+ list(PREPEND _tensoracle_nvinfer_names nvinfer_11)
16
+ endif()
17
+ find_library(TENSORACLE_NVINFER_LIBRARY NAMES ${_tensoracle_nvinfer_names}
14
18
  PATHS "${ARG_TENSORRT_ROOT}/lib" "${ARG_TENSORRT_ROOT}/lib64"
15
19
  NO_DEFAULT_PATH REQUIRED)
16
20
 
@@ -0,0 +1,199 @@
1
+ # Build a C++ and Python repository
2
+
3
+ Use this guide to organize a repository with a standalone C++ library and a Python package, then build and inspect its Linux wheels. Keep the C++ build independent of Python, put the Python project in its own directory, and make the package build collect the files it needs from those sources. The binding and wheel examples below illustrate a package named `example`; adapt the target names and dependencies to your project.
4
+
5
+ ## 1. Separate the language projects
6
+
7
+ Keep `cpp/` and `python/` at the repository root:
8
+
9
+ ```text
10
+ README.md
11
+ LICENSE
12
+ docs/
13
+ cpp/
14
+ CMakeLists.txt
15
+ include/
16
+ src/
17
+ tests/
18
+ bindings.cpp # Optional Python binding source
19
+ python/
20
+ pyproject.toml
21
+ uv.lock
22
+ CMakeLists.txt # Only when the Python build compiles an extension
23
+ src/
24
+ example/
25
+ __init__.py
26
+ tests/
27
+ ```
28
+
29
+ `cpp/` owns the C++ sources, headers, CMake targets, and CTest tests. Its standalone configuration builds and tests the C++ library without discovering Python or nanobind. The Python build can compile `bindings.cpp` separately and link it to that library.
30
+
31
+ `python/` is the Python project root. It owns package metadata, runtime dependencies, development dependencies, the lockfile, and the src-layout package. Run the project's uv commands there. Keep repository-wide documentation, the license, and examples at the repository root; keep `pyproject.toml`, Python tests, and the Python environment under `python/`.
32
+
33
+ Keep one editable copy of each source file. Configure the package build to collect C++ sources or compiled libraries into the package as appropriate. A build that uses sibling `cpp/` files must also make those files available when building from a source distribution: stage a complete source tree or arrange an equivalent archive layout, then verify a build from the extracted archive.
34
+
35
+ Tensoracle is an example of source packaging: its wheel includes the shared C++ headers, sources, and CMake helpers under `tensoracle/cpp/`, and the caller compiles its own plugin. Tensoracle's wheel contains no native binaries and uses `py3-none-any`. A repository that builds a Python extension needs the additional steps in sections 4–6.
36
+
37
+ ## 2. Keep development tools in the appropriate environment
38
+
39
+ Create the Python environment at `python/.venv`, alongside `python/pyproject.toml` and `python/uv.lock`; keep the repository root free of a second `.venv`. uv uses a project-local [virtual environment](https://docs.astral.sh/uv/concepts/projects/layout/#the-project-environment). For this layout, start from the repository root and run:
40
+
41
+ ```bash
42
+ cd python
43
+ uv sync
44
+ ```
45
+
46
+ Declare Python development tools such as pytest, Ruff, and a type checker in the Python project's development dependency group. Keep runtime dependencies in the `[project]` table's `dependencies` field, optional runtime features in extras, and isolated build requirements in the `[build-system]` table's `requires` field.
47
+
48
+ Keep one CMake and one Ninja installation on the host's `PATH`, shared by standalone C++ builds and tests that invoke CMake. Do not add `cmake` or `ninja` to each project's Python development dependency group. Their installation method can follow the developer's platform and package manager.
49
+
50
+ Each CMake entry point declares its minimum supported version with [`cmake_minimum_required`](https://cmake.org/cmake/help/latest/command/cmake_minimum_required.html). The host installation must meet all projects' minimums. Tensoracle's standalone C++ project requires CMake 3.20; the binding example below uses CMake 3.26 for `Development.SABIModule`. Verify affected C++ builds before upgrading a shared host installation.
51
+
52
+ An isolated wheel build has separate requirements. Keep any CMake requirement it needs in `[build-system] requires`; that environment does not replace the host tools. [scikit-build-core](https://scikit-build-core.readthedocs.io/en/stable/configuration/index.html#cmake-and-ninja-minimum-versions) can obtain CMake or Ninja when the available versions do not satisfy its configuration.
53
+
54
+ ## 3. Test each language and identify GPU tests
55
+
56
+ Run pytest from `python/` so that the Python project's configuration and environment apply:
57
+
58
+ ```bash
59
+ uv run pytest
60
+ uv run pytest -m "not gpu"
61
+ ```
62
+
63
+ Register a `gpu` marker in the pytest configuration and apply `@pytest.mark.gpu` to tests that need a GPU. Use strict marker checking to catch misspelled markers. The second command selects tests that can run without a GPU; those tests must also avoid GPU initialization during collection. See [pytest's marker documentation](https://docs.pytest.org/en/stable/how-to/mark.html).
64
+
65
+ Register the standalone C++ tests with CTest, using `include(CTest)` and `add_test`. From the repository root, configure and run them without activating the Python environment:
66
+
67
+ ```bash
68
+ cmake -S cpp -B build/cpp -G Ninja -DBUILD_TESTING=ON
69
+ cmake --build build/cpp
70
+ ctest --test-dir build/cpp --output-on-failure
71
+ ctest --test-dir build/cpp --output-on-failure -LE gpu
72
+ ```
73
+
74
+ Supply any required SDK or toolchain paths at configuration time. Python independence does not remove C++ library, header, or CUDA toolkit prerequisites. For TensorRT plugins, follow [Prepare a TensorRT SDK](tensorrt-sdk.md).
75
+
76
+ Give GPU-dependent CTest tests a [`gpu` label](https://cmake.org/cmake/help/latest/prop_test/LABELS.html); the final command excludes that label. A machine without a CUDA toolkit may also need a configuration that omits GPU targets. Test C++ library behavior through CTest and Python imports, bindings, and integration through pytest. Before distributing a wheel, install it into a clean environment and test the installed package outside the source tree.
77
+
78
+ ## 4. Install nanobind extensions inside the package
79
+
80
+ Keep the standalone library's CMake configuration independent of the Python bindings. The Python project's CMake configuration discovers Python and nanobind, adds the C++ library, and installs the extension into the Python package. For a C++ target named `example_core`, these fragments illustrate that arrangement.
81
+
82
+ In `python/pyproject.toml`, alongside the project's metadata:
83
+
84
+ ```toml
85
+ [build-system]
86
+ requires = ["scikit-build-core", "nanobind"]
87
+ build-backend = "scikit_build_core.build"
88
+
89
+ [tool.scikit-build]
90
+ wheel.packages = ["src/example"]
91
+ wheel.py-api = "cp312"
92
+ ```
93
+
94
+ In `python/CMakeLists.txt`:
95
+
96
+ ```cmake
97
+ cmake_minimum_required(VERSION 3.26)
98
+ project(example_python LANGUAGES CXX)
99
+
100
+ find_package(Python 3.12 REQUIRED COMPONENTS
101
+ Interpreter Development.Module Development.SABIModule)
102
+ find_package(nanobind CONFIG REQUIRED)
103
+
104
+ add_subdirectory(../cpp cpp)
105
+ set_target_properties(example_core PROPERTIES POSITION_INDEPENDENT_CODE ON)
106
+ nanobind_add_module(_native STABLE_ABI ../cpp/bindings.cpp)
107
+ target_link_libraries(_native PRIVATE example_core)
108
+ install(TARGETS _native LIBRARY DESTINATION example)
109
+ ```
110
+
111
+ The binding source declares `NB_MODULE(_native, m)`, and `python/src/example/__init__.py` imports from `._native`. The installed wheel contains `example/__init__.py` and the extension, such as `example/_native.abi3.so`. The snippets assume that `cpp/CMakeLists.txt` defines `example_core` and that the package build supplies the sibling C++ sources as described in section 1. See [nanobind packaging](https://nanobind.readthedocs.io/en/latest/packaging.html) for the binding build and installation mechanism.
112
+
113
+ For nanobind's linked build mode, [`STABLE_ABI`](https://nanobind.readthedocs.io/en/latest/api_cmake.html#command:nanobind_add_module) requires Python 3.12 or later. Pair it with `wheel.py-api = "cp312"` so that the binary and wheel metadata agree. This produces a CPython stable-ABI extension for compatible GIL-enabled Python versions from that floor, subject to the package's `requires-python`. It does not remove platform, C++ ABI, or runtime library constraints. Free-threaded Python needs its own build and compatibility decisions.
114
+
115
+ Read the three parts of the [wheel compatibility tag](https://packaging.python.org/en/latest/specifications/platform-compatibility-tags/) separately:
116
+
117
+ | Wheel contents | Example Python–ABI–platform tag |
118
+ | --- | --- |
119
+ | Python and source files, without native binaries | `py3-none-any` |
120
+ | Native libraries that do not use the Python C API | `py3-none-manylinux_2_28_x86_64` |
121
+ | A CPython stable-ABI extension with a Python 3.12 floor | `cp312-abi3-manylinux_2_28_x86_64` |
122
+ | A CPython 3.12 extension using its version-specific ABI | `cp312-cp312-manylinux_2_28_x86_64` |
123
+
124
+ These are illustrative targets, not tags to assign before inspecting the binaries. `none` describes the Python ABI; a wheel carrying a shared library still needs a platform tag. `abi3` retains a minimum Python version and does not mean every Python implementation or build is supported.
125
+
126
+ ## 5. Check manylinux compatibility before uploading to PyPI
127
+
128
+ For glibc-based Linux x86_64 wheels, use a supported manylinux platform tag. PyPI's [platform validation](https://github.com/pypi/warehouse/blob/main/warehouse/utils/wheel.py) rejects the generic `linux_x86_64` tag. Under [PEP 600](https://peps.python.org/pep-0600/), `manylinux_2_28_x86_64` promises compatibility with mainstream x86_64 Linux systems using glibc 2.28 or later. It does not describe CUDA or GPU driver requirements; document those separately.
129
+
130
+ The actual minimum follows the symbols and libraries used by the built artifacts. Linking on a newer system can introduce newer glibc requirements even when the source code has not changed. The host's glibc version alone is not a measurement of the wheel's minimum, and changing the filename cannot lower that minimum. Inspect required `GLIBC_*` versions, along with `GLIBCXX_*` and `CXXABI_*` requirements for the C++ runtime.
131
+
132
+ Run [`auditwheel show`](https://github.com/pypa/auditwheel) in the build container. Extract the wheel and inspect its ELF files with [`readelf`](https://sourceware.org/binutils/docs/binutils/readelf.html). For example, after setting `WHEEL` to the exact wheel path and choosing a new extraction directory:
133
+
134
+ ```bash
135
+ auditwheel show "$WHEEL"
136
+ python -m zipfile -e "$WHEEL" wheel-inspect
137
+ LC_ALL=C readelf --version-info --wide wheel-inspect/example/_native.abi3.so
138
+ LC_ALL=C readelf --dynamic --wide wheel-inspect/example/_native.abi3.so
139
+ ```
140
+
141
+ Repeat the ELF checks for every shared library and executable in the wheel, including nested dependencies. Inspect the version requirements and `NEEDED`, `RPATH`, and `RUNPATH` entries. Use `LC_ALL=C` when tools or scripts rely on English output headings, and compare numeric version components rather than sorting version strings lexically. Rebuild in an appropriate environment if a required symbol exceeds the intended baseline; auditwheel cannot repair an overly new glibc or libstdc++ dependency.
142
+
143
+ ### Shared libraries and search paths
144
+
145
+ Assign each shipped shared library to one package. If another wheel supplies a library, declare that package as a runtime dependency and arrange a documented runtime lookup path. Do not copy its library into the consuming wheel. RAPIDS publishes separate [Python binding](https://pypi.org/project/pylibcudf-cu12/) and [C++ library](https://pypi.org/project/libcudf-cu12/) distributions as `pylibcudf-cu12` and `libcudf-cu12`; their release files illustrate the distinction between Python ABI tags and platform tags.
146
+
147
+ `auditwheel repair` normally copies non-policy shared libraries into the wheel and changes their search paths. Review that list before repair, and exclude libraries owned by dependency wheels and libraries provided by the GPU driver. An exclusion does not establish manylinux compliance. Resolve and test those dependencies separately, and inspect the final wheel again. Also test libraries loaded through `dlopen` or `ctypes`, which auditwheel cannot discover from `NEEDED` entries alone.
148
+
149
+ Use `$ORIGIN`-relative ELF search paths, where `$ORIGIN` is the directory containing the referencing binary. For an extension whose own package contains a `lib/` subdirectory, a CMake target can use:
150
+
151
+ ```cmake
152
+ set_target_properties(_native PROPERTIES
153
+ BUILD_RPATH_USE_ORIGIN ON
154
+ INSTALL_RPATH "$ORIGIN/lib")
155
+ ```
156
+
157
+ [`INSTALL_RPATH`](https://cmake.org/cmake/help/latest/prop_tgt/INSTALL_RPATH.html) controls the installed artifact; `BUILD_RPATH_USE_ORIGIN` applies to build-tree paths. Select the relative path for the actual installed layout, including dependency packages where needed, and check every library's own dependencies. Remove absolute build-machine paths, including paths introduced by imported CMake targets. Keep `$ORIGIN` literal when passing a value through a shell.
158
+
159
+ Keep NVIDIA driver libraries such as `libcuda.so.1`, `libnvidia-encode.so.1`, and `libnvcuvid.so.1` outside the wheel. The target system supplies the compatible driver. Link-time SDK stubs must also stay out of the runtime package and its search paths; NVIDIA's [Video Codec SDK instructions](https://docs.nvidia.com/video-technologies/video-codec-sdk/13.0/read-me/index.html) distinguish these stubs from the installed driver. Treat CUDA runtime libraries separately, using an appropriate static runtime or declared runtime package dependencies for the chosen toolkit.
160
+
161
+ Check artifact size before upload. PyPI's [default individual file limit](https://docs.pypi.org/project-management/storage-limits/) is 100 MB; projects can have an approved increase. Installing and testing the final wheel with only its declared dependencies is still necessary after tag and ELF inspection.
162
+
163
+ ## 6. Record the wheel build environment
164
+
165
+ Build release wheels in a [manylinux container](https://github.com/pypa/manylinux) for the intended architecture and compatibility floor. For example, `quay.io/pypa/manylinux_2_28_x86_64` provides a glibc 2.28 baseline. Select compiler, SDK, CUDA toolkit, and dependency versions that can build and run against that baseline. A recent compiler does not require building against a recent host glibc.
166
+
167
+ Pin the image by an immutable [image digest](https://docs.docker.com/reference/cli/docker/image/pull/#pull-an-image-by-digest-immutable-identifier), using `image@sha256:<digest>` with the actual digest of the selected image. A moving tag is useful for discovering updates but does not identify a repeatable build input. Pin any derived image as well, and record additional package installation inputs.
168
+
169
+ Keep a build record with:
170
+
171
+ - The source revision, patches, and source manifest.
172
+ - The image reference, manifest digest, image configuration digest, and architecture.
173
+ - The compiler, linker, CMake, Ninja, Python interpreter, and build backend versions.
174
+ - The CUDA toolkit and SDK versions, when used, and relevant compiler or CMake options.
175
+ - The resolved build and runtime dependencies, resulting wheel hashes, ELF inspection results, and test results.
176
+
177
+ Build from clean inputs inside that container, inspect the final artifacts there, and test their installation in a separate runtime environment. When native C++ objects cross extension boundaries, align the C++ library ABI, compiler compatibility, debug mode, symbol visibility, and nanobind ABI. Python's stable ABI does not make incompatible C++ objects interchangeable. [nanobind's compatibility requirements](https://nanobind.readthedocs.io/en/latest/faq.html#how-can-i-avoid-conflicts-with-other-projects-using-nanobind) describe those constraints.
178
+
179
+ ## 7. Record and reconstruct upstream C++ sources
180
+
181
+ When development needs a local copy of an upstream C++ project, copy the selected files into a dedicated directory and keep the source inputs explicit. Record the upstream URL and immutable revision, the selected paths, the ordered local patches, and the license information. Keep a SHA-256 manifest covering every file in the resulting source tree, including files added by patches.
182
+
183
+ For example, a provenance directory can contain:
184
+
185
+ ```text
186
+ upstream/library/
187
+ PROVENANCE.md
188
+ patches/
189
+ MANIFEST.sha256
190
+ fetch-and-verify.py
191
+ ```
192
+
193
+ `PROVENANCE.md` identifies the upstream revision and explains the selection and patch order. `MANIFEST.sha256` records the expected relative paths and hashes after patching. The acquisition script reads these recorded inputs, retrieves the exact revision, selects the required files, applies the patches, and verifies the resulting tree. Keep the revision in one authoritative location that the script reads.
194
+
195
+ Use ordinary copied files for the development tree, rather than a Git submodule. A submodule records a commit reference instead of ordinary source files, so a publication process that copies tracked files into a snapshot does not materialize that source tree. An explicit acquisition script also makes the build independent of recursive Git checkout behavior.
196
+
197
+ Keep the copied upstream source tree out of the public repository. Publish the revision record, patches, complete file manifest, acquisition and verification script, and instructions for building and testing from the reconstructed sources. Preserve required license notices in the appropriate distributed artifacts. The public checkout must let another developer reconstruct the inputs and build the native components without access to the development copy.
198
+
199
+ Verify both file contents and the complete set of paths: missing, changed, and unexpected files must fail verification. A checksum command that only checks listed files will not detect extra files by itself. Verify before configuring or compiling, and stop on a download, patch, or manifest failure. When updating upstream, regenerate the manifest from the reviewed source selection and rerun the native build and tests. If publishing a source distribution, ensure its documented acquisition process makes the same verified inputs available for its build.
@@ -4,6 +4,8 @@
4
4
 
5
5
  Follow the [four-stage optimization workflow](optimization.md) to establish output quality, evaluate lower precision and plugins, and measure speed.
6
6
 
7
+ Follow [Build a C++ and Python repository](cpp-python-repositories.md) for source layout, development environments, bindings, and Linux wheel packaging.
8
+
7
9
  ## Terms
8
10
 
9
11
  - A **TensorRT engine** is an executable form of a model optimized for a GPU, precision, and TensorRT version. It can be kept in memory or saved to disk.
@@ -29,7 +31,7 @@ Follow the [four-stage optimization workflow](optimization.md) to establish outp
29
31
  | TensorRT 11 SDK | Not needed | Not needed | Native plugin build |
30
32
  | CMake 3.20 or later and C++17 compiler | Not needed | Not needed | Native plugin build |
31
33
 
32
- The supported platform is Linux x86_64 (including WSL2) with sm86, sm89, or sm120 GPUs and TensorRT 11. The producer and native build tools are separate from the `tensoracle` runtime dependencies. Engine building, engine reuse, output comparison, and cubin production do not require torch. Converting `.pth` checkpoints requires the `convert` extra.
34
+ The supported platforms are Linux x86_64 (including WSL2) and Windows x86_64 with sm86, sm89, or sm120 GPUs and TensorRT 11. The same `py3-none-any` wheel installs on both operating systems. Cubin production with `tensoracle[producer]` runs on Linux; a plugin DLL built on Windows can embed cubins produced on Linux. The producer and native build tools are separate from the `tensoracle` runtime dependencies. Engine building, engine reuse, output comparison, and cubin production do not require torch. Converting `.pth` checkpoints requires the `convert` extra.
33
35
 
34
36
  ### Convert a PyTorch checkpoint
35
37
 
@@ -70,7 +72,7 @@ handle = open_engine(
70
72
  )
71
73
  ```
72
74
 
73
- `my_model` represents the application's model package. On a valid cache hit, `open_engine` does not call `graph`; on a miss, it builds and saves a new engine. Raise `graph_version` when the graph code changes or when any other caller value that changes the engine contents but is not part of the cache identity changes, such as a plugin manifest or a build recipe. `open_engine` itself does not execute the engine or manage GPU buffers. Create an execution unit from its returned handle to enqueue inference. Saved engines live under `XDG_CACHE_HOME/tensoracle`, or `~/.cache/tensoracle` when `XDG_CACHE_HOME` is unset. See the [complete cache example](https://github.com/sync-dev-org/tensoracle#save-and-reopen-an-engine) for the declaration and expected input and output types.
75
+ `my_model` represents the application's model package. On a valid cache hit, `open_engine` does not call `graph`; on a miss, it builds and saves a new engine. Raise `graph_version` when the graph code changes or when any other caller value that changes the engine contents but is not part of the cache identity changes, such as a plugin manifest or a build recipe. `open_engine` itself does not execute the engine or manage GPU buffers. Create an execution unit from its returned handle to enqueue inference. Saved engines live under `XDG_CACHE_HOME/tensoracle`, or `~/.cache/tensoracle` when `XDG_CACHE_HOME` is unset. On Windows, `~` is `%USERPROFILE%`. See the [complete cache example](https://github.com/sync-dev-org/tensoracle#save-and-reopen-an-engine) for the declaration and expected input and output types.
74
76
 
75
77
  ### Execute an engine
76
78
 
@@ -123,7 +123,7 @@ reference_handle = open_linear("fp32")
123
123
  candidate_handle = open_linear("bf16") # Or "int8"; "fp8" on sm89/sm120.
124
124
  ```
125
125
 
126
- TF32 remains disabled by tensoracle, including for the fp32 reference. Engines are saved under `XDG_CACHE_HOME/tensoracle`, or `~/.cache/tensoracle`. Repeat the same call with unchanged build conditions in another process to reuse the plan without invoking the graph function. Keep the weight file and the engine names/versions stable across the restart. Follow [Execute an engine](index.md#execute-an-engine) to allocate fp32 input/output buffers and enqueue each handle with the same inputs.
126
+ TF32 remains disabled by tensoracle, including for the fp32 reference. Engines are saved under `XDG_CACHE_HOME/tensoracle`, or `~/.cache/tensoracle` (`%USERPROFILE%\.cache\tensoracle` on Windows). Repeat the same call with unchanged build conditions in another process to reuse the plan without invoking the graph function. Keep the weight file and the engine names/versions stable across the restart. Follow [Execute an engine](index.md#execute-an-engine) to allocate fp32 input/output buffers and enqueue each handle with the same inputs.
127
127
 
128
128
  ## Compare outputs and choose limits
129
129
 
@@ -1,6 +1,6 @@
1
1
  # Prepare a TensorRT SDK
2
2
 
3
- Use this procedure to prepare the headers and `libnvinfer` needed to build a native cubin plugin on Linux x86_64, including WSL2. The SDK root contains 13 headers in `include/`, `lib/libnvinfer.so.11`, and a relative `lib/libnvinfer.so` symlink pointing to `libnvinfer.so.11`. The CUDA toolkit, CMake, and a C++17 compiler are separate build prerequisites. Normal engine reuse does not need this SDK root.
3
+ Use the Linux procedure below to prepare the headers and `libnvinfer` needed to build a native cubin plugin on Linux x86_64, including WSL2. For Windows x86_64, use the [Windows procedure](#windows-x86_64). The Linux SDK root contains 13 headers in `include/`, `lib/libnvinfer.so.11`, and a relative `lib/libnvinfer.so` symlink pointing to `libnvinfer.so.11`. The CUDA toolkit, CMake, and a C++17 compiler are separate build prerequisites. Normal engine reuse does not need this SDK root.
4
4
 
5
5
  The inputs below are fixed for SDK **11.2.1.2**: headers from a release commit of [NVIDIA TensorRT OSS](https://github.com/NVIDIA/TensorRT), and the exact `tensorrt-cu13-libs` wheel from [NVIDIA's package index](https://pypi.nvidia.com/tensorrt-cu13-libs/). The wheel platform is `manylinux_2_28_x86_64`; use that file rather than an aarch64 or Windows wheel.
6
6
 
@@ -110,3 +110,90 @@ The tests also need the CUDA toolkit; tests marked `gpu` require an NVIDIA GPU a
110
110
  ## Use another TensorRT 11 release
111
111
 
112
112
  Use the same acquisition and verification steps for another TensorRT 11 release, but first establish its release commit, exact wheel filename and platform, expected wheel and library digests, and expected digests of every required header. Check that release's exact `NV_TENSORRT_MAJOR`, `MINOR`, `PATCH`, and `BUILD` values and library SONAME. The caller must verify and record those inputs; the 11.2.1.2 values above apply only to that SDK and cannot verify another release. Build and test the caller's plugin with the selected SDK and runtime.
113
+
114
+ ## Windows x86_64
115
+
116
+ Use NVIDIA's official Windows ZIP to obtain both the headers and the MSVC import library. The TensorRT runtime wheel supplies DLLs, but it does not replace the SDK's `include/` directory and `lib/nvinfer_11.lib`. See NVIDIA's [Windows ZIP installation guide](https://docs.nvidia.com/deeplearning/tensorrt/latest/installing-tensorrt/install-zip.html) and [TensorRT 11 downloads](https://developer.nvidia.com/tensorrt/download/11x).
117
+
118
+ The following inputs are fixed for **11.4.0.106**, Windows amd64, CUDA 13.4. Use Visual Studio 2022 with MSVC, CMake, Ninja, and a CUDA toolkit available in an **x64 Native Tools Command Prompt for VS 2022**, then start PowerShell from that prompt. The example below selects CUDA toolkit 12.8 as a build input; tensoracle's Python runtime dependencies select the CUDA 13 TensorRT runtime separately. Do not combine Windows import libraries with Linux shared libraries.
119
+
120
+ Choose a new workspace. The command creating it must fail if the directory already exists. Download the fixed ZIP, record its digest, and extract it without installing software system-wide:
121
+
122
+ ```powershell
123
+ $ErrorActionPreference = 'Stop'
124
+ $SdkWork = Join-Path $env:USERPROFILE '.cache/tensoracle-sdk-11.4.0.106-windows'
125
+ New-Item -ItemType Directory -Path $SdkWork | Out-Null
126
+ Set-Location $SdkWork
127
+ $ZipName = 'TensorRT-Enterprise-11.4.0.106-Windows-amd64-cuda-13.4-Release-external.zip'
128
+ $Url = 'https://developer.download.nvidia.com/compute/machine-learning/tensorrt/11.4.0/zip/' + $ZipName
129
+ Invoke-WebRequest -Uri $Url -OutFile $ZipName
130
+ Get-FileHash -Algorithm SHA256 $ZipName | Format-List | Out-File archive-sha256.txt
131
+ Expand-Archive -LiteralPath $ZipName -DestinationPath extracted
132
+ $env:TENSORRT_ROOT = Join-Path $SdkWork 'extracted/TensorRT-11.4.0.106'
133
+ ```
134
+
135
+ Verify the extracted build inputs against these SHA-256 values. These values identify the SDK members needed by the build, including the nested Python plugin header; they are not a digest of the whole ZIP. Stop on a mismatch rather than using an incomplete or mixed SDK:
136
+
137
+ ```powershell
138
+ $Expected = @'
139
+ 64a59d5bfdb1dd0b7a6a98992d3b617d926b760a6134c09a8bec0e62227ff5ff lib/nvinfer_11.lib
140
+ 886f693c1d958651eeee58ed4d02c0f31da355c112102539d6bd4d567f56a3a4 include/NvOnnxConfig.h
141
+ 81fb4be15a2432bf45c858176e347e017a8f5d9a20d82225141cd263a5114c32 include/NvInfer.h
142
+ 870a47268d1d5e08dcb72b14157292a16ba541cc9d95327a860977aba11c759a include/NvInferPluginBase.h
143
+ e5558eb96fc2b08a964f73ca096213a2bab9f356a897122f2c0c56a2a6553315 include/NvInferImpl.h
144
+ 7629d76e5a6bc1ee910ab90c117cdfa1f350349321e211cc9003dbad3f03b5ef include/NvInferRuntimePlugin.h
145
+ 7141cc8fc7d0274ba76c085a395b2be195b68d2ef205a381ddd41f8d0b323299 include/NvInferRuntime.h
146
+ e8c04d3cd04fd3e6abdb95a3398d2bee5c171f86eb772b3b8f30f66d21006e9a include/NvInferRuntimeBase.h
147
+ 8b155e73287ca63e276fc55297ae5b8723888d925afbf63a392e908faede8e02 include/NvInferPluginUtils.h
148
+ c28e2c4cbd8f1f0ed7ea6a4fe002906b92916abd3b778e71344649e522509b39 include/NvInferVersion.h
149
+ 6c30ffcd9c688bd286362aae3e00c0369961b78e7b0bffd08cae739f5d780ca1 include/NvInferRuntimeCommon.h
150
+ 3ab7107afc15e4317a17a57b31d7d42d677091380918bfc2dc45eb4ab38570ad include/NvInferPlugin.h
151
+ 440c0ea9cdfc8940d598daff766bc6db098b83d4250f7404c0930dd013ecd0eb include/NvOnnxParser.h
152
+ 99a80d98a7cdcac515d64a5f48dafe2a6d4f920c4513ec3f2b07bacf7c4ab09f include/NvInferLegacyDims.h
153
+ 2ee14ba7c2cf595af1d8f3ad33bc340fbadaa03a8e1bcea1bbfbe18235d965e7 include/impl/NvInferPythonPlugin.h
154
+ '@
155
+ $Expected -split "`n" | ForEach-Object {
156
+ $Digest, $Relative = $_.Trim() -split ' ', 2
157
+ $File = Join-Path $env:TENSORRT_ROOT $Relative
158
+ if ((Get-FileHash -Algorithm SHA256 -LiteralPath $File).Hash -ne $Digest) {
159
+ throw "SDK checksum differs: $Relative"
160
+ }
161
+ }
162
+ $Expected | Set-Content -Encoding ascii SHA256SUMS
163
+ ```
164
+
165
+ Check the exact header version using MSVC's preprocessor. It must print `11`, `4`, `0`, and `106`, in that order; the import library's filename identifies only the major version:
166
+
167
+ ```powershell
168
+ @'
169
+ #include "NvInferVersion.h"
170
+ NV_TENSORRT_MAJOR
171
+ NV_TENSORRT_MINOR
172
+ NV_TENSORRT_PATCH
173
+ NV_TENSORRT_BUILD
174
+ '@ | Set-Content -Encoding ascii version.cpp
175
+ cl /nologo /EP /I "$env:TENSORRT_ROOT/include" version.cpp
176
+ if ($LASTEXITCODE) { throw 'SDK version check failed' }
177
+ ```
178
+
179
+ From the tensoracle repository root, configure and test the standalone C++ project, then build the example plugin wheel with the same verified SDK:
180
+
181
+ ```powershell
182
+ $env:TENSORACLE_SDK_ROOT = $env:TENSORRT_ROOT
183
+ $env:TENSORACLE_CUDA_ROOT = 'C:/Program Files/NVIDIA GPU Computing Toolkit/CUDA/v12.8'
184
+ cmake -S cpp -B build/windows -G Ninja -DCMAKE_BUILD_TYPE=Release `
185
+ "-DTENSORRT_ROOT=$env:TENSORRT_ROOT" "-DCUDAToolkit_ROOT=$env:TENSORACLE_CUDA_ROOT"
186
+ if ($LASTEXITCODE) { throw 'CMake configuration failed' }
187
+ cmake --build build/windows --config Release
188
+ if ($LASTEXITCODE) { throw 'C++ build failed' }
189
+ ctest --test-dir build/windows -C Release --output-on-failure
190
+ if ($LASTEXITCODE) { throw 'CTest failed' }
191
+ uv build examples/cubin_plugin --wheel `
192
+ "--config-setting=cmake.define.TENSORRT_ROOT=$env:TENSORRT_ROOT" `
193
+ "--config-setting=cmake.define.CUDAToolkit_ROOT=$env:TENSORACLE_CUDA_ROOT"
194
+ if ($LASTEXITCODE) { throw 'Example wheel build failed' }
195
+ uv run --project python pytest python/tests/test_example_plugin.py
196
+ if ($LASTEXITCODE) { throw 'Example plugin tests failed' }
197
+ ```
198
+
199
+ The example build uses `cpp/cmake/TensoracleCubinPlugin.cmake`, which finds `nvinfer_11.lib` in the SDK's `lib/` directory. The built plugin is a DLL. Keep its TensorRT runtime available through the application's installed Python dependencies; the SDK directory is a build input and does not need to be added to the runtime `PATH`. For another TensorRT 11 release, establish new expected digests and check that release's exact header version before building.
@@ -35,6 +35,7 @@ nav:
35
35
  - Optimization workflow: optimization.md
36
36
  - bf16, int8, and fp8 engines: precision.md
37
37
  - TensorRT SDK setup: tensorrt-sdk.md
38
+ - C++ and Python repositories: cpp-python-repositories.md
38
39
  - API reference:
39
40
  - Engine and comparison: api/index.md
40
41
  - Cubin bundle inspection: api/bundle.md
@@ -12,6 +12,7 @@ classifiers = [
12
12
  "Intended Audience :: Developers",
13
13
  "License :: OSI Approved :: MIT License",
14
14
  "Operating System :: POSIX :: Linux",
15
+ "Operating System :: Microsoft :: Windows",
15
16
  "Programming Language :: Python :: 3.12",
16
17
  "Programming Language :: Python :: 3.13",
17
18
  "Topic :: Software Development :: Libraries",
@@ -18,7 +18,7 @@ version_tuple: tuple[int | str, ...]
18
18
  commit_id: str | None
19
19
  __commit_id__: str | None
20
20
 
21
- __version__ = version = '0.5.1'
22
- __version_tuple__ = version_tuple = (0, 5, 1)
21
+ __version__ = version = '1.0.0'
22
+ __version_tuple__ = version_tuple = (1, 0, 0)
23
23
 
24
24
  __commit_id__ = commit_id = None
@@ -4,7 +4,7 @@ import hashlib
4
4
  import json
5
5
  import struct
6
6
  import tempfile
7
- from pathlib import Path
7
+ from pathlib import Path, PurePosixPath, PureWindowsPath
8
8
  from zipfile import ZipFile
9
9
 
10
10
  from ._plugins import PluginLibraryError, exported_data
@@ -125,6 +125,18 @@ def _validate_entry(entry: dict) -> None:
125
125
  raise BundleError("unsupported floating point specialization rule")
126
126
 
127
127
 
128
+ def _relative_path(name: str) -> bool:
129
+ posix = PurePosixPath(name)
130
+ windows = PureWindowsPath(name)
131
+ return not (
132
+ posix.is_absolute()
133
+ or windows.drive
134
+ or windows.root
135
+ or ".." in posix.parts
136
+ or ".." in windows.parts
137
+ )
138
+
139
+
128
140
  def inspect_bundle(root: Path, *, plugin: Path | None = None) -> str:
129
141
  """Verify cubin bytes, ELF SM, supported launch metadata, and plugin identity."""
130
142
  root = Path(root)
@@ -144,7 +156,7 @@ def inspect_bundle(root: Path, *, plugin: Path | None = None) -> str:
144
156
  raise BundleError("invalid cubin entry")
145
157
  _validate_entry(entry)
146
158
  name = entry.get("file")
147
- if not isinstance(name, str) or Path(name).is_absolute() or ".." in Path(name).parts:
159
+ if not isinstance(name, str) or not _relative_path(name):
148
160
  raise BundleError("invalid cubin path")
149
161
  if name in visited:
150
162
  raise BundleError("duplicate cubin path")
@@ -189,9 +201,9 @@ def inspect_wheel(path: Path, *, plugin: str | None = None) -> str:
189
201
  with tempfile.TemporaryDirectory() as directory, ZipFile(path) as archive:
190
202
  root = Path(directory)
191
203
  for info in archive.infolist():
192
- member = Path(info.filename)
193
- if member.is_absolute() or ".." in member.parts:
204
+ if not _relative_path(info.filename):
194
205
  raise BundleError("wheel contains an invalid path")
206
+ member = Path(info.filename)
195
207
  if info.is_dir():
196
208
  continue
197
209
  destination = root / member
@@ -200,7 +212,7 @@ def inspect_wheel(path: Path, *, plugin: str | None = None) -> str:
200
212
  manifests = list(root.rglob("bundle.json"))
201
213
  if len(manifests) != 1:
202
214
  raise BundleError("wheel must contain exactly one cubin bundle")
203
- library = root / plugin if plugin is not None else None
204
- if library is not None and (Path(plugin).is_absolute() or ".." in Path(plugin).parts):
215
+ if plugin is not None and not _relative_path(plugin):
205
216
  raise BundleError("invalid plugin path in wheel")
217
+ library = root / plugin if plugin is not None else None
206
218
  return inspect_bundle(manifests[0].parent, plugin=library)
@@ -5,6 +5,10 @@
5
5
  #include <stdexcept>
6
6
  #include <utility>
7
7
 
8
+ #if defined(NDEBUG)
9
+ #error "The native IO contract requires active assertions"
10
+ #endif
11
+
8
12
  using namespace nvinfer1;
9
13
  using namespace tensoracle::cubin;
10
14
 
@@ -111,7 +111,7 @@ def _control():
111
111
  sm = f"sm{properties.major * 10 + properties.minor}"
112
112
  entry = next(item for item in manifest["entries"] if item["id"] == f"{sm}.dot.tf32-control")
113
113
  image = (library_path().parent / "bundle" / entry["file"]).read_bytes()
114
- driver = ctypes.CDLL("libcuda.so.1")
114
+ driver = ctypes.CDLL("nvcuda.dll" if sys.platform == "win32" else "libcuda.so.1")
115
115
 
116
116
  def call(name, *args):
117
117
  method = getattr(driver, name)
@@ -192,7 +192,7 @@ def _control():
192
192
 
193
193
  def _separate_cuda_contexts():
194
194
  """Reopen the cached plan in two owner contexts at the same time."""
195
- driver = ctypes.CDLL("libcuda.so.1")
195
+ driver = ctypes.CDLL("nvcuda.dll" if sys.platform == "win32" else "libcuda.so.1")
196
196
 
197
197
  def call(name, *args):
198
198
  method = getattr(driver, name)
@@ -229,7 +229,7 @@ def _duplicate_creator(directory):
229
229
  register_libraries((original,))
230
230
  registry = trt.get_plugin_registry()
231
231
  assert registry.get_creator("TensoracleExampleDot", "1", "tensoracle.example") is not None
232
- changed = Path(directory) / "same-creators-changed-bytes.so"
232
+ changed = Path(directory) / f"same-creators-changed-bytes{original.suffix}"
233
233
  shutil.copyfile(original, changed)
234
234
  with changed.open("ab") as stream:
235
235
  stream.write(b"different bytes with the same creators")