diff --git a/build.zig b/build.zig index 8407d743c..21f6a0523 100644 --- a/build.zig +++ b/build.zig @@ -44,14 +44,31 @@ pub fn build(b: *std.Build) !void { // to set since header files will use this to determine the availability // of certain APIs and I believe it is also encoded in the Mach-O // binaries. - if (result.result.os.tag == .macos and - result.query.os_version_min == null) - { - result.query.os_version_min = .{ .semver = .{ - .major = 12, - .minor = 0, - .patch = 0, - } }; + if (result.query.os_version_min == null) { + switch (result.result.os.tag) { + // The lowest supported version of macOS is 12.x because + // this is the first version to support Apple Silicon so it is + // the earliest version we can virtualize to test (I only have + // an Apple Silicon machine for macOS). + .macos => { + result.query.os_version_min = .{ .semver = .{ + .major = 12, + .minor = 0, + .patch = 0, + } }; + }, + + // iOS 17 picked arbitrarily + .ios => { + result.query.os_version_min = .{ .semver = .{ + .major = 17, + .minor = 0, + .patch = 0, + } }; + }, + + else => {}, + } } break :target result; @@ -542,6 +559,65 @@ pub fn build(b: *std.Build) !void { b.default_step.dependOn(xcframework.step); } + // iOS + if (builtin.target.isDarwin() and target.result.os.tag == .ios) { + const ios_config: BuildConfig = config: { + var copy = config; + copy.static = true; + break :config copy; + }; + + const lib = b.addStaticLibrary(.{ + .name = "ghostty", + .root_source_file = .{ .path = "src/main_c.zig" }, + .target = b.resolveTargetQuery(.{ + .cpu_arch = .aarch64, + .os_tag = .ios, + .os_version_min = target.query.os_version_min, + }), + .optimize = optimize, + }); + lib.bundle_compiler_rt = true; + lib.linkLibC(); + lib.root_module.addOptions("build_options", exe_options); + + // Create a single static lib with all our dependencies merged + var lib_list = try addDeps(b, lib, ios_config); + try lib_list.append(lib.getEmittedBin()); + const libtool = LibtoolStep.create(b, .{ + .name = "ghostty", + .out_name = "libghostty-ios-fat.a", + .sources = lib_list.items, + }); + libtool.step.dependOn(&lib.step); + b.default_step.dependOn(libtool.step); + + // Add our library to zig-out + const lib_install = b.addInstallLibFile( + libtool.output, + "libghostty.a", + ); + b.getInstallStep().dependOn(&lib_install.step); + + // Copy our ghostty.h to include + const header_install = b.addInstallHeaderFile( + "include/ghostty.h", + "ghostty.h", + ); + b.getInstallStep().dependOn(&header_install.step); + + // // The xcframework wraps our ghostty library so that we can link + // // it to the final app built with Swift. + // const xcframework = XCFrameworkStep.create(b, .{ + // .name = "GhosttyKit", + // .out_path = "macos/GhosttyKit.xcframework", + // .library = libtool.output, + // .headers = .{ .path = "include" }, + // }); + // xcframework.step.dependOn(libtool.step); + // b.default_step.dependOn(xcframework.step); + } + // wasm { // Build our Wasm target. @@ -830,7 +906,14 @@ fn addDeps( // Mac Stuff if (step.rootModuleTarget().isDarwin()) { - step.root_module.addImport("objc", objc_dep.module("objc")); + // This is a bit of a hack that should probably be fixed upstream + // in zig-objc, but we need to add the apple SDK paths to the + // zig-objc module so that it can find the objc runtime headers. + const module = objc_dep.module("objc"); + module.resolved_target = step.root_module.resolved_target; + try @import("apple_sdk").addPaths(b, module); + step.root_module.addImport("objc", module); + step.root_module.addImport("macos", macos_dep.module("macos")); step.linkLibrary(macos_dep.artifact("macos")); try static_libs.append(macos_dep.artifact("macos").getEmittedBin()); diff --git a/build.zig.zon b/build.zig.zon index 3db6b645e..43aab7d27 100644 --- a/build.zig.zon +++ b/build.zig.zon @@ -5,8 +5,8 @@ .dependencies = .{ // Zig libs .libxev = .{ - .url = "https://github.com/mitchellh/libxev/archive/74bc7aea4a8f88210f0ad4215108613ab7e7af1a.tar.gz", - .hash = "122029743e5d96aa1b57a1b99ff58bf13ff9ed6d8f624ac3ae8074062feb91c5bd8d", + .url = "https://github.com/mitchellh/libxev/archive/4e6781895e4e6c477597c8c2713d36cd82b57d07.tar.gz", + .hash = "12203f87e00caa6c07c02a748f234a5c0ee2ca5c334ec464e88810d93e7b5495a56f", }, .mach_glfw = .{ .url = "https://github.com/der-teufel-programming/mach-glfw/archive/a9aae000cdc104dabe75d829ff9dab6809e47604.tar.gz", diff --git a/pkg/apple-sdk/build.zig b/pkg/apple-sdk/build.zig index 62f1372c6..ffb1671da 100644 --- a/pkg/apple-sdk/build.zig +++ b/pkg/apple-sdk/build.zig @@ -45,6 +45,7 @@ const SDK = struct { pub fn fromTarget(target: std.Target) !SDK { return switch (target.os.tag) { + .ios => .{ .platform = "iPhoneOS", .version = "" }, .macos => .{ .platform = "MacOSX", .version = "14" }, else => { std.log.err("unsupported os={}", .{target.os.tag}); diff --git a/pkg/cimgui/build.zig b/pkg/cimgui/build.zig index 34585bac9..3e397f955 100644 --- a/pkg/cimgui/build.zig +++ b/pkg/cimgui/build.zig @@ -71,10 +71,12 @@ pub fn build(b: *std.Build) !void { .file = imgui.path("backends/imgui_impl_metal.mm"), .flags = flags.items, }); - lib.addCSourceFile(.{ - .file = imgui.path("backends/imgui_impl_osx.mm"), - .flags = flags.items, - }); + if (target.result.os.tag == .macos) { + lib.addCSourceFile(.{ + .file = imgui.path("backends/imgui_impl_osx.mm"), + .flags = flags.items, + }); + } } lib.installHeadersDirectoryOptions(.{ diff --git a/pkg/freetype/build.zig b/pkg/freetype/build.zig index 1770e3e49..8716c572a 100644 --- a/pkg/freetype/build.zig +++ b/pkg/freetype/build.zig @@ -15,6 +15,11 @@ pub fn build(b: *std.Build) !void { }); lib.linkLibC(); lib.addIncludePath(upstream.path("include")); + if (target.result.isDarwin()) { + const apple_sdk = @import("apple_sdk"); + try apple_sdk.addPaths(b, &lib.root_module); + } + module.addIncludePath(upstream.path("include")); module.addIncludePath(.{ .path = "" }); @@ -86,7 +91,7 @@ pub fn build(b: *std.Build) !void { b.installArtifact(lib); - { + if (target.query.isNative()) { const test_exe = b.addTest(.{ .name = "test", .root_source_file = .{ .path = "main.zig" }, diff --git a/pkg/freetype/build.zig.zon b/pkg/freetype/build.zig.zon index 29b694973..5c6538fd5 100644 --- a/pkg/freetype/build.zig.zon +++ b/pkg/freetype/build.zig.zon @@ -1,12 +1,14 @@ .{ .name = "freetype", .version = "2.13.2", + .paths = .{""}, .dependencies = .{ .freetype = .{ .url = "https://github.com/freetype/freetype/archive/refs/tags/VER-2-13-2.tar.gz", .hash = "1220b81f6ecfb3fd222f76cf9106fecfa6554ab07ec7fdc4124b9bb063ae2adf969d", }, + .apple_sdk = .{ .path = "../apple-sdk" }, .libpng = .{ .path = "../libpng" }, .zlib = .{ .path = "../zlib" }, }, diff --git a/pkg/glslang/build.zig b/pkg/glslang/build.zig index d73306071..8d6fc1ff1 100644 --- a/pkg/glslang/build.zig +++ b/pkg/glslang/build.zig @@ -12,8 +12,15 @@ pub fn build(b: *std.Build) !void { module.addIncludePath(upstream.path("")); module.addIncludePath(.{ .path = "override" }); + if (target.result.isDarwin()) { + // See pkg/harfbuzz/build.zig + module.resolved_target = target; + defer module.resolved_target = null; + const apple_sdk = @import("apple_sdk"); + try apple_sdk.addPaths(b, module); + } - { + if (target.query.isNative()) { const test_exe = b.addTest(.{ .name = "test", .root_source_file = .{ .path = "main.zig" }, @@ -45,6 +52,10 @@ fn buildGlslang( lib.linkLibCpp(); lib.addIncludePath(upstream.path("")); lib.addIncludePath(.{ .path = "override" }); + if (target.result.isDarwin()) { + const apple_sdk = @import("apple_sdk"); + try apple_sdk.addPaths(b, &lib.root_module); + } var flags = std.ArrayList([]const u8).init(b.allocator); defer flags.deinit(); diff --git a/pkg/glslang/build.zig.zon b/pkg/glslang/build.zig.zon index d1ffcfa5c..d4b469204 100644 --- a/pkg/glslang/build.zig.zon +++ b/pkg/glslang/build.zig.zon @@ -7,5 +7,7 @@ .url = "https://github.com/KhronosGroup/glslang/archive/refs/tags/13.1.1.tar.gz", .hash = "1220481fe19def1172cd0728743019c0f440181a6342b62d03e24d05c70141516799", }, + + .apple_sdk = .{ .path = "../apple-sdk" }, }, } diff --git a/pkg/harfbuzz/build.zig b/pkg/harfbuzz/build.zig index 51aeb6f81..9b5778584 100644 --- a/pkg/harfbuzz/build.zig +++ b/pkg/harfbuzz/build.zig @@ -34,6 +34,18 @@ pub fn build(b: *std.Build) !void { lib.addIncludePath(upstream.path("src")); module.addIncludePath(upstream.path("src")); + if (target.result.isDarwin()) { + // This is definitely super sketchy and not right but without this + // zig build test breaks on macOS. We have to look into what exactly + // is going on here but this getting comitted in the interest of + // unblocking zig build test. + module.resolved_target = target; + defer module.resolved_target = null; + + try apple_sdk.addPaths(b, &lib.root_module); + try apple_sdk.addPaths(b, module); + } + const freetype_dep = b.dependency("freetype", .{ .target = target, .optimize = optimize }); lib.linkLibrary(freetype_dep.artifact("freetype")); module.addIncludePath(freetype_dep.builder.dependency("freetype", .{}).path("include")); @@ -59,19 +71,10 @@ pub fn build(b: *std.Build) !void { "-DHAVE_FT_DONE_MM_VAR=1", "-DHAVE_FT_GET_TRANSFORM=1", }); - if (coretext_enabled and target.result.isDarwin()) { - // This is definitely super sketchy and not right but without this - // zig build test breaks on macOS. We have to look into what exactly - // is going on here but this getting comitted in the interest of - // unblocking zig build test. - module.resolved_target = target; - defer module.resolved_target = null; - + if (coretext_enabled) { try flags.appendSlice(&.{"-DHAVE_CORETEXT=1"}); - try apple_sdk.addPaths(b, &lib.root_module); - try apple_sdk.addPaths(b, module); - lib.linkFramework("ApplicationServices"); - module.linkFramework("ApplicationServices", .{}); + lib.linkFramework("CoreText"); + module.linkFramework("CoreText", .{}); } lib.addCSourceFile(.{ diff --git a/pkg/harfbuzz/build.zig.zon b/pkg/harfbuzz/build.zig.zon index a9bc2ba7e..1fa67abc9 100644 --- a/pkg/harfbuzz/build.zig.zon +++ b/pkg/harfbuzz/build.zig.zon @@ -1,6 +1,7 @@ .{ .name = "harfbuzz", .version = "8.2.2", + .paths = .{""}, .dependencies = .{ .harfbuzz = .{ .url = "https://github.com/harfbuzz/harfbuzz/archive/refs/tags/8.2.2.tar.gz", diff --git a/pkg/libpng/build.zig b/pkg/libpng/build.zig index 10785c07d..accbdd9cc 100644 --- a/pkg/libpng/build.zig +++ b/pkg/libpng/build.zig @@ -15,6 +15,10 @@ pub fn build(b: *std.Build) !void { if (target.result.os.tag == .linux) { lib.linkSystemLibrary("m"); } + if (target.result.isDarwin()) { + const apple_sdk = @import("apple_sdk"); + try apple_sdk.addPaths(b, &lib.root_module); + } const zlib_dep = b.dependency("zlib", .{ .target = target, .optimize = optimize }); lib.linkLibrary(zlib_dep.artifact("z")); diff --git a/pkg/libpng/build.zig.zon b/pkg/libpng/build.zig.zon index ebad1dcb4..6f0985812 100644 --- a/pkg/libpng/build.zig.zon +++ b/pkg/libpng/build.zig.zon @@ -1,14 +1,14 @@ .{ .name = "libpng", .version = "1.6.40", + .paths = .{""}, .dependencies = .{ .libpng = .{ .url = "https://github.com/glennrp/libpng/archive/refs/tags/v1.6.40.tar.gz", .hash = "12203d2722e3af6f9556503b114c25fe3eead528a93f5f26eefcb187a460d1548e07", }, - .zlib = .{ - .path = "../zlib", - }, + .zlib = .{ .path = "../zlib" }, + .apple_sdk = .{ .path = "../apple-sdk" }, }, } diff --git a/pkg/macos/build.zig b/pkg/macos/build.zig index 3891553f2..1a43c8daf 100644 --- a/pkg/macos/build.zig +++ b/pkg/macos/build.zig @@ -28,14 +28,16 @@ pub fn build(b: *std.Build) !void { .file = .{ .path = "text/ext.c" }, .flags = flags.items, }); - lib.linkFramework("Carbon"); lib.linkFramework("CoreFoundation"); lib.linkFramework("CoreGraphics"); lib.linkFramework("CoreText"); lib.linkFramework("CoreVideo"); + if (target.result.os.tag == .macos) { + lib.linkFramework("Carbon"); + module.linkFramework("Carbon", .{}); + } if (target.result.isDarwin()) { - module.linkFramework("Carbon", .{}); module.linkFramework("CoreFoundation", .{}); module.linkFramework("CoreGraphics", .{}); module.linkFramework("CoreText", .{}); diff --git a/pkg/oniguruma/build.zig b/pkg/oniguruma/build.zig index 9fa8772cd..0b5d43e83 100644 --- a/pkg/oniguruma/build.zig +++ b/pkg/oniguruma/build.zig @@ -12,7 +12,7 @@ pub fn build(b: *std.Build) !void { module.addIncludePath(upstream.path("src")); b.installArtifact(lib); - { + if (target.query.isNative()) { const test_exe = b.addTest(.{ .name = "test", .root_source_file = .{ .path = "main.zig" }, @@ -44,6 +44,11 @@ fn buildOniguruma( lib.linkLibC(); lib.addIncludePath(upstream.path("src")); + if (target.result.isDarwin()) { + const apple_sdk = @import("apple_sdk"); + try apple_sdk.addPaths(b, &lib.root_module); + } + lib.addConfigHeader(b.addConfigHeader(.{ .style = .{ .cmake = upstream.path("src/config.h.cmake.in") }, }, .{ diff --git a/pkg/oniguruma/build.zig.zon b/pkg/oniguruma/build.zig.zon index 8e08a0ad2..2120f77ae 100644 --- a/pkg/oniguruma/build.zig.zon +++ b/pkg/oniguruma/build.zig.zon @@ -7,5 +7,7 @@ .url = "https://github.com/kkos/oniguruma/archive/refs/tags/v6.9.9.tar.gz", .hash = "1220c15e72eadd0d9085a8af134904d9a0f5dfcbed5f606ad60edc60ebeccd9706bb", }, + + .apple_sdk = .{ .path = "../apple-sdk" }, }, } diff --git a/pkg/pixman/build.zig b/pkg/pixman/build.zig index a74fece29..42c514e9d 100644 --- a/pkg/pixman/build.zig +++ b/pkg/pixman/build.zig @@ -16,6 +16,10 @@ pub fn build(b: *std.Build) !void { if (target.result.os.tag != .windows) { lib.linkSystemLibrary("pthread"); } + if (target.result.isDarwin()) { + const apple_sdk = @import("apple_sdk"); + try apple_sdk.addPaths(b, &lib.root_module); + } lib.addIncludePath(upstream.path("")); lib.addIncludePath(.{ .path = "" }); @@ -68,7 +72,7 @@ pub fn build(b: *std.Build) !void { b.installArtifact(lib); - { + if (target.query.isNative()) { const test_exe = b.addTest(.{ .name = "test", .root_source_file = .{ .path = "main.zig" }, diff --git a/pkg/pixman/build.zig.zon b/pkg/pixman/build.zig.zon index c4ed35a62..af6813e07 100644 --- a/pkg/pixman/build.zig.zon +++ b/pkg/pixman/build.zig.zon @@ -1,10 +1,13 @@ .{ .name = "pixman", .version = "0.42.2", + .paths = .{""}, .dependencies = .{ .pixman = .{ .url = "https://deps.files.ghostty.dev/pixman-pixman-0.42.2.tar.gz", .hash = "12209b9206f9a5d31ccd9a2312cc72cb9dfc3e034aee1883c549dc1d753fae457230", }, + + .apple_sdk = .{ .path = "../apple-sdk" }, }, } diff --git a/pkg/spirv-cross/build.zig b/pkg/spirv-cross/build.zig index 76b29a279..37da13eee 100644 --- a/pkg/spirv-cross/build.zig +++ b/pkg/spirv-cross/build.zig @@ -12,7 +12,7 @@ pub fn build(b: *std.Build) !void { const lib = try buildSpirvCross(b, upstream, target, optimize); b.installArtifact(lib); - { + if (target.query.isNative()) { const test_exe = b.addTest(.{ .name = "test", .root_source_file = .{ .path = "main.zig" }, @@ -42,8 +42,10 @@ fn buildSpirvCross( }); lib.linkLibC(); lib.linkLibCpp(); - //lib.addIncludePath(upstream.path("")); - //lib.addIncludePath(.{ .path = "override" }); + if (target.result.isDarwin()) { + const apple_sdk = @import("apple_sdk"); + try apple_sdk.addPaths(b, &lib.root_module); + } var flags = std.ArrayList([]const u8).init(b.allocator); defer flags.deinit(); diff --git a/pkg/spirv-cross/build.zig.zon b/pkg/spirv-cross/build.zig.zon index 8338b7a61..9100bb967 100644 --- a/pkg/spirv-cross/build.zig.zon +++ b/pkg/spirv-cross/build.zig.zon @@ -7,5 +7,7 @@ .url = "https://github.com/KhronosGroup/SPIRV-Cross/archive/4818f7e7ef7b7078a3a7a5a52c4a338e0dda22f4.tar.gz", .hash = "1220b2d8a6cff1926ef28a29e312a0a503b555ebc2f082230b882410f49e672ac9c6", }, + + .apple_sdk = .{ .path = "../apple-sdk" }, }, } diff --git a/pkg/zlib/build.zig b/pkg/zlib/build.zig index de00f4b73..695ebcb40 100644 --- a/pkg/zlib/build.zig +++ b/pkg/zlib/build.zig @@ -13,6 +13,11 @@ pub fn build(b: *std.Build) !void { }); lib.linkLibC(); lib.addIncludePath(upstream.path("")); + if (target.result.isDarwin()) { + const apple_sdk = @import("apple_sdk"); + try apple_sdk.addPaths(b, &lib.root_module); + } + lib.installHeadersDirectoryOptions(.{ .source_dir = upstream.path(""), .install_dir = .header, diff --git a/pkg/zlib/build.zig.zon b/pkg/zlib/build.zig.zon index 7550da4a3..1f23bd588 100644 --- a/pkg/zlib/build.zig.zon +++ b/pkg/zlib/build.zig.zon @@ -1,10 +1,13 @@ .{ .name = "zlib", .version = "1.3.0", + .paths = .{""}, .dependencies = .{ .zlib = .{ .url = "https://github.com/madler/zlib/archive/refs/tags/v1.3.tar.gz", .hash = "12207d353609d95cee9da7891919e6d9582e97b7aa2831bd50f33bf523a582a08547", }, + + .apple_sdk = .{ .path = "../apple-sdk" }, }, } diff --git a/src/Command.zig b/src/Command.zig index 4a15d1229..af3979b3e 100644 --- a/src/Command.zig +++ b/src/Command.zig @@ -290,7 +290,7 @@ fn setupFd(src: File.Handle, target: i32) !void { } } }, - .macos => { + .ios, .macos => { // Mac doesn't support dup3 so we use dup2. We purposely clear // CLO_ON_EXEC for this fd. const flags = try os.fcntl(src, os.F.GETFD, 0); diff --git a/src/input.zig b/src/input.zig index 14140a524..47024ff67 100644 --- a/src/input.zig +++ b/src/input.zig @@ -17,7 +17,7 @@ pub const SplitResizeDirection = Binding.Action.SplitResizeDirection; // Keymap is only available on macOS right now. We could implement it // in theory for XKB too on Linux but we don't need it right now. pub const Keymap = switch (builtin.os.tag) { - .macos => @import("input/KeymapDarwin.zig"), + .ios, .macos => @import("input/KeymapDarwin.zig"), else => struct {}, }; diff --git a/src/input/keycodes.zig b/src/input/keycodes.zig index 170739aa9..82f526818 100644 --- a/src/input/keycodes.zig +++ b/src/input/keycodes.zig @@ -9,7 +9,7 @@ const Key = @import("key.zig").Key; /// The full list of entries for the current platform. pub const entries: []const Entry = entries: { const native_idx = switch (builtin.os.tag) { - .macos => 4, // mac + .ios, .macos => 4, // mac .windows => 3, // win .linux => 2, // xkb else => @compileError("unsupported platform"), diff --git a/src/inspector/main.zig b/src/inspector/main.zig index 57612ddee..920491dd8 100644 --- a/src/inspector/main.zig +++ b/src/inspector/main.zig @@ -1,3 +1,4 @@ +const std = @import("std"); pub const cursor = @import("cursor.zig"); pub const key = @import("key.zig"); pub const termio = @import("termio.zig"); diff --git a/src/os/desktop.zig b/src/os/desktop.zig index 6475c278e..efc3b1541 100644 --- a/src/os/desktop.zig +++ b/src/os/desktop.zig @@ -52,6 +52,9 @@ pub fn launchedFromDesktop() bool { // TODO: This should have some logic to detect this. Perhaps std.builtin.subsystem .windows => false, + // iPhone/iPad is always launched from the "desktop" + .ios => true, + else => @compileError("unsupported platform"), }; } diff --git a/src/os/homedir.zig b/src/os/homedir.zig index ab60cdf26..854c7d62c 100644 --- a/src/os/homedir.zig +++ b/src/os/homedir.zig @@ -14,6 +14,10 @@ pub inline fn home(buf: []u8) !?[]u8 { return switch (builtin.os.tag) { inline .linux, .macos => try homeUnix(buf), .windows => try homeWindows(buf), + + // iOS doesn't have a user-writable home directory + .ios => null, + else => @compileError("unimplemented"), }; } diff --git a/src/os/open.zig b/src/os/open.zig index 14e21111f..8bf8bb7ca 100644 --- a/src/os/open.zig +++ b/src/os/open.zig @@ -8,6 +8,7 @@ pub fn open(alloc: Allocator, url: []const u8) !void { .linux => &.{ "xdg-open", url }, .macos => &.{ "open", url }, .windows => &.{ "rundll32", "url.dll,FileProtocolHandler", url }, + .ios => return error.Unimplemented, else => @compileError("unsupported OS"), }; diff --git a/src/pty.zig b/src/pty.zig index f31d5f97d..66014dc57 100644 --- a/src/pty.zig +++ b/src/pty.zig @@ -14,10 +14,41 @@ pub const winsize = extern struct { ws_ypixel: u16 = 600, }; -pub const Pty = if (builtin.os.tag == .windows) - WindowsPty -else - PosixPty; +pub const Pty = switch (builtin.os.tag) { + .windows => WindowsPty, + .ios => NullPty, + else => PosixPty, +}; + +// A pty implementation that does nothing. +// +// TODO: This should be removed. This is only temporary until we have +// a termio that doesn't use a pty. This isn't used in any user-facing +// artifacts, this is just a stopgap to get compilation to work on iOS. +const NullPty = struct { + pub const Fd = std.os.fd_t; + + master: Fd, + slave: Fd, + + pub fn open(size: winsize) !Pty { + _ = size; + return .{ .master = 0, .slave = 0 }; + } + + pub fn deinit(self: *Pty) void { + _ = self; + } + + pub fn setSize(self: *Pty, size: winsize) !void { + _ = self; + _ = size; + } + + pub fn childPreExec(self: Pty) !void { + _ = self; + } +}; /// Linux PTY creation and management. This is just a thin layer on top /// of Linux syscalls. The caller is responsible for detail-oriented handling