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.
@@ -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
@@ -0,0 +1,11 @@
1
+ __pycache__/
2
+ *.egg-info/
3
+ .venv/
4
+ dist/
5
+ build/
6
+ .nimlang/
7
+ src/nimlang/nim/
8
+ *.so
9
+ *.pyd
10
+ *.dll
11
+ *.dylib
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).
@@ -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).
@@ -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,5 @@
1
+ .nimlang/
2
+ .venv/
3
+ dist/
4
+ *.so
5
+ *.pyd
@@ -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,3 @@
1
+ from hello_nim.nimcore import fib, greet
2
+
3
+ __all__ = ["fib", "greet"]
@@ -0,0 +1,4 @@
1
+ import std/os
2
+
3
+ let name = if paramCount() > 0: paramStr(1) else: "world"
4
+ echo "Hello, ", name, " from a Nim binary!"
@@ -0,0 +1,10 @@
1
+ import nimpy
2
+
3
+ proc greet(name: string): string {.exportpy.} =
4
+ "Hello, " & name & " from Nim!"
5
+
6
+ proc fib(n: int): int {.exportpy.} =
7
+ var (a, b) = (0, 1)
8
+ for _ in 0 ..< n:
9
+ (a, b) = (b, a + b)
10
+ a
@@ -0,0 +1,9 @@
1
+ import hello_nim
2
+
3
+
4
+ def test_greet():
5
+ assert hello_nim.greet("Python") == "Hello, Python from Nim!"
6
+
7
+
8
+ def test_fib():
9
+ assert [hello_nim.fib(n) for n in range(8)] == [0, 1, 1, 2, 3, 5, 8, 13]
@@ -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