about summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--flake.lock133
-rw-r--r--flake.nix187
-rw-r--r--pyproject.toml187
-rw-r--r--setup.py436
-rw-r--r--uv.lock94
5 files changed, 597 insertions, 440 deletions
diff --git a/flake.lock b/flake.lock
new file mode 100644
index 00000000..10b95228
--- /dev/null
+++ b/flake.lock
@@ -0,0 +1,133 @@
+{
+  "nodes": {
+    "flake-utils": {
+      "inputs": {
+        "systems": "systems"
+      },
+      "locked": {
+        "lastModified": 1731533236,
+        "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
+        "owner": "numtide",
+        "repo": "flake-utils",
+        "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
+        "type": "github"
+      },
+      "original": {
+        "owner": "numtide",
+        "repo": "flake-utils",
+        "type": "github"
+      }
+    },
+    "nixpkgs": {
+      "locked": {
+        "lastModified": 1759831965,
+        "narHash": "sha256-vgPm2xjOmKdZ0xKA6yLXPJpjOtQPHfaZDRtH+47XEBo=",
+        "owner": "NixOS",
+        "repo": "nixpkgs",
+        "rev": "c9b6fb798541223bbb396d287d16f43520250518",
+        "type": "github"
+      },
+      "original": {
+        "owner": "NixOS",
+        "ref": "nixos-unstable",
+        "repo": "nixpkgs",
+        "type": "github"
+      }
+    },
+    "pyproject-build-systems": {
+      "inputs": {
+        "nixpkgs": [
+          "nixpkgs"
+        ],
+        "pyproject-nix": [
+          "pyproject-nix"
+        ],
+        "uv2nix": [
+          "uv2nix"
+        ]
+      },
+      "locked": {
+        "lastModified": 1759113590,
+        "narHash": "sha256-fgxP2RCN4cg0jYiMYoETYc7TZ2JjgyvJa2y9l8oSUFE=",
+        "owner": "pyproject-nix",
+        "repo": "build-system-pkgs",
+        "rev": "dbfc0483b5952c6b86e36f8b3afeb9dde30ea4b5",
+        "type": "github"
+      },
+      "original": {
+        "owner": "pyproject-nix",
+        "repo": "build-system-pkgs",
+        "type": "github"
+      }
+    },
+    "pyproject-nix": {
+      "inputs": {
+        "nixpkgs": [
+          "nixpkgs"
+        ]
+      },
+      "locked": {
+        "lastModified": 1759739877,
+        "narHash": "sha256-XfcxM4nzSuuRmFGiy/MhGwYf9EennQ2+0jjR2aJqtKE=",
+        "owner": "pyproject-nix",
+        "repo": "pyproject.nix",
+        "rev": "966e0961f9670f847439ba90dc25ffaa112d8803",
+        "type": "github"
+      },
+      "original": {
+        "owner": "pyproject-nix",
+        "repo": "pyproject.nix",
+        "type": "github"
+      }
+    },
+    "root": {
+      "inputs": {
+        "flake-utils": "flake-utils",
+        "nixpkgs": "nixpkgs",
+        "pyproject-build-systems": "pyproject-build-systems",
+        "pyproject-nix": "pyproject-nix",
+        "uv2nix": "uv2nix"
+      }
+    },
+    "systems": {
+      "locked": {
+        "lastModified": 1681028828,
+        "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
+        "owner": "nix-systems",
+        "repo": "default",
+        "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
+        "type": "github"
+      },
+      "original": {
+        "owner": "nix-systems",
+        "repo": "default",
+        "type": "github"
+      }
+    },
+    "uv2nix": {
+      "inputs": {
+        "nixpkgs": [
+          "nixpkgs"
+        ],
+        "pyproject-nix": [
+          "pyproject-nix"
+        ]
+      },
+      "locked": {
+        "lastModified": 1759917780,
+        "narHash": "sha256-2cwD6my+D+RELgv0czBCnx+y77Raj++4ku8unX/WZAI=",
+        "owner": "pyproject-nix",
+        "repo": "uv2nix",
+        "rev": "a529973358dae46fac521a5f0fa97f5f327f9f7e",
+        "type": "github"
+      },
+      "original": {
+        "owner": "pyproject-nix",
+        "repo": "uv2nix",
+        "type": "github"
+      }
+    }
+  },
+  "root": "root",
+  "version": 7
+}
diff --git a/flake.nix b/flake.nix
new file mode 100644
index 00000000..89818257
--- /dev/null
+++ b/flake.nix
@@ -0,0 +1,187 @@
+{
+	description = "Focaccia: A Symbolic Tester for QEMU";
+
+	inputs = {
+		self.submodules = true;
+
+		nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
+
+		flake-utils.url = "github:numtide/flake-utils";
+
+		pyproject-nix = {
+			url = "github:pyproject-nix/pyproject.nix";
+			inputs.nixpkgs.follows = "nixpkgs";
+		};
+
+		uv2nix = {
+			url = "github:pyproject-nix/uv2nix";
+			inputs.nixpkgs.follows = "nixpkgs";
+			inputs.pyproject-nix.follows = "pyproject-nix";
+		};
+
+		pyproject-build-systems = {
+			url = "github:pyproject-nix/build-system-pkgs";
+			inputs.uv2nix.follows = "uv2nix";
+			inputs.nixpkgs.follows = "nixpkgs";
+			inputs.pyproject-nix.follows = "pyproject-nix";
+		};
+	};
+
+	outputs = {
+		uv2nix,
+		nixpkgs,
+		flake-utils,
+		pyproject-nix,
+		pyproject-build-systems,
+		...
+	}:
+	flake-utils.lib.eachSystem [ "x86_64-linux" "aarch64-linux" "aarch64-darwin" ] (system:
+	let
+		# Refine nixpkgs used in flake to system arch
+		pkgs = import nixpkgs {
+			inherit system;
+		};
+
+		# Pin Python version
+		python = pkgs.python312;
+
+		# Define workspace root and load uv workspace metadata
+		workspace = uv2nix.lib.workspace.loadWorkspace { workspaceRoot = ./.; };
+
+		# Create an overlay for Nix that includes extracted Python packages declared as dependencies
+		# in uv
+		overlay = workspace.mkPyprojectOverlay { sourcePreference = "wheel"; };
+
+		editableOverlay = workspace.mkEditablePyprojectOverlay {
+			# Use environment variable
+			root = "$REPO_ROOT";
+
+			members = [ "miasm" ];
+		};
+
+		# Another overlay layer for flake-specific overloads
+		# This might be needed because uv does not have sufficient metadata
+		# Here, uv does include metadata about build systems used by each dependency
+		# Ergo we need to add a nativeBuildInput to miasm because it depends on setuptools for its
+		# installation
+		pyprojectOverrides = self: super: {
+			miasm = super.miasm.overrideAttrs (old: {
+				nativeBuildInputs = (old.nativeBuildInputs or []) ++ [ self.setuptools ];
+			});
+
+			z3-solver = super.z3-solver.overrideAttrs (old: {
+				nativeBuildInputs = (old.nativeBuildInputs or []) ++ [ self.setuptools self.cmake ];
+			});
+		};
+
+		pyprojectOverridesEditable = self: super: {
+			miasm = super.miasm.overrideAttrs (old: {
+				nativeBuildInputs = (old.nativeBuildInputs or []) ++ [ self.setuptools ];
+
+				src = pkgs.lib.fileset.toSource {
+					root = old.src;
+					fileset = pkgs.lib.fileset.unions [
+						(old.src + "/pyproject.toml")
+						(old.src + "/README.md")
+						(old.src + "/miasm/__init__.py")
+					];
+				};
+			});
+
+			z3-solver = super.z3-solver.overrideAttrs (old: {
+				nativeBuildInputs = (old.nativeBuildInputs or []) ++ [ self.setuptools self.cmake ];
+			});
+		};
+
+		# Build a set of Python packages
+		# The call to callPackage here uses the base package set from pyproject.nix
+		# We inherit the Python version to ensure that the packages have the same version
+		#
+		# The overrideScope here customizes the Python package set with an overlay defined by the
+		# composition of three overlay functions
+		pythonSet = (pkgs.callPackage pyproject-nix.build.packages { inherit python; }).
+					 overrideScope (pkgs.lib.composeManyExtensions [
+						 pyproject-build-systems.overlays.default
+						 overlay
+						 pyprojectOverrides 
+					 ]);
+
+		pythonSetEditable = pythonSet.overrideScope (
+			pkgs.lib.composeManyExtensions [
+				editableOverlay
+				pyprojectOverridesEditable
+			]
+		);
+
+		 # Create a Python venv with the default dependency group
+		 pythonEnv = pythonSet.mkVirtualEnv "miasm-env" workspace.deps.default;
+
+		 # Create a Python venv with the default dependency group
+		 pythonDevEnv = pythonSetEditable.mkVirtualEnv "miasm-env" workspace.deps.all;
+
+		 uvEnv = {
+			UV_NO_SYNC = "1";
+			UV_PYTHON = python.interpreter;
+			UV_PYTHON_DOWNLOADS = "never";
+		};
+
+		uvShellHook = ''
+			unset PYTHONPATH
+
+			export REPO_ROOT=$(git rev-parse --show-toplevel)
+		'';
+	in rec {
+		# Default package just builds Focaccia
+		packages = rec {
+			miasm = pythonEnv;
+
+			dev = pythonDevEnv.overrideAttrs (old: {
+				propagatedBuildInputs = (old.propagatedBuildInputs or []) ++ [ 
+					pkgs.uv
+				];
+			});
+
+			default = miasm;
+		};
+
+		devShells = {
+			default = pkgs.mkShell {
+				packages = [ packages.dev ];
+
+				env = uvEnv;
+				shellHook = uvShellHook;
+			};
+			
+			basic = pkgs.mkShell {
+				packages = [ pkgs.uv packages.miasm ];
+
+				env = uvEnv;
+				shellHook = uvShellHook;
+			};
+		};
+
+		# TODO
+		checks = {
+			miasm-tests = pkgs.stdenv.mkDerivation {
+				name = "miasm-tests";
+				src = ./.;
+
+				doCheck = true;
+				dontBuild = true;
+
+				nativeCheckInputs = [ packages.dev pythonDevEnv ];
+
+				checkPhase = ''
+					set -euo pipefail
+					export REPO_ROOT="$PWD"
+					${packages.dev}/bin/python -m 'pytest' -q tests
+					touch $out
+				'';
+
+				env = uvEnv;
+				shellHook = uvShellHook;
+			};
+		};
+	});
+}
+
diff --git a/pyproject.toml b/pyproject.toml
index 196a4fbc..26a85c33 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,16 +1,195 @@
 [project]
 name = "miasm"
-version = "0.1.4"
+version = "0.1.5"
+license = "GPL-2.0"
 requires-python = "==3.12.*"
-description = "Reverse engineering framework in Python"
+description = "Machine code manipulation library"
 readme = {file = "README.md", content-type = "text/markdown"}
+
+authors = [{ name = "Fabrice Desclaux", email = "serpilliere@droid-corp.org" },
+		   { name = "Theofilos Augoustis", email = "theofilos.augoustis@tum.de" },
+		   { name = "Christian Krinitsin", email = "christian.krinitsin@tum.de" }]
+
 dependencies = [
 	"future",
-	"pyparsing",
-	"setuptools",
+	"pyparsing>=2.4.1",
+]
+
+keywords = [
+	"reverse engineering",
+	"disassembler",
+	"emulator",
+	"symbolic execution",
+	"intermediate representation",
+	"assembler",
+]
+
+classifiers=[
+	"Programming Language :: Python :: 2",
+	"Programming Language :: Python :: 3",
+	"Programming Language :: Python :: 2.7",
+	"Programming Language :: Python :: 3.6",
+]
+
+[project.urls]
+Homepage = "http://miasm.re"
+
+[project.optional-dependencies]
+dev = [
+	"llvmlite",
+	"pycparser",
+	"z3-solver",
+	"parameterized"
 ]
 
 [build-system]
 requires = ["setuptools", "wheel"]
 build-backend = "setuptools.build_meta"
 
+[tool.setuptools.packages.find]
+where = ["."]
+include = ["miasm*"]
+
+[tool.setuptools.package-data]
+miasm = ["jitter/*.h", "jitter/arch/*.h", "runtime/*.h", "VERSION"]
+
+# setuptools >= 74.1
+[tool.setuptools]
+include-package-data = true
+
+[[tool.setuptools.ext-modules]]
+name = "miasm.jitter.VmMngr"
+optional = true
+sources = [
+  "miasm/jitter/vm_mngr.c",
+  "miasm/jitter/vm_mngr_py.c",
+  "miasm/jitter/bn.c",
+]
+
+[[tool.setuptools.ext-modules]]
+name = "miasm.jitter.arch.JitCore_x86"
+optional = true
+sources = [
+  "miasm/jitter/JitCore.c",
+  "miasm/jitter/vm_mngr.c",
+  "miasm/jitter/vm_mngr_py.c",
+  "miasm/jitter/op_semantics.c",
+  "miasm/jitter/bn.c",
+  "miasm/jitter/arch/JitCore_x86.c",
+]
+
+[[tool.setuptools.ext-modules]]
+name = "miasm.jitter.arch.JitCore_arm"
+optional = true
+sources = [
+  "miasm/jitter/JitCore.c",
+  "miasm/jitter/vm_mngr.c",
+  "miasm/jitter/vm_mngr_py.c",
+  "miasm/jitter/op_semantics.c",
+  "miasm/jitter/bn.c",
+  "miasm/jitter/arch/JitCore_arm.c",
+]
+
+[[tool.setuptools.ext-modules]]
+name = "miasm.jitter.arch.JitCore_aarch64"
+optional = true
+sources = [
+  "miasm/jitter/JitCore.c",
+  "miasm/jitter/vm_mngr.c",
+  "miasm/jitter/vm_mngr_py.c",
+  "miasm/jitter/op_semantics.c",
+  "miasm/jitter/bn.c",
+  "miasm/jitter/arch/JitCore_aarch64.c",
+]
+
+[[tool.setuptools.ext-modules]]
+name = "miasm.jitter.arch.JitCore_msp430"
+optional = true
+sources = [
+  "miasm/jitter/JitCore.c",
+  "miasm/jitter/vm_mngr.c",
+  "miasm/jitter/vm_mngr_py.c",
+  "miasm/jitter/op_semantics.c",
+  "miasm/jitter/bn.c",
+  "miasm/jitter/arch/JitCore_msp430.c",
+]
+
+[[tool.setuptools.ext-modules]]
+name = "miasm.jitter.arch.JitCore_mep"
+optional = true
+sources = [
+  "miasm/jitter/JitCore.c",
+  "miasm/jitter/vm_mngr.c",
+  "miasm/jitter/vm_mngr_py.c",
+  "miasm/jitter/op_semantics.c",
+  "miasm/jitter/bn.c",
+  "miasm/jitter/arch/JitCore_mep.c",
+]
+
+[[tool.setuptools.ext-modules]]
+name = "miasm.jitter.arch.JitCore_mips32"
+optional = true
+sources = [
+  "miasm/jitter/JitCore.c",
+  "miasm/jitter/vm_mngr.c",
+  "miasm/jitter/vm_mngr_py.c",
+  "miasm/jitter/op_semantics.c",
+  "miasm/jitter/bn.c",
+  "miasm/jitter/arch/JitCore_mips32.c",
+]
+
+[[tool.setuptools.ext-modules]]
+name = "miasm.jitter.arch.JitCore_ppc32"
+optional = true
+sources = [
+  "miasm/jitter/JitCore.c",
+  "miasm/jitter/vm_mngr.c",
+  "miasm/jitter/vm_mngr_py.c",
+  "miasm/jitter/op_semantics.c",
+  "miasm/jitter/bn.c",
+  "miasm/jitter/arch/JitCore_ppc32.c",
+]
+depends = [
+  "miasm/jitter/arch/JitCore_ppc32.h",
+  "miasm/jitter/arch/JitCore_ppc32_regs.h",
+  "miasm/jitter/bn.h",
+]
+
+[[tool.setuptools.ext-modules]]
+name = "miasm.jitter.arch.JitCore_m68k"
+optional = true
+sources = [
+  "miasm/jitter/JitCore.c",
+  "miasm/jitter/vm_mngr.c",
+  "miasm/jitter/vm_mngr_py.c",
+  "miasm/jitter/op_semantics.c",
+  "miasm/jitter/bn.c",
+  "miasm/jitter/arch/JitCore_m68k.c",
+]
+
+[[tool.setuptools.ext-modules]]
+name = "miasm.jitter.Jitllvm"
+optional = true
+sources = [
+  "miasm/jitter/Jitllvm.c",
+  "miasm/jitter/bn.c",
+  "miasm/runtime/udivmodti4.c",
+  "miasm/runtime/divti3.c",
+  "miasm/runtime/udivti3.c",
+]
+depends = [
+  "miasm/runtime/export.h",
+  "miasm/runtime/int_endianness.h",
+  "miasm/runtime/int_lib.h",
+  "miasm/runtime/int_types.h",
+  "miasm/runtime/int_util.h",
+]
+
+[[tool.setuptools.ext-modules]]
+name = "miasm.jitter.Jitgcc"
+optional = true
+sources = [
+  "miasm/jitter/Jitgcc.c",
+  "miasm/jitter/bn.c",
+]
+
diff --git a/setup.py b/setup.py
deleted file mode 100644
index 3cc7b5a5..00000000
--- a/setup.py
+++ /dev/null
@@ -1,436 +0,0 @@
-#! /usr/bin/env python2
-
-from __future__ import print_function
-# Reference: https://stackoverflow.com/a/13468644/1806760
-from setuptools import setup, Extension
-from distutils.util import get_platform
-from distutils.sysconfig import get_python_lib, get_config_vars
-from distutils.dist import DistributionMetadata
-from distutils.command.install_data import install_data
-import subprocess
-from tempfile import TemporaryFile
-import fnmatch
-import io
-import os
-import platform
-from shutil import copy2, copyfile, rmtree, which
-import sys
-import tempfile
-import atexit
-import re
-
-is_win = platform.system() == "Windows"
-is_mac = platform.system() == "Darwin"
-is_64bit = platform.architecture()[0] == "64bit"
-if is_win:
-    import winreg
-
-def set_extension_compile_args(extension):
-    rel_lib_path = extension.name.replace(".", "/")
-    abs_lib_path = os.path.join(get_python_lib(), rel_lib_path)
-    lib_name = abs_lib_path + ".so"
-    extension.extra_link_args = [ "-Wl,-install_name," + lib_name]
-
-class smart_install_data(install_data):
-    """Replacement for distutils.command.install_data to handle
-    configuration files location.
-    """
-    def run(self):
-        # install files to /etc when target was /usr(/local)/etc
-        self.data_files = [
-            (path, files) for path, files in self.data_files
-            if path  # skip README.md or any file with an empty path
-        ]
-        return install_data.run(self)
-
-def win_get_llvm_reg():
-    REG_PATH = "SOFTWARE\\LLVM\\LLVM"
-    try:
-      return winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, REG_PATH, 0, winreg.KEY_READ | winreg.KEY_WOW64_32KEY)
-    except FileNotFoundError:
-      pass
-    return winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, REG_PATH, 0, winreg.KEY_READ)
-
-def win_find_clang_path():
-    try:
-        with win_get_llvm_reg() as rkey:
-            return winreg.QueryValueEx(rkey, None)[0]
-    except FileNotFoundError:
-        # Visual Studio ships with an optional Clang distribution, try to detect it
-        clang_cl = which("clang-cl")
-        if clang_cl is None:
-            return None
-        return os.path.abspath(os.path.join(os.path.dirname(clang_cl), "..", ".."))
-
-def win_get_clang_version(clang_path):
-    try:
-        clang_cl = os.path.join(clang_path, "bin", "clang.exe")
-        stdout = subprocess.check_output("\"{}\" --version".format(clang_cl))
-        version = stdout.splitlines(False)[0].decode()
-        match = re.search(r"version (\d+\.\d+\.\d+)", version)
-        if match is None:
-            return None
-        version = list(map(lambda s: int(s), match.group(1).split(".")))
-        return version
-    except FileNotFoundError:
-        return None
-
-def win_use_clang():
-    # To force python to use clang we copy the binaries in a temporary directory that's added to the PATH.
-    # We could use the build directory created by distutils for this, but it seems non-trivial to gather
-    # (https://stackoverflow.com/questions/12896367/reliable-way-to-get-the-build-directory-from-within-setup-py).
-
-    clang_path = win_find_clang_path()
-    if clang_path is None:
-        return False
-    clang_version = win_get_clang_version(clang_path)
-    if clang_version is None:
-        return False
-    tmpdir = tempfile.mkdtemp(prefix="llvm")
-
-    copyfile(os.path.join(clang_path, "bin", "clang-cl.exe"), os.path.join(tmpdir, "cl.exe"))
-
-    # If you run the installation from a Visual Studio command prompt link.exe will already exist
-    # Fall back to LLVM's lld-link.exe which is compatible with link's command line
-    if True:#which("link") is None:
-        # LLVM >= 14.0.0 started supporting the /LTCG flag
-        # Earlier versions will error during the linking phase so bail out now
-        if clang_version[0] < 14:
-            return False
-        copyfile(os.path.join(clang_path, "bin", "lld-link.exe"), os.path.join(tmpdir, "link.exe"))
-
-    # Add the temporary directory at the front of the PATH and clean up on exit
-    os.environ["PATH"] = "%s;%s" % (tmpdir, os.environ["PATH"])
-    atexit.register(lambda dir_: rmtree(dir_), tmpdir)
-    print("Found Clang {}.{}.{}: {}".format(clang_version[0], clang_version[1], clang_version[2], clang_path))
-    return True
-
-build_extensions = True
-build_warnings = []
-win_force_clang = False
-if is_win:
-    if is_64bit or which("cl") is None:
-        # We do not change to clang if under 32 bits, because even with Clang we
-        # do not use uint128_t with the 32 bits ABI. Regardless we can try to
-        # find it when building in 32-bit mode if cl.exe was not found in the PATH.
-        win_force_clang = win_use_clang()
-        if is_64bit and not win_force_clang:
-            build_warnings.append("Could not find a suitable Clang/LLVM installation. You can download LLVM from https://releases.llvm.org")
-            build_warnings.append("Alternatively you can select the 'C++ Clang-cl build tools' in the Visual Studio Installer")
-            build_extensions = False
-    cl = which("cl")
-    link = which("link")
-    if cl is None or link is None:
-        build_warnings.append("Could not find cl.exe and/or link.exe in the PATH, try building miasm from a Visual Studio command prompt")
-        build_warnings.append("More information at: https://wiki.python.org/moin/WindowsCompilers")
-        build_extensions = False
-    else:
-        print("Found cl.exe: {}".format(cl))
-        print("Found link.exe: {}".format(link))
-
-def build_all():
-    packages=[
-        "miasm",
-        "miasm/arch",
-        "miasm/arch/x86",
-        "miasm/arch/arm",
-        "miasm/arch/aarch64",
-        "miasm/arch/msp430",
-        "miasm/arch/mep",
-        "miasm/arch/sh4",
-        "miasm/arch/mips32",
-        "miasm/arch/ppc",
-        "miasm/core",
-        "miasm/expression",
-        "miasm/ir",
-        "miasm/ir/translators",
-        "miasm/analysis",
-        "miasm/os_dep",
-        "miasm/os_dep/linux",
-        "miasm/loader",
-        "miasm/jitter",
-        "miasm/jitter/arch",
-        "miasm/jitter/loader",
-    ]
-    ext_modules_all = [
-        Extension(
-            "miasm.jitter.VmMngr",
-            [
-                "miasm/jitter/vm_mngr.c",
-                "miasm/jitter/vm_mngr_py.c",
-                "miasm/jitter/bn.c",
-            ]
-        ),
-        Extension(
-            "miasm.jitter.arch.JitCore_x86",
-            [
-                "miasm/jitter/JitCore.c",
-                "miasm/jitter/vm_mngr.c",
-                "miasm/jitter/vm_mngr_py.c",
-                "miasm/jitter/op_semantics.c",
-                "miasm/jitter/bn.c",
-                "miasm/jitter/arch/JitCore_x86.c"
-            ]
-        ),
-        Extension(
-            "miasm.jitter.arch.JitCore_arm",
-            [
-                "miasm/jitter/JitCore.c",
-                "miasm/jitter/vm_mngr.c",
-                "miasm/jitter/vm_mngr_py.c",
-                "miasm/jitter/op_semantics.c",
-                "miasm/jitter/bn.c",
-                "miasm/jitter/arch/JitCore_arm.c"
-            ]
-        ),
-        Extension(
-            "miasm.jitter.arch.JitCore_aarch64",
-            [
-                "miasm/jitter/JitCore.c",
-                "miasm/jitter/vm_mngr.c",
-                "miasm/jitter/vm_mngr_py.c",
-                "miasm/jitter/op_semantics.c",
-                "miasm/jitter/bn.c",
-                "miasm/jitter/arch/JitCore_aarch64.c"
-            ]
-        ),
-        Extension(
-            "miasm.jitter.arch.JitCore_msp430",
-            [
-                "miasm/jitter/JitCore.c",
-                "miasm/jitter/vm_mngr.c",
-                "miasm/jitter/vm_mngr_py.c",
-                "miasm/jitter/op_semantics.c",
-                "miasm/jitter/bn.c",
-                "miasm/jitter/arch/JitCore_msp430.c"
-            ]
-        ),
-        Extension(
-            "miasm.jitter.arch.JitCore_mep",
-            [
-                "miasm/jitter/JitCore.c",
-                "miasm/jitter/vm_mngr.c",
-                "miasm/jitter/vm_mngr_py.c",
-                "miasm/jitter/bn.c",
-                "miasm/jitter/arch/JitCore_mep.c"
-            ]
-        ),
-        Extension(
-            "miasm.jitter.arch.JitCore_mips32",
-            [
-                "miasm/jitter/JitCore.c",
-                "miasm/jitter/vm_mngr.c",
-                "miasm/jitter/vm_mngr_py.c",
-                "miasm/jitter/op_semantics.c",
-                "miasm/jitter/bn.c",
-                "miasm/jitter/arch/JitCore_mips32.c"
-            ]
-        ),
-        Extension(
-            "miasm.jitter.arch.JitCore_ppc32",
-            [
-                "miasm/jitter/JitCore.c",
-                "miasm/jitter/vm_mngr.c",
-                "miasm/jitter/vm_mngr_py.c",
-                "miasm/jitter/op_semantics.c",
-                "miasm/jitter/bn.c",
-                "miasm/jitter/arch/JitCore_ppc32.c"
-            ],
-            depends=[
-                "miasm/jitter/arch/JitCore_ppc32.h",
-                "miasm/jitter/arch/JitCore_ppc32_regs.h",
-                "miasm/jitter/bn.h",
-            ]
-        ),
-        Extension(
-            "miasm.jitter.arch.JitCore_m68k",
-            [
-                "miasm/jitter/JitCore.c",
-                "miasm/jitter/vm_mngr.c",
-                "miasm/jitter/vm_mngr_py.c",
-                "miasm/jitter/op_semantics.c",
-                "miasm/jitter/bn.c",
-                "miasm/jitter/arch/JitCore_m68k.c"
-            ]
-        ),
-        Extension(
-            "miasm.jitter.Jitllvm",
-            [
-                "miasm/jitter/Jitllvm.c",
-                "miasm/jitter/bn.c",
-                "miasm/runtime/udivmodti4.c",
-                "miasm/runtime/divti3.c",
-                "miasm/runtime/udivti3.c"
-            ],
-            depends=[
-                "miasm/runtime/export.h",
-                "miasm/runtime/int_endianness.h",
-                "miasm/runtime/int_lib.h",
-                "miasm/runtime/int_types.h",
-                "miasm/runtime/int_util.h",
-            ]
-        ),
-        Extension("miasm.jitter.Jitgcc",
-                  ["miasm/jitter/Jitgcc.c",
-                   "miasm/jitter/bn.c",
-                  ]),
-        ]
-
-    if is_win:
-        # Force setuptools to use whatever msvc version installed
-        # https://docs.python.org/3/distutils/apiref.html#module-distutils.msvccompiler
-        os.environ["MSSdk"] = "1"
-        os.environ["DISTUTILS_USE_SDK"] = "1"
-        extra_compile_args = ["-D_CRT_SECURE_NO_WARNINGS"]
-        if win_force_clang:
-            march = "-m64" if is_64bit else "-m32"
-            extra_compile_args += [
-                march,
-                "-Wno-unused-command-line-argument",
-                "-Wno-visibility",
-                "-Wno-dll-attribute-on-redeclaration",
-                "-Wno-tautological-compare",
-                "-Wno-unused-but-set-variable",
-            ]
-        for extension in ext_modules_all:
-            extension.extra_compile_args = extra_compile_args
-    elif is_mac:
-        for extension in ext_modules_all:
-            set_extension_compile_args(extension)
-        cfg_vars = get_config_vars()
-        cfg_vars["LDSHARED"] = cfg_vars["LDSHARED"].replace("-bundle", "-dynamiclib")
-
-    # Do not attempt to build the extensions when disabled
-    if not build_extensions:
-        ext_modules_all = []
-
-    print("building")
-    if not os.path.exists("build"):
-        os.mkdir("build")
-    build_ok = False
-    for name, ext_modules in [("all", ext_modules_all)]:
-        print("build with", repr(name))
-        try:
-            s = setup(
-                name = "miasm",
-                version = "0.1.5",
-                packages = packages,
-                data_files=[("", ["README.md"])],
-                package_data = {
-                    "miasm": [
-                        "jitter/*.h",
-                        "jitter/arch/*.h",
-                        "runtime/*.h",
-                        "VERSION"
-                    ]
-                },
-                install_requires=["future", "pyparsing>=2.4.1"],
-                cmdclass={"install_data": smart_install_data},
-                ext_modules = ext_modules,
-                # Metadata
-                author = "Fabrice Desclaux",
-                author_email = "serpilliere@droid-corp.org",
-                description = "Machine code manipulation library",
-                license = "GPLv2",
-                long_description=long_description,
-                long_description_content_type=long_description_content_type,
-                keywords = [
-                    "reverse engineering",
-                    "disassembler",
-                    "emulator",
-                    "symbolic execution",
-                    "intermediate representation",
-                    "assembler",
-                ],
-                classifiers=[
-                    "Programming Language :: Python :: 2",
-                    "Programming Language :: Python :: 3",
-                    "Programming Language :: Python :: 2.7",
-                    "Programming Language :: Python :: 3.6",
-                ],
-                url = "http://miasm.re",
-            )
-        except SystemExit as e:
-            print(repr(e))
-            continue
-        build_ok = True
-        break
-    if not build_ok:
-        if len(build_warnings) > 0:
-            print("ERROR: There was an issue setting up the build environment:")
-            for warning in build_warnings:
-                print("  " + warning)
-        raise ValueError("Unable to build Miasm!")
-    print("build", name)
-    # we copy libraries from build dir to current miasm directory
-    build_base = "build"
-    if "build" in s.command_options:
-        if "build_base" in s.command_options["build"]:
-            build_base = s.command_options["build"]["build_base"]
-
-    print(build_base)
-    if is_win and build_extensions:
-        libs = []
-        for root, _, files in os.walk(build_base):
-            for filename in files:
-                if not filename.endswith(".lib"):
-                    continue
-                f_path = os.path.join(root, filename)
-                libs.append(f_path)
-
-        lib_dirname = None
-        for dirname in os.listdir(build_base):
-            if not dirname.startswith("lib"):
-                continue
-            lib_dirname = dirname
-            break
-
-        jitters = []
-        for lib in libs:
-            filename = os.path.basename(lib)
-            dst = os.path.join(build_base, lib_dirname, "miasm", "jitter")
-            # Windows built libraries may have a name like VmMngr.cp38-win_amd64.lib
-            if not any([fnmatch.fnmatch(filename, pattern) for pattern in ["VmMngr.*lib", "Jitgcc.*lib", "Jitllvm.*lib"]]):
-                dst = os.path.join(dst, "arch")
-            dst = os.path.join(dst, filename)
-            if not os.path.isfile(dst):
-                print("Copying", lib, "to", dst)
-                copy2(lib, dst)
-
-    # Inform the user about the skipped build
-    if not build_extensions:
-        print("WARNING: miasm jit extensions were not compiled, details:")
-        for warning in build_warnings:
-            print("  " + warning)
-
-with io.open(os.path.join(os.path.abspath(os.path.dirname("__file__")),
-                       "README.md"), encoding="utf-8") as fdesc:
-    long_description = fdesc.read()
-long_description_content_type = "text/markdown"
-
-
-# Monkey patching (distutils does not handle Description-Content-Type
-# from long_description_content_type parameter in setup()).
-_write_pkg_file_orig = DistributionMetadata.write_pkg_file
-
-
-def _write_pkg_file(self, file):
-    with TemporaryFile(mode="w+", encoding="utf-8") as tmpfd:
-        _write_pkg_file_orig(self, tmpfd)
-        tmpfd.seek(0)
-        for line in tmpfd:
-            if line.startswith("Metadata-Version: "):
-                file.write("Metadata-Version: 2.1\n")
-            elif line.startswith("Description: "):
-                file.write("Description-Content-Type: %s; charset=UTF-8\n" %
-                           long_description_content_type)
-                file.write(line)
-            else:
-                file.write(line)
-
-
-DistributionMetadata.write_pkg_file = _write_pkg_file
-
-
-build_all()
-
diff --git a/uv.lock b/uv.lock
new file mode 100644
index 00000000..459a136d
--- /dev/null
+++ b/uv.lock
@@ -0,0 +1,94 @@
+version = 1
+revision = 2
+requires-python = "==3.12.*"
+
+[[package]]
+name = "future"
+version = "1.0.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/a7/b2/4140c69c6a66432916b26158687e821ba631a4c9273c474343badf84d3ba/future-1.0.0.tar.gz", hash = "sha256:bd2968309307861edae1458a4f8a4f3598c03be43b97521076aebf5d94c07b05", size = 1228490, upload-time = "2024-02-21T11:52:38.461Z" }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/da/71/ae30dadffc90b9006d77af76b393cb9dfbfc9629f339fc1574a1c52e6806/future-1.0.0-py3-none-any.whl", hash = "sha256:929292d34f5872e70396626ef385ec22355a1fae8ad29e1a734c3e43f9fbc216", size = 491326, upload-time = "2024-02-21T11:52:35.956Z" },
+]
+
+[[package]]
+name = "llvmlite"
+version = "0.45.1"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/99/8d/5baf1cef7f9c084fb35a8afbde88074f0d6a727bc63ef764fe0e7543ba40/llvmlite-0.45.1.tar.gz", hash = "sha256:09430bb9d0bb58fc45a45a57c7eae912850bedc095cd0810a57de109c69e1c32", size = 185600, upload-time = "2025-10-01T17:59:52.046Z" }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/e2/7c/82cbd5c656e8991bcc110c69d05913be2229302a92acb96109e166ae31fb/llvmlite-0.45.1-cp312-cp312-macosx_10_15_x86_64.whl", hash = "sha256:28e763aba92fe9c72296911e040231d486447c01d4f90027c8e893d89d49b20e", size = 43043524, upload-time = "2025-10-01T18:03:30.666Z" },
+    { url = "https://files.pythonhosted.org/packages/9d/bc/5314005bb2c7ee9f33102c6456c18cc81745d7055155d1218f1624463774/llvmlite-0.45.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1a53f4b74ee9fd30cb3d27d904dadece67a7575198bd80e687ee76474620735f", size = 37253123, upload-time = "2025-10-01T18:04:18.177Z" },
+    { url = "https://files.pythonhosted.org/packages/96/76/0f7154952f037cb320b83e1c952ec4a19d5d689cf7d27cb8a26887d7bbc1/llvmlite-0.45.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:5b3796b1b1e1c14dcae34285d2f4ea488402fbd2c400ccf7137603ca3800864f", size = 56288211, upload-time = "2025-10-01T18:01:24.079Z" },
+    { url = "https://files.pythonhosted.org/packages/00/b1/0b581942be2683ceb6862d558979e87387e14ad65a1e4db0e7dd671fa315/llvmlite-0.45.1-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:779e2f2ceefef0f4368548685f0b4adde34e5f4b457e90391f570a10b348d433", size = 55140958, upload-time = "2025-10-01T18:02:30.482Z" },
+    { url = "https://files.pythonhosted.org/packages/33/94/9ba4ebcf4d541a325fd8098ddc073b663af75cc8b065b6059848f7d4dce7/llvmlite-0.45.1-cp312-cp312-win_amd64.whl", hash = "sha256:9e6c9949baf25d9aa9cd7cf0f6d011b9ca660dd17f5ba2b23bdbdb77cc86b116", size = 38132231, upload-time = "2025-10-01T18:05:03.664Z" },
+]
+
+[[package]]
+name = "miasm"
+version = "0.1.5"
+source = { editable = "." }
+dependencies = [
+    { name = "future" },
+    { name = "pyparsing" },
+]
+
+[package.optional-dependencies]
+dev = [
+    { name = "llvmlite" },
+    { name = "parameterized" },
+    { name = "pycparser" },
+    { name = "z3-solver" },
+]
+
+[package.metadata]
+requires-dist = [
+    { name = "future" },
+    { name = "llvmlite", marker = "extra == 'dev'" },
+    { name = "parameterized", marker = "extra == 'dev'" },
+    { name = "pycparser", marker = "extra == 'dev'" },
+    { name = "pyparsing", specifier = ">=2.4.1" },
+    { name = "z3-solver", marker = "extra == 'dev'" },
+]
+provides-extras = ["dev"]
+
+[[package]]
+name = "parameterized"
+version = "0.9.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/ea/49/00c0c0cc24ff4266025a53e41336b79adaa5a4ebfad214f433d623f9865e/parameterized-0.9.0.tar.gz", hash = "sha256:7fc905272cefa4f364c1a3429cbbe9c0f98b793988efb5bf90aac80f08db09b1", size = 24351, upload-time = "2023-03-27T02:01:11.592Z" }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/00/2f/804f58f0b856ab3bf21617cccf5b39206e6c4c94c2cd227bde125ea6105f/parameterized-0.9.0-py2.py3-none-any.whl", hash = "sha256:4e0758e3d41bea3bbd05ec14fc2c24736723f243b28d702081aef438c9372b1b", size = 20475, upload-time = "2023-03-27T02:01:09.31Z" },
+]
+
+[[package]]
+name = "pycparser"
+version = "2.23"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/fe/cf/d2d3b9f5699fb1e4615c8e32ff220203e43b248e1dfcc6736ad9057731ca/pycparser-2.23.tar.gz", hash = "sha256:78816d4f24add8f10a06d6f05b4d424ad9e96cfebf68a4ddc99c65c0720d00c2", size = 173734, upload-time = "2025-09-09T13:23:47.91Z" }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/a0/e3/59cd50310fc9b59512193629e1984c1f95e5c8ae6e5d8c69532ccc65a7fe/pycparser-2.23-py3-none-any.whl", hash = "sha256:e5c6e8d3fbad53479cab09ac03729e0a9faf2bee3db8208a550daf5af81a5934", size = 118140, upload-time = "2025-09-09T13:23:46.651Z" },
+]
+
+[[package]]
+name = "pyparsing"
+version = "3.2.5"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/f2/a5/181488fc2b9d093e3972d2a472855aae8a03f000592dbfce716a512b3359/pyparsing-3.2.5.tar.gz", hash = "sha256:2df8d5b7b2802ef88e8d016a2eb9c7aeaa923529cd251ed0fe4608275d4105b6", size = 1099274, upload-time = "2025-09-21T04:11:06.277Z" }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/10/5e/1aa9a93198c6b64513c9d7752de7422c06402de6600a8767da1524f9570b/pyparsing-3.2.5-py3-none-any.whl", hash = "sha256:e38a4f02064cf41fe6593d328d0512495ad1f3d8a91c4f73fc401b3079a59a5e", size = 113890, upload-time = "2025-09-21T04:11:04.117Z" },
+]
+
+[[package]]
+name = "z3-solver"
+version = "4.15.3.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/a3/60/9a924ee28cd1d12f2482834581d9024bf05110aa1098c056e847f05f7f76/z3_solver-4.15.3.0.tar.gz", hash = "sha256:78f69aebda5519bfd8af146a129f36cf4721a3c2667e80d9fe35cc9bb4d214a6", size = 4985945, upload-time = "2025-08-16T02:27:37.706Z" }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/63/45/dd8e9d7500faa05eafa589cc8f0f0b982ce575d51b455d62dab8e19dd571/z3_solver-4.15.3.0-py3-none-macosx_13_0_arm64.whl", hash = "sha256:65335aab295ded7c0ce27c85556067087a87052389ff160777d1a1d48ef0d74f", size = 36882388, upload-time = "2025-08-16T02:27:18.721Z" },
+    { url = "https://files.pythonhosted.org/packages/54/9e/a11186061d9fead8be43bad7c75055585694124b2ccdd896ef249fe5824f/z3_solver-4.15.3.0-py3-none-macosx_13_0_x86_64.whl", hash = "sha256:3e62e93adff2def3537ff1ca67c3d58a6ca6d1944e0b5e774f88627b199d50e7", size = 39637842, upload-time = "2025-08-16T02:27:22.177Z" },
+    { url = "https://files.pythonhosted.org/packages/b9/0b/f15168475e5493ea44fa3c5e642903f05d2b870db71ad05662ed87a06976/z3_solver-4.15.3.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a9afd9ceb290482097474d43f08415bcc1874f433189d1449f6c1508e9c68384", size = 29056003, upload-time = "2025-08-16T02:27:27.951Z" },
+    { url = "https://files.pythonhosted.org/packages/a7/04/32a97b1f04175ec56213168ee3659709e876e3feacacb891ed3c26c1a82c/z3_solver-4.15.3.0-py3-none-manylinux_2_34_aarch64.whl", hash = "sha256:f61ef44552489077eedd7e6d9bed52ef1875decf86d66027742099a2703b1c77", size = 27074143, upload-time = "2025-08-16T02:27:30.755Z" },
+    { url = "https://files.pythonhosted.org/packages/75/77/da54076a584557ea34f20800c68f725fe61f1dd987493fcb410b4a26f99f/z3_solver-4.15.3.0-py3-none-win32.whl", hash = "sha256:0c603f6bad7423d6411adda6af55030b725e3d30f54ea91b714abcedd73b848a", size = 13123666, upload-time = "2025-08-16T02:27:33.309Z" },
+    { url = "https://files.pythonhosted.org/packages/c1/59/abc1bad8b25e9c576484ba65ca5ed225c8ed24d601ec242712f1c370b693/z3_solver-4.15.3.0-py3-none-win_amd64.whl", hash = "sha256:06abdf6c36f97c463aea827533504fd59476d015a65cf170a88bd6a53ba13ab5", size = 16203065, upload-time = "2025-08-16T02:27:35.763Z" },
+]