455 lines
15 KiB
Zig
455 lines
15 KiB
Zig
const std = @import("std");
|
|
const builtin = @import("builtin");
|
|
const Build = std.Build;
|
|
|
|
const log = std.log.scoped(.glslang_zig);
|
|
|
|
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 regenerate_headers = b.option(bool, "regenerate_headers", "Regenerate glslang header libraries.") orelse false;
|
|
const minimal_test_exe = b.option(bool, "minimal_test", "Build a minimal test for linking.") orelse false;
|
|
|
|
if (shared and (standalone_glslang or standalone_spvremap)) {
|
|
log.err("Cannot build standalone sources with shared glslang. Recompile without `-Dshared` or `-Dstandalone/-Dstandalone-remap`", .{});
|
|
std.process.exit(1);
|
|
}
|
|
|
|
const tag = target.result.os.tag;
|
|
|
|
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",
|
|
"-static",
|
|
};
|
|
|
|
try cppflags.appendSlice(base_flags);
|
|
|
|
downloadOrPull(b, "sinnwrig", "SPIRV-Tools-zig", &b.path("External/spirv-tools"));
|
|
downloadOrPull(b, "KhronosGroup", "SPIRV-Headers", &b.path("External/spirv-tools/external/spirv-headers"));
|
|
|
|
var tools_lib: *Build.Step.Compile = undefined;
|
|
var tools_opt: *Build.Step.Compile = undefined;
|
|
var tools_val: *Build.Step.Compile = undefined;
|
|
|
|
const path: []const u8 = "external/spirv-headers";
|
|
|
|
if (b.lazyDependency("SPIRV-Tools", .{ .target = target, .optimize = optimize, .debug = debug, .shared = shared_tools, .header_path = path, .no_link = true, .no_reduce = true, .rebuild_headers = regenerate_headers })) |dep| {
|
|
tools_lib = dep.artifact("SPIRV-Tools");
|
|
tools_opt = dep.artifact("SPIRV-Tools-opt");
|
|
tools_val = dep.artifact("SPIRV-Tools-val");
|
|
} else {
|
|
log.err("Error building SPIRV-Tools libraries", .{});
|
|
std.process.exit(1);
|
|
}
|
|
|
|
const sources = sources_spirv ++
|
|
sources_generic_codegen ++
|
|
sources_machine_independent ++
|
|
sources_resource_limits ++
|
|
sources_c_interface;
|
|
|
|
var glslang_lib: *std.Build.Step.Compile = b.addStaticLibrary(.{
|
|
.name = "glslang",
|
|
.root_source_file = b.addWriteFiles().add("empty.c", ""),
|
|
.optimize = optimize,
|
|
.target = target,
|
|
});
|
|
|
|
if (regenerate_headers) {
|
|
glslang_lib.step.dependOn(generateHeaders(b));
|
|
}
|
|
|
|
glslang_lib.addCSourceFiles(.{
|
|
.files = &sources,
|
|
.flags = cppflags.items,
|
|
});
|
|
|
|
glslang_lib.linkLibrary(tools_lib);
|
|
addIncludes(b, glslang_lib);
|
|
|
|
glslang_lib.linkLibCpp();
|
|
|
|
// OS-specific headers
|
|
if (tag == .windows) {
|
|
glslang_lib.addCSourceFiles(.{
|
|
.files = &sources_win,
|
|
.flags = cppflags.items,
|
|
});
|
|
} else {
|
|
glslang_lib.addCSourceFiles(.{
|
|
.files = &sources_unix,
|
|
.flags = cppflags.items,
|
|
});
|
|
}
|
|
|
|
glslang_lib.defineCMacro("ENABLE_SPIRV", "1");
|
|
|
|
// Add HLSL sources
|
|
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");
|
|
}
|
|
|
|
// Add SPIRV-Tools-opt sources
|
|
if (enable_opt) {
|
|
glslang_lib.addCSourceFiles(.{
|
|
.files = &sources_opt,
|
|
.flags = cppflags.items,
|
|
});
|
|
|
|
glslang_lib.defineCMacro("ENABLE_OPT", "1");
|
|
|
|
glslang_lib.linkLibrary(tools_opt);
|
|
glslang_lib.linkLibrary(tools_val);
|
|
} else {
|
|
glslang_lib.defineCMacro("ENABLE_OPT", "0");
|
|
}
|
|
|
|
const build_step = b.step("glslang-library", "Build the glslang library");
|
|
build_step.dependOn(&b.addInstallArtifact(glslang_lib, .{}).step);
|
|
|
|
b.installArtifact(glslang_lib);
|
|
|
|
// Core glslang sources CANNOT be built as a standalone shared library or segfaults happen in c std::
|
|
// no idea if this is a zig or glslang problem, but it seems like zig
|
|
// the workaround is to build core glslang as a static library, then link it into a stub shared library
|
|
var shared_glslang: *std.Build.Step.Compile = undefined;
|
|
|
|
if (shared) {
|
|
shared_glslang = b.addSharedLibrary(.{
|
|
.name = "glslang",
|
|
.optimize = optimize,
|
|
.target = target,
|
|
});
|
|
|
|
const shared_glslang_step = b.step("glslang", "Build and install shared glslang.exe");
|
|
shared_glslang_step.dependOn(&b.addInstallArtifact(shared_glslang, .{}).step);
|
|
shared_glslang.addCSourceFile(.{
|
|
.file = b.path("StandAlone/shared_glslang.cpp"),
|
|
.flags = &.{"-std=c++17"},
|
|
});
|
|
|
|
addIncludes(b, shared_glslang);
|
|
|
|
b.installArtifact(shared_glslang);
|
|
shared_glslang.linkLibrary(glslang_lib);
|
|
|
|
glslang_lib.defineCMacro("GLSLANG_IS_SHARED_LIBRARY", "1");
|
|
glslang_lib.defineCMacro("GLSLANG_EXPORTING", "1");
|
|
}
|
|
|
|
if (standalone_glslang) {
|
|
const glslang_exe = b.addExecutable(.{
|
|
.name = "glslang",
|
|
.optimize = optimize,
|
|
.target = target,
|
|
});
|
|
|
|
glslang_exe.pie = true;
|
|
|
|
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(b, glslang_exe);
|
|
|
|
b.installArtifact(glslang_exe);
|
|
|
|
if (shared) {
|
|
glslang_exe.defineCMacro("GLSLANG_IS_SHARED_LIBRARY", "");
|
|
glslang_exe.linkLibrary(shared_glslang);
|
|
}
|
|
else {
|
|
glslang_exe.linkLibrary(glslang_lib);
|
|
}
|
|
|
|
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,
|
|
});
|
|
|
|
spirv_remap.pie = true;
|
|
|
|
if (shared) {
|
|
spirv_remap.defineCMacro("GLSLANG_IS_SHARED_LIBRARY", "");
|
|
spirv_remap.linkLibrary(shared_glslang);
|
|
}
|
|
else {
|
|
spirv_remap.linkLibrary(glslang_lib);
|
|
}
|
|
|
|
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(b, spirv_remap);
|
|
|
|
b.installArtifact(spirv_remap);
|
|
spirv_remap.linkLibrary(glslang_lib);
|
|
}
|
|
|
|
if (minimal_test_exe) {
|
|
const min_test = b.addExecutable(.{
|
|
.name = "minimal-test",
|
|
.optimize = optimize,
|
|
.target = target,
|
|
});
|
|
|
|
min_test.pie = true;
|
|
|
|
if (shared) {
|
|
min_test.defineCMacro("GLSLANG_IS_SHARED_LIBRARY", "");
|
|
min_test.linkLibrary(shared_glslang);
|
|
}
|
|
else {
|
|
min_test.linkLibrary(glslang_lib);
|
|
}
|
|
|
|
const min_test_step = b.step("minimal-test", "Build and install minimal-test.exe");
|
|
min_test_step.dependOn(&b.addInstallArtifact(min_test, .{}).step);
|
|
min_test.addCSourceFile(.{
|
|
.file = b.path("StandAlone/minimal-test.cpp"),
|
|
.flags = &.{"-std=c++17"},
|
|
});
|
|
|
|
addIncludes(b, min_test);
|
|
|
|
b.installArtifact(min_test);
|
|
|
|
}
|
|
}
|
|
|
|
fn addIncludes(b: *Build, step: *std.Build.Step.Compile) void {
|
|
step.addIncludePath(b.path(header_output_path));
|
|
step.addIncludePath(b.path(""));
|
|
step.addIncludePath(b.path("External/spirv-tools/include"));
|
|
}
|
|
|
|
fn ensureCommandExists(allocator: std.mem.Allocator, name: []const u8, exist_check: []const u8) bool {
|
|
const result = std.process.Child.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;
|
|
}
|
|
|
|
// --------------------------
|
|
// spirv-tools download logic
|
|
// --------------------------
|
|
|
|
fn downloadOrPull(b: *Build, comptime user: []const u8, comptime repo: []const u8, out_path: *const std.Build.LazyPath) void {
|
|
if (!ensureCommandExists(b.allocator, "git", "--version")) {
|
|
log.err("'git --version' failed. Ensure a valid git installation is present on the path.", .{});
|
|
std.process.exit(1);
|
|
}
|
|
|
|
const git_cmd = b.addSystemCommand(&.{"git"});
|
|
git_cmd.setCwd(out_path.dirname());
|
|
|
|
_ = std.fs.openDirAbsolute(out_path.getPath(b), .{}) catch |err| {
|
|
if (err == error.FileNotFound) {
|
|
_ = b.run(&.{ "git", "clone", "https://github.com/" ++ user ++ "/" ++ repo, out_path.getPath(b) });
|
|
|
|
return;
|
|
}
|
|
};
|
|
|
|
_ = b.run(&.{
|
|
"git", "-C", out_path.getPath(b), "pull",
|
|
});
|
|
}
|
|
|
|
// -----------------------
|
|
// Header generation logic
|
|
// -----------------------
|
|
|
|
pub const header_output_path = "generated-include";
|
|
|
|
const build_info_script = "build_info.py";
|
|
const ext_header_script = "gen_extension_headers.py";
|
|
|
|
fn genBuildInfo(b: *Build) *Build.Step.Run {
|
|
const python_cmd = b.addSystemCommand(&.{"python3"});
|
|
|
|
python_cmd.setCwd(b.path("."));
|
|
python_cmd.addFileArg(b.path(build_info_script));
|
|
python_cmd.addFileArg(b.path("."));
|
|
python_cmd.addArg("-i");
|
|
python_cmd.addFileArg(b.path("build_info.h.tmpl"));
|
|
python_cmd.addArg("-o");
|
|
python_cmd.addFileArg(b.path(header_output_path).path(b, "glslang").path(b, "build_info.h"));
|
|
|
|
return python_cmd;
|
|
}
|
|
|
|
fn genExtensionHeaders(b: *Build) *Build.Step.Run {
|
|
const python_cmd = b.addSystemCommand(&.{"python3"});
|
|
|
|
python_cmd.setCwd(b.path("."));
|
|
python_cmd.addFileArg(b.path(ext_header_script));
|
|
python_cmd.addArg("-i");
|
|
python_cmd.addFileArg(b.path("glslang").path(b, "ExtensionHeaders"));
|
|
python_cmd.addArg("-o");
|
|
python_cmd.addFileArg(b.path(header_output_path).path(b, "glslang").path(b, "glsl_intrinsic_header.h"));
|
|
|
|
return python_cmd;
|
|
}
|
|
|
|
fn generateHeaders(b: *Build) *std.Build.Step {
|
|
if (!ensureCommandExists(b.allocator, "python3", "--version")) {
|
|
log.err("'python3 --version' failed. Ensure a valid python3 installation is present on the path.", .{});
|
|
std.process.exit(1);
|
|
}
|
|
|
|
const headers_step = b.step("build-headers", "Build glslang headers");
|
|
|
|
headers_step.dependOn(&genBuildInfo(b).step);
|
|
headers_step.dependOn(&genExtensionHeaders(b).step);
|
|
|
|
return headers_step;
|
|
}
|
|
|
|
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"};
|