glslang-zig/build.zig
2024-05-31 23:59:48 -07:00

441 lines
No EOL
14 KiB
Zig

const std = @import("std");
const builtin = @import("builtin");
const spvtools = @import("External/spirv-tools/build.zig");
const Build = std.Build;
const log = std.log.scoped(.glslang_zig);
const spirv_header_name = "spirv-headers"; // Since update_glslang_sources downloads it as spirv-headers instead of SPIRV-Headers
pub fn build(b: *Build) !void {
const optimize = b.standardOptimizeOption(.{});
const target = b.standardTargetOptions(.{});
const debug = b.option(bool, "debug", "Whether to produce detailed debug symbols (g0) or not. These increase binary size considerably.") orelse false;
const shared = b.option(bool, "shared", "Build glslang as a shared library.") orelse false;
const enable_hlsl = !(b.option(bool, "no-hlsl", "Skip building glslang HLSL support.") orelse false);
const enable_opt = !(b.option(bool, "no-opt", "Skip building spirv-tools optimization.") orelse false);
const shared_tools = b.option(bool, "shared-tools", "Build and link spirv-tools as a shared library.") orelse false;
const standalone_glslang = b.option(bool, "standalone", "Build glslang.exe standalone command-line compiler.") orelse false;
const standalone_spvremap = b.option(bool, "standalone-remap", "Build spirv-remap.exe standalone command-line remapper.") orelse false;
const tools_libs: spvtools.SPVLibs = spvtools.build_spirv(b, optimize, target, shared_tools, debug, spirv_header_name) catch |err| {
log.err("Error building SPIRV-Tools: {s}", .{ @errorName(err) });
std.process.exit(1);
};
var cppflags = std.ArrayList([]const u8).init(b.allocator);
if (!debug) {
try cppflags.append("-g0");
}
try cppflags.append("-std=c++17");
const base_flags = &.{
"-Wno-conversion",
"-Wno-extra-semi",
"-Wno-ignored-qualifiers",
"-Wno-implicit-fallthrough",
"-Wno-inconsistent-missing-override",
"-Wno-missing-field-initializers",
"-Wno-newline-eof",
"-Wno-sign-compare",
"-Wno-suggest-destructor-override",
"-Wno-suggest-override",
"-Wno-unused-variable",
"-fPIC",
};
try cppflags.appendSlice(base_flags);
// ------------------
// SPIRV-Tools
// ------------------
const build_headers = BuildHeadersStep.init(b);
const sources = sources_spirv ++
sources_generic_codegen ++
sources_machine_independent ++
sources_resource_limits ++
sources_c_interface;
var glslang_lib: *std.Build.Step.Compile = undefined;
if (shared) {
glslang_lib = b.addSharedLibrary(.{
.name = "glslang",
.root_source_file = b.addWriteFiles().add("empty.c", ""),
.optimize = optimize,
.target = target,
});
glslang_lib.defineCMacro("GLSLANG_IS_SHARED_LIBRARY", "");
glslang_lib.defineCMacro("GLSLANG_EXPORTING", "");
} else {
glslang_lib = b.addStaticLibrary(.{
.name = "glslang",
.root_source_file = b.addWriteFiles().add("empty.c", ""),
.optimize = optimize,
.target = target,
});
}
glslang_lib.addCSourceFiles(.{
.files = &sources,
.flags = cppflags.items,
});
const tag = target.result.os.tag;
if (tag == .windows) {
glslang_lib.addCSourceFiles(.{
.files = &sources_win,
.flags = cppflags.items,
});
glslang_lib.defineCMacro("GLSLANG_OSINCLUDE_WIN32", "");
} else {
glslang_lib.addCSourceFiles(.{
.files = &sources_unix,
.flags = cppflags.items,
});
glslang_lib.defineCMacro("GLSLANG_OSINCLUDE_UNIX", "");
}
if (enable_hlsl) {
glslang_lib.addCSourceFiles(.{
.files = &sources_hlsl,
.flags = cppflags.items,
});
glslang_lib.defineCMacro("ENABLE_HLSL", "1");
} else {
glslang_lib.defineCMacro("ENABLE_HLSL", "0");
}
if (enable_opt) {
glslang_lib.addCSourceFiles(.{
.files = &sources_opt,
.flags = cppflags.items,
});
glslang_lib.defineCMacro("ENABLE_OPT", "1");
glslang_lib.step.dependOn(&tools_libs.tools_opt.step);
glslang_lib.step.dependOn(&tools_libs.tools_val.step);
glslang_lib.linkLibrary(tools_libs.tools_opt);
glslang_lib.linkLibrary(tools_libs.tools_val);
} else {
glslang_lib.defineCMacro("ENABLE_OPT", "0");
}
addIncludes(glslang_lib);
spvtools.addSPIRVPublicIncludes(glslang_lib, spirv_header_name);
glslang_lib.linkLibCpp();
glslang_lib.step.dependOn(&build_headers.step);
const build_step = b.step("glslang-library", "Build the glslang library");
build_step.dependOn(&b.addInstallArtifact(glslang_lib, .{}).step);
b.installArtifact(glslang_lib);
if (standalone_glslang) {
const glslang_exe = b.addExecutable(.{
.name = "glslang",
.optimize = optimize,
.target = target,
});
const install_glslang_step = b.step("glslang-standalone", "Build and install glslang.exe");
install_glslang_step.dependOn(&b.addInstallArtifact(glslang_exe, .{}).step);
glslang_exe.addCSourceFiles(.{
.files = &sources_standalone_glslang,
.flags = &.{ "-std=c++17" },
});
addIncludes(glslang_exe);
b.installArtifact(glslang_exe);
glslang_exe.linkLibrary(glslang_lib);
if (target.result.os.tag == .windows) {
// windows must be built with LTO disabled due to:
// https://github.com/ziglang/zig/issues/15958
glslang_exe.want_lto = false;
}
if (enable_hlsl) {
glslang_exe.defineCMacro("ENABLE_HLSL", "1");
} else {
glslang_exe.defineCMacro("ENABLE_HLSL", "0");
}
if (enable_opt) {
glslang_exe.defineCMacro("ENABLE_OPT", "1");
} else {
glslang_exe.defineCMacro("ENABLE_OPT", "0");
}
}
if (standalone_spvremap) {
const spirv_remap = b.addExecutable(.{
.name = "spirv-remap",
.optimize = optimize,
.target = target,
});
const install_remap_step = b.step("spirv-remap", "Build and install spirv-remap.exe");
install_remap_step.dependOn(&b.addInstallArtifact(spirv_remap, .{}).step);
spirv_remap.addCSourceFiles(.{
.files = &sources_standalone_remap,
.flags = &.{ "-std=c++17" },
});
addIncludes(spirv_remap);
b.installArtifact(spirv_remap);
spirv_remap.linkLibrary(glslang_lib);
if (target.result.os.tag == .windows) {
spirv_remap.want_lto = false;
}
}
}
fn addIncludes(step: *std.Build.Step.Compile) void {
step.addIncludePath(.{ .path = sdkPath("/" ++ output_path) });
step.addIncludePath(.{ .path = sdkPath("/") });
}
fn ensureCommandExists(allocator: std.mem.Allocator, name: []const u8, exist_check: []const u8) bool {
const result = std.ChildProcess.run(.{
.allocator = allocator,
.argv = &[_][]const u8{ name, exist_check },
.cwd = ".",
}) catch // e.g. FileNotFound
{
return false;
};
defer {
allocator.free(result.stderr);
allocator.free(result.stdout);
}
if (result.term.Exited != 0)
return false;
return true;
}
fn exec(allocator: std.mem.Allocator, argv: []const []const u8, cwd: []const u8) !void {
log.info("cd {s}", .{cwd});
var buf = std.ArrayList(u8).init(allocator);
for (argv) |arg| {
try std.fmt.format(buf.writer(), "{s} ", .{arg});
}
log.info("{s}", .{buf.items});
var child = std.ChildProcess.init(argv, allocator);
child.cwd = cwd;
_ = try child.spawnAndWait();
}
fn sdkPath(comptime suffix: []const u8) []const u8 {
if (suffix[0] != '/') @compileError("suffix must be an absolute path");
return comptime blk: {
const root_dir = std.fs.path.dirname(@src().file) orelse ".";
break :blk root_dir ++ suffix;
};
}
fn ensurePython(allocator: std.mem.Allocator) void {
if (!ensureCommandExists(allocator, "python3", "--version")) {
log.err("'python3 --version' failed. Is python not installed?", .{});
std.process.exit(1);
}
}
fn runPython(allocator: std.mem.Allocator, args: []const []const u8, errMsg: []const u8) void {
exec(allocator, args, sdkPath("/")) catch |err| {
log.err("{s}. error: {s}", .{ errMsg, @errorName(err) });
std.process.exit(1);
};
}
// ------------------------------------------
// Include generation logic
// ------------------------------------------
pub const output_path = "build";
const build_info_script = "build_info.py";
const ext_header_script = "gen_extension_headers.py";
fn outPath(comptime out_name: []const u8) []const u8 {
if (out_name[0] != '/') @compileError("suffix must be an absolute path");
return sdkPath("/" ++ output_path ++ out_name);
}
// Script usage derived from the BUILD.gn
fn genBuildInfo(allocator: std.mem.Allocator) void {
const args = &[_][]const u8{
"python3", build_info_script,
sdkPath("/"),
"-i", sdkPath("/build_info.h.tmpl"),
"-o", outPath("/glslang/build_info.h"),
};
runPython(allocator, args, "Failed to generate build info file.");
}
fn genExtensionHeaders(allocator: std.mem.Allocator) void {
const args = &[_][]const u8 {
"python3", ext_header_script,
"-i", sdkPath("/glslang/ExtensionHeaders"),
"-o", outPath("/glslang/glsl_intrinsic_header.h"),
};
runPython(allocator, args, "Failed to generate extension headers");
}
fn generateHeaders(allocator: std.mem.Allocator) void {
if (!ensureCommandExists(allocator, "python3", "--version")) {
log.err("'python3 --version' failed. Is python not installed?", .{});
std.process.exit(1);
}
genBuildInfo(allocator);
genExtensionHeaders(allocator);
}
var build_mutex = std.Thread.Mutex{};
pub const BuildHeadersStep = struct {
step: std.Build.Step,
b: *std.Build,
pub fn init(b: *std.Build) *BuildHeadersStep {
const build_headers = b.allocator.create(BuildHeadersStep) catch unreachable;
build_headers.* = .{
.step = std.Build.Step.init(.{
.id = .custom,
.name = "Build header files.",
.owner = b,
.makeFn = &make,
}),
.b = b,
};
return build_headers;
}
fn make(step_ptr: *std.Build.Step, prog_node: *std.Progress.Node) anyerror!void {
_ = prog_node;
const build_headers: *BuildHeadersStep = @fieldParentPtr("step", step_ptr);
const b = build_headers.b;
// Zig will run build steps in parallel if possible, so if there were two invocations of
// then this function would be called in parallel. We're manipulating the FS here
// and so need to prevent that.
build_mutex.lock();
defer build_mutex.unlock();
generateHeaders(b.allocator);
}
};
const sources_spirv = [_][]const u8{
"SPIRV/GlslangToSpv.cpp",
"SPIRV/InReadableOrder.cpp",
"SPIRV/Logger.cpp",
"SPIRV/SPVRemapper.cpp",
"SPIRV/SpvBuilder.cpp",
"SPIRV/SpvPostProcess.cpp",
"SPIRV/disassemble.cpp",
"SPIRV/doc.cpp",
};
const sources_c_interface = [_][]const u8{
"glslang/CInterface/glslang_c_interface.cpp",
"SPIRV/CInterface/spirv_c_interface.cpp",
};
const sources_resource_limits = [_][]const u8{
"glslang/ResourceLimits/resource_limits_c.cpp",
"glslang/ResourceLimits/ResourceLimits.cpp",
};
const sources_generic_codegen = [_][]const u8{
"glslang/GenericCodeGen/CodeGen.cpp",
"glslang/GenericCodeGen/Link.cpp",
};
const sources_machine_independent = [_][]const u8{
"glslang/MachineIndependent/Constant.cpp",
"glslang/MachineIndependent/InfoSink.cpp",
"glslang/MachineIndependent/Initialize.cpp",
"glslang/MachineIndependent/IntermTraverse.cpp",
"glslang/MachineIndependent/Intermediate.cpp",
"glslang/MachineIndependent/ParseContextBase.cpp",
"glslang/MachineIndependent/ParseHelper.cpp",
"glslang/MachineIndependent/PoolAlloc.cpp",
"glslang/MachineIndependent/RemoveTree.cpp",
"glslang/MachineIndependent/Scan.cpp",
"glslang/MachineIndependent/ShaderLang.cpp",
"glslang/MachineIndependent/SpirvIntrinsics.cpp",
"glslang/MachineIndependent/SymbolTable.cpp",
"glslang/MachineIndependent/Versions.cpp",
"glslang/MachineIndependent/attribute.cpp",
"glslang/MachineIndependent/glslang_tab.cpp",
"glslang/MachineIndependent/intermOut.cpp",
"glslang/MachineIndependent/iomapper.cpp",
"glslang/MachineIndependent/limits.cpp",
"glslang/MachineIndependent/linkValidate.cpp",
"glslang/MachineIndependent/parseConst.cpp",
"glslang/MachineIndependent/preprocessor/Pp.cpp",
"glslang/MachineIndependent/preprocessor/PpAtom.cpp",
"glslang/MachineIndependent/preprocessor/PpContext.cpp",
"glslang/MachineIndependent/preprocessor/PpScanner.cpp",
"glslang/MachineIndependent/preprocessor/PpTokens.cpp",
"glslang/MachineIndependent/propagateNoContraction.cpp",
"glslang/MachineIndependent/reflection.cpp",
};
const sources_win = [_][]const u8{
"glslang/OSDependent/Windows/ossource.cpp"
};
const sources_unix = [_][]const u8{
"glslang/OSDependent/Unix/ossource.cpp"
};
const sources_hlsl = [_][]const u8{
"glslang/HLSL/hlslAttributes.cpp",
"glslang/HLSL/hlslGrammar.cpp",
"glslang/HLSL/hlslOpMap.cpp",
"glslang/HLSL/hlslParseHelper.cpp",
"glslang/HLSL/hlslParseables.cpp",
"glslang/HLSL/hlslScanContext.cpp",
"glslang/HLSL/hlslTokenStream.cpp",
};
const sources_opt = [_][]const u8{
"SPIRV/SpvTools.cpp",
};
const sources_standalone_glslang = [_][]const u8{
"StandAlone/StandAlone.cpp"
};
const sources_standalone_remap = [_][]const u8{
"StandAlone/spirv-remap.cpp"
};