GENWRAP(8)
π 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 tostderr. 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 debugginggenwrapitself.-nname β Use name for the generated wrapper's name. This will be used as the name within/var/selectto 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 wrapperfoo.wrappershould use/var/select/foo.-ooutput β Switch the output file to output. The default is to write the shim tostdout, andstdoutmay also be specified by explicitly passing-for output.
β οΈ Note thatgenwraponly generates a C source file for the shim.genwrapdoes 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:
- If an env var is configured, the variable is set in the environment, then it will be used.
- 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.
- 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 theenvdirective 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 nodefaultdirective is specified, then the resulting shim will use the first specified application as the default. If a/var/selectsymlink is specified for the given wrapper, then the named application will be considered the default instead.argmode logonlyβ Indicates that anyflagdirectives specified should only be considered for logging purposes. If arguments are evaluated to determine which application to choose, one withlogonlyset 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 atargv[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 theapplicationdirective, 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 anoargskeyword after theanalytics, 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 thatgenwrapwill 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 forgenwrapto 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
- Copyright (c) 2023 Apple Inc. All rights reserved
- Copyright (c) 1999 Apple Computer, Inc. All Rights
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash-1017 on : a language model's rewrite of the original, under its terms