Py2Native Compile custom Python into native machine code to protect proprietary code

← All posts

2026-09-17

Cython Alternative: Compile Python Without Writing .pyx Files

Cython Alternative: Compile Python Without Writing .pyx Files
python compiler cython code protection open source

Cython Alternative: Compile Python Without Writing .pyx Files

If you ship proprietary Python software, you eventually face the same decision: ship readable .py files, or compile your custom code into native machine code that is much harder to reverse engineer. Raw Cython can do the second job, but it demands .pyx files, static declarations, manual cythonize steps, and platform-specific C compiler flags. Py2Native takes a different road. It uses Cython under the hood but hides that complexity behind a single CLI command. You write plain Python, and Py2Native produces the native binary, shared library, or wheel.

This article compares the raw Cython path with Py2Native as a zero-config way to protect Python source code.

The Decision: Cython or a Simpler Path to Native Code?

For many teams, the buying decision is not really “should we protect our code?” It is “how much build tooling are we willing to own?” Native code raises the barrier against casual copying and reverse engineering. The question is whether you want to build and maintain the Cython compilation pipeline yourself, or whether you want a tool that automates that pipeline from plain Python.

Raw Cython is powerful. It can compile Python-like code to C and create native extensions or executables. But it also asks you to work in .pyx files, understand cdef declarations, manage cythonize, and configure a C compiler for every target platform. That is fine for Cython specialists. It is less fine for a product team that just wants to ship.

Py2Native frames the choice differently: what if you could get the protection of native binaries without ever writing a .pyx file, without learning Cython syntax, and without maintaining a custom build system? That is exactly what Py2Native aims to do. It compiles plain Python to native machine code from a single command:

uv run py2native build main.py '*.py' --wheel dist

No manual Cython step. No C extension boilerplate. Just your normal Python files.

The Landscape: Options for Compiling Python to Native Code

If you are evaluating alternatives to raw Cython, there are several common options, but they often trade one kind of configuration burden for another.

Raw Cython gives you fine-grained control. You write .pyx and .pxd files, declare C-level types when you want speed, and drive the build through cythonize plus a C compiler. That is the hard way: powerful, but you own the entire toolchain, platform flags, and wheel repair process.

PyInstaller and Nuitka can bundle or compile Python into distributable artifacts, but they may require project-specific configuration or produce packages that do not match the native-library model many teams want. They are not always a drop-in answer for code protection.

Py2Native is a Python-to-native compiler focused on one job: compile your custom Python code into native machine code so you can ship protected binaries instead of readable source. The core compiler is open source under the MIT license. It uses Cython internally but hides it completely. You write plain Python, and Py2Native handles globbing, Cython transpilation, C compilation, linking, and optional wheel or uv-managed embedding.

Py2Native supports cross-platform compilation for Windows, Linux, and macOS on x86-64 or ARM64. It can produce a library, an executable, or a PEP 427 wheel from the same command. Third-party Python libraries remain as normal Python source and work with minimal or no configuration.

Selection Criteria: What Matters for Code Protection

When comparing code-protection workflows, the most practical criteria are ease of use, automation, security, integration, and price.

Ease of use

Raw Cython requires you to learn its syntax, understand .pyx and .pxd conventions, and run multiple build steps. Py2Native reduces this to one CLI command:

uv run py2native build main.py 'src/**/*.py' --library

The main.py argument is your entry point; the remaining globs are expanded automatically. There are no handwritten cythonize invocations and no C extension files to maintain.

Automation

Py2Native automates the full pipeline: source globbing, Cython-to-C translation, C compilation, linking, and optional wheel creation or embedding. For a library build, it creates a shared library plus the __init__.py and __main__.py files needed by Python’s import system. For an embedded deployment, it creates a uv-managed directory.

Security

Native binaries raise the barrier to reverse engineering compared with shipping .py or .pyc files. Py2Native keeps the same native-output model but removes the manual steps that often cause teams to skip protection altogether.

For stronger license enforcement, the closed-source Pro plugin adds signed JWT license verification. The verification logic and public key are baked into the executable, and only the public key is stored. There is no external license server at runtime.

Integration

Py2Native works with plain Python projects and leaves third-party libraries as Python source. It targets CPython 3.11 through 3.15, including free-threaded 3.14t and 3.15t builds. It supports Windows 8+, manylinux2014/musl Linux, and macOS on x86-64 or ARM64.

Price

The open-source core is MIT licensed and free for commercial use. The Pro plugin is proprietary and adds JWT license verification and string compression.

Side-by-Side Comparison: Cython vs. Py2Native

The two approaches can produce the same class of native output. The differences are mostly in who does the build engineering.

Criterion Raw Cython Py2Native
Required files .pyx, .pxd, build configuration Plain .py files
Build process Manual cythonize plus C compiler/linker Single uv run py2native build command
Learning curve Cython syntax and C extension build Plain Python, one CLI
Code protection Native extension or executable, if you manage the build Native machine code, with automation
License verification Not built in Pro plugin with JWT verification via _runtime_verify_es256_jwt
Output flexibility Manual shared object, executable, or wheel Library, executable, or PEP 427 wheel; optional uv embed
Third-party libraries Requires you to decide what to compile Left as Python source and work as-is
Supported Python versions Depends on your setup CPython 3.11–3.15, including free-threaded 3.14t/3.15t

The key difference is not the final native artifact but the amount of manual tooling you maintain. Raw Cython is the hard way: you own the cythonize step, static declarations, platform flags, and wheel repair. Py2Native is the productized path: one glob, one command, and the same native protection.

For example, with Py2Native, this plain Python file is compiled without modification:

# main.py
def calculate_score(events: list[dict]) -> int:
    return sum(event["value"] for event in events)

if __name__ == "__main__":
    print(calculate_score([{"value": 1}, {"value": 2}]))

Then you run:

uv run py2native build main.py '*.py' --library --wheel dist

Py2Native handles the Cython transpilation, C compilation, linking, and wheel packaging. The wheel contains the compiled shared library and the import-system bridge files.

License verification with Py2Native Pro

Py2Native Pro adds JWT verification without requiring an external SDK. Generate a keypair first:

uv run py2native keygen private.pem public.pem

Sign a license payload:

uv run py2native sign --private private.pem \
  '{"iss":"RSJ Software GmbH","aud":"TimestampGIT","sub":"acme-42"}' \
  license.dat

For builds that need license checks, the Pro plugin bakes the signature verification code and public key into the executable. In your project, you add a small .pxd declaration for the bootstrap symbol:

# py2native_license.pxd
from _p2n_bootstrap cimport _runtime_verify_es256_jwt

cdef _runtime_verify_es256_jwt(
    token,
    expected_iss=*,
    expected_aud=*,
)

Then call it from your Python entry point:

def start_server(licenseString: str) -> None:
    license = _runtime_verify_es256_jwt(
        licenseString,
        expected_iss="RSJ Software GmbH",
        expected_aud="TimestampGIT",
    )
    if not license:
        raise RuntimeError("invalid license")

    # start your protected application

Finally, build with the license and public key flags:

uv run py2native build main.py '*.py' \
  --license license.dat \
  --public public.pem

The elliptic-key verification is handled with compiled code inside Py2Native Pro, so no third-party verification libraries are required at runtime.

Verdict: Who Should Pick Which?

Choose raw Cython if you need fine-grained control over C-level types and optimizations, or if you already have a working Cython build pipeline that your team maintains. In that case, the extra control may be worth the extra build engineering.

Choose Py2Native if you want to protect Python source code quickly, without learning Cython syntax or maintaining manual build steps. This is especially true if you need license verification: Py2Native Pro bakes the JWT verifier and public key directly into the executable.

Py2Native is a strong fit for teams shipping proprietary Python applications or libraries, particularly when the team wants a repeatable compile step that works across Windows, Linux, and macOS without per-platform build scripts.

For a deeper walkthrough of the compile workflow, see How to Compile Python to a Native Binary Without Cython Syntax. For the license-verification model, see Secure License Verification for Python Native Binaries.

FAQ

Q: Do I need to know Cython to use Py2Native?

A: No. Py2Native hides Cython completely. You write plain Python files, and Py2Native handles the transpilation to C and compilation to native code automatically. No .pyx or .pxd files are required.

Q: Can I still use third-party Python libraries with Py2Native?

A: Yes. Py2Native leaves third-party libraries as Python source; they work as-is with minimal or no configuration. Only your custom Python code is compiled to native machine code.

Q: How does license verification work in Py2Native Pro?

A: Py2Native Pro includes a plugin that adds JWT license verification. You generate a keypair, sign a license, and then in your code call _runtime_verify_es256_jwt with the license string and expected issuer/audience. The verification logic and public key are baked into the executable, so no external libraries are needed.

Q: Is Py2Native free to use?

A: The core Py2Native compiler is open source and MIT licensed, free for commercial use. The Pro plugin, which adds license verification and string compression, is proprietary and requires a commercial license.

Conclusion

You do not have to choose between shipping readable Python source and becoming a Cython build engineer. Py2Native gives you native-machine-code protection from plain Python files, with one uv run py2native build command. The open-source core is free under the MIT license, and the Pro plugin adds signed JWT license verification when you need stronger enforcement.

If you are looking for a practical Cython alternative for code protection, start with Py2Native and a single build command:

uv run py2native build main.py '*.py' --wheel dist

Get native protection without writing a single .pyx file.

Related posts

EU label: AI-generated content