nimlang 0.0.1__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.
- nimlang-0.0.1/.github/workflows/ci.yml +180 -0
- nimlang-0.0.1/.gitignore +11 -0
- nimlang-0.0.1/LICENSE +21 -0
- nimlang-0.0.1/PKG-INFO +65 -0
- nimlang-0.0.1/README.md +51 -0
- nimlang-0.0.1/ROADMAP.md +43 -0
- nimlang-0.0.1/docs/design.md +126 -0
- nimlang-0.0.1/examples/hello-nim/.gitignore +5 -0
- nimlang-0.0.1/examples/hello-nim/README.md +12 -0
- nimlang-0.0.1/examples/hello-nim/pyproject.toml +24 -0
- nimlang-0.0.1/examples/hello-nim/src/hello_nim/__init__.py +3 -0
- nimlang-0.0.1/examples/hello-nim/src/hello_nim/hello_nim_cli.nim +4 -0
- nimlang-0.0.1/examples/hello-nim/src/hello_nim/nimcore.nim +10 -0
- nimlang-0.0.1/examples/hello-nim/tests/test_hello.py +9 -0
- nimlang-0.0.1/pyproject.toml +45 -0
- nimlang-0.0.1/scripts/make_wheels.py +170 -0
- nimlang-0.0.1/src/nimlang/__init__.py +30 -0
- nimlang-0.0.1/src/nimlang/__main__.py +3 -0
- nimlang-0.0.1/src/nimlang/_build.py +65 -0
- nimlang-0.0.1/src/nimlang/_project.py +143 -0
- nimlang-0.0.1/src/nimlang/_toolchain.py +206 -0
- nimlang-0.0.1/src/nimlang/cli.py +173 -0
- nimlang-0.0.1/src/nimlang/hatch_hook.py +118 -0
- nimlang-0.0.1/tests/test_nimlang.py +121 -0
- nimlang-0.0.1/uv.lock +298 -0
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
tags: ["v*"]
|
|
7
|
+
pull_request:
|
|
8
|
+
workflow_dispatch:
|
|
9
|
+
|
|
10
|
+
env:
|
|
11
|
+
# The Nim version bundled in this nimlang release (`nimlang info` reports it).
|
|
12
|
+
NIM_VERSION: "2.2.6"
|
|
13
|
+
|
|
14
|
+
jobs:
|
|
15
|
+
# Official Nim release binaries, repackaged into nimlang wheels.
|
|
16
|
+
wheel-official:
|
|
17
|
+
runs-on: ubuntu-latest
|
|
18
|
+
strategy:
|
|
19
|
+
fail-fast: false
|
|
20
|
+
matrix:
|
|
21
|
+
include:
|
|
22
|
+
- archive: linux_x64.tar.xz
|
|
23
|
+
tag: manylinux_2_17_x86_64
|
|
24
|
+
- archive: windows_x64.zip
|
|
25
|
+
tag: win_amd64
|
|
26
|
+
steps:
|
|
27
|
+
- uses: actions/checkout@v4
|
|
28
|
+
- uses: astral-sh/setup-uv@v6
|
|
29
|
+
- name: Download Nim ${{ env.NIM_VERSION }}
|
|
30
|
+
run: |
|
|
31
|
+
case "${{ matrix.archive }}" in
|
|
32
|
+
windows_x64.zip) url="https://nim-lang.org/download/nim-${NIM_VERSION}_x64.zip" ;;
|
|
33
|
+
*) url="https://nim-lang.org/download/nim-${NIM_VERSION}-${{ matrix.archive }}" ;;
|
|
34
|
+
esac
|
|
35
|
+
curl -fsSL -o "nim-dist-${{ matrix.archive }}" "$url"
|
|
36
|
+
- name: Build nimlang wheel with bundled Nim
|
|
37
|
+
run: |
|
|
38
|
+
uv run --no-project python scripts/make_wheels.py \
|
|
39
|
+
--nim-dist "nim-dist-${{ matrix.archive }}" --platform-tag ${{ matrix.tag }} --out-dir wheelhouse
|
|
40
|
+
- uses: actions/upload-artifact@v4
|
|
41
|
+
with:
|
|
42
|
+
name: wheel-${{ matrix.tag }}
|
|
43
|
+
path: wheelhouse/*.whl
|
|
44
|
+
|
|
45
|
+
# No official binaries for these platforms: build Nim from its source release.
|
|
46
|
+
wheel-source:
|
|
47
|
+
runs-on: ${{ matrix.os }}
|
|
48
|
+
strategy:
|
|
49
|
+
fail-fast: false
|
|
50
|
+
matrix:
|
|
51
|
+
include:
|
|
52
|
+
- os: macos-14
|
|
53
|
+
tag: macosx_11_0_arm64
|
|
54
|
+
deployment-target: "11.0"
|
|
55
|
+
- os: macos-15-intel
|
|
56
|
+
tag: macosx_10_13_x86_64
|
|
57
|
+
deployment-target: "10.13"
|
|
58
|
+
- os: ubuntu-24.04-arm
|
|
59
|
+
tag: manylinux_2_17_aarch64
|
|
60
|
+
# Link against glibc 2.17 with zig cc so the binaries are manylinux-compatible.
|
|
61
|
+
zig-target: aarch64-linux-gnu.2.17
|
|
62
|
+
env:
|
|
63
|
+
MACOSX_DEPLOYMENT_TARGET: ${{ matrix.deployment-target }}
|
|
64
|
+
steps:
|
|
65
|
+
- uses: actions/checkout@v4
|
|
66
|
+
- uses: astral-sh/setup-uv@v6
|
|
67
|
+
# Only the compiled Nim is cached; the wheel is rebuilt so it carries the current nimlang code.
|
|
68
|
+
- id: cache
|
|
69
|
+
uses: actions/cache@v4
|
|
70
|
+
with:
|
|
71
|
+
path: nim-${{ env.NIM_VERSION }}
|
|
72
|
+
key: nim-build-${{ env.NIM_VERSION }}-${{ matrix.tag }}
|
|
73
|
+
- name: Build Nim ${{ env.NIM_VERSION }} from source
|
|
74
|
+
if: steps.cache.outputs.cache-hit != 'true'
|
|
75
|
+
run: |
|
|
76
|
+
curl -fsSL -o nim-src.tar.xz "https://nim-lang.org/download/nim-${NIM_VERSION}.tar.xz"
|
|
77
|
+
tar xf nim-src.tar.xz
|
|
78
|
+
flags=""
|
|
79
|
+
if [ -n "${{ matrix.zig-target }}" ]; then
|
|
80
|
+
uv venv zigenv && uv pip install --python zigenv ziglang
|
|
81
|
+
printf '#!/bin/sh\nexec "%s" -m ziglang cc "$@"\n' "$PWD/zigenv/bin/python" > zigcc && chmod +x zigcc
|
|
82
|
+
t="${{ matrix.zig-target }}"
|
|
83
|
+
flags="--cc:clang --clang.exe:$PWD/zigcc --clang.linkerexe:$PWD/zigcc --passC:--target=$t --passL:--target=$t"
|
|
84
|
+
fi
|
|
85
|
+
cd "nim-${NIM_VERSION}"
|
|
86
|
+
sh build.sh
|
|
87
|
+
bin/nim c -d:release koch
|
|
88
|
+
./koch boot -d:release $flags
|
|
89
|
+
./koch tools -d:release $flags
|
|
90
|
+
bin/nim --version
|
|
91
|
+
- name: Build nimlang wheel with bundled Nim
|
|
92
|
+
run: |
|
|
93
|
+
uv run --no-project python scripts/make_wheels.py \
|
|
94
|
+
--nim-dist "nim-${NIM_VERSION}" --platform-tag ${{ matrix.tag }} --out-dir wheelhouse
|
|
95
|
+
- uses: actions/upload-artifact@v4
|
|
96
|
+
with:
|
|
97
|
+
name: wheel-${{ matrix.tag }}
|
|
98
|
+
path: wheelhouse/*.whl
|
|
99
|
+
|
|
100
|
+
test:
|
|
101
|
+
needs: [wheel-official, wheel-source]
|
|
102
|
+
strategy:
|
|
103
|
+
fail-fast: false
|
|
104
|
+
matrix:
|
|
105
|
+
os: [ubuntu-latest, ubuntu-24.04-arm, macos-14, macos-15-intel, windows-latest]
|
|
106
|
+
runs-on: ${{ matrix.os }}
|
|
107
|
+
env:
|
|
108
|
+
UV_FIND_LINKS: ${{ github.workspace }}/wheelhouse
|
|
109
|
+
defaults:
|
|
110
|
+
run:
|
|
111
|
+
shell: bash
|
|
112
|
+
steps:
|
|
113
|
+
- uses: actions/checkout@v4
|
|
114
|
+
- uses: astral-sh/setup-uv@v6
|
|
115
|
+
- uses: actions/download-artifact@v4
|
|
116
|
+
with:
|
|
117
|
+
pattern: wheel-*
|
|
118
|
+
path: wheelhouse
|
|
119
|
+
merge-multiple: true
|
|
120
|
+
- name: Install this platform's nimlang wheel
|
|
121
|
+
run: |
|
|
122
|
+
uv venv check-env
|
|
123
|
+
uv pip install --python check-env nimlang pytest hatchling
|
|
124
|
+
if [ "$RUNNER_OS" = "Windows" ]; then bin=check-env/Scripts; else bin=check-env/bin; fi
|
|
125
|
+
echo "BIN=$PWD/$bin" >> "$GITHUB_ENV"
|
|
126
|
+
- name: Unit tests against the installed wheel
|
|
127
|
+
run: $BIN/python -m pytest -v tests
|
|
128
|
+
- name: nimlang info
|
|
129
|
+
run: $BIN/nimlang info
|
|
130
|
+
- name: Build example package through the hatch hook
|
|
131
|
+
run: uv build --wheel --out-dir dist-example examples/hello-nim
|
|
132
|
+
- name: Install and run the example wheel
|
|
133
|
+
run: |
|
|
134
|
+
uv pip install --python check-env dist-example/*.whl
|
|
135
|
+
$BIN/python -c "import hello_nim; print(hello_nim.greet('CI'), hello_nim.fib(20))"
|
|
136
|
+
$BIN/hello_nim_cli CI
|
|
137
|
+
|
|
138
|
+
cross:
|
|
139
|
+
# One Linux machine builds the example wheel for every platform via zig cc.
|
|
140
|
+
needs: [wheel-official]
|
|
141
|
+
runs-on: ubuntu-latest
|
|
142
|
+
strategy:
|
|
143
|
+
fail-fast: false
|
|
144
|
+
matrix:
|
|
145
|
+
target: [x86_64-linux-gnu.2.17, aarch64-linux-gnu.2.17, aarch64-macos, x86_64-macos, x86_64-windows-gnu]
|
|
146
|
+
env:
|
|
147
|
+
UV_FIND_LINKS: ${{ github.workspace }}/wheelhouse
|
|
148
|
+
steps:
|
|
149
|
+
- uses: actions/checkout@v4
|
|
150
|
+
- uses: astral-sh/setup-uv@v6
|
|
151
|
+
- uses: actions/download-artifact@v4
|
|
152
|
+
with:
|
|
153
|
+
pattern: wheel-*
|
|
154
|
+
path: wheelhouse
|
|
155
|
+
merge-multiple: true
|
|
156
|
+
- name: Cross-build example wheel
|
|
157
|
+
env:
|
|
158
|
+
NIMLANG_TARGET: ${{ matrix.target }}
|
|
159
|
+
run: |
|
|
160
|
+
uv build --wheel --out-dir dist-example examples/hello-nim
|
|
161
|
+
ls dist-example
|
|
162
|
+
|
|
163
|
+
publish:
|
|
164
|
+
# Push a vX.Y.Z tag to release nimlang (platform wheels plus sdist) to PyPI.
|
|
165
|
+
if: startsWith(github.ref, 'refs/tags/v')
|
|
166
|
+
needs: [test, cross]
|
|
167
|
+
runs-on: ubuntu-latest
|
|
168
|
+
environment: pypi
|
|
169
|
+
permissions:
|
|
170
|
+
id-token: write
|
|
171
|
+
steps:
|
|
172
|
+
- uses: actions/checkout@v4
|
|
173
|
+
- uses: astral-sh/setup-uv@v6
|
|
174
|
+
- uses: actions/download-artifact@v4
|
|
175
|
+
with:
|
|
176
|
+
pattern: wheel-*
|
|
177
|
+
path: dist
|
|
178
|
+
merge-multiple: true
|
|
179
|
+
- run: uv build --sdist --out-dir dist
|
|
180
|
+
- uses: pypa/gh-action-pypi-publish@release/v1
|
nimlang-0.0.1/.gitignore
ADDED
nimlang-0.0.1/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 nimlang contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
nimlang-0.0.1/PKG-INFO
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: nimlang
|
|
3
|
+
Version: 0.0.1
|
|
4
|
+
Summary: Use Nim in your Python project: `uv add nimlang` gives you a Nim toolchain that compiles with zig cc.
|
|
5
|
+
Project-URL: Repository, https://github.com/pietroppeter/uv-add-nimlang
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
License-File: LICENSE
|
|
8
|
+
Classifier: Programming Language :: Python :: 3
|
|
9
|
+
Classifier: Topic :: Software Development :: Compilers
|
|
10
|
+
Requires-Python: >=3.9
|
|
11
|
+
Requires-Dist: tomlkit>=0.12
|
|
12
|
+
Requires-Dist: ziglang>=0.13
|
|
13
|
+
Description-Content-Type: text/markdown
|
|
14
|
+
|
|
15
|
+
# uv add nimlang
|
|
16
|
+
|
|
17
|
+
Use [Nim](https://nim-lang.org) in a Python project with nothing but uv.
|
|
18
|
+
|
|
19
|
+
`nimlang` is a Python package that ships the Nim compiler in its wheels and compiles C through
|
|
20
|
+
`zig cc` from the [ziglang](https://pypi.org/project/ziglang/) package, so you need no system
|
|
21
|
+
Nim and no C compiler.
|
|
22
|
+
|
|
23
|
+
> Status: early scaffold, not on PyPI yet. See [docs/design.md](docs/design.md) for what works
|
|
24
|
+
> and what is planned.
|
|
25
|
+
|
|
26
|
+
## Use Nim in your project
|
|
27
|
+
|
|
28
|
+
```sh
|
|
29
|
+
uv add nimlang
|
|
30
|
+
uv run nim c -r hello.nim # nim and nimble live in your venv
|
|
31
|
+
uv run nimlang add nimpy # tracked in [tool.nimlang] in pyproject.toml
|
|
32
|
+
uv run nimlang build-ext fast.nim # build a nimpy extension module next to fast.nim
|
|
33
|
+
uv run nimlang info # bundled Nim version and where everything lives
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Ship Nim code in a Python package
|
|
37
|
+
|
|
38
|
+
```toml
|
|
39
|
+
[build-system]
|
|
40
|
+
requires = ["hatchling", "nimlang"]
|
|
41
|
+
build-backend = "hatchling.build"
|
|
42
|
+
|
|
43
|
+
[tool.hatch.build.hooks.nimlang]
|
|
44
|
+
extensions = ["src/mypkg/nimcore.nim"] # importable as mypkg.nimcore
|
|
45
|
+
binaries = ["src/mypkg/mytool.nim"] # installed as the `mytool` command
|
|
46
|
+
|
|
47
|
+
[tool.nimlang]
|
|
48
|
+
dependencies = ["nimpy"]
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
`uv build` produces a `py3-none-<platform>` wheel that works on every CPython 3 version.
|
|
52
|
+
On Linux it is manylinux-compliant out of the box, and `NIMLANG_TARGET=aarch64-macos uv build`
|
|
53
|
+
cross-builds for other platforms. See [examples/hello-nim](examples/hello-nim).
|
|
54
|
+
|
|
55
|
+
## Building nimlang wheels
|
|
56
|
+
|
|
57
|
+
```sh
|
|
58
|
+
python scripts/make_wheels.py --nim-dist nim-2.2.6-linux_x64.tar.xz --platform-tag manylinux_2_17_x86_64
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
CI builds them for Linux (x86_64, aarch64), macOS (arm64, x86_64) and Windows x86_64, and
|
|
62
|
+
publishes to PyPI when a `v*` tag is pushed. For development without a bundled Nim, set
|
|
63
|
+
`NIMLANG_NIM_HOME` or put `nim` on `PATH`.
|
|
64
|
+
|
|
65
|
+
What's next: [ROADMAP.md](ROADMAP.md).
|
nimlang-0.0.1/README.md
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# uv add nimlang
|
|
2
|
+
|
|
3
|
+
Use [Nim](https://nim-lang.org) in a Python project with nothing but uv.
|
|
4
|
+
|
|
5
|
+
`nimlang` is a Python package that ships the Nim compiler in its wheels and compiles C through
|
|
6
|
+
`zig cc` from the [ziglang](https://pypi.org/project/ziglang/) package, so you need no system
|
|
7
|
+
Nim and no C compiler.
|
|
8
|
+
|
|
9
|
+
> Status: early scaffold, not on PyPI yet. See [docs/design.md](docs/design.md) for what works
|
|
10
|
+
> and what is planned.
|
|
11
|
+
|
|
12
|
+
## Use Nim in your project
|
|
13
|
+
|
|
14
|
+
```sh
|
|
15
|
+
uv add nimlang
|
|
16
|
+
uv run nim c -r hello.nim # nim and nimble live in your venv
|
|
17
|
+
uv run nimlang add nimpy # tracked in [tool.nimlang] in pyproject.toml
|
|
18
|
+
uv run nimlang build-ext fast.nim # build a nimpy extension module next to fast.nim
|
|
19
|
+
uv run nimlang info # bundled Nim version and where everything lives
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Ship Nim code in a Python package
|
|
23
|
+
|
|
24
|
+
```toml
|
|
25
|
+
[build-system]
|
|
26
|
+
requires = ["hatchling", "nimlang"]
|
|
27
|
+
build-backend = "hatchling.build"
|
|
28
|
+
|
|
29
|
+
[tool.hatch.build.hooks.nimlang]
|
|
30
|
+
extensions = ["src/mypkg/nimcore.nim"] # importable as mypkg.nimcore
|
|
31
|
+
binaries = ["src/mypkg/mytool.nim"] # installed as the `mytool` command
|
|
32
|
+
|
|
33
|
+
[tool.nimlang]
|
|
34
|
+
dependencies = ["nimpy"]
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
`uv build` produces a `py3-none-<platform>` wheel that works on every CPython 3 version.
|
|
38
|
+
On Linux it is manylinux-compliant out of the box, and `NIMLANG_TARGET=aarch64-macos uv build`
|
|
39
|
+
cross-builds for other platforms. See [examples/hello-nim](examples/hello-nim).
|
|
40
|
+
|
|
41
|
+
## Building nimlang wheels
|
|
42
|
+
|
|
43
|
+
```sh
|
|
44
|
+
python scripts/make_wheels.py --nim-dist nim-2.2.6-linux_x64.tar.xz --platform-tag manylinux_2_17_x86_64
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
CI builds them for Linux (x86_64, aarch64), macOS (arm64, x86_64) and Windows x86_64, and
|
|
48
|
+
publishes to PyPI when a `v*` tag is pushed. For development without a bundled Nim, set
|
|
49
|
+
`NIMLANG_NIM_HOME` or put `nim` on `PATH`.
|
|
50
|
+
|
|
51
|
+
What's next: [ROADMAP.md](ROADMAP.md).
|
nimlang-0.0.1/ROADMAP.md
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# Roadmap
|
|
2
|
+
|
|
3
|
+
Ideas for after the first release, roughly in priority order.
|
|
4
|
+
|
|
5
|
+
## Choose the Nim version per project
|
|
6
|
+
|
|
7
|
+
Today each nimlang release bundles one Nim version. The goal is for a project to pick its Nim
|
|
8
|
+
(say 2.0 for an older codebase) while keeping `uv add nimlang` as the only setup step.
|
|
9
|
+
|
|
10
|
+
Two ways to get there:
|
|
11
|
+
|
|
12
|
+
- **Compiler package (preferred).** Ship Nim in a separate `nimlang-nim` package whose
|
|
13
|
+
version is the Nim version, with `nimlang` depending on it. A project pins Nim with
|
|
14
|
+
`uv add "nimlang-nim==2.0.16"` and uv.lock records it. This was prototyped in commit
|
|
15
|
+
`d81715d` on the scaffold branch: it built a 9.4 MB `nimlang-nim` wheel per platform, and
|
|
16
|
+
switching a project from Nim 2.2.6 to 2.2.4 worked locally.
|
|
17
|
+
- **Download on demand.** `nim = "2.0"` in `[tool.nimlang]`, with nimlang downloading and
|
|
18
|
+
caching that compiler on first use, like `uv python`. This is more flexible, but sits
|
|
19
|
+
outside uv.lock and needs network access at first use.
|
|
20
|
+
|
|
21
|
+
## Optional nimporter integration (after the first release)
|
|
22
|
+
|
|
23
|
+
nimlang does not depend on nimporter for now. The idea is an optional `nimlang[import]`
|
|
24
|
+
extra that gives a dev-time `import foo` for `foo.nim`, compiled through nimlang (zig cc and
|
|
25
|
+
the project's `[tool.nimlang]` dependencies). It would likely be a maintained fork of
|
|
26
|
+
nimporter, with fixes also sent upstream. Problems with upstream today:
|
|
27
|
+
|
|
28
|
+
- The latest real release is 1.1.0 (November 2021). The 2.0.0 uploaded in March 2022 was a
|
|
29
|
+
release candidate and was yanked, and master has carried the unreleased 2.0 since July 2023.
|
|
30
|
+
- It doesn't declare setuptools, so `import nimporter` fails in a fresh uv venv on Python 3.12.
|
|
31
|
+
- It pulls in about 28 packages, including cookiecutter and icecream.
|
|
32
|
+
- It compiles with `nimble c --accept` against the global `~/.nimble`, not a project's
|
|
33
|
+
dependencies.
|
|
34
|
+
|
|
35
|
+
## Other items
|
|
36
|
+
|
|
37
|
+
- **Lock file for Nim dependencies:** record resolved versions/commits of `[tool.nimlang]`
|
|
38
|
+
dependencies next to uv.lock.
|
|
39
|
+
- **Native `zigcc` shim on Windows:** a tiny executable instead of the `.cmd` file.
|
|
40
|
+
- **`nimlang init`:** scaffold a mixed Python/Nim project (nimpy module, build hook, tests).
|
|
41
|
+
- **Editor support:** point nimsuggest/nimlangserver at the venv's Nim and the project's
|
|
42
|
+
dependency paths.
|
|
43
|
+
- **More platforms:** musllinux, Windows arm64, Linux armv7.
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
# nimlang: design notes
|
|
2
|
+
|
|
3
|
+
Goal: `uv add nimlang` is all a Python project needs to start using Nim.
|
|
4
|
+
|
|
5
|
+
- `nim` and `nimble` work inside the project (`uv run nim c -r app.nim`), with no system C compiler.
|
|
6
|
+
- Nim dependencies are declared and tracked in `pyproject.toml` (`nimlang add nimpy`).
|
|
7
|
+
- A package can ship Nim-built extension modules and executables in ordinary wheels,
|
|
8
|
+
with `nimlang` as a build dependency.
|
|
9
|
+
|
|
10
|
+
## What was verified
|
|
11
|
+
|
|
12
|
+
All of this ran in a Linux x86_64 sandbox with no Nim install, using Nim 2.2.6 and the
|
|
13
|
+
`ziglang` 0.16.0 wheel from PyPI:
|
|
14
|
+
|
|
15
|
+
| Check | Result |
|
|
16
|
+
|---|---|
|
|
17
|
+
| Nim compiles with `zig cc` as its C compiler (`--cc:clang --clang.exe:<zigcc shim>`) | works |
|
|
18
|
+
| Cross-compiling a Nim program to Windows x64, macOS arm64 and Linux arm64 from Linux | works (binaries not run on those OSes yet) |
|
|
19
|
+
| nimpy extension module built with zig cc, imported from Python | works |
|
|
20
|
+
| Same extension built against glibc 2.17 (`-target x86_64-linux-gnu.2.17`) | max symbol version GLIBC_2.14, so manylinux_2_17 compliant |
|
|
21
|
+
| Nim distribution repackaged into a `nimlang` platform wheel | 9.4 MB wheel (26 MB unpacked) |
|
|
22
|
+
| `uv add nimlang` (from that wheel) then `uv run nim c -r hello.nim` | works |
|
|
23
|
+
| `nimlang add nimpy` → nimble installs into `.nimlang/`, then `nimlang build-ext` | works |
|
|
24
|
+
| `examples/hello-nim`: `uv build` with the hatch hook | `py3-none-manylinux_2_17_x86_64` wheel with extension + CLI |
|
|
25
|
+
| That one wheel on CPython 3.11 and 3.13 | works on both: nimpy has no compile-time libpython dependency |
|
|
26
|
+
| `NIMLANG_TARGET=aarch64-macos uv build`, `NIMLANG_TARGET=x86_64-windows-gnu uv build` from Linux | correct Mach-O / PE files and wheel tags |
|
|
27
|
+
|
|
28
|
+
## Architecture
|
|
29
|
+
|
|
30
|
+
### 1. The toolchain wheel (`nimlang`)
|
|
31
|
+
|
|
32
|
+
Same trick as [ziglang](https://pypi.org/project/ziglang/): a Python package whose platform
|
|
33
|
+
wheels contain a compiler distribution. `scripts/make_wheels.py` builds the pure-Python wheel
|
|
34
|
+
and injects a Nim distribution (`bin/`, `lib/`, `config/`) under `nimlang/nim/`, retagged as
|
|
35
|
+
`py3-none-<platform>`. Only `nim`, `nimble`, `nimsuggest`, `nimpretty`, `nimgrep` and `atlas`
|
|
36
|
+
(plus DLLs and `cacert.pem` on Windows) are kept from `bin/`. For manylinux tags the script
|
|
37
|
+
checks the binaries' glibc symbol versions against the tag.
|
|
38
|
+
|
|
39
|
+
Each nimlang release bundles one Nim version (set by `NIM_VERSION` in CI), and nimlang keeps
|
|
40
|
+
its own version numbers; `nimlang info` reports the Nim version. Choosing a Nim version per
|
|
41
|
+
project is on the [roadmap](../ROADMAP.md).
|
|
42
|
+
|
|
43
|
+
Where the binaries come from: official Nim release builds where they exist (Linux x86_64,
|
|
44
|
+
Windows x86_64), built from the source release elsewhere (macOS arm64 and x86_64 natively;
|
|
45
|
+
Linux aarch64 linked against glibc 2.17 with zig cc).
|
|
46
|
+
|
|
47
|
+
Lookup order for the compiler: `$NIMLANG_NIM_HOME`, the bundled distribution, then a `nim` on
|
|
48
|
+
`PATH` (choosenim-style proxies are resolved with `nim dump`).
|
|
49
|
+
|
|
50
|
+
`ziglang` is a regular dependency, so the C compiler arrives with the same `uv add`.
|
|
51
|
+
|
|
52
|
+
### 2. zig cc wiring
|
|
53
|
+
|
|
54
|
+
Nim calls its C compiler as a single executable, so it cannot be pointed at `zig cc` directly.
|
|
55
|
+
nimlang writes a two-line shim (`zigcc` shell script, `zigcc.cmd` on Windows) into the user
|
|
56
|
+
cache, keyed by the zig path of the environment, and passes
|
|
57
|
+
`--cc:clang --clang.exe:<shim> --clang.linkerexe:<shim>`.
|
|
58
|
+
|
|
59
|
+
Flags are inserted right after the Nim command, and only for commands that run the C
|
|
60
|
+
compiler (`c`, `cpp`, `r`, ...). `nim e` is left alone: nimble evaluates `.nimble` files
|
|
61
|
+
with it and NimScript sees every command-line argument (injecting there broke nimble).
|
|
62
|
+
`NIMLANG_CC=system` opts out and uses Nim's default compiler.
|
|
63
|
+
|
|
64
|
+
Cross-compilation is the same mechanism plus `--os/--cpu` and `-target <zig triple>`.
|
|
65
|
+
|
|
66
|
+
### 3. Nim dependencies
|
|
67
|
+
|
|
68
|
+
```toml
|
|
69
|
+
[tool.nimlang]
|
|
70
|
+
dependencies = ["nimpy", "cligen >= 1.7"]
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
`nimlang add/remove` edit this table (format-preserving, via tomlkit) and `nimlang sync`
|
|
74
|
+
runs the bundled nimble with `--nimbleDir:.nimlang/nimble`. Compiles through nimlang get
|
|
75
|
+
`--noNimblePath` plus one `--path` per installed package, so a build sees exactly the
|
|
76
|
+
project's dependencies and nothing from `~/.nimble`.
|
|
77
|
+
|
|
78
|
+
### 4. Distributing Nim code in Python packages
|
|
79
|
+
|
|
80
|
+
A hatchling build hook ships with nimlang (registered through the `hatch` entry point):
|
|
81
|
+
|
|
82
|
+
```toml
|
|
83
|
+
[build-system]
|
|
84
|
+
requires = ["hatchling", "nimlang"]
|
|
85
|
+
build-backend = "hatchling.build"
|
|
86
|
+
|
|
87
|
+
[tool.hatch.build.hooks.nimlang]
|
|
88
|
+
extensions = ["src/mypkg/nimcore.nim"] # -> mypkg.nimcore (nimpy)
|
|
89
|
+
binaries = ["src/mypkg/mytool.nim"] # -> `mytool` on PATH
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
- Missing `[tool.nimlang]` dependencies are synced before compiling.
|
|
93
|
+
- Extensions use the plain `.so`/`.pyd` suffix and wheels are tagged `py3-none-<platform>`:
|
|
94
|
+
one wheel per platform covers every CPython 3.
|
|
95
|
+
- On Linux the default target pins glibc 2.17, so native wheels are manylinux-compliant
|
|
96
|
+
without a manylinux container.
|
|
97
|
+
- `NIMLANG_TARGET` (or `target =` in the hook config) cross-builds: a single Linux CI job can
|
|
98
|
+
produce wheels for every platform. No cibuildwheel needed.
|
|
99
|
+
- Editable installs (`uv sync`) build extensions in place next to the sources; add
|
|
100
|
+
`[tool.uv] cache-keys` on `*.nim` so uv rebuilds when they change (see the example).
|
|
101
|
+
|
|
102
|
+
### nimpy and nimporter
|
|
103
|
+
|
|
104
|
+
nimpy is the core dependency for extensions and works well with this approach. nimporter's
|
|
105
|
+
last release is 1.1.0 from November 2021 (a 2.0.0 uploaded in March 2022 was yanked). It
|
|
106
|
+
compiles at import time or via setuptools and expects a C compiler on the user's machine,
|
|
107
|
+
which is the problem nimlang removes, so nimlang does not depend on it. Its "import .nim
|
|
108
|
+
files directly" convenience could come back as an optional import hook built on nimlang's
|
|
109
|
+
toolchain (undecided; see the roadmap).
|
|
110
|
+
|
|
111
|
+
## Decisions (2026-10-04)
|
|
112
|
+
|
|
113
|
+
1. **Nim binaries:** official release builds where they exist, source builds elsewhere.
|
|
114
|
+
2. **Versioning:** `nimlang` has its own versions and bundles one Nim per release. Per-project
|
|
115
|
+
Nim versions are on the roadmap.
|
|
116
|
+
3. **Nim dependencies:** `[tool.nimlang]` in pyproject.toml. A lock file is not implemented
|
|
117
|
+
yet; the likely route is recording resolved versions/commits next to `uv.lock`.
|
|
118
|
+
4. **Build integration:** the hatchling hook (a dedicated PEP 517 backend is more work for
|
|
119
|
+
little gain right now).
|
|
120
|
+
5. **PyPI:** reserve `nimlang` with an early release, published from CI through trusted
|
|
121
|
+
publishing when a `v*` tag is pushed.
|
|
122
|
+
|
|
123
|
+
## Next steps
|
|
124
|
+
|
|
125
|
+
See [ROADMAP.md](../ROADMAP.md). Building from an sdist needs network access for the nimble
|
|
126
|
+
dependencies, as with any nimble-based build.
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# hello-nim
|
|
2
|
+
|
|
3
|
+
A Python package whose core is written in Nim, built with `nimlang`'s hatch hook:
|
|
4
|
+
|
|
5
|
+
- `src/hello_nim/nimcore.nim` becomes the extension module `hello_nim.nimcore` (via nimpy)
|
|
6
|
+
- `src/hello_nim/hello_nim_cli.nim` becomes the `hello_nim_cli` executable
|
|
7
|
+
|
|
8
|
+
```sh
|
|
9
|
+
uv run nimlang sync # install the Nim deps from [tool.nimlang] (nimpy)
|
|
10
|
+
uv build # wheel tagged py3-none-<platform>
|
|
11
|
+
NIMLANG_TARGET=aarch64-macos uv build # cross-build a macOS arm64 wheel from Linux
|
|
12
|
+
```
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "hello-nim"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = "Example: a Python package with a Nim extension module and a Nim CLI, built with nimlang."
|
|
5
|
+
requires-python = ">=3.9"
|
|
6
|
+
dependencies = []
|
|
7
|
+
|
|
8
|
+
[build-system]
|
|
9
|
+
requires = ["hatchling", "nimlang"]
|
|
10
|
+
build-backend = "hatchling.build"
|
|
11
|
+
|
|
12
|
+
[tool.hatch.build.hooks.nimlang]
|
|
13
|
+
extensions = ["src/hello_nim/nimcore.nim"]
|
|
14
|
+
binaries = ["src/hello_nim/hello_nim_cli.nim"]
|
|
15
|
+
|
|
16
|
+
[tool.nimlang]
|
|
17
|
+
dependencies = ["nimpy"]
|
|
18
|
+
|
|
19
|
+
[tool.uv]
|
|
20
|
+
# Rebuild the editable install (and so the Nim extension) when Nim sources change.
|
|
21
|
+
cache-keys = [{ file = "pyproject.toml" }, { file = "src/**/*.nim" }]
|
|
22
|
+
|
|
23
|
+
[dependency-groups]
|
|
24
|
+
dev = ["nimlang", "pytest"]
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "nimlang"
|
|
3
|
+
version = "0.0.1"
|
|
4
|
+
description = "Use Nim in your Python project: `uv add nimlang` gives you a Nim toolchain that compiles with zig cc."
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
license = "MIT"
|
|
7
|
+
requires-python = ">=3.9"
|
|
8
|
+
dependencies = [
|
|
9
|
+
"ziglang>=0.13",
|
|
10
|
+
"tomlkit>=0.12",
|
|
11
|
+
]
|
|
12
|
+
classifiers = [
|
|
13
|
+
"Programming Language :: Python :: 3",
|
|
14
|
+
"Topic :: Software Development :: Compilers",
|
|
15
|
+
]
|
|
16
|
+
|
|
17
|
+
[project.urls]
|
|
18
|
+
Repository = "https://github.com/pietroppeter/uv-add-nimlang"
|
|
19
|
+
|
|
20
|
+
[project.scripts]
|
|
21
|
+
nimlang = "nimlang.cli:main"
|
|
22
|
+
nim = "nimlang.cli:nim_main"
|
|
23
|
+
nimble = "nimlang.cli:nimble_main"
|
|
24
|
+
|
|
25
|
+
[project.entry-points.hatch]
|
|
26
|
+
nimlang = "nimlang.hatch_hook"
|
|
27
|
+
|
|
28
|
+
[build-system]
|
|
29
|
+
requires = ["hatchling"]
|
|
30
|
+
build-backend = "hatchling.build"
|
|
31
|
+
|
|
32
|
+
[tool.hatch.build.targets.wheel]
|
|
33
|
+
packages = ["src/nimlang"]
|
|
34
|
+
# The Nim distribution is injected by scripts/make_wheels.py into platform wheels;
|
|
35
|
+
# a local checkout may have one unpacked under src/nimlang/nim for testing.
|
|
36
|
+
exclude = ["src/nimlang/nim"]
|
|
37
|
+
|
|
38
|
+
[dependency-groups]
|
|
39
|
+
dev = ["pytest>=8", "hatchling"]
|
|
40
|
+
|
|
41
|
+
[tool.pytest.ini_options]
|
|
42
|
+
testpaths = ["tests"]
|
|
43
|
+
|
|
44
|
+
[tool.ruff]
|
|
45
|
+
line-length = 110
|