{"id":16908595,"url":"https://github.com/byteit101/subspawn","last_synced_at":"2025-07-06T04:36:29.878Z","repository":{"id":63059150,"uuid":"544485291","full_name":"byteit101/subspawn","owner":"byteit101","description":"SubSpawn Native Process Launching in Ruby","archived":false,"fork":false,"pushed_at":"2024-05-23T03:27:59.000Z","size":277,"stargazers_count":1,"open_issues_count":1,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2024-05-30T01:31:34.656Z","etag":null,"topics":["ffi-bindings","jruby","native","posix","ruby","subprocess"],"latest_commit_sha":null,"homepage":"","language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/byteit101.png","metadata":{"files":{"readme":"README.md","changelog":"Changelog.md","contributing":null,"funding":null,"license":"LICENSE.EPL-2.0","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-10-02T15:48:47.000Z","updated_at":"2024-06-09T21:58:49.819Z","dependencies_parsed_at":"2024-05-01T23:50:20.118Z","dependency_job_id":"1c3c88f8-5f11-4d44-909b-a3a8ad055671","html_url":"https://github.com/byteit101/subspawn","commit_stats":{"total_commits":75,"total_committers":1,"mean_commits":75.0,"dds":0.0,"last_synced_commit":"0ab0c647ee5172b3213f3d653fbd7a412b709913"},"previous_names":[],"tags_count":5,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/byteit101%2Fsubspawn","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/byteit101%2Fsubspawn/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/byteit101%2Fsubspawn/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/byteit101%2Fsubspawn/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/byteit101","download_url":"https://codeload.github.com/byteit101/subspawn/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":221826533,"owners_count":16887179,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ffi-bindings","jruby","native","posix","ruby","subprocess"],"created_at":"2024-10-13T18:52:06.690Z","updated_at":"2024-10-28T12:35:27.106Z","avatar_url":"https://github.com/byteit101.png","language":"Ruby","readme":"\u003cp align=\"center\"\u003e\u003cimg src=\"doc/logo-export.svg\" alt=\"SubSpawn Logo\" height=150 /\u003e\u003c/p\u003e\n\nRuby SubSpawn (Native)\n================\n\nSubSpawn is an advanced set of gems and packages to make natively spawning subprocesses from all Ruby implementations possible. It started out as a way to add `PTY.spawn` support to JRuby, but is usable by CRuby (MRI) and TruffleRuby.\n\nThere are 3 levels of API's supported: basic/ffi, mid-level, and high-level. Basic/ffi support is simply the ffi wrapper and has no other Ruby support. The mid-level API is specific to the host (POSIX, Win32), but otherwise has a more Ruby-like interface and avoids raw pointers. The high-level API is as consistent as possible across all platforms, and hews closely to standard Rubyisms.\n\n\nThe primary feature of SubSpawn is the ability to control advanced attributes of launched subprocesses such as specifying the controlling TTY, changing file descriptors, and `pgroup` and `setsid` configuration.\n\n\u003ctable\u003e\n    \u003cthead\u003e\n        \u003ctr\u003e\n\t\t\t\u003cth\u003ePlatform\u003c/th\u003e\n            \u003cth\u003eBasic/FFI\u003c/th\u003e\n            \u003cth\u003eMid-level\u003c/th\u003e\n            \u003cth\u003eHigh-level\u003c/th\u003e\n        \u003c/tr\u003e\n    \u003c/thead\u003e\n    \u003ctbody\u003e\n        \u003ctr\u003e\n            \u003ctd\u003eLinux\u003c/td\u003e\n            \u003ctd rowspan=3\u003e\u003ctt\u003effi-bindings-libfixposix\u003c/tt\u003e\u003c/td\u003e\n            \u003ctd rowspan=3\u003e\u003ctt\u003esubspawn-posix\u003c/tt\u003e\u003c/td\u003e\n            \u003ctd rowspan=4\u003e\u003ctt\u003esubspawn\u003c/tt\u003e\u003c/td\u003e\n        \u003c/tr\u003e\n        \u003ctr\u003e\n            \u003ctd\u003eMac OS\u003c/td\u003e\n        \u003c/tr\u003e\n        \u003ctr\u003e\n            \u003ctd\u003eBSD\u003c/td\u003e\n        \u003c/tr\u003e\n        \u003ctr\u003e\n            \u003ctd\u003eWindows\u003c/td\u003e\n            \u003ctd colspan=2 align=center\u003e\u003ctt\u003esubspawn-win32\u003c/tt\u003e\u003c/td\u003e\n        \u003c/tr\u003e\n        \u003ctr\u003e\n            \u003ctd\u003eJVM/Jar\u003c/td\u003e\n            \u003ctd colspan=3 align=center\u003e\u003ctt\u003esubspawn-jar\u003c/tt\u003e\u003c/td\u003e\n        \u003c/tr\u003e\n    \u003c/tbody\u003e\n\u003c/table\u003e\n\nInstallation\n-----------\nFor now, subspawn uses hard dependencies, but this may change.\n\nUsing JRuby 9.4 or later? A compatible version of SubSpawn is already installed!\n\nFor POSIX systems (MacOS, Linux, etc...):\n```\n$ gem install subspawn subspawn-posix\n```\n\nFor Windows systems:\n```\n$ gem install subspawn subspawn-win32\n```\n\nThen:\n```rb\nrequire 'subspawn'\n# or, to replace the built in spawn methods:\n# require 'subspawn/replace'\n```\n\nWhat is in this repository\n-------\n\nFolders:\n - libfixposix (build only, subrepository, for ffi-generator)\n - ffi-generator (build only)\n - ffi-bindings-libfixposix (gem)\n - ffi-binary-libfixposix (native gem)\n - engine-hacks (native gem)\n - subspawn-common (gem)\n - subspawn-posix (gem)\n - subspawn-win32 (gem)\n - subspawn (gem)\n - jruby-jar (gem/jar building utilities)\n\n\nlibfixposix\n-----------\nThe underlying library used is libfixposix. Currently the most recent and most widely distributed version in distros is 0.4.3. However, it doesn't support features we need, so we bundle 0.5.0.\nIn order to use libfixposix, you must configure the build, or just remove the `#if @VAR@` statements in the headers. See where ffi-generator complains to know what to remove.\n\nffi-generator\n-------------\nffi_gen takes the libfixposix include headers and generates ruby ffi bindings for ffi-bindings-libfixposix. It it tailored specifically to this project and not generally portable at this time, but patches are welcome\n\nffi-bindings-libfixposix\n------------------------\nRaw bindings to libfixposix. binary not included, but attempts to load if present. No translation, pure pointers. Usable if you want to use libfixposix in unrelated Ruby code. Generated output is ffi.rb to map all C functions to Ruby.\n\nffi-binary-libfixposix\n----------------------\nA compiled binary gem of libfixposix in case you do not have or do not want to use a system-installed library. Use `require 'libfixposix/binary'` to get the path.\n\nNote that to support cross-compiling, rake tasks are nonstandard. See `rake -T -a` for all options, but in essence, for local development, `rake local` will build a gem file in pkg/ as usual, that you can `gem install pkg/*.gem`. For building for publishing, try `rake cross:$TARGET` or `rake \"target[x86_64-linux]\" gem` (change target as appropriate). To just build the `.so` files, `rake binary` (local host) or `rake \"binary[$TARGET]\"` should be called.\n\nengine-hacks\n-----------\nRuby engine-specific hacks. Currently used to set `$?` in a platform-independent manner, as well as to make IO.popen \"fake duplex\" IO objects. C extension for MRI and TruffleRuby, JI for JRuby. Entirely independent of SubSpawn, and can be used externally.\n\nsubspawn-common\n-----------\nUtilities common to all subspawn platforms and API's.\n\nsubspawn-posix\n-----------\nThe mid-level API for Unixy machines. Exposes all the capabilities of libfixposix with none of the hassle of C or FFI. Look at the included RBS file for all methods and types. Also includes minimal PTY opening helper.\n\nAs a backup, it also inclues a JRuby fallback that is very limited, but has basic functionality. If you are using the JRuby fallback, please report a bug for your platform, and then compile libfixposix and jffi for your platform.\n\nsubspawn-win32\n-----------\nThe mid-level API for Windows machines. Win32 API's are exposed via FFI, then regularized via the mid-level API, like subspawn-posix. Also includes an early PTY \u003c-\u003e ConPTY translation layer. Yes, you heard that right, PTY.open/PTY.spawn on Windows! (Require [ConPTY from Windows 10 1803](https://devblogs.microsoft.com/commandline/windows-command-line-introducing-the-windows-pseudo-console-conpty/) or later)\n\nNote: PTY's currently work best on CRuby. JRuby support is being worked on, this gem will eventually ship with JRuby once this is fixed.\n\nsubspawn\n-----------\nThe unified high-level API for all Ruby platforms. Also includes post-launch utilities and a `PTY` library implementation. The main interface is `SubSpawn.spawn()` which is modeled after `Process.spawn`, but with extended features. These extended features can be brought into `Process.spawn` itself with `subspawn/replace`. This lets `Open3` and other utilities that pass args to `spawn` also benefit from the extra features of SubSpawn.\n\n\nRoadmap\n------------\n\n * 0.1 - intial release (DONE)\n * 0.2 - windows (WIP, everything except PTY's should work right now though)\n * 0.3 - install-time builds\n * 0.4 - better validation/errors\n\nPlease note that SubSpawn is still in its infancy and is being actively developed.\n\nAPI guarantees:\n\n * Rubyspec will continue to pass (Process.spawn \u0026 PTY.spawn are compatble with Subspawn.compat*)\n * subspawn-`$PLATFORM` may change from 0.1 to 0.2, etc\n * subspawn (high-level) will otherwise use semantic versioning\n\nAPI support\n-------------\n\nThere are 3 platforms, and they don't all support the same features. Here is a matrix of what features each platform supports\n\n| Feature                   | libfixposix+ffi    | Win32 API           | JRuby Fallback (JDK) |\n|---------------------------|--------------------|---------------------|----------------------|\n| basic spawn               | :heavy_check_mark: | :heavy_check_mark:  | :heavy_check_mark:   |\n| basic waitpid             | :x:/Built-in       | :heavy_check_mark:  | :heavy_check_mark:   |\n| full waitpid              | :x:/Built-in       | :heavy_check_mark:* | :x:                  |\n| working directory (cwd)   | :heavy_check_mark: | :heavy_check_mark:  | :heavy_check_mark:   |\n| env                       | :heavy_check_mark: | :heavy_check_mark:  | :heavy_check_mark:   |\n| set argv[0]               | :heavy_check_mark: | N/A                 | :x:                  |\n| redirect stdio (file, pipe, inherit, close) | :heavy_check_mark: | :heavy_check_mark:  | :heavy_check_mark:   |\n| merge stdio               | :heavy_check_mark: | :heavy_check_mark:  | :heavy_check_mark:   |\n| stdio in select           | :heavy_check_mark: | ?                   | :x:                  |\n| arbitrary io redirections | :heavy_check_mark: | :x:                 | :x:                  |\n| arbitrary io opens        | :heavy_check_mark: | :x:                 | :x:                  |\n| arbitrary io closes       | :heavy_check_mark: | ?                   | :x:                  |\n| pgroup                    | :heavy_check_mark: | N/A                 | :x:                  |\n| sid                       | :heavy_check_mark: | N/A                 | :x:                  |\n| pty                       | :heavy_check_mark: | WIP                 | :x:                  |\n| umask                     | :heavy_check_mark: | N/A                 | :x:                  |\n| signals                   | :heavy_check_mark: | N/A                 | :x:                  |\n| rlimits                   | :heavy_check_mark: | :x:                 | :x:                  |\n\n\n\nThere are 2 APIs: the Ruby API, and the SubSpawn API. They are mostly the same, but have a few important differences:\n\n * `Process.spawn` and `IO.popen` allow single-string commands. `SubSpawn.spawn` and `SubSpawn.popen` do not allow this for security reasons. Use a array of strings instead.\n * `SubSpawn.spawn` returns a `[pid, iomap]` pair, where `iomap[2]` is whatever you redirected stderr to. This allows SubSpawn to return all the io redirections at once. This is especially important for the JRuby Fallback. `iomap[:pty]` is the PTY master\n * `SubSpawn.*` functions allow extra options and redirections. In addition to `FD`, `:close`, and other `Process.spawn` redirection values, they alow specifying `:pipe`, `:pipe_r`, `:pipe_w`, `:pty`, `:tty`, `File` objects, `java.io.File` objects, and `java.nio.Path` objects. When using SubSpawn replacement, `Process.spawn` and `IO.popen` are agumented too.\n * `SubSpawn.wait*`, `SubSpawn.detach`, and `SubSpawn.last_status` mirror the same functions in `Process`. The Win32 and JRuby fallback platforms define them separarely, unless using replacement. Mixing and matching should not be done unless using libfixposix or replacement.\n\n# Development\n\nAfter checking out the repo with `--recursive`, run `bundle install` to install dependencies. Then, run `bundle exec rake dev` to set up a working environment. Note: CAST, used by the binary package to parse the libfixposix header, requires a native extension. As such, the first time you do this, it must be with CRuby/MRI, and NOT JRuby. Subsequent development can be done with any ruby.\n\nTo build the binary locally for development (highly recommended): `cd ffi-binary-libfixposix \u0026\u0026 rake local`\n\nTo install these gem onto your local machine, run `bundle exec rake build` and install all the gems with `gem install */pkg/*.gem`.\n\nTest by integrating into JRuby. Notable tests:\n\n * io/console. check out and run `TESTOPTS=\"--verbose\" jruby -S rake test`\n * rspec tests. check out jruby and run `bin/jruby -S rake spec:ruby`, looking for spawn or PTY errors \n\nFor local JRuby integration testing, consider running `rerun --no-notify --ignore 'java-jar/*' 'cd java-jar \u0026\u0026 rake'` after you export `JRUBY_DIR` to the path to your jruby source checkout\n\nFor unit testing, `subspawn` and `subspawn-posix` have rspec tests that run on MacOS \u0026 Linux, while `subspawn-win32` has rspec tests that run on Windows.\n\n## Contributing\n\nBug reports and pull requests are welcome on GitHub at https://github.com/byteit101/subspawn.\n\n# Binary CI\n\nBecause SubSpawn grew out of the JRuby project, we aim for parity with the JRuby FFI platforms. As such, CI builds all platforms. \n\n\n| jffi target                  | SubSpawn JRuby Support | jruby target       | byteit101's preference                          |\n| ---------------------------- | ---------------------- | ------------------ | ----------------------------------------------- |\n| jffi-Darwin.jar              | {arm64,x86_64}-darwin  | :heavy_check_mark: |                                                 |\n| jffi-aarch64-FreeBSD.jar     | arm64-freebsd          | :heavy_check_mark: |                                                 |\n| jffi-aarch64-Linux.jar       | arm64-linux            | :heavy_check_mark: |                                                 |\n| jffi-aarch64-Windows.jar     | :heavy_check_mark:     | :heavy_check_mark: |                                                 |\n| jffi-arm-Linux.jar           | armv6sf-linux          | :heavy_check_mark: | v6+                                             |\n| jffi-i386-FreeBSD.jar        | x86-freebsd            |                    |                                                 |\n| jffi-i386-Linux.jar          | x86-linux              | :heavy_check_mark: |                                                 |\n| jffi-i386-OpenBSD.jar        |                        |                    |                                                 |\n| jffi-i386-SunOS.jar          |                        | :heavy_check_mark: | drop                                            |\n| jffi-i386-Windows.jar        | :heavy_check_mark:     | :heavy_check_mark: |                                                 |\n| jffi-loongarch64-Linux.jar   | loongarch64-linux      | :heavy_check_mark: |                                                 |\n| jffi-mips64el-Linux.jar      | mips64el-linux         | :heavy_check_mark: |                                                 |\n| jffi-ppc-AIX.jar             |                        | :heavy_check_mark: | drop                                            |\n| jffi-ppc-Linux.jar           |                        |                    | drop                                            |\n| jffi-ppc64-AIX.jar           |                        | :heavy_check_mark: |                                                 |\n| jffi-ppc64-Linux.jar         | ppc64-linux            | :heavy_check_mark: | investigate/drop                                |\n| jffi-ppc64le-Linux.jar       | ppc64le-linux          | :heavy_check_mark: |                                                 |\n| jffi-s390x-Linux.jar         | s390x-linux            | :heavy_check_mark: |                                                 |\n| jffi-sparc-SunOS.jar         |                        |                    | drop                                            |\n| jffi-sparcv9-Linux.jar       |                        | :heavy_check_mark: | investigate/drop                                |\n| jffi-sparcv9-SunOS.jar       |                        | :heavy_check_mark: | investigate (jdk11 binaries exist, jdk17 don't) |\n| jffi-x86_64-DragonFlyBSD.jar |                        | :heavy_check_mark: | Wait until RubyGems support                     |\n| jffi-x86_64-FreeBSD.jar      | x86_64-freebsd         | :heavy_check_mark: |                                                 |\n| jffi-x86_64-Linux.jar        | x86_64-linux           | :heavy_check_mark: |                                                 |\n| jffi-x86_64-OpenBSD.jar      | x86_64-openbsd         | :heavy_check_mark: |                                                 |\n| jffi-x86_64-SunOS.jar        |                        | :heavy_check_mark: | drop                                            |\n| jffi-x86_64-Windows.jar      | :heavy_check_mark:     | :heavy_check_mark: |                                                 |\n| *(riscv32-linux)             |                        |                    | maybe add                                       |\n| *                            | riscv64-linux          |                    | add                                             |\n\n| Architecture      |Linux |Mac |FreeBSD|AIX |Solaris|OpenBSD|DragonFlyBSD|\n|-------------------|------|----|-------|----|-------|-------|------------|\n| arm5              | ,T   |    |       |    |       |       |            |\n| arm6              | y?   |    |       |    |       |       |            |\n| arm7              | y ?  |    |       |    |       |       |            |\n| arm8/aarch64      | y,9T |y,9T| j     |    |       |       |            |        \n| i386              | y    |    | y\u003c    |    | j     | j\u003c    |            |\n| x86_64            | y,9T |y,9T| y     |    | j     | j     | j          |    \n| sparc             |      |    |       |    | j\u003c    |       |            |\n| sparcv9           | j-   |    |       |    | j     |       |            |    \n| ppc               | j*\u003c  |    |       |  j |       |       |            |\n| ppc64             | j*   |    |       |j,9T|       |       |            |\n| ppc64le           | y,9T |    |       |    |       |       |            |\n| mips              |      |    |       |    |       |       |            |\n| mipsel            |      |    |       |    |       |       |            |\n| mips64el          | j\u0026   |    |       |    |       |       |            |    \n| s390x             | y,9T |    |       |    |       |       |            |\n| loongarch64       | j@   |    |       |    |       |       |            |\n| riscv32           | s    |    |       |    |       |       |            |\n| riscv64           | s,T  |    |       |    |       |       |            |\n| -Docker or runner-| ✔    |✔  | ✔     | ?IBM Cloud | ?Oracle Cloud |   ?   |            |\n\n\nKey:\n - y = JFFI \u0026 subspawn CI\n - j = jffi only\n - s = Subspawn only\n - 9 = J9 Semeru build\n - T = Adoptium Temurin OpenJDK build\n - _ = dockcross support\n - * = crosstools-ng support (easy-ish dockcross support)\n - - - partial ct-ng support\n - \u003c = not shipped by jruby\n\n// https://github.com/boxcutter/bsd \n\n### Prebuild binary OS support\n\n * Linux: 3.10 and glibc 2.17+ (Mostly, see table below)\n * MacOS: 12\n * FreeBSD: 9+\n * OpenBSD: 6.8+\n * DragonFlyBSD: No support until RubyGems adds support\n * AIX: ???\n * Solaris: ???\n * Windows: 7+ (via direct FFI)\n\n\n| Architecture      |Linux        |Mac |FreeBSD|AIX |Solaris|OpenBSD|DragonFlyBSD|\n|-------------------|-------------|----|-------|----|-------|-------|------------|\n| armv5             |             |    |       |    |       |       |            |\n| armv6/armv7       | 3.12/2.17   |    |       |    |       |       |            |\n| arm8/aarch64      | 3.12/2.17   | 12 | 11.4  |    |       |       |            |        \n| i386              | 3.10/2.17   |    | 9.3   |    | -     | -*    |            |\n| x86_64            | 3.10/2.17   | 12 | 9.3   |    | -*    | 6.8   | *Rubygems  |    \n| sparc             |             |    |       |    | -     |       |            |\n| sparcv9           | -*          |    |       |    | -*    |       |            |    \n| ppc               | -           |    |       | -  |       |       |            |\n| ppc64             | 3.10/2.17   |    |       | ?? |       |       |            |\n| ppc64le           | 3.10/2.17   |    |       |    |       |       |            |\n| mips              |             |    |       |    |       |       |            |\n| mipsel            |             |    |       |    |       |       |            |\n| mips64el          | 3.10/2.17   |    |       |    |       |       |            |    \n| s390x             | 3.10/2.17   |    |       |    |       |       |            |\n| loongarch64       | 5.19/2.36   |    |       |    |       |       |            |\n| riscv32           |             |    |       |    |       |       |            |\n| riscv64           | 5.10/2.35   |    |       |    |       |       |            |\n| -Docker or runner-| ✔           |✔  | ✔     | ?IBM Cloud | ?Oracle Cloud |   ?   |            |\n\nhttps://github.com/byteit101/jruby-dockcross\n\nopenbsd: add pkg-config make\nmkdir /usr/libexec/\nln -s {/opt,}/usr/libexec/ld.so\n# License\n\nSubSpawn is licensed under a tri EPL/LGPL/Ruby license. You can use it, redistribute it and/or modify it under the terms of the:\n\n[Eclipse Public License version 2.0](https://spdx.org/licenses/EPL-2.0.html) OR [GNU Lesser General Public License version 2.1 (or later)](https://spdx.org/licenses/LGPL-2.1-or-later.html) OR [Ruby License](https://spdx.org/licenses/Ruby.html)\n\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbyteit101%2Fsubspawn","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbyteit101%2Fsubspawn","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbyteit101%2Fsubspawn/lists"}