GENWRAP(8)

πŸ“¦ version 237, in nixpkgs unstable

πŸ’– GENWRAP(8) πŸ’–

System Manager's Manual Β· genwrap β€” generate parameterized program wrappers

πŸŽ€ NAME πŸŽ€

genwrap β€” generate parameterized program wrappers

✨ SYNOPSIS ✨

genwrap [-d] [-n name] [-o output] spec

πŸ’… DESCRIPTION πŸ’…

Okay so the genwrap utility generates program wrappers β€” officially β€œshims” from here on β€” from a specification. It’s giving β€œmiddleware but make it tiny.” genwrap is primarily intended to be used for these scenarios:

  • Adding a shim that reports analytics on program usage.
  • Adding a shim that allows switching between multiple application implementations based on an environment variable.
  • Adding a shim that may switch between multiple application implementations based on the arguments being used.

spec should be a file written in the format specified later in β€œSPECIFICATION FORMAT”.

Here’s the option menu, bestie:

  • -d β€” Enables debug output to stderr. In particular, this emits notice of each action taken as a result of the specified wrapper definition as it is parsed, without any filtering. This is mainly intended to aide in debugging genwrap itself.
  • -n name β€” Use name for the generated wrapper's name. This will be used as the name within /var/select to check for a defined system choice. The name will be automatically derived from a filename by omitting a trailing .wrapper, so it is not necessary to specify for cases where the wrapper foo.wrapper should use /var/select/foo.
  • -o output β€” Switch the output file to output. The default is to write the shim to stdout, and stdout may also be specified by explicitly passing - for output.
⚠️ Note that genwrap only generates a C source file for the shim. genwrap does not directly offer the ability to build a binary from the shim. It does not do the whole β€œcompile and ship it” moment for you, bestie.

The genwrap generated wrapper will use the following logic to choose the application to execute, in this order of precedence:

  1. If an env var is configured, the variable is set in the environment, then it will be used.
  2. If argument-based switching is used, then the default application is checked first for compatibility with the arguments presented. The default application is discussed below in the β€œSPECIFICATION FORMAT” section. The applications are checked in the defined order after the default application is checked.
  3. If the above criteria did not result in anything to execute, then the default application will be executed.

🧚 SPECIFICATION FORMAT 🧚

genwrap uses a minimal custom language for generating shims. This language is best described as two primary functional blocks: the shim setting block and the application specification block. The shim setting block must appear before application specifications. Comments begin with a #, and whitespace is generally irrelevant outside of quoted values. By convention, one line corresponds to exactly one directive.

Listings in the rest of this section may be interpreted and written literally into a specification file. If a keyword appears in [brackets], then the keyword is optional and the brackets should be omitted when writing the keyword.

The following optional directives may be specified in the shim setting block:

  • analytics "identifier" β€” Report CoreAnalytics events with the specified identifier. CoreAnalytics is disabled if this directive is not in use.
  • env "variable" β€” Use the specified variable to switch specified application implementations based on the environment that the generated shim is run in. Values for the environment variable match the names specified later in the application specification block.

Applications are defined after the shim setting block. At least one application must be defined. Every application must have a path set.

All directives besides the application directives apply to the last specified application prior to the directive. By convention, all directives besides the application directives are indented by some consistent amount of whitespace to improve readability of the specification.

The following directives may be specified in the application specification block:

  • application "name" β€” Defines an application with the specified name. The given name typically corresponds to the name of the binary that this application block will represent, but its exact value is not significant. If the env directive is specified above, then the specified environment variable may be set to name to indicate that this application block's path should be used.
  • default β€” Optionally specifies that this application block is the default application. If no default directive is specified, then the resulting shim will use the first specified application as the default. If a /var/select symlink is specified for the given wrapper, then the named application will be considered the default instead.
  • argmode logonly β€” Indicates that any flag directives specified should only be considered for logging purposes. If arguments are evaluated to determine which application to choose, one with logonly set will be considered acceptable by default.
  • path "path" β€” This directive is required for each specified application. The given path should be the path to the binary to be used if this application is selected.

If a relative path is given, then it will be prefixed with the active developer directory as provided by xcode-select(1) at runtime, with one exception. If the relative path begins with a literal $XCODE/ component, then genwrap will instead invoke xcrun(1) with the trailing part of the relative path as the tool name. For example, $XCODE/yacc will do the equivalent behavior of:

xcrun yacc ...

If an absolute path is given, then it will be used as-is.

  • addarg "argv[1]" ["argv[n]" ...] β€” Adds the given quoted words to the arguments we pass to this application, if selected. These arguments are inserted at argv[1], before any arguments that the wrapper was invoked with.
  • flag "flag" [optional_arg | arg] [logonly] [pattern "pattern"] β€” Adds the given flag as a recognized flag by this application. If flag is a long flag, it must not have a short flag alias when used in this form.

If optional_arg or arg are specified, then it is noted in the shim that this flag takes an argument.

If logonly is specified, then this argument will not be considered an acceptable argument for the application in argument-based switching.

Specifying a pattern enables collection of option arguments if and only if they match the described pattern. The pattern will be interpreted and executed as a POSIX extended regular expression, as described in re_format(7).

  • flag "longflag" "shortflag" [optional_arg | arg] [logonly] [pattern "pattern"] β€” This is equivalent to the above form, except that longflag explicitly has a shortflag alias.

The flag directives are only necessary if argument-based switching is desired, rather than environment-based switching. Informing the shim of argument structure may also be used to limit reported analytics to avoid inadvertently including arguments. See β€œANALYTICS” for more details.

πŸ¦‹ ANALYTICS πŸ¦‹

genwrap may be used to generate shims that collect analytics on application usage. The details reported can be useful in understanding how applications are used in practice to inform relevant decisions.

When analytics are enabled, genwrap shims report events with the following details:

  • name β€” The name the wrapper was invoked as, i.e., argv[0].
  • chosen β€” The name, provided in the application directive, of the specific application that was chosen to be invoked.
  • arguments β€” The array of arguments passed to the wrapper.
😭 Note that, currently, all arguments passed to the wrapper are reported in these events. The specification grammar accepts a noargs keyword after the analytics, which may be used to omit flags' argument values as well as any non-option arguments to prevent an inadvertent information disclosure through, e.g., file names.

πŸ’Ύ FILES πŸ’Ύ

  • /nix/store/brg965nzdn7k33q7wcqf8376y4ndjdh3-adv_cmds-237/share/genwrap/wrapper-head.c β€” The prologue for the shim that genwrap will write out, containing some include files and definitions that will later be used in the implementation.
  • /nix/store/brg965nzdn7k33q7wcqf8376y4ndjdh3-adv_cmds-237/share/genwrap/wrapper-tail.c β€” The implementation of the shim that is written out at the end of the file.
  • /nix/store/brg965nzdn7k33q7wcqf8376y4ndjdh3-adv_cmds-237/share/genwrap/examples β€” Directory containing examples that are ready for genwrap to be run against for demonstration.

🌸 EXAMPLES 🌸

Ok bestie, this is the part where it all comes together β€” real configs, real vibes, zero cap πŸ’…


Example numero uno: a shim that can switch between different make(1) implementations depending on the COMMAND_MAKE environment variable πŸŽ€

env "COMMAND_MAKE"
# Arbitrarily specified in alphabetical order.
application "bmake"
        # A minimal application specification only consists of a path.
        path "usr/bin/bmake"
application "gnumake"
        default
        # Note that both of these will be invoked out of developer tools,
        # because they're relative paths.
        path "usr/bin/gnumake"
# usr/bin/bmake will be selected if the resulting shim is compiled and run in
# an environment with COMMAND_MAKE="bmake", and usr/bin/gmake will be selected
# if the resulting shim is run in an environment with COMMAND_MAKE="gnumake".

Notice how bmake is listed first and gnumake got the default label, because "arbitrarily specified in alphabetical order" is literally a comment in the file 😌 also notice the paths are relative β€” usr/bin/bmake, no leading slash β€” and per that comment right there, that means both of these get invoked out of developer tools. iykyk 🧚


Example dos: a shim that switches to another application if flags show up that aren't described anywhere. The default application gets checked first, then every other defined application in the order they're defined πŸ¦‹

# Collect analytics on this one primarily because we want to see how often
# our shim ends up selecting the oldapp, along with what arguments are most
# commonly being used when the shim is forced to switch to oldapp.
analytics "com.example.newapp"
env "COMMAND_APP"
# If newapp is forced by setting COMMAND_APP=newapp in the environment when the
# shim is ran, then we will simply execute it without checking any flags.  This
# can be useful if support for a flag is added to /usr/bin/newapp but it is
# being tested before recognizing it as valid in the shim.
application "newapp"
        path "/usr/bin/newapp"
        # Supports -b, --bytes; that flag takes an argument.
        flag "bytes" "b" arg
        # Supports a --verbose flag that takes no argument.
        flag "verbose"
        # Transform the wrapper being called as `app ...` into `newapp -g ...`
        addarg "-g"
application "oldapp"
        path "/usr/bin/oldapp"
        # No flags directives here indicates that we do not need to check the
        # specified flags to try and use this application, so if a flag that
        # newapp does not support is specified then we will immediately fallback
        # to oldapp.

Obsessed with this one honestly 🫢 quick tour: flag "bytes" "b" arg means it supports -b / --bytes and that flag takes an argument, flag "verbose" takes no argument, and addarg "-g" transforms a wrapper call of app ... into newapp -g ... ✨ and oldapp has no flags directives at all, which is the whole point β€” it means we don't need to check the specified flags to try and use it, so any flag newapp doesn't support means we immediately fallback to oldapp. slay πŸ’…


More examples live in /nix/store/brg965nzdn7k33q7wcqf8376y4ndjdh3-adv_cmds-237/share/examples/genwrap β€” go look, there's treasure in there πŸ“

πŸ‘€ SEE ALSO πŸ‘€

  • analyticsd(1)
  • xcode-select(1)
  • xcrun(1)
  • analytics_tool(8)

πŸ’€ BUGS πŸ’€

Ok so there's one known little gremlin πŸ™ˆ the shims generated by genwrap cannot be used with argument-based switching when β€œ?” is a valid flag. that's it, that's the bug, no cap 😭


and that's the whole page bestie!! you ate it, you read it, you're basically a genwrap expert now πŸ‘‘

This one's from the Debian build, dated April 28, 2024 β€” GENWRAP(8), section 8, your fave πŸ’œ

πŸ“¦ where this page comes from
  • nixpkgs unstable: adv_cmds 237
  • πŸ’– girlified by deepseek-ai/DeepSeek-V4.1-Flash-1017 on : a language model's rewrite of the original, under its terms