Skip to content

Package Manager - source only dependencies MVP #15577

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Conversation

DraagrenKirneh
Copy link
Contributor

@DraagrenKirneh DraagrenKirneh commented May 5, 2023

This PR implements support for ("source only" / freestanding / non-zigged) dependencies in a zig.build.zon manifest.
It adds a new build function: current pending name "sourceDependency" which takes 3 parameters: the name of the free standing dependency, a struct with a build function for that dependency, and any arguments needed.
This makes it possible to construct simple sub builds for packages which do not have their own build.zig yet.

Example use-case: adding c libraries.

build.zig

const std = @import("std");

fn join(allocator: std.mem.Allocator, paths: []const []const u8) []const u8 {
    return std.fs.path.join(allocator, paths) catch unreachable;
}

fn joinSources(allocator: std.mem.Allocator, root: []const u8, sources: []const []const u8) []const []const u8 {
    const buf = allocator.alloc([]const u8, sources.len) catch unreachable;
    for (sources, 0..) |s, i| {
        buf[i] = join(allocator, &.{ root, s });
    }
    return buf;
}

// const zlib = @import("zlib.zig");
pub const Zlib = struct {
    pub fn build(b: *std.Build) void {
        const target = b.standardTargetOptions(.{});
        const optimize = b.standardOptimizeOption(.{});

        const root = b.build_root.path.?;

        const lib = b.addStaticLibrary(.{
            .name = "z",
            .target = target,
            .optimize = optimize,
        });
        lib.linkLibC();
        const source_files = joinSources(b.allocator, root, srcs);
        lib.addCSourceFiles(source_files, &.{"-std=c89"});
        lib.installHeadersDirectory(root, "");

        b.installArtifact(lib);
    }
    const srcs: []const []const u8 = &.{
        "adler32.c",
        "compress.c",
        "crc32.c",
        "deflate.c",
        "gzclose.c",
        "gzlib.c",
        "gzread.c",
        "gzwrite.c",
        "inflate.c",
        "infback.c",
        "inftrees.c",
        "inffast.c",
        "trees.c",
        "uncompr.c",
        "zutil.c",
    };
};

pub const LibPng = struct {
    pub fn build(b: *std.Build) void {
        const target = b.standardTargetOptions(.{});
        const optimize = b.standardOptimizeOption(.{});
        const root = b.build_root.path.?;
        const lib = b.addStaticLibrary(.{
            .name = "libpng",
            .target = target,
            .optimize = optimize,
        });

        lib.linkLibC();
        const source_files = joinSources(b.allocator, root, srcs);
        lib.addCSourceFiles(source_files, &.{
            "-std=c89",
        });

        const zlib_dep = b.sourceDependency("zlib", Zlib, .{
            .target = target,
            .optimize = optimize,
        });

        lib.linkLibrary(zlib_dep.artifact("z"));
        lib.installHeadersDirectory(root, "");

        b.installArtifact(lib);
    }

    const srcs: []const []const u8 = &.{
        "png.c",
        "pngerror.c",
        "pngget.c",
        "pngmem.c",
        "pngpread.c",
        "pngread.c",
        "pngrio.c",
        "pngrtran.c",
        "pngrutil.c",
        "pngset.c",
        "pngtrans.c",
        "pngwio.c",
        "pngwrite.c",
        "pngwtran.c",
        "pngwutil.c",
    };
};

pub fn build(b: *std.Build) void {
    const target = b.standardTargetOptions(.{});
    const optimize = b.standardOptimizeOption(.{});

    const main_tests = b.addTest(.{
        .root_source_file = .{ .path = "src/main.zig" },
        .target = target,
        .optimize = optimize,
    });

    const png_dep = b.sourceDependency("libpng", LibPng, .{
        .target = target,
        .optimize = optimize,
    });

    main_tests.linkLibrary(png_dep.artifact("libpng"));

    const run_main_tests = b.addRunArtifact(main_tests);
    const test_step = b.step("test", "Run library tests");
    test_step.dependOn(&run_main_tests.step);
}

zig.build.zon

.{
    .name = "test",
    .version = "0.0.0",
    .dependencies = .{
        .zlib = .{
            .url = "https://www.zlib.net/zlib-1.2.13.tar.gz",
            .hash = "1220a190b73e8f91ba4f19ee3dc651847d049c27da8db81bfa1bfd1f4df36d74f032",
            .source_only = true,
        },
        .libpng = .{
            .url = "http://prdownloads.sourceforge.net/libpng/libpng-1.6.39.tar.gz?download",
            .hash = "1220782f1d65d3d87b7f247c6b9c0c88fb38c12799ae9cb528c8c15c4895fcdcb649",
            .source_only = true,
        },
    },
}

@andrewrk
Copy link
Member

andrewrk commented May 5, 2023

Looks like you implemented this rejected proposal:

@DraagrenKirneh
Copy link
Contributor Author

Looks like you implemented this rejected proposal:

Hmm, well kind of, but in the context of any source file(s) not just zig ones as modules, and only for dependencies that have no build.zig nor build.zig.zon file in them + and explicit field showing the intent of the dependency (source_only and sourceDependency may not be the best names for this kind of dependency, but works for now as a placeholder).
I have also updated the code + example to not just use a hacky build_root_path, but actually be a usable build step/dependency.

I do think it is worth having the option include a dependency even though they may not have a build or zon file in them. Yes one could always create a new package/fork/extract of the dependency and add the required files, but it do feel kind of wrong to have to go through that step for simple and common use cases, and one do also kind of "lose" the hash of the original package and are left with a extracted files+build stuff hash which can be harder to verify against the original one.

@andrewrk andrewrk closed this Jun 18, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants