Skip to content

Commit

Permalink
Fix generated build.zig to defer resolving pydust src (#11)
Browse files Browse the repository at this point in the history
  • Loading branch information
gatesn authored Sep 1, 2023
1 parent f9c4453 commit 0f0ad40
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 15 deletions.
4 changes: 3 additions & 1 deletion build.zig
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,9 @@ pub fn build(b: *std.Build) void {
}
}

fn getPythonIncludePath(allocator: std.mem.Allocator) ![]const u8 {
fn getPythonIncludePath(
allocator: std.mem.Allocator,
) ![]const u8 {
const includeResult = try std.process.Child.exec(.{
.allocator = allocator,
.argv = &.{ "python", "-c", "import sysconfig; print(sysconfig.get_path('include'), end='')" },
Expand Down
59 changes: 45 additions & 14 deletions pydust/buildzig.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,12 @@
import contextlib
import os
import subprocess
import sys
import sysconfig
import textwrap
from typing import TextIO

import pydust
from pydust import config

# We ship the PyDust Zig library inside our Python package to make it easier
# for us to auto-configure user projects.
PYDUST_ROOT = os.path.join(os.path.dirname(pydust.__file__), "src", "pydust.zig")

PYVER_MINOR = ".".join(str(v) for v in sys.version_info[:2])
PYVER_HEX = f"{sys.hexversion:#010x}"
PYINC = sysconfig.get_path("include")
Expand Down Expand Up @@ -45,13 +39,46 @@ def generate_build_zig(build_zig_file):
b.writeln('const std = @import("std");')
b.writeln()

# We choose to ship Pydust source code inside our PyPi package. This means the that once the PyPi package has
# been downloaded there are no further requests out to the internet.
#
# As a result of this though, we need some way to locate the source code. We can't use a reference to the
# currently running pydust, since that could be inside a temporary build env which won't exist later when the
# user is developing locally. Therefore, we defer resolving the path until the build.zig is invoked by shelling
# out to Python.
#
# We also want to avoid creating a pydust module (and instead prefer anonymous modules) so that we can populate
# a separate pyconf options object for each Python extension module.
b.write(
"""
fn getPydustRootPath(allocator: std.mem.Allocator) ![]const u8 {
const includeResult = try std.process.Child.exec(.{
.allocator = allocator,
.argv = &.{
"python",
"-c",
\\\\import os
\\\\import pydust
\\\\print(os.path.join(os.path.dirname(pydust.__file__), 'src', 'pydust.zig'), end='')
\\\\
},
});
allocator.free(includeResult.stderr);
return includeResult.stdout;
}
"""
)
b.writeln()

with b.block("pub fn build(b: *std.Build) void"):
b.write(
"""
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});
const test_step = b.step("test", "Run library tests");
const pydust = getPydustRootPath(b.allocator) catch @panic("Failed to locate Pydust source code");
"""
)

Expand All @@ -76,7 +103,7 @@ def generate_build_zig(build_zig_file):
.target = target,
.optimize = optimize,
}});
configurePythonInclude(lib{ext_module.libname}, pyconf);
configurePythonInclude(pydust, lib{ext_module.libname}, pyconf);
// Install the shared library within the source tree
const install{ext_module.libname} = b.addInstallFileWithDir(
Expand All @@ -92,7 +119,7 @@ def generate_build_zig(build_zig_file):
.target = target,
.optimize = optimize,
}});
configurePythonRuntime(test{ext_module.libname}, pyconf);
configurePythonRuntime(pydust, test{ext_module.libname}, pyconf);
const run_test{ext_module.libname} = b.addRunArtifact(test{ext_module.libname});
test_step.dependOn(&run_test{ext_module.libname}.step);
Expand All @@ -119,7 +146,7 @@ def generate_build_zig(build_zig_file):
.target = target,
.optimize = optimize,
}});
configurePythonRuntime(testdebug, pyconf);
configurePythonRuntime(pydust, testdebug, pyconf);
const debugBin = b.addInstallBinFile(testdebug.getEmittedBin(), "debug.bin");
b.getInstallStep().dependOn(&debugBin.step);
Expand All @@ -129,18 +156,22 @@ def generate_build_zig(build_zig_file):

b.write(
f"""
fn configurePythonInclude(compile: *std.Build.CompileStep, pyconf: *std.Build.Step.Options) void {{
fn configurePythonInclude(
pydust: []const u8, compile: *std.Build.CompileStep, pyconf: *std.Build.Step.Options,
) void {{
compile.addAnonymousModule("pydust", .{{
.source_file = .{{ .path = "{PYDUST_ROOT}" }},
.source_file = .{{ .path = pydust }},
.dependencies = &.{{.{{ .name = "pyconf", .module = pyconf.createModule() }}}},
}});
compile.addIncludePath(.{{ .path = "{PYINC}" }});
compile.linkLibC();
compile.linker_allow_shlib_undefined = true;
}}
fn configurePythonRuntime(compile: *std.Build.CompileStep, pyconf: *std.Build.Step.Options) void {{
configurePythonInclude(compile, pyconf);
fn configurePythonRuntime(
pydust: []const u8, compile: *std.Build.CompileStep, pyconf: *std.Build.Step.Options
) void {{
configurePythonInclude(pydust, compile, pyconf);
compile.linkSystemLibrary("python{PYVER_MINOR}");
compile.addLibraryPath(.{{ .path = "{PYLIB}" }});
}}
Expand Down Expand Up @@ -180,4 +211,4 @@ def writeln(self, text: str = ""):


if __name__ == "__main__":
generate_build_zig()
generate_build_zig("test.build.zig")

0 comments on commit 0f0ad40

Please sign in to comment.