zig-zon 0.2.4__tar.gz → 0.2.5__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.
Files changed (26) hide show
  1. {zig-zon-0.2.4 → zig-zon-0.2.5}/PKG-INFO +1 -1
  2. zig-zon-0.2.5/build.zig +118 -0
  3. {zig-zon-0.2.4 → zig-zon-0.2.5}/build.zig.zon +3 -5
  4. {zig-zon-0.2.4 → zig-zon-0.2.5}/setup.py +10 -7
  5. zig-zon-0.2.5/setup.zig.json +1 -0
  6. zig-zon-0.2.5/src/zig_zon.pyi +5 -0
  7. {zig-zon-0.2.4 → zig-zon-0.2.5}/src/zig_zon.zig +39 -13
  8. {zig-zon-0.2.4/zig-pkg/zig_python_sdist-0.0.3 → zig-zon-0.2.5/zig-pkg/zig_python_sdist-0.0.4}/README.md +7 -0
  9. {zig-zon-0.2.4/zig-pkg/zig_python_sdist-0.0.3 → zig-zon-0.2.5/zig-pkg/zig_python_sdist-0.0.4}/build.zig +45 -2
  10. {zig-zon-0.2.4/zig-pkg/zig_python_sdist-0.0.3 → zig-zon-0.2.5/zig-pkg/zig_python_sdist-0.0.4}/build.zig.zon +1 -1
  11. {zig-zon-0.2.4/zig-pkg/zig_python_sdist-0.0.3 → zig-zon-0.2.5/zig-pkg/zig_python_sdist-0.0.4}/src/build/CPython.zig +21 -5
  12. zig-zon-0.2.5/zig-pkg/zig_python_sdist-0.0.4/src/build/Compression.zig +33 -0
  13. {zig-zon-0.2.4/zig-pkg/zig_python_sdist-0.0.3 → zig-zon-0.2.5/zig-pkg/zig_python_sdist-0.0.4}/src/build/SDistStep.zig +13 -16
  14. {zig-zon-0.2.4/zig-pkg/zig_python_sdist-0.0.3 → zig-zon-0.2.5/zig-pkg/zig_python_sdist-0.0.4}/src/build/VenvInstallTest.zig +1 -1
  15. {zig-zon-0.2.4/zig-pkg/zig_python_sdist-0.0.3 → zig-zon-0.2.5/zig-pkg/zig_python_sdist-0.0.4}/src/build/extract_link_info.py +4 -12
  16. zig-zon-0.2.5/zig-pkg/zig_python_sdist-0.0.4/src/build/python-translatec.h +6 -0
  17. {zig-zon-0.2.4/zig-pkg/zig_python_sdist-0.0.3 → zig-zon-0.2.5/zig-pkg/zig_python_sdist-0.0.4}/src/build/python.zig +95 -25
  18. zig-zon-0.2.5/zig-pkg/zig_python_sdist-0.0.4/src/build/python_allocator.zig +201 -0
  19. {zig-zon-0.2.4/zig-pkg/zig_python_sdist-0.0.3 → zig-zon-0.2.5/zig-pkg/zig_python_sdist-0.0.4}/src/build/setup_json.zig +13 -5
  20. zig-zon-0.2.4/build.zig +0 -75
  21. zig-zon-0.2.4/setup.zig.json +0 -1
  22. {zig-zon-0.2.4 → zig-zon-0.2.5}/pkg-info.zon +0 -0
  23. {zig-zon-0.2.4/zig-pkg/zig_python_sdist-0.0.3 → zig-zon-0.2.5/zig-pkg/zig_python_sdist-0.0.4}/LICENSE +0 -0
  24. {zig-zon-0.2.4/zig-pkg/zig_python_sdist-0.0.3 → zig-zon-0.2.5/zig-pkg/zig_python_sdist-0.0.4}/pkg-info.zon +0 -0
  25. {zig-zon-0.2.4/zig-pkg/zig_python_sdist-0.0.3 → zig-zon-0.2.5/zig-pkg/zig_python_sdist-0.0.4}/src/build/LowerDashString.zig +0 -0
  26. {zig-zon-0.2.4/zig-pkg/zig_python_sdist-0.0.3 → zig-zon-0.2.5/zig-pkg/zig_python_sdist-0.0.4}/src/build/pkg_info.zig +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: zig-zon
3
- Version: 0.2.4
3
+ Version: 0.2.5
4
4
  Summary: a native cpython extension to parse zig object notation strings
5
5
  Author-email: Tobias Simetsreiter <dasimmet@gmail.com>
6
6
  Maintainer-email: Tobias Simetsreiter <dasimmet@gmail.com>
@@ -0,0 +1,118 @@
1
+ const std = @import("std");
2
+ const Build = std.Build;
3
+ const zig_python_sdist = @import("zig_python_sdist");
4
+ const zon = @import("build.zig.zon");
5
+
6
+ pub fn build(b: *Build) void {
7
+ const target = b.standardTargetOptions(.{});
8
+ const optimize = b.standardOptimizeOption(.{});
9
+
10
+ // this target and section of our build is used at pip install time
11
+ const ext_install_step = b.step("bdist-wheel", "build python extension module");
12
+ ext_install_step.dependOn(
13
+ &b.addInstallFile(b.path("src/zig_zon.pyi"), "lib/zig_zon.pyi").step,
14
+ );
15
+
16
+ // this generates a python sdist archive
17
+ const sdist = zig_python_sdist.createSdistStep(b, .{
18
+ .name = "zig-zon",
19
+ .version = zon.version,
20
+ .description = b.path("README.md"),
21
+ .build = .{
22
+ .args = &.{
23
+ ext_install_step.name,
24
+ b.fmt("-Doptimize={s}", .{@tagName(optimize)}),
25
+ },
26
+ },
27
+ .extra_pkg_info = @import("pkg-info.zon"),
28
+ .files = &.{
29
+ .{ .src = b.path("pkg-info.zon"), .dest = "pkg-info.zon" },
30
+ .{ .src = b.path("build.zig.zon"), .dest = "build.zig.zon" },
31
+ .{ .src = b.path("build.zig"), .dest = "build.zig" },
32
+ .{ .src = b.path("src/zig_zon.zig"), .dest = "src/zig_zon.zig" },
33
+ .{ .src = b.path("src/zig_zon.pyi"), .dest = "src/zig_zon.pyi" },
34
+ },
35
+ .compression = .best,
36
+ });
37
+
38
+ const sdistfile = b.addInstallFileWithDir(
39
+ sdist.getEmittedArchive(),
40
+ .{ .custom = "src" },
41
+ sdist.basename,
42
+ );
43
+ b.getInstallStep().dependOn(&sdistfile.step);
44
+
45
+ // we can use a python virtual environment inside
46
+ // the zig cache to test pip installation
47
+ const test_pip_install = zig_python_sdist.createVenvInstallTest(
48
+ b,
49
+ .{
50
+ .sdist = sdist.getEmittedArchive(),
51
+ .unittest_py = &.{b.path("src/test_zig_zon.py")},
52
+ .twine_check = true,
53
+ .no_clean = b.option(bool, "pip-no-clean", "dont cleanup pip temp dirs") orelse false,
54
+ },
55
+ );
56
+ b.step("test-pip-install", "").dependOn(test_pip_install.step);
57
+
58
+ const cpython = zig_python_sdist.createCPythonModule(b, .{
59
+ .target = target,
60
+ .version = zon.version,
61
+ .optimize = .ReleaseSmall,
62
+ });
63
+ const lib = b.addLibrary(.{
64
+ .name = "zig_zon",
65
+ .root_module = b.addModule("zig_zon", .{
66
+ .root_source_file = b.path("src/zig_zon.zig"),
67
+ .target = target,
68
+ .optimize = optimize,
69
+ .imports = &.{
70
+ .{ .name = "cpython", .module = cpython },
71
+ },
72
+ }),
73
+ .linkage = .dynamic,
74
+ });
75
+ const ext_install = zig_python_sdist.installExtLib(b, lib);
76
+ ext_install_step.dependOn(&ext_install.step);
77
+
78
+ ext_install_step.dependOn(&ext_install.step);
79
+
80
+ const ext_path = zig_python_sdist.CPython.renameExtLib(b, lib);
81
+
82
+ {
83
+ const ext_tests = ext_path.wf.addCopyFile(b.path("src/test_zig_zon.py"), "test_zig_zon.py");
84
+ _ = ext_path.wf.addCopyFile(b.path("build.zig.zon"), "build.zig.zon");
85
+ const test_run = Build.Step.Run.create(b, "unittest");
86
+ test_run.setCwd(ext_path.wf.getDirectory());
87
+ test_run.setEnvironmentVariable("PYTHONPATH", ".");
88
+ test_run.addFileArg(zig_python_sdist.CPython.find(b));
89
+ if (b.option(bool, "tracetest", "run unittest with tracing") orelse false) {
90
+ test_run.addArgs(&.{ "-m", "trace", "--trace" });
91
+ } else {
92
+ test_run.addArgs(&.{ "-m", "unittest" });
93
+ }
94
+ test_run.addDirectoryArg(ext_tests);
95
+ b.step("test-bdist", "run unittests against the extension").dependOn(&test_run.step);
96
+ }
97
+
98
+ const usf = b.addUpdateSourceFiles();
99
+ b.step("update-src", "updates the pyi file. needs 'mypy' installed").dependOn(&usf.step);
100
+
101
+ {
102
+ const stubgen_run = Build.Step.Run.create(b, "stubgen");
103
+ stubgen_run.setCwd(ext_path.wf.getDirectory());
104
+ stubgen_run.addArgs(&.{
105
+ "stubgen",
106
+ "-m",
107
+ lib.name,
108
+ "-o",
109
+ });
110
+ const stub_dir = stubgen_run.addOutputDirectoryArg("stubgen");
111
+ stubgen_run.addArg("--search-path");
112
+ stubgen_run.addDirectoryArg(ext_path.wf.getDirectory());
113
+ usf.addCopyFileToSource(
114
+ stub_dir.path(b, b.fmt("{s}.pyi", .{lib.name})),
115
+ b.fmt("src/{s}.pyi", .{lib.name}),
116
+ );
117
+ }
118
+ }
@@ -1,12 +1,12 @@
1
1
  .{
2
2
  .name = .python_zig_zon,
3
3
  .fingerprint = 0x3d332656a3644fc9,
4
- .version = "0.2.4",
4
+ .version = "0.2.5",
5
5
  .minimum_zig_version = "0.16.0",
6
6
  .dependencies = .{
7
7
  .zig_python_sdist = .{
8
- .url = "git+https://codeberg.org/dasimmet/zig-python-sdist.git#b09744edafe683ae6000a96498cc68e86173dbe7",
9
- .hash = "zig_python_sdist-0.0.3-wjgdOlzvAADTtFV1n4xTLUwlgCsiLDcmhebfZ7kWM05z",
8
+ .url = "git+https://codeberg.org/dasimmet/zig-python-sdist.git?ref=0.0.4#79469a3698fe6c11ad0420282e71ff858642a4ac",
9
+ .hash = "zig_python_sdist-0.0.4-wjgdOukkAQBzC1YymFsy5h5_nZTUlWKUFI9oseCgGkKP",
10
10
  },
11
11
  },
12
12
  .paths = .{
@@ -16,7 +16,5 @@
16
16
  "pkg-info.zon",
17
17
  "LICENSE",
18
18
  "README.md",
19
- "setup.py",
20
- "pyproject.toml",
21
19
  },
22
20
  }
@@ -14,6 +14,7 @@ with open("setup.zig.json") as fd:
14
14
 
15
15
 
16
16
  def mkversion(v, need_release=False):
17
+ '''assembles a dict of semantic version to string'''
17
18
  if need_release:
18
19
  assert v['pre'] == None, "cannot use version with pre: " + str(v)
19
20
  assert v['build'] == None, "cannot use version with build: " + str(v)
@@ -40,14 +41,15 @@ class ZigBuildWheel(bdist_wheel):
40
41
 
41
42
  os.makedirs(self.bdist_dir, exist_ok=True)
42
43
  copy_pattern = setup_json['build']['copy_pattern']
43
- artifacts = glob.glob(copy_pattern)
44
- if len(artifacts) == 0:
45
- raise Exception(
46
- 'no zig artifacts found in {}/{}'.format(cwd, copy_pattern))
44
+ for pattern in copy_pattern:
45
+ artifacts = glob.glob(pattern)
46
+ if len(artifacts) == 0:
47
+ raise Exception(
48
+ 'no zig artifacts found in {}/{}'.format(cwd, pattern))
47
49
 
48
- for it in artifacts:
49
- shutil.copyfile(it, os.path.join(
50
- self.bdist_dir, os.path.basename(it)))
50
+ for it in artifacts:
51
+ shutil.copyfile(it, os.path.join(
52
+ self.bdist_dir, os.path.basename(it)))
51
53
 
52
54
  return super().run(*args, **kwargs)
53
55
 
@@ -58,6 +60,7 @@ setup(
58
60
  cmdclass={'bdist_wheel': ZigBuildWheel},
59
61
  install_requires=setup_json['install_requires'],
60
62
  entry_points=setup_json['entry_points'],
63
+ packages=setup_json['build']['packages'],
61
64
  setup_requires=[
62
65
  "setuptools",
63
66
  "wheel",
@@ -0,0 +1 @@
1
+ {"name":"zig_zon","version":{"major":0,"minor":2,"patch":5,"pre":null,"build":null},"zig_version":{"major":0,"minor":16,"patch":0,"pre":null,"build":null},"build":{"args":["--fork=zig-pkg/zig_python_sdist-0.0.4","bdist-wheel","-Doptimize=ReleaseSmall"],"requires":[],"packages":[],"copy_pattern":["zig-out/lib/*"]},"install_requires":[],"entry_points":{"console_scripts":[],"gui_scripts":[]}}
@@ -0,0 +1,5 @@
1
+ __version__: dict
2
+ __version_str__: str
3
+ __zig_builtin__: dict
4
+
5
+ def parse(*args, **kwargs): ...
@@ -8,28 +8,54 @@ const cpython = @import("cpython");
8
8
  const c = cpython.c;
9
9
  const PyObject = c.PyObject;
10
10
 
11
- pub var methods = [_]c.PyMethodDef{
12
- c.PyMethodDef{
13
- .ml_name = "parse",
14
- .ml_meth = @ptrCast(@alignCast(&parse)),
15
- .ml_flags = @as(c_int, 1),
16
- .ml_doc = "parse a zon literal to a python object",
17
- },
18
- c.PyMethodDef{},
19
- };
20
-
21
- pub var zigmodule = c.PyModuleDef{
11
+ pub var zigmodule: c.PyModuleDef = .{
22
12
  .m_name = "zig_zon",
23
- .m_methods = &methods,
13
+ .m_methods = @constCast(&[_]c.PyMethodDef{
14
+ .{
15
+ .ml_name = "parse",
16
+ .ml_meth = @ptrCast(@alignCast(&parse)),
17
+ .ml_flags = 1,
18
+ .ml_doc = "parse a zon literal to a python object",
19
+ },
20
+ .{},
21
+ }),
24
22
  };
25
23
 
26
24
  pub export fn PyInit_zig_zon() [*c]c.PyObject {
27
25
  const mod = c.PyModule_Create(&zigmodule);
26
+
27
+ {
28
+ // const annotations = c.PyDict_New();
29
+ // defer c.Py_DecRef(annotations);
30
+ // const builtins = c.PyImport_ImportModule("builtins");
31
+ // defer c.Py_DecRef(builtins);
32
+
33
+ // const str_type = c.PyObject_GetAttrString(builtins, "str") orelse PyErrPanic();
34
+ // defer c.Py_DecRef(str_type);
35
+
36
+ // assert(0 <= c.PyDict_SetItemString(annotations, "value", str_type));
37
+
38
+ // const parse_ref = c.PyObject_GetAttrString(mod, "parse") orelse PyErrPanic();
39
+ // defer c.Py_DecRef(parse_ref);
40
+
41
+ //TODO: find another way to set annotations, since a builtin function is immutable.
42
+
43
+ // if (0 > c.PyObject_SetAttrString(parse_ref, "__annotations__", annotations)) {
44
+ // c.PyErr_Print();
45
+ // @panic("WTF");
46
+ // }
47
+ }
48
+
28
49
  cpython.addVersion(mod);
29
50
  cpython.addZigBuiltin(mod);
30
51
  return mod;
31
52
  }
32
53
 
54
+ pub fn PyErrPanic() noreturn {
55
+ c.PyErr_Print();
56
+ @panic("Unexpected PyErr!");
57
+ }
58
+
33
59
  pub fn parse(self: [*]PyObject, args: [*]PyObject) callconv(.c) [*c]PyObject {
34
60
  _ = self;
35
61
  const zon_slice: [:0]u8 = zon_slice: {
@@ -38,7 +64,7 @@ pub fn parse(self: [*]PyObject, args: [*]PyObject) callconv(.c) [*c]PyObject {
38
64
  break :zon_slice std.mem.sliceTo(zon_txt, 0);
39
65
  };
40
66
 
41
- var arena_instance = std.heap.ArenaAllocator.init(std.heap.c_allocator);
67
+ var arena_instance = std.heap.ArenaAllocator.init(cpython.py_allocator);
42
68
  defer arena_instance.deinit();
43
69
  const arena = arena_instance.allocator();
44
70
 
@@ -112,3 +112,10 @@ that will:
112
112
  - compile and install your package
113
113
  - run python unittest files against the installed package
114
114
  - run entrypoints from the installed package to test them
115
+
116
+ ## References
117
+
118
+ - [Deinventing the Wheel - Loris Cro](https://www.youtube.com/watch?v=HPmefnqirHk)
119
+ - <https://pypi.org/project/setuptools-zig/>
120
+ - <https://pypi.org/project/zig-zon>
121
+ - <https://codeberg.org/dasimmet/python-zig-zon>
@@ -12,6 +12,7 @@ pub const createSdistStep = createSdist;
12
12
  pub const createVenvInstallTest = VenvInstallTest.create;
13
13
  pub const createCPythonModule = createModule;
14
14
  pub const installExtLib = CPython.installExtLib;
15
+ pub const renameExtLib = CPython.renameExtLib;
15
16
 
16
17
  pub fn build(b: *Build) void {
17
18
  const target = b.standardTargetOptions(.{});
@@ -54,12 +55,52 @@ pub fn build(b: *Build) void {
54
55
  const build_ext_step = b.step("bdist-wheel", "build the sdist dummy python module");
55
56
  build_ext_step.dependOn(&install_ext.step);
56
57
 
58
+ {
59
+ const ext_path = CPython.renameExtLib(b, sdist_dummy);
60
+ const ext_tests = ext_path.wf.addCopyFile(b.path("example/test_ext.py"), "test_ext.py");
61
+ const test_run = Build.Step.Run.create(b, "unittest");
62
+ test_run.setCwd(ext_path.wf.getDirectory());
63
+ test_run.setEnvironmentVariable("PYTHONPATH", ".");
64
+ test_run.addFileArg(CPython.find(b));
65
+ test_run.addArgs(&.{ "-m", "unittest" });
66
+ test_run.addDirectoryArg(ext_tests);
67
+ b.step("test-bdist", "test the extension against the local python version").dependOn(&test_run.step);
68
+ }
69
+
70
+ {
71
+ const ext_path = CPython.renameExtLib(b, sdist_dummy);
72
+ const stubgen_run = Build.Step.Run.create(b, "stubgen");
73
+ stubgen_run.setCwd(ext_path.wf.getDirectory());
74
+ stubgen_run.addArgs(&.{
75
+ "stubgen",
76
+ "-m",
77
+ sdist_dummy.name,
78
+ "-o",
79
+ });
80
+ const stub_dir = stubgen_run.addOutputDirectoryArg("stubgen");
81
+ stubgen_run.addArg("--search-path");
82
+ stubgen_run.addDirectoryArg(ext_path.wf.getDirectory());
83
+ const usf = b.addUpdateSourceFiles();
84
+ usf.addCopyFileToSource(
85
+ stub_dir.path(b, b.fmt("{s}.pyi", .{sdist_dummy.name})),
86
+ b.fmt("example/{s}.pyi", .{sdist_dummy.name}),
87
+ );
88
+ b.step("stubgen", "generate .pyi from module with mypy stubgen").dependOn(&usf.step);
89
+ }
90
+
57
91
  const sdist = SDistStep.createInternal(b, exe, .{
58
92
  .name = "sdist-dummy",
59
93
  .version = zon.version,
60
94
  .description = b.path("README.md"),
61
95
  .build = .{
62
- .args = &.{ b.fmt("-Doptimize={s}", .{@tagName(optimize)}), build_ext_step.name },
96
+ .args = &.{
97
+ b.fmt("-Doptimize={s}", .{@tagName(optimize)}),
98
+ build_ext_step.name,
99
+ },
100
+ .copy_pattern = &.{
101
+ "zig-out/lib/*",
102
+ "example/sdist_dummy.pyi",
103
+ },
63
104
  },
64
105
  .extra_pkg_info = @import("pkg-info.zon"),
65
106
  .files = &.{
@@ -67,6 +108,7 @@ pub fn build(b: *Build) void {
67
108
  .{ .src = b.path("build.zig"), .dest = "build.zig" },
68
109
  .{ .src = b.path("pkg-info.zon"), .dest = "pkg-info.zon" },
69
110
  .{ .src = b.path("example/sdist_dummy.zig"), .dest = "example/sdist_dummy.zig" },
111
+ .{ .src = b.path("example/sdist_dummy.pyi"), .dest = "example/sdist_dummy.pyi" },
70
112
  },
71
113
  .directories = &.{
72
114
  .{ .src = b.path("src/build"), .dest = "src/build" },
@@ -78,6 +120,7 @@ pub fn build(b: *Build) void {
78
120
  },
79
121
  .install_requires = &.{"ruamel.yaml.clibz"},
80
122
  .zig_version = std.SemanticVersion.parse("0.16.0") catch unreachable,
123
+ .compression = .best,
81
124
  });
82
125
  const sdist_install = sdist.install();
83
126
  b.getInstallStep().dependOn(&sdist_install.step);
@@ -96,7 +139,7 @@ pub fn build(b: *Build) void {
96
139
  .no_clean = b.option(bool, "pip-no-clean", "cleanup pip temp dirs") orelse false,
97
140
  },
98
141
  );
99
- b.step("test-pip-install", "").dependOn(test_pip_install.step);
142
+ b.step("test-pip-install", "test build and install sdist with pip").dependOn(test_pip_install.step);
100
143
  }
101
144
 
102
145
  fn createModule(b: *Build, options: CPython.LinkOptions) *Build.Module {
@@ -1,6 +1,6 @@
1
1
  .{
2
2
  .name = .zig_python_sdist,
3
- .version = "0.0.3",
3
+ .version = "0.0.4",
4
4
  .minimum_zig_version = "0.17.0-dev.1245+efd6f190f",
5
5
  .paths = .{
6
6
  "build.zig",
@@ -13,6 +13,7 @@ pub const LinkOptions = struct {
13
13
  target: Build.ResolvedTarget,
14
14
  optimize: std.builtin.OptimizeMode,
15
15
  version: ?[]const u8 = null,
16
+ header_file: ?LazyPath = null,
16
17
  // pass in the python executable for finding headers. use "python" from PATH if omitted.
17
18
  python_exe: ?LazyPath = null,
18
19
  macros: []const [2][]const u8 = &default_macros,
@@ -29,10 +30,10 @@ pub fn createModuleInternal(b: *Build, sdist_build: *Build, options: LinkOptions
29
30
  else
30
31
  CPython.find(b);
31
32
 
32
- const python_inc = generateIncludeDir(b, python);
33
+ const python_inc = generateIncludeDir(b, sdist_build, python);
33
34
 
34
35
  const cpython = b.addTranslateC(.{
35
- .root_source_file = python_inc.path(b, "zig_python_include.h"),
36
+ .root_source_file = options.header_file orelse sdist_build.path("src/build/python-translatec.h"),
36
37
  .optimize = options.optimize,
37
38
  .target = options.target,
38
39
  });
@@ -64,18 +65,33 @@ pub fn createModuleInternal(b: *Build, sdist_build: *Build, options: LinkOptions
64
65
  .imports = &.{
65
66
  .{ .name = "c", .module = cpy_mod },
66
67
  .{ .name = "version", .module = version },
68
+ .{ .name = "pyhexver", .module = b.createModule(.{
69
+ .root_source_file = python_inc.path(b, "pyhexver.zig"),
70
+ }) },
67
71
  },
68
72
  });
69
73
  }
70
74
 
71
- pub fn generateIncludeDir(b: *Build, python: LazyPath) LazyPath {
75
+ pub fn generateIncludeDir(b: *Build, sdist_build: *Build, python: LazyPath) LazyPath {
72
76
  const extract_link_info = Build.Step.Run.create(b, "python header extraction run");
73
77
  extract_link_info.addFileArg(python);
74
- const wf = b.addWriteFiles();
75
- extract_link_info.addFileArg(wf.add("extract_link_info.py", @embedFile("extract_link_info.py")));
78
+ extract_link_info.addFileArg(sdist_build.path("src/build/extract_link_info.py"));
76
79
  return extract_link_info.addOutputDirectoryArg("pyinclude");
77
80
  }
78
81
 
82
+ pub fn renameExtLib(b: *Build, lib: *Build.Step.Compile) struct {
83
+ wf: *Build.Step.WriteFile,
84
+ ext: LazyPath,
85
+ } {
86
+ const ext_lib_name = lib_ext_name(b, lib);
87
+ const wf = b.addWriteFiles();
88
+ const ext = wf.addCopyFile(lib.getEmittedBin(), ext_lib_name);
89
+ return .{
90
+ .wf = wf,
91
+ .ext = ext,
92
+ };
93
+ }
94
+
79
95
  pub fn installExtLib(b: *Build, lib: *Build.Step.Compile) *Build.Step.InstallFile {
80
96
  const ext_lib_name = lib_ext_name(b, lib);
81
97
  return b.addInstallLibFile(lib.getEmittedBin(), ext_lib_name);
@@ -0,0 +1,33 @@
1
+ const std = @import("std");
2
+
3
+ pub const Compression = enum {
4
+ fastest,
5
+ default,
6
+ best,
7
+ level_1,
8
+ level_2,
9
+ level_3,
10
+ level_4,
11
+ level_5,
12
+ level_6,
13
+ level_7,
14
+ level_8,
15
+ level_9,
16
+
17
+ pub fn toGzipOptions(self: @This()) std.compress.flate.Compress.Options {
18
+ return switch (self) {
19
+ .fastest => .fastest,
20
+ .default => .default,
21
+ .best => .best,
22
+ .level_1 => .level_1,
23
+ .level_2 => .level_2,
24
+ .level_3 => .level_3,
25
+ .level_4 => .level_4,
26
+ .level_5 => .level_5,
27
+ .level_6 => .level_6,
28
+ .level_7 => .level_7,
29
+ .level_8 => .level_8,
30
+ .level_9 => .level_9,
31
+ };
32
+ }
33
+ };
@@ -6,6 +6,7 @@ const LazyPath = Build.LazyPath;
6
6
  const LowerDashString = @import("LowerDashString.zig");
7
7
  const PkgInfo = @import("pkg_info.zig");
8
8
  const SetupJson = @import("setup_json.zig");
9
+ const Compression = @import("Compression.zig").Compression;
9
10
 
10
11
  const SDistStep = @This();
11
12
 
@@ -29,14 +30,7 @@ pub const Options = struct {
29
30
  description: ?LazyPath = null,
30
31
 
31
32
  /// extra configuration for building th python wheel
32
- build: struct {
33
- /// extra arguments for `zig build` at wheel build time
34
- args: []const []const u8 = &.{},
35
- /// additional build dependencies for wheel build
36
- requires: []const []const u8 = &.{},
37
- /// files to copy from zig build to wheel directory. passed glob.glob() after build
38
- copy_pattern: ?[]const u8 = null,
39
- } = .{},
33
+ build: SetupJson.Build,
40
34
 
41
35
  ///additional python packages to depend on at runtime
42
36
  install_requires: []const []const u8 = &.{},
@@ -56,6 +50,9 @@ pub const Options = struct {
56
50
 
57
51
  /// entry points pip should create on install
58
52
  entry_points: SetupJson.EntryPoints = .{},
53
+
54
+ /// gzip compression level
55
+ compression: ?Compression = null,
59
56
  };
60
57
 
61
58
  pub fn createInternal(b: *Build, builder: *Build.Step.Compile, options: Options) *SDistStep {
@@ -95,17 +92,17 @@ pub fn createInternal(b: *Build, builder: *Build.Step.Compile, options: Options)
95
92
  for (options.directories) |content| {
96
93
  self.addDirectory(content);
97
94
  }
98
- for (options.build.args) |ba| {
99
- run.addArg(b.fmt("--build={s}", .{ba}));
100
- }
101
- for (options.build.requires) |br| {
102
- run.addArg(b.fmt("--build-requires={s}", .{br}));
103
- }
95
+
96
+ run.addArg(b.fmt("--build={f}", .{
97
+ std.json.fmt(options.build, .{ .whitespace = .minified }),
98
+ }));
99
+
104
100
  for (options.install_requires) |br| {
105
101
  run.addArg(b.fmt("--install-requires={s}", .{br}));
106
102
  }
107
- if (options.build.copy_pattern) |copy_pattern| {
108
- run.addArg(b.fmt("--copy-pattern={s}", .{copy_pattern}));
103
+
104
+ if (options.compression) |compression| {
105
+ run.addArg(b.fmt("--compression={s}", .{@tagName(compression)}));
109
106
  }
110
107
  if (options.extra_pkg_info.len > 0) {
111
108
  const extra_info = std.fmt.allocPrint(b.allocator, "--extra-pkg-info={f}", .{
@@ -46,7 +46,7 @@ pub fn create(b: *Build, options: Options) *VenvInstallTest {
46
46
  venv_run.addDirectoryArg(venv.getDirectory());
47
47
 
48
48
  self.python = if (builtin.target.os.tag == .windows)
49
- venv.getDirectory().path(b, "Scripts/python")
49
+ venv.getDirectory().path(b, "Scripts/python.exe")
50
50
  else
51
51
  venv.getDirectory().path(b, "bin/python");
52
52
 
@@ -11,7 +11,7 @@ def main():
11
11
  syspath = sysconfig.get_paths()
12
12
 
13
13
  python_h = os.path.join(output_dir, 'Python.h')
14
- output_header = os.path.join(output_dir, 'zig_python_include.h')
14
+ output_header = os.path.join(output_dir, 'pyhexver.zig')
15
15
 
16
16
  os.makedirs(output_dir, exist_ok=True)
17
17
  shutil.copytree(syspath['include'], output_dir, dirs_exist_ok=True)
@@ -26,18 +26,10 @@ def main():
26
26
  syspath['include'], output_dir))
27
27
 
28
28
  output_h_str = '''
29
- // zig_python_include.h generated by extract_link_info.py
29
+ // pyhexver.zig generated by extract_link_info.py
30
30
  // sources: {}
31
- #ifndef PY_SSIZE_T_CLEAN
32
- #define PY_SSIZE_T_CLEAN
33
- #endif
34
-
35
- #ifndef PYHEXVER
36
- #define PYHEXVER {}
37
- #endif
38
-
39
- #include "Python.h"
40
- '''.format(sources, sys.hexversion)
31
+ pub const PYHEXVER={};
32
+ '''.format(sources, hex(sys.hexversion))
41
33
 
42
34
  with open(output_header, 'w') as fd:
43
35
  fd.write(output_h_str)
@@ -0,0 +1,6 @@
1
+ #ifndef PY_SSIZE_T_CLEAN
2
+ #define PY_SSIZE_T_CLEAN
3
+ #endif
4
+
5
+ #include "Python.h"
6
+ #include "structmember.h"
@@ -3,9 +3,21 @@ const builtin = @import("builtin");
3
3
  const assert = std.debug.assert;
4
4
  pub const c = @import("c");
5
5
  pub const version = @embedFile("version");
6
+ pub const PYHEXVER = @import("pyhexver").PYHEXVER;
7
+
8
+ pub const py_allocator = @import("python_allocator.zig").py_allocator;
9
+
10
+ /// get the type of 'type'. in the c header this is an opaque type not acessible
11
+ /// by zig
12
+ pub fn getPyType() [*]c.PyObject {
13
+ const builtins = c.PyImport_ImportModule("builtins");
14
+ defer c.Py_DecRef(builtins);
15
+ return c.PyObject.GetAttrString(builtins, "type");
16
+ }
6
17
 
7
18
  pub const WrapMainOptions = struct {};
8
19
 
20
+ /// wraps a zig "Juicy Main" function with a std.process.Init based on pythons args, allocator and environment
9
21
  pub fn wrapMain(wrap_main: anytype, comptime options: WrapMainOptions) fn ([*]c.PyObject, [*]c.PyObject) callconv(.c) [*c]c.PyObject {
10
22
  _ = options;
11
23
 
@@ -52,16 +64,24 @@ pub fn wrapMain(wrap_main: anytype, comptime options: WrapMainOptions) fn ([*]c.
52
64
  pub fn main_fn(fn_self: [*]c.PyObject, fn_args: [*]c.PyObject) callconv(.c) [*c]c.PyObject {
53
65
  _ = fn_self;
54
66
  _ = fn_args;
55
- var arena: std.heap.ArenaAllocator = .init(std.heap.c_allocator);
56
- defer arena.deinit();
57
- const alloc = arena.allocator();
67
+ var arena_impl: std.heap.ArenaAllocator = .init(py_allocator);
68
+ defer arena_impl.deinit();
69
+ const arena = arena_impl.allocator();
70
+
71
+ var gpa_impl: std.heap.DebugAllocator(.{}) = .{
72
+ .backing_allocator = py_allocator,
73
+ };
74
+ defer _ = gpa_impl.deinit();
75
+ const gpa = gpa_impl.allocator();
58
76
 
59
- var threaded: std.Io.Threaded = .init(std.heap.c_allocator, .{});
77
+ var threaded: std.Io.Threaded = .init(gpa, .{});
60
78
  defer threaded.deinit();
61
79
 
62
80
  const args = args: {
63
81
  const sys = c.PyImport_ImportModule("sys");
82
+ defer c.Py_DecRef(sys);
64
83
  const argv = c.PyObject_GetAttrString(sys, "argv");
84
+ defer c.Py_DecRef(argv);
65
85
  const arglen = c.PySequence_Length(argv);
66
86
 
67
87
  switch (builtin.os.tag) {
@@ -70,54 +90,64 @@ pub fn wrapMain(wrap_main: anytype, comptime options: WrapMainOptions) fn ([*]c.
70
90
 
71
91
  for (0..@intCast(arglen)) |arg_i| {
72
92
  const arg_str = c.PySequence_GetItem(argv, @intCast(arg_i));
93
+ defer c.Py_DecRef(arg_str);
73
94
  const arg_bytes = c.PyUnicode_AsEncodedString(arg_str, "UTF-8", "strict");
95
+ defer c.Py_DecRef(arg_bytes);
74
96
  var arg_ptr: [*c]u8 = undefined;
75
97
  var arg_len: isize = undefined;
76
98
  assert(0 <= c.PyBytes_AsStringAndSize(arg_bytes, &arg_ptr, &arg_len));
77
99
  const arg = arg_ptr[0..@intCast(arg_len) :0];
78
- const arg16 = std.unicode.wtf8ToWtf16LeAllocZ(alloc, arg) catch @panic("OOM");
100
+ const arg16 = std.unicode.wtf8ToWtf16LeAllocZ(gpa, arg) catch @panic("OOM");
101
+ defer gpa.free(arg16);
79
102
 
80
103
  // check if we need add quoting for windows characters
81
104
  if (std.mem.findAny(u16, arg16, &.{ ' ', '\t' }) != null) {
82
- args_list.append(alloc, '"') catch @panic("OOM");
105
+ args_list.append(arena, '"') catch @panic("OOM");
83
106
  for (arg16) |a| {
84
107
  switch (a) {
85
- '"' => args_list.appendSlice(alloc, &.{ '\\', '"' }) catch @panic("OOM"),
86
- else => args_list.append(alloc, a) catch @panic("OOM"),
108
+ '"' => args_list.appendSlice(arena, &.{ '\\', '"' }) catch @panic("OOM"),
109
+ '\\' => args_list.appendSlice(arena, &.{ '\\', '\\' }) catch @panic("OOM"),
110
+ else => args_list.append(arena, a) catch @panic("OOM"),
87
111
  }
88
112
  }
89
- args_list.appendSlice(alloc, &.{ '"', ' ' }) catch @panic("OOM");
113
+ args_list.appendSlice(arena, &.{ '"', ' ' }) catch @panic("OOM");
90
114
  } else {
91
- args_list.appendSlice(alloc, arg16) catch @panic("OOM");
92
- args_list.append(alloc, ' ') catch @panic("OOM");
115
+ args_list.appendSlice(arena, arg16) catch @panic("OOM");
116
+ args_list.append(arena, ' ') catch @panic("OOM");
93
117
  }
94
118
  }
95
119
 
96
- break :args args_list.toOwnedSlice(alloc) catch @panic("OOM");
120
+ break :args args_list.toOwnedSlice(arena) catch @panic("OOM");
97
121
  },
98
122
  else => {
99
123
  var args_list: std.ArrayList([*:0]u8) = .empty;
100
124
 
101
125
  for (0..@intCast(arglen)) |arg_i| {
102
126
  const arg_str = c.PySequence_GetItem(argv, @intCast(arg_i));
127
+ defer c.Py_DecRef(arg_str);
103
128
  const arg_bytes = c.PyUnicode_AsEncodedString(arg_str, "UTF-8", "strict");
129
+ defer c.Py_DecRef(arg_bytes);
104
130
  var arg_ptr: [*c]u8 = undefined;
105
131
  var arg_len: isize = undefined;
106
132
  assert(0 <= c.PyBytes_AsStringAndSize(arg_bytes, &arg_ptr, &arg_len));
107
133
  const arg = arg_ptr[0..@intCast(arg_len) :0];
108
- args_list.append(alloc, arg) catch @panic("OOM");
134
+ args_list.append(arena, arg) catch @panic("OOM");
109
135
  }
110
- break :args args_list.toOwnedSlice(alloc) catch @panic("OOM");
136
+ break :args args_list.toOwnedSlice(arena) catch @panic("OOM");
111
137
  },
112
138
  }
113
139
  };
114
140
 
115
- var env: std.process.Environ.Map = .init(alloc);
141
+ var env: std.process.Environ.Map = .init(gpa);
116
142
  defer env.deinit();
117
143
  {
118
144
  const os = c.PyImport_ImportModule("os");
145
+ defer c.Py_DecRef(os);
119
146
  const os_environ = c.PyObject_GetAttrString(os, "environ");
147
+ defer c.Py_DecRef(os_environ);
120
148
  const env_dict = c.PyDict_New();
149
+ defer c.Py_DecRef(env_dict);
150
+
121
151
  assert(0 <= c.PyDict_Merge(env_dict, os_environ, 1));
122
152
 
123
153
  var dict_key: [*c]c.PyObject = undefined;
@@ -125,12 +155,14 @@ pub fn wrapMain(wrap_main: anytype, comptime options: WrapMainOptions) fn ([*]c.
125
155
  var dict_pos: c.Py_ssize_t = 0;
126
156
  while (c.PyDict_Next(env_dict, &dict_pos, &dict_key, &dict_value) != 0) {
127
157
  const key_bytes = c.PyUnicode_AsEncodedString(dict_key, "UTF-8", "strict");
158
+ defer c.Py_DecRef(key_bytes);
128
159
  var key_ptr: [*c]u8 = undefined;
129
160
  var key_len: isize = undefined;
130
161
  assert(0 <= c.PyBytes_AsStringAndSize(key_bytes, &key_ptr, &key_len));
131
162
  const key_str = key_ptr[0..@intCast(key_len) :0];
132
163
 
133
164
  const val_bytes = c.PyUnicode_AsEncodedString(dict_value, "UTF-8", "strict");
165
+ defer c.Py_DecRef(val_bytes);
134
166
  var val_ptr: [*c]u8 = undefined;
135
167
  var val_len: isize = undefined;
136
168
  assert(0 <= c.PyBytes_AsStringAndSize(val_bytes, &val_ptr, &val_len));
@@ -141,8 +173,8 @@ pub fn wrapMain(wrap_main: anytype, comptime options: WrapMainOptions) fn ([*]c.
141
173
  }
142
174
 
143
175
  const init: std.process.Init = .{
144
- .arena = &arena,
145
- .gpa = std.heap.c_allocator,
176
+ .arena = &arena_impl,
177
+ .gpa = gpa,
146
178
  .io = threaded.io(),
147
179
  .environ_map = &env,
148
180
  .minimal = .{
@@ -175,12 +207,14 @@ pub fn wrapMain(wrap_main: anytype, comptime options: WrapMainOptions) fn ([*]c.
175
207
  }
176
208
  }
177
209
 
210
+ /// adds a __version__ and __version_str__ to the object
178
211
  pub fn addVersion(mod: [*c]c.PyObject) void {
179
212
  const semver = comptime std.SemanticVersion.parse(version) catch {
180
213
  @compileLog("could not parse version:");
181
214
  @compileError(version);
182
215
  };
183
216
  const version_dict = c.PyDict_New();
217
+ defer c.Py_DecRef(version_dict);
184
218
  const None = c.Py_BuildValue("");
185
219
 
186
220
  assert(0 <= c.PyDict_SetItemString(version_dict, "major", c.Py_BuildValue("n", semver.major)));
@@ -188,12 +222,16 @@ pub fn addVersion(mod: [*c]c.PyObject) void {
188
222
  assert(0 <= c.PyDict_SetItemString(version_dict, "patch", c.Py_BuildValue("n", semver.patch)));
189
223
 
190
224
  if (semver.pre) |pre| {
191
- assert(0 <= c.PyDict_SetItemString(version_dict, "pre", c.Py_BuildValue("s#", pre.ptr, pre.len)));
225
+ const pre_str = c.Py_BuildValue("s#", pre.ptr, pre.len);
226
+ defer c.Py_DecRef(pre_str);
227
+ assert(0 <= c.PyDict_SetItemString(version_dict, "pre", pre_str));
192
228
  } else {
193
229
  assert(0 <= c.PyDict_SetItemString(version_dict, "pre", None));
194
230
  }
195
231
  if (semver.build) |build| {
196
- assert(0 <= c.PyDict_SetItemString(version_dict, "build", c.Py_BuildValue("s#", build.ptr, build.len)));
232
+ const build_str = c.Py_BuildValue("s#", build.ptr, build.len);
233
+ defer c.Py_DecRef(build_str);
234
+ assert(0 <= c.PyDict_SetItemString(version_dict, "build", build_str));
197
235
  } else {
198
236
  assert(0 <= c.PyDict_SetItemString(version_dict, "build", None));
199
237
  }
@@ -211,8 +249,10 @@ pub fn addVersion(mod: [*c]c.PyObject) void {
211
249
  ));
212
250
  }
213
251
 
252
+ /// adds a dict of zigs builtin module info to the object
214
253
  pub fn addZigBuiltin(mod: [*c]c.PyObject) void {
215
254
  const zig_dict = getZigBuitin();
255
+ defer c.Py_DecRef(zig_dict);
216
256
  assert(0 <= c.PyObject_SetAttrString(
217
257
  mod,
218
258
  "__zig_builtin__",
@@ -221,7 +261,7 @@ pub fn addZigBuiltin(mod: [*c]c.PyObject) void {
221
261
  }
222
262
 
223
263
  pub fn getZigBuitin() *c.PyObject {
224
- var arena_instance = std.heap.ArenaAllocator.init(std.heap.c_allocator);
264
+ var arena_instance = std.heap.ArenaAllocator.init(py_allocator);
225
265
  defer arena_instance.deinit();
226
266
  const arena = arena_instance.allocator();
227
267
  const None = c.Py_BuildValue("");
@@ -229,6 +269,7 @@ pub fn getZigBuitin() *c.PyObject {
229
269
  const zig_dict = c.PyDict_New();
230
270
  {
231
271
  const version_str = c.Py_BuildValue("s#", builtin.zig_version_string.ptr, builtin.zig_version_string.len);
272
+ defer c.Py_DecRef(version_str);
232
273
  assert(0 <= c.PyDict_SetItemString(
233
274
  zig_dict,
234
275
  "zig_version",
@@ -243,6 +284,7 @@ pub fn getZigBuitin() *c.PyObject {
243
284
  .{@tagName(builtin.mode)},
244
285
  ) catch @panic("OOM");
245
286
  const optmode_str = c.Py_BuildValue("s#", optmode.ptr, optmode.len);
287
+ defer c.Py_DecRef(optmode_str);
246
288
  assert(0 <= c.PyDict_SetItemString(
247
289
  zig_dict,
248
290
  "optimize",
@@ -257,6 +299,7 @@ pub fn getZigBuitin() *c.PyObject {
257
299
  .{@tagName(builtin.zig_backend)},
258
300
  ) catch @panic("OOM");
259
301
  const backend_str = c.Py_BuildValue("s#", backend.ptr, backend.len);
302
+ defer c.Py_DecRef(backend_str);
260
303
  assert(0 <= c.PyDict_SetItemString(
261
304
  zig_dict,
262
305
  "backend",
@@ -266,6 +309,7 @@ pub fn getZigBuitin() *c.PyObject {
266
309
 
267
310
  {
268
311
  const target_dict = c.PyDict_New();
312
+ defer c.Py_DecRef(target_dict);
269
313
  assert(0 <= c.PyDict_SetItemString(
270
314
  zig_dict,
271
315
  "target",
@@ -275,6 +319,7 @@ pub fn getZigBuitin() *c.PyObject {
275
319
  {
276
320
  const target_triple = builtin.target.zigTriple(arena) catch @panic("OOM");
277
321
  const target_triple_str = c.Py_BuildValue("s#", target_triple.ptr, target_triple.len);
322
+ defer c.Py_DecRef(target_triple_str);
278
323
  assert(0 <= c.PyDict_SetItemString(
279
324
  target_dict,
280
325
  "triple",
@@ -284,31 +329,44 @@ pub fn getZigBuitin() *c.PyObject {
284
329
 
285
330
  {
286
331
  const cpu_dict = c.PyDict_New();
332
+ defer c.Py_DecRef(cpu_dict);
287
333
  assert(0 <= c.PyDict_SetItemString(target_dict, "cpu", cpu_dict));
334
+
288
335
  const arch_tag = @tagName(builtin.cpu.arch);
289
336
  const arch_str = c.Py_BuildValue("s#", arch_tag.ptr, arch_tag.len);
337
+ defer c.Py_DecRef(arch_str);
290
338
  assert(0 <= c.PyDict_SetItemString(cpu_dict, "arch", arch_str));
339
+
291
340
  const model_str = c.Py_BuildValue("s#", builtin.cpu.model.name.ptr, builtin.cpu.model.name.len);
341
+ defer c.Py_DecRef(model_str);
292
342
  assert(0 <= c.PyDict_SetItemString(cpu_dict, "model", model_str));
343
+
293
344
  const features = c.PyList_New(0);
345
+ defer c.Py_DecRef(features);
294
346
  assert(0 <= c.PyDict_SetItemString(cpu_dict, "features", features));
295
347
 
296
348
  inline for (comptime builtin.target.cpu.arch.allFeaturesList()) |feature| {
297
349
  if (builtin.target.cpu.has(builtin.target.cpu.arch.family(), @enumFromInt(feature.index))) {
298
350
  const feature_str = c.Py_BuildValue("s#", feature.name.ptr, feature.name.len);
351
+ defer c.Py_DecRef(feature_str);
299
352
  assert(c.PyList_Append(features, feature_str) >= 0);
300
353
  }
301
354
  }
302
355
  }
303
356
  {
304
357
  const os_dict = c.PyDict_New();
358
+ defer c.Py_DecRef(os_dict);
305
359
  assert(0 <= c.PyDict_SetItemString(target_dict, "os", os_dict));
360
+
306
361
  const os_tag = @tagName(builtin.os.tag);
307
362
  const os_str = c.Py_BuildValue("s#", os_tag.ptr, os_tag.len);
363
+ defer c.Py_DecRef(os_str);
308
364
  assert(0 <= c.PyDict_SetItemString(os_dict, "tag", os_str));
365
+
309
366
  switch (builtin.target.os.versionRange()) {
310
367
  .linux => |vrange| {
311
- const android = c.Py_BuildValue("d", vrange.android);
368
+ const android = c.Py_BuildValue("I", vrange.android);
369
+ defer c.Py_DecRef(android);
312
370
  assert(0 <= c.PyDict_SetItemString(os_dict, "android", android));
313
371
 
314
372
  const glibc = std.fmt.allocPrint(
@@ -317,6 +375,7 @@ pub fn getZigBuitin() *c.PyObject {
317
375
  .{vrange.glibc},
318
376
  ) catch @panic("OOM");
319
377
  const glibc_str = c.Py_BuildValue("s#", glibc.ptr, glibc.len);
378
+ defer c.Py_DecRef(glibc_str);
320
379
  assert(0 <= c.PyDict_SetItemString(os_dict, "glibc_version", glibc_str));
321
380
 
322
381
  const min = std.fmt.allocPrint(
@@ -325,6 +384,7 @@ pub fn getZigBuitin() *c.PyObject {
325
384
  .{vrange.range.min},
326
385
  ) catch @panic("OOM");
327
386
  const min_str = c.Py_BuildValue("s#", min.ptr, min.len);
387
+ defer c.Py_DecRef(min_str);
328
388
  assert(0 <= c.PyDict_SetItemString(os_dict, "min_version", min_str));
329
389
 
330
390
  const max = std.fmt.allocPrint(
@@ -333,23 +393,26 @@ pub fn getZigBuitin() *c.PyObject {
333
393
  .{vrange.range.max},
334
394
  ) catch @panic("OOM");
335
395
  const max_str = c.Py_BuildValue("s#", max.ptr, max.len);
396
+ defer c.Py_DecRef(max_str);
336
397
  assert(0 <= c.PyDict_SetItemString(os_dict, "max_version", max_str));
337
398
  },
338
399
  .windows => |vrange| {
339
400
  const min = std.fmt.allocPrint(
340
401
  arena,
341
- "{f}",
342
- .{vrange.min},
402
+ "{s}",
403
+ .{@tagName(vrange.min)},
343
404
  ) catch @panic("OOM");
344
405
  const min_str = c.Py_BuildValue("s#", min.ptr, min.len);
406
+ defer c.Py_DecRef(min_str);
345
407
  assert(0 <= c.PyDict_SetItemString(os_dict, "min_version", min_str));
346
408
 
347
409
  const max = std.fmt.allocPrint(
348
410
  arena,
349
- "{f}",
350
- .{vrange.max},
411
+ "{s}",
412
+ .{@tagName(vrange.max)},
351
413
  ) catch @panic("OOM");
352
414
  const max_str = c.Py_BuildValue("s#", max.ptr, max.len);
415
+ defer c.Py_DecRef(max_str);
353
416
  assert(0 <= c.PyDict_SetItemString(os_dict, "max_version", max_str));
354
417
  },
355
418
  .semver => |vrange| {
@@ -359,6 +422,7 @@ pub fn getZigBuitin() *c.PyObject {
359
422
  .{vrange.min},
360
423
  ) catch @panic("OOM");
361
424
  const min_str = c.Py_BuildValue("s#", min.ptr, min.len);
425
+ defer c.Py_DecRef(min_str);
362
426
  assert(0 <= c.PyDict_SetItemString(os_dict, "min_version", min_str));
363
427
 
364
428
  const max = std.fmt.allocPrint(
@@ -367,6 +431,7 @@ pub fn getZigBuitin() *c.PyObject {
367
431
  .{vrange.max},
368
432
  ) catch @panic("OOM");
369
433
  const max_str = c.Py_BuildValue("s#", max.ptr, max.len);
434
+ defer c.Py_DecRef(max_str);
370
435
  assert(0 <= c.PyDict_SetItemString(os_dict, "max_version", max_str));
371
436
  },
372
437
  .hurd => |vrange| {
@@ -376,6 +441,7 @@ pub fn getZigBuitin() *c.PyObject {
376
441
  .{vrange.glibc},
377
442
  ) catch @panic("OOM");
378
443
  const glibc_str = c.Py_BuildValue("s#", glibc.ptr, glibc.len);
444
+ defer c.Py_DecRef(glibc_str);
379
445
  assert(0 <= c.PyDict_SetItemString(os_dict, "glibc_version", glibc_str));
380
446
 
381
447
  const min = std.fmt.allocPrint(
@@ -384,6 +450,7 @@ pub fn getZigBuitin() *c.PyObject {
384
450
  .{vrange.range.min},
385
451
  ) catch @panic("OOM");
386
452
  const min_str = c.Py_BuildValue("s#", min.ptr, min.len);
453
+ defer c.Py_DecRef(min_str);
387
454
  assert(0 <= c.PyDict_SetItemString(os_dict, "min_version", min_str));
388
455
 
389
456
  const max = std.fmt.allocPrint(
@@ -392,6 +459,7 @@ pub fn getZigBuitin() *c.PyObject {
392
459
  .{vrange.range.max},
393
460
  ) catch @panic("OOM");
394
461
  const max_str = c.Py_BuildValue("s#", max.ptr, max.len);
462
+ defer c.Py_DecRef(max_str);
395
463
  assert(0 <= c.PyDict_SetItemString(os_dict, "max_version", max_str));
396
464
  },
397
465
  .none => {},
@@ -401,11 +469,13 @@ pub fn getZigBuitin() *c.PyObject {
401
469
  {
402
470
  const abi_tag = @tagName(builtin.target.abi);
403
471
  const abi_str = c.Py_BuildValue("s#", abi_tag.ptr, abi_tag.len);
472
+ defer c.Py_DecRef(abi_str);
404
473
  assert(0 <= c.PyDict_SetItemString(target_dict, "abi", abi_str));
405
474
  }
406
475
 
407
476
  if (builtin.target.dynamic_linker.get()) |linker| {
408
477
  const dynamic_linker = c.Py_BuildValue("s#", linker.ptr, linker.len);
478
+ defer c.Py_DecRef(dynamic_linker);
409
479
  assert(0 <= c.PyDict_SetItemString(target_dict, "dynamic_linker", dynamic_linker));
410
480
  } else {
411
481
  assert(0 <= c.PyDict_SetItemString(target_dict, "dynamic_linker", None));
@@ -0,0 +1,201 @@
1
+ const std = @import("std");
2
+ const Alignment = std.mem.Alignment;
3
+ const Allocator = std.mem.Allocator;
4
+ const builtin = @import("builtin");
5
+ const assert = std.debug.assert;
6
+ pub const c = @import("c");
7
+
8
+ comptime {
9
+ if (!builtin.link_libc) {
10
+ @compileError("C allocator is only available when linking against libc");
11
+ }
12
+ }
13
+
14
+ pub const py_allocator: std.mem.Allocator = .{
15
+ .ptr = undefined,
16
+ .vtable = &vtable,
17
+ };
18
+
19
+ const vtable: Allocator.VTable = .{
20
+ .alloc = alloc,
21
+ .resize = std.mem.Allocator.noResize,
22
+ .remap = std.mem.Allocator.noRemap,
23
+ .free = free,
24
+ };
25
+
26
+ const have_posix_memalign = switch (builtin.os.tag) {
27
+ .dragonfly,
28
+ .netbsd,
29
+ .freebsd,
30
+ .illumos,
31
+ .openbsd,
32
+ .linux,
33
+ .driverkit,
34
+ .ios,
35
+ .maccatalyst,
36
+ .macos,
37
+ .tvos,
38
+ .visionos,
39
+ .watchos,
40
+ .serenity,
41
+ => true,
42
+ else => false,
43
+ };
44
+
45
+ fn allocStrat(need_align: Alignment) union(enum) {
46
+ raw,
47
+ posix_memalign: if (have_posix_memalign) void else noreturn,
48
+ manual_align: if (have_posix_memalign) noreturn else void,
49
+ } {
50
+ // If `malloc` guarantees `need_align`, always prefer a raw allocation.
51
+ if (Alignment.compare(need_align, .lte, .of(c.max_align_t))) {
52
+ return .raw;
53
+ }
54
+ // Use `posix_memalign` if available. Otherwise, we must manually align the allocation.
55
+ return if (have_posix_memalign) .posix_memalign else .manual_align;
56
+ }
57
+
58
+ /// If `allocStrat(a) == .manual_align`, an allocation looks like this:
59
+ ///
60
+ /// unaligned_ptr hdr_ptr aligned_ptr
61
+ /// v v v
62
+ /// +---------------+--------+--------------+
63
+ /// | padding | header | usable bytes |
64
+ /// +---------------+--------+--------------+
65
+ ///
66
+ /// * `unaligned_ptr` is the raw return value of `malloc`.
67
+ /// * `aligned_ptr` is computed by aligning `unaligned_ptr` forward; it is what `alloc` returns.
68
+ /// * `hdr_ptr` points to a pointer-sized header directly before the usable space. This header
69
+ /// contains the value `unaligned_ptr`, so that we can pass it to `free` later. This is
70
+ /// necessary because the width of the padding is unknown.
71
+ ///
72
+ /// This function accepts `aligned_ptr` and offsets it backwards to return `hdr_ptr`.
73
+ fn manualAlignHeader(aligned_ptr: [*]u8) *[*]u8 {
74
+ return @ptrCast(@alignCast(aligned_ptr - @sizeOf(usize)));
75
+ }
76
+
77
+ fn alloc(
78
+ _: *anyopaque,
79
+ len: usize,
80
+ alignment: Alignment,
81
+ return_address: usize,
82
+ ) ?[*]u8 {
83
+ _ = return_address;
84
+ assert(len > 0);
85
+ switch (allocStrat(alignment)) {
86
+ .raw => {
87
+ // `std.c.max_align_t` isn't the whole story, because if `len` is smaller than
88
+ // every C type with alignment `max_align_t`, the allocation can be less-aligned.
89
+ // The implementation need only guarantee that any type of length `len` would be
90
+ // suitably aligned.
91
+ //
92
+ // For instance, if `len == 8` and `alignment == .@"16"`, then `malloc` may not
93
+ // fulfil this request, because there is necessarily no C type with 8-byte size
94
+ // but 16-byte alignment.
95
+ //
96
+ // In theory, the resulting rule here would be target-specific, but in practice,
97
+ // the smallest type with an alignment of `max_align_t` has the same size (it's
98
+ // usually `c_longdouble`), so we can just extend the allocation size up to the
99
+ // alignment of `max_align_t` if necessary.
100
+ const actual_len = @max(len, @alignOf(std.c.max_align_t));
101
+ const ptr = c.PyMem_Malloc(actual_len) orelse return null;
102
+ assert(alignment.check(@intFromPtr(ptr)));
103
+ return @ptrCast(ptr);
104
+ },
105
+ .posix_memalign => {
106
+ // The posix_memalign only accepts alignment values that are a
107
+ // multiple of the pointer size
108
+ const effective_alignment = @max(alignment.toByteUnits(), @sizeOf(usize));
109
+ var aligned_ptr: ?*anyopaque = undefined;
110
+ if (c.posix_memalign(&aligned_ptr, effective_alignment, len) != 0) {
111
+ return null;
112
+ }
113
+ assert(alignment.check(@intFromPtr(aligned_ptr)));
114
+ return @ptrCast(aligned_ptr);
115
+ },
116
+ .manual_align => {
117
+ // Overallocate to account for alignment padding and store the original pointer
118
+ // returned by `malloc` before the aligned address.
119
+ const padded_len = len + @sizeOf(usize) + alignment.toByteUnits() - 1;
120
+ const unaligned_ptr: [*]u8 = @ptrCast(c.PyMem_Malloc(padded_len) orelse return null);
121
+ const unaligned_addr = @intFromPtr(unaligned_ptr);
122
+ const aligned_addr = alignment.forward(unaligned_addr + @sizeOf(usize));
123
+ const aligned_ptr = unaligned_ptr + (aligned_addr - unaligned_addr);
124
+ manualAlignHeader(aligned_ptr).* = unaligned_ptr;
125
+ return aligned_ptr;
126
+ },
127
+ }
128
+ }
129
+
130
+ fn resize(
131
+ _: *anyopaque,
132
+ memory: []u8,
133
+ alignment: Alignment,
134
+ new_len: usize,
135
+ return_address: usize,
136
+ ) bool {
137
+ _ = return_address;
138
+ assert(new_len > 0);
139
+ if (new_len <= memory.len) {
140
+ return true; // in-place shrink always works
141
+ }
142
+ const mallocSize = func: {
143
+ if (@TypeOf(std.c.malloc_size) != void) break :func std.c.malloc_size;
144
+ if (@TypeOf(std.c.malloc_usable_size) != void) break :func std.c.malloc_usable_size;
145
+ if (@TypeOf(std.c._msize) != void) break :func std.c._msize;
146
+ return false; // we don't know how much space is actually available
147
+ };
148
+ const usable_len: usize = switch (allocStrat(alignment)) {
149
+ .raw, .posix_memalign => mallocSize(memory.ptr),
150
+ .manual_align => usable_len: {
151
+ const unaligned_ptr = manualAlignHeader(memory.ptr).*;
152
+ const full_len = mallocSize(unaligned_ptr);
153
+ const padding = @intFromPtr(memory.ptr) - @intFromPtr(unaligned_ptr);
154
+ break :usable_len full_len - padding;
155
+ },
156
+ };
157
+ return new_len <= usable_len;
158
+ }
159
+
160
+ fn remap(
161
+ ctx: *anyopaque,
162
+ memory: []u8,
163
+ alignment: Alignment,
164
+ new_len: usize,
165
+ return_address: usize,
166
+ ) ?[*]u8 {
167
+ assert(new_len > 0);
168
+ // Prefer resizing in-place if possible, since `realloc` could be expensive even if legal.
169
+ if (resize(ctx, memory, alignment, new_len, return_address)) {
170
+ return memory.ptr;
171
+ }
172
+ switch (allocStrat(alignment)) {
173
+ .raw => {
174
+ // `malloc` and friends guarantee the required alignment, so we can try `realloc`.
175
+ // C only needs to respect `max_align_t` up to the allocation size due to object
176
+ // alignment rules. If necessary, extend the allocation size.
177
+ const actual_len = @max(new_len, @alignOf(std.c.max_align_t));
178
+ const new_ptr = c.PyMem_Realloc(memory.ptr, actual_len) orelse return null;
179
+ assert(alignment.check(@intFromPtr(new_ptr)));
180
+ return @ptrCast(new_ptr);
181
+ },
182
+ .posix_memalign, .manual_align => {
183
+ // `realloc` would potentially return a new allocation which does not respect
184
+ // the original alignment, so we can't do anything more.
185
+ return null;
186
+ },
187
+ }
188
+ }
189
+
190
+ fn free(
191
+ _: *anyopaque,
192
+ memory: []u8,
193
+ alignment: Alignment,
194
+ return_address: usize,
195
+ ) void {
196
+ _ = return_address;
197
+ switch (allocStrat(alignment)) {
198
+ .raw, .posix_memalign => c.PyMem_Free(memory.ptr),
199
+ .manual_align => c.PyMem_Free(manualAlignHeader(memory.ptr).*),
200
+ }
201
+ }
@@ -3,14 +3,22 @@ const std = @import("std");
3
3
  name: []const u8,
4
4
  version: std.SemanticVersion,
5
5
  zig_version: std.SemanticVersion,
6
- build: struct {
6
+ build: Build = .{},
7
+ install_requires: []const []const u8 = &.{},
8
+ entry_points: EntryPoints = .{},
9
+
10
+ pub const Build = struct {
7
11
  args: []const []const u8 = &.{},
12
+ // extra build dependencies
8
13
  requires: []const []const u8 = &.{},
14
+ // python packages to include
15
+ packages: []const []const u8 = &.{},
9
16
  // pattern of files to copy to bdist after zig build
10
- copy_pattern: []const u8 = "zig-out/lib/*",
11
- } = .{},
12
- install_requires: []const []const u8 = &.{},
13
- entry_points: EntryPoints = .{},
17
+ // defaults to "zig-out/lib/*"
18
+ copy_pattern: []const []const u8 = &.{
19
+ "zig-out/lib/*",
20
+ },
21
+ };
14
22
 
15
23
  pub const EntryPoints = struct {
16
24
  console_scripts: []const []const u8 = &.{},
zig-zon-0.2.4/build.zig DELETED
@@ -1,75 +0,0 @@
1
- const std = @import("std");
2
- const Build = std.Build;
3
- const zig_python_sdist = @import("zig_python_sdist");
4
- const zon = @import("build.zig.zon");
5
-
6
- pub fn build(b: *Build) void {
7
- const target = b.standardTargetOptions(.{});
8
- const optimize = b.standardOptimizeOption(.{});
9
-
10
- // this target and section of our build is used at pip install time
11
- const ext_install_step = b.step("bdist-wheel", "build python extension module");
12
-
13
- // this generates a python sdist archive
14
- const sdist = zig_python_sdist.createSdistStep(b, .{
15
- .name = "zig-zon",
16
- .version = zon.version,
17
- .description = b.path("README.md"),
18
- .build = .{
19
- .args = &.{
20
- ext_install_step.name,
21
- b.fmt("-Doptimize={s}", .{@tagName(optimize)}),
22
- },
23
- },
24
- .extra_pkg_info = @import("pkg-info.zon"),
25
- .files = &.{
26
- .{ .src = b.path("pkg-info.zon"), .dest = "pkg-info.zon" },
27
- .{ .src = b.path("build.zig.zon"), .dest = "build.zig.zon" },
28
- .{ .src = b.path("build.zig"), .dest = "build.zig" },
29
- .{ .src = b.path("src/zig_zon.zig"), .dest = "src/zig_zon.zig" },
30
- },
31
- });
32
-
33
- const sdistfile = b.addInstallFileWithDir(
34
- sdist.getEmittedArchive(),
35
- .{ .custom = "src" },
36
- sdist.basename,
37
- );
38
- b.getInstallStep().dependOn(&sdistfile.step);
39
-
40
- // we can use a python virtual environment inside
41
- // the zig cache to test pip installation
42
- const test_pip_install = zig_python_sdist.createVenvInstallTest(
43
- b,
44
- .{
45
- .sdist = sdist.getEmittedArchive(),
46
- .unittest_py = &.{b.path("src/test_zig_zon.py")},
47
- .twine_check = true,
48
- .no_clean = b.option(bool, "pip-no-clean", "dont cleanup pip temp dirs") orelse false,
49
- },
50
- );
51
- b.step("test-pip-install", "").dependOn(test_pip_install.step);
52
-
53
- {
54
- const cpython = zig_python_sdist.createCPythonModule(b, .{
55
- .target = target,
56
- .version = zon.version,
57
- .optimize = .ReleaseSmall,
58
- });
59
- const lib = b.addLibrary(.{
60
- .name = "zig_zon",
61
- .root_module = b.addModule("zig_zon", .{
62
- .root_source_file = b.path("src/zig_zon.zig"),
63
- .target = target,
64
- .optimize = optimize,
65
- .imports = &.{
66
- .{ .name = "cpython", .module = cpython },
67
- },
68
- }),
69
- .linkage = .dynamic,
70
- });
71
- const ext_install = zig_python_sdist.installExtLib(b, lib);
72
-
73
- ext_install_step.dependOn(&ext_install.step);
74
- }
75
- }
@@ -1 +0,0 @@
1
- {"name":"zig_zon","version":{"major":0,"minor":2,"patch":4,"pre":null,"build":null},"zig_version":{"major":0,"minor":16,"patch":0,"pre":null,"build":null},"build":{"args":["--fork=zig-pkg/zig_python_sdist-0.0.3","bdist-wheel","-Doptimize=ReleaseSmall"],"requires":[],"copy_pattern":"zig-out/lib/*"},"install_requires":[],"entry_points":{"console_scripts":[],"gui_scripts":[]}}
File without changes