hatch-cpp 0.0.0__tar.gz → 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,164 @@
1
+ # Byte-compiled / optimized / DLL files
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+
6
+ # C extensions
7
+ *.so
8
+
9
+ # Distribution / packaging
10
+ .Python
11
+ env/
12
+ build/
13
+ develop-eggs/
14
+ dist/
15
+ downloads/
16
+ eggs/
17
+ .eggs/
18
+ lib/
19
+ lib64/
20
+ parts/
21
+ sdist/
22
+ var/
23
+ *.egg-info/
24
+ .installed.cfg
25
+ *.egg
26
+
27
+ # PyInstaller
28
+ # Usually these files are written by a python script from a template
29
+ # before PyInstaller builds the exe, so as to inject date/other infos into it.
30
+ *.manifest
31
+ *.spec
32
+
33
+ # Installer logs
34
+ pip-log.txt
35
+ pip-delete-this-directory.txt
36
+
37
+ # Unit test / coverage reports
38
+ htmlcov/
39
+ .tox/
40
+ .coverage
41
+ .coverage.*
42
+ .cache
43
+ python_junit.xml
44
+ junit.xml
45
+ nosetests.xml
46
+ coverage.xml
47
+ *,cover
48
+ .hypothesis/
49
+ .pytest_cache
50
+ .ruff_cache
51
+ js/playwright-report
52
+
53
+ # Translations
54
+ *.mo
55
+ *.pot
56
+
57
+ # Django stuff:
58
+ *.log
59
+ local_settings.py
60
+
61
+ # Flask instance folder
62
+ instance/
63
+
64
+ # Scrapy stuff:
65
+ .scrapy
66
+
67
+ # Sphinx documentation
68
+ docs/_build/
69
+ docs/source
70
+
71
+ # PyBuilder
72
+ target/
73
+
74
+ # IPython Notebook
75
+ .ipynb_checkpoints
76
+ *.ipynb
77
+ .autoversion
78
+
79
+ # pyenv
80
+ .python-version
81
+
82
+ # celery beat schedule file
83
+ celerybeat-schedule
84
+
85
+ # dotenv
86
+ .env
87
+
88
+ # virtualenv
89
+ venv/
90
+ ENV/
91
+
92
+ # Spyder project settings
93
+ .spyderproject
94
+
95
+ # Rope project settings
96
+ .ropeproject
97
+
98
+ # =========================
99
+ # Operating System Files
100
+ # =========================
101
+
102
+ # OSX
103
+ # =========================
104
+
105
+ .DS_Store
106
+ .AppleDouble
107
+ .LSOverride
108
+
109
+ # Thumbnails
110
+ ._*
111
+
112
+ # Files that might appear in the root of a volume
113
+ .DocumentRevisions-V100
114
+ .fseventsd
115
+ .Spotlight-V100
116
+ .TemporaryItems
117
+ .Trashes
118
+ .VolumeIcon.icns
119
+
120
+ # Directories potentially created on remote AFP share
121
+ .AppleDB
122
+ .AppleDesktop
123
+ Network Trash Folder
124
+ Temporary Items
125
+ .apdisk
126
+
127
+ # Windows
128
+ # =========================
129
+
130
+ # Windows image file caches
131
+ Thumbs.db
132
+ ehthumbs.db
133
+
134
+ # Folder config file
135
+ Desktop.ini
136
+
137
+ # Recycle Bin used on file shares
138
+ $RECYCLE.BIN/
139
+
140
+ # Windows Installer files
141
+ *.cab
142
+ *.msi
143
+ *.msm
144
+ *.msp
145
+
146
+ # Windows shortcuts
147
+ *.lnk
148
+
149
+
150
+ # NPM
151
+ # ----
152
+ **/node_modules/
153
+
154
+ # Coverage data
155
+ # -------------
156
+ **/coverage/
157
+
158
+ # Notebook and lab extensions
159
+
160
+ nbprint/extension/*
161
+ nbprint/templates/nbprint/static/*
162
+ nbprint/voila/static/*
163
+ tmp.html
164
+ examples/output/
@@ -186,7 +186,7 @@
186
186
  same "printed page" as the copyright notice for easier
187
187
  identification within third-party archives.
188
188
 
189
- Copyright 2024, the hatch-cpp authors
189
+ Copyright [yyyy] [name of copyright owner]
190
190
 
191
191
  Licensed under the Apache License, Version 2.0 (the "License");
192
192
  you may not use this file except in compliance with the License.
@@ -0,0 +1,46 @@
1
+ Metadata-Version: 2.4
2
+ Name: hatch-cpp
3
+ Version: 0.1.0
4
+ Summary: Hatch plugin for C++ builds
5
+ Project-URL: Repository, https://github.com/python-project-templates/hatch-cpp
6
+ Project-URL: Homepage, https://github.com/python-project-templates/hatch-cpp
7
+ Author-email: the hatch-cpp authors <t.paine154@gmail.com>
8
+ License: Apache-2.0
9
+ License-File: LICENSE
10
+ Keywords: build,c++,cmake,cpp,hatch,python
11
+ Classifier: Development Status :: 3 - Alpha
12
+ Classifier: License :: OSI Approved :: Apache Software License
13
+ Classifier: Programming Language :: Python
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3.9
16
+ Classifier: Programming Language :: Python :: 3.10
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Programming Language :: Python :: Implementation :: CPython
20
+ Classifier: Programming Language :: Python :: Implementation :: PyPy
21
+ Requires-Python: >=3.9
22
+ Requires-Dist: hatchling>=1.20
23
+ Provides-Extra: develop
24
+ Requires-Dist: build; extra == 'develop'
25
+ Requires-Dist: bump-my-version; extra == 'develop'
26
+ Requires-Dist: check-manifest; extra == 'develop'
27
+ Requires-Dist: pytest; extra == 'develop'
28
+ Requires-Dist: pytest-cov; extra == 'develop'
29
+ Requires-Dist: ruff<0.9,>=0.3; extra == 'develop'
30
+ Requires-Dist: twine; extra == 'develop'
31
+ Requires-Dist: wheel; extra == 'develop'
32
+ Description-Content-Type: text/markdown
33
+
34
+ # hatch-cpp
35
+
36
+ Hatch plugin for C++ builds
37
+
38
+ [![Build Status](https://github.com/python-project-templates/hatch-cpp/actions/workflows/build.yml/badge.svg?branch=main&event=push)](https://github.com/python-project-templates/hatch-cpp/actions/workflows/build.yml)
39
+ [![codecov](https://codecov.io/gh/python-project-templates/hatch-cpp/branch/main/graph/badge.svg)](https://codecov.io/gh/python-project-templates/hatch-cpp)
40
+ [![License](https://img.shields.io/github/license/python-project-templates/hatch-cpp)](https://github.com/python-project-templates/hatch-cpp)
41
+ [![PyPI](https://img.shields.io/pypi/v/hatch-cpp.svg)](https://pypi.python.org/pypi/hatch-cpp)
42
+
43
+ ## Overview
44
+
45
+ > [!NOTE]
46
+ > This library was generated using [copier](https://copier.readthedocs.io/en/stable/) from the [Base Python Project Template repository](https://github.com/python-project-templates/base).
@@ -0,0 +1,13 @@
1
+ # hatch-cpp
2
+
3
+ Hatch plugin for C++ builds
4
+
5
+ [![Build Status](https://github.com/python-project-templates/hatch-cpp/actions/workflows/build.yml/badge.svg?branch=main&event=push)](https://github.com/python-project-templates/hatch-cpp/actions/workflows/build.yml)
6
+ [![codecov](https://codecov.io/gh/python-project-templates/hatch-cpp/branch/main/graph/badge.svg)](https://codecov.io/gh/python-project-templates/hatch-cpp)
7
+ [![License](https://img.shields.io/github/license/python-project-templates/hatch-cpp)](https://github.com/python-project-templates/hatch-cpp)
8
+ [![PyPI](https://img.shields.io/pypi/v/hatch-cpp.svg)](https://pypi.python.org/pypi/hatch-cpp)
9
+
10
+ ## Overview
11
+
12
+ > [!NOTE]
13
+ > This library was generated using [copier](https://copier.readthedocs.io/en/stable/) from the [Base Python Project Template repository](https://github.com/python-project-templates/base).
@@ -0,0 +1 @@
1
+ __version__ = "0.1.0"
@@ -0,0 +1,4 @@
1
+ from .cli import main
2
+
3
+ if __name__ == "__main__":
4
+ main()
@@ -0,0 +1,10 @@
1
+ from typing import Type
2
+
3
+ from hatchling.plugin import hookimpl
4
+
5
+ from .plugin import HatchCppBuildHook
6
+
7
+
8
+ @hookimpl
9
+ def hatch_register_build_hook() -> Type[HatchCppBuildHook]:
10
+ return HatchCppBuildHook
@@ -0,0 +1,85 @@
1
+ from __future__ import annotations
2
+
3
+ import logging
4
+ import os
5
+ import typing as t
6
+ from dataclasses import fields
7
+
8
+ from hatchling.builders.hooks.plugin.interface import BuildHookInterface
9
+
10
+ from .structs import HatchCppBuildConfig, HatchCppBuildPlan, HatchCppLibrary, HatchCppPlatform
11
+
12
+ __all__ = ("HatchCppBuildHook",)
13
+
14
+
15
+ class HatchCppBuildHook(BuildHookInterface[HatchCppBuildConfig]):
16
+ """The hatch-cpp build hook."""
17
+
18
+ PLUGIN_NAME = "hatch-cpp"
19
+ _logger = logging.getLogger(__name__)
20
+
21
+ def initialize(self, version: str, _: dict[str, t.Any]) -> None:
22
+ """Initialize the plugin."""
23
+ self._logger.info("Running hatch-cpp")
24
+
25
+ if self.target_name != "wheel":
26
+ self._logger.info("ignoring target name %s", self.target_name)
27
+ return
28
+
29
+ if os.getenv("SKIP_HATCH_CPP"):
30
+ self._logger.info("Skipping the build hook since SKIP_HATCH_CPP was set")
31
+ return
32
+
33
+ kwargs = {k.replace("-", "_"): v if not isinstance(v, bool) else str(v) for k, v in self.config.items()}
34
+ available_fields = [f.name for f in fields(HatchCppBuildConfig)]
35
+ for key in list(kwargs):
36
+ if key not in available_fields:
37
+ del kwargs[key]
38
+ config = HatchCppBuildConfig(**kwargs)
39
+
40
+ library_kwargs = [
41
+ {k.replace("-", "_"): v if not isinstance(v, bool) else str(v) for k, v in library_kwargs.items()} for library_kwargs in config.libraries
42
+ ]
43
+ libraries = [HatchCppLibrary(**library_kwargs) for library_kwargs in library_kwargs]
44
+ platform = HatchCppPlatform.default()
45
+ if config.toolchain == "raw":
46
+ # g++ basic-project/basic.cpp -I. -I/opt/homebrew/opt/python@3.11/Frameworks/Python.framework/Versions/3.11/include/python3.11/ -undefined dynamic_lookup -fPIC -shared -o extension.so
47
+ build_plan = HatchCppBuildPlan(libraries=libraries, platform=platform)
48
+ build_plan.generate()
49
+ build_plan.execute(verbose=config.verbose)
50
+ # build_kwargs = config.build_kwargs
51
+ # if version == "editable":
52
+ # build_kwargs = config.editable_build_kwargs or build_kwargs
53
+
54
+ # should_skip_build = False
55
+ # if not config.build_function:
56
+ # log.warning("No build function found")
57
+ # should_skip_build = True
58
+
59
+ # elif config.skip_if_exists and version == "standard":
60
+ # should_skip_build = should_skip(config.skip_if_exists)
61
+ # if should_skip_build:
62
+ # log.info("Skip-if-exists file(s) found")
63
+
64
+ # # Get build function and call it with normalized parameter names.
65
+ # if not should_skip_build and config.build_function:
66
+ # build_func = get_build_func(config.build_function)
67
+ # build_kwargs = normalize_kwargs(build_kwargs)
68
+ # log.info("Building with %s", config.build_function)
69
+ # log.info("With kwargs: %s", build_kwargs)
70
+ # try:
71
+ # build_func(self.target_name, version, **build_kwargs)
72
+ # except Exception as e:
73
+ # if version == "editable" and config.optional_editable_build.lower() == "true":
74
+ # warnings.warn(f"Encountered build error:\n{e}", stacklevel=2)
75
+ # else:
76
+ # raise e
77
+ # else:
78
+ # log.info("Skipping build")
79
+
80
+ # # Ensure targets in distributable dists.
81
+ # if version == "standard":
82
+ # ensure_targets(config.ensured_targets)
83
+
84
+ self._logger.info("Finished running hatch-cpp")
85
+ return
@@ -0,0 +1,146 @@
1
+ from __future__ import annotations
2
+
3
+ from dataclasses import dataclass, field
4
+ from os import environ, system
5
+ from sys import platform as sys_platform
6
+ from sysconfig import get_path
7
+ from typing import Literal
8
+
9
+ from hatchling.builders.config import BuilderConfig
10
+
11
+ __all__ = (
12
+ "HatchCppBuildConfig",
13
+ "HatchCppLibrary",
14
+ "HatchCppPlatform",
15
+ "HatchCppBuildPlan",
16
+ )
17
+
18
+ Platform = Literal["linux", "darwin", "win32"]
19
+ CompilerToolchain = Literal["gcc", "clang", "msvc"]
20
+ PlatformDefaults = {
21
+ "linux": {"CC": "gcc", "CXX": "g++"},
22
+ "darwin": {"CC": "clang", "CXX": "clang++"},
23
+ "win32": {"CC": "cl", "CXX": "cl"},
24
+ }
25
+
26
+
27
+ @dataclass
28
+ class HatchCppBuildConfig(BuilderConfig):
29
+ """Build config values for Hatch C++ Builder."""
30
+
31
+ toolchain: str | None = field(default="raw")
32
+ libraries: list[dict[str, str]] = field(default_factory=list)
33
+ verbose: bool | None = field(default=False)
34
+ # build_function: str | None = None
35
+ # build_kwargs: t.Mapping[str, str] = field(default_factory=dict)
36
+ # editable_build_kwargs: t.Mapping[str, str] = field(default_factory=dict)
37
+ # ensured_targets: list[str] = field(default_factory=list)
38
+ # skip_if_exists: list[str] = field(default_factory=list)
39
+
40
+
41
+ @dataclass
42
+ class HatchCppLibrary(object):
43
+ """A C++ library."""
44
+
45
+ name: str
46
+ sources: list[str]
47
+
48
+ include_dirs: list[str] = field(default_factory=list)
49
+ library_dirs: list[str] = field(default_factory=list)
50
+ libraries: list[str] = field(default_factory=list)
51
+ extra_compile_args: list[str] = field(default_factory=list)
52
+ extra_link_args: list[str] = field(default_factory=list)
53
+ extra_objects: list[str] = field(default_factory=list)
54
+ define_macros: list[str] = field(default_factory=list)
55
+ undef_macros: list[str] = field(default_factory=list)
56
+
57
+ export_symbols: list[str] = field(default_factory=list)
58
+ depends: list[str] = field(default_factory=list)
59
+
60
+
61
+ @dataclass
62
+ class HatchCppPlatform(object):
63
+ cc: str
64
+ cxx: str
65
+ platform: Platform
66
+ toolchain: CompilerToolchain
67
+
68
+ @staticmethod
69
+ def default() -> HatchCppPlatform:
70
+ platform = environ.get("HATCH_CPP_PLATFORM", sys_platform)
71
+ CC = environ.get("CC", PlatformDefaults[platform]["CC"])
72
+ CXX = environ.get("CXX", PlatformDefaults[platform]["CXX"])
73
+ if "gcc" in CC and "g++" in CXX:
74
+ toolchain = "gcc"
75
+ elif "clang" in CC and "clang++" in CXX:
76
+ toolchain = "clang"
77
+ elif "cl" in CC and "cl" in CXX:
78
+ toolchain = "msvc"
79
+ else:
80
+ raise Exception(f"Unrecognized toolchain: {CC}, {CXX}")
81
+ return HatchCppPlatform(cc=CC, cxx=CXX, platform=platform, toolchain=toolchain)
82
+
83
+ def get_flags(self, library: HatchCppLibrary) -> str:
84
+ flags = ""
85
+ if self.toolchain == "gcc":
86
+ flags = f"-I{get_path('include')}"
87
+ flags += " " + " ".join(f"-I{d}" for d in library.include_dirs)
88
+ flags += " -fPIC -shared"
89
+ flags += " " + " ".join(library.extra_compile_args)
90
+ flags += " " + " ".join(library.extra_link_args)
91
+ flags += " " + " ".join(library.extra_objects)
92
+ flags += " " + " ".join(f"-l{lib}" for lib in library.libraries)
93
+ flags += " " + " ".join(f"-L{lib}" for lib in library.library_dirs)
94
+ flags += " " + " ".join(f"-D{macro}" for macro in library.define_macros)
95
+ flags += " " + " ".join(f"-U{macro}" for macro in library.undef_macros)
96
+ flags += f" -o {library.name}.so"
97
+ elif self.toolchain == "clang":
98
+ flags = f"-I{get_path('include')} "
99
+ flags += " ".join(f"-I{d}" for d in library.include_dirs)
100
+ flags += " -undefined dynamic_lookup -fPIC -shared"
101
+ flags += " " + " ".join(library.extra_compile_args)
102
+ flags += " " + " ".join(library.extra_link_args)
103
+ flags += " " + " ".join(library.extra_objects)
104
+ flags += " " + " ".join(f"-l{lib}" for lib in library.libraries)
105
+ flags += " " + " ".join(f"-L{lib}" for lib in library.library_dirs)
106
+ flags += " " + " ".join(f"-D{macro}" for macro in library.define_macros)
107
+ flags += " " + " ".join(f"-U{macro}" for macro in library.undef_macros)
108
+ flags += f" -o {library.name}.so"
109
+ elif self.toolchain == "msvc":
110
+ flags = f"/I{get_path('include')} "
111
+ flags += " ".join(f"/I{d}" for d in library.include_dirs)
112
+ flags += " /LD"
113
+ flags += " " + " ".join(library.extra_compile_args)
114
+ flags += " " + " ".join(library.extra_link_args)
115
+ flags += " " + " ".join(library.extra_objects)
116
+ flags += " " + " ".join(f"{lib}.lib" for lib in library.libraries)
117
+ flags += " " + " ".join(f"/LIBPATH:{lib}" for lib in library.library_dirs)
118
+ flags += " " + " ".join(f"/D{macro}" for macro in library.define_macros)
119
+ flags += " " + " ".join(f"/U{macro}" for macro in library.undef_macros)
120
+ flags += f" /Fo{library.name}.obj"
121
+ flags += f" /Fe{library.name}.pyd"
122
+ # clean
123
+ while flags.count(" "):
124
+ flags = flags.replace(" ", " ")
125
+ return flags
126
+
127
+
128
+ @dataclass
129
+ class HatchCppBuildPlan(object):
130
+ libraries: list[HatchCppLibrary] = field(default_factory=list)
131
+ platform: HatchCppPlatform = field(default_factory=HatchCppPlatform.default)
132
+ commands: list[str] = field(default_factory=list)
133
+
134
+ def generate(self):
135
+ self.commands = []
136
+ for library in self.libraries:
137
+ flags = self.platform.get_flags(library)
138
+ self.commands.append(f"{self.platform.cc} {' '.join(library.sources)} {flags}")
139
+ return self.commands
140
+
141
+ def execute(self, verbose: bool = True):
142
+ for command in self.commands:
143
+ if verbose:
144
+ print(f"Running command: {command}")
145
+ system(command)
146
+ return self.commands
@@ -0,0 +1,2 @@
1
+ def test_import():
2
+ pass
@@ -0,0 +1,5 @@
1
+ #include "basic-project/basic.hpp"
2
+
3
+ PyObject* hello(PyObject*, PyObject*) {
4
+ return PyUnicode_FromString("A string");
5
+ }
@@ -0,0 +1,17 @@
1
+ #pragma once
2
+ #include "Python.h"
3
+
4
+ PyObject* hello(PyObject*, PyObject*);
5
+
6
+ static PyMethodDef extension_methods[] = {
7
+ {"hello", (PyCFunction)hello, METH_NOARGS},
8
+ {nullptr, nullptr, 0, nullptr}
9
+ };
10
+
11
+ static PyModuleDef extension_module = {
12
+ PyModuleDef_HEAD_INIT, "extension", "extension", -1, extension_methods};
13
+
14
+ PyMODINIT_FUNC PyInit_extension(void) {
15
+ Py_Initialize();
16
+ return PyModule_Create(&extension_module);
17
+ }
@@ -0,0 +1,63 @@
1
+ [build-system]
2
+ requires = ["hatchling>=1.20"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "hatch-cpp-test-project-basic"
7
+ description = "Basic test project for hatch-cpp"
8
+ version = "0.1.0"
9
+ requires-python = ">=3.9"
10
+ dependencies = [
11
+ "hatchling>=1.20",
12
+ "hatch-cpp",
13
+ ]
14
+
15
+ [tool.hatch.build]
16
+ artifacts = [
17
+ "basic_project/*.dll",
18
+ "basic_project/*.dylib",
19
+ "basic_project/*.so",
20
+ ]
21
+
22
+ [tool.hatch.build.sources]
23
+ src = "/"
24
+
25
+ [tool.hatch.build.targets.sdist]
26
+ packages = ["basic_project"]
27
+
28
+ [tool.hatch.build.targets.wheel]
29
+ packages = ["basic_project"]
30
+
31
+ [tool.hatch.build.hooks.hatch-cpp]
32
+ verbose = true
33
+ libraries = [
34
+ {name = "basic_project/extension", sources = ["cpp/basic-project/basic.cpp"], include-dirs = ["cpp"]}
35
+ ]
36
+
37
+ # build-function = "hatch_cpp.cpp_builder"
38
+
39
+ # [tool.hatch.build.hooks.defaults]
40
+ # build-type = "release"
41
+
42
+ # [tool.hatch.build.hooks.env-vars]
43
+ # TODO: these will all be available via
44
+ # CLI after https://github.com/pypa/hatch/pull/1743
45
+ # e.g. --hatch-cpp-build-type=debug
46
+ # build-type = "BUILD_TYPE"
47
+ # ccache = "USE_CCACHE"
48
+ # manylinux = "MANYLINUX"
49
+ # vcpkg = "USE_VCPKG"
50
+
51
+ # [tool.hatch.build.hooks.cmake]
52
+
53
+ # [tool.hatch.build.hooks.vcpkg]
54
+ # triplets = {linux="x64-linux", macos="x64-osx", windows="x64-windows-static-md"}
55
+ # clone = true
56
+ # update = true
57
+
58
+ # [tool.hatch.build.hooks.hatch-cpp.build-kwargs]
59
+ # path = "cpp"
60
+
61
+ [tool.pytest.ini_options]
62
+ asyncio_mode = "strict"
63
+ testpaths = "basic_project/tests"
@@ -0,0 +1,22 @@
1
+ from os import listdir
2
+ from shutil import rmtree
3
+ from subprocess import check_output
4
+ from sys import platform
5
+
6
+
7
+ class TestProject:
8
+ def test_basic(self):
9
+ rmtree("hatch_cpp/tests/test_project_basic/basic_project/extension.so", ignore_errors=True)
10
+ rmtree("hatch_cpp/tests/test_project_basic/basic_project/extension.pyd", ignore_errors=True)
11
+ check_output(
12
+ [
13
+ "hatchling",
14
+ "build",
15
+ "--hooks-only",
16
+ ],
17
+ cwd="hatch_cpp/tests/test_project_basic",
18
+ )
19
+ if platform == "win32":
20
+ assert "extension.pyd" in listdir("hatch_cpp/tests/test_project_basic/basic_project")
21
+ else:
22
+ assert "extension.so" in listdir("hatch_cpp/tests/test_project_basic/basic_project")
File without changes
File without changes