# TensorFlow Op CodeGen Machinery (Experimental) ## Usage ``` usage: generate_cpp [flags] OpName1 [OpName2 ...] Flags: --help=false bool Print this help message. --category="" string Category for generated ops (e.g. 'math', 'array'). --namespace="" string Compact C++ namespace, default is 'tensorflow::ops'. --output_dir="" string Directory into which output files will be generated. --source_dir="" string The tensorflow root directory, e.g. 'tensorflow/' for in-source include paths. Any path underneath the tensorflow root is also accepted. --api_dirs="" string Comma-separated list of directories containing API definitions. ``` ## Design ### Generator Framework The generator framework is a loose Model/View/Controller arrangement: The *Model* classes live in the ***model/*** directory. They are representations of the `OpDef` and `ApiDef` protos, normalized and resolved. > _For example, an `OpDef` proto's `ArgDef` members contain a type string, which > must be dereferenced to an `AttrDef` by name to determine its type. This > `AttrDef` proto message in turn contains a type string which may need to be > parsed as "list(type)". Other `AttrDef` messages are not types, but instead > argument-like modifiers. In contrast, the generator model `ArgSpec` contains a > resolved `ArgType` which provides a boolean `is_list()` method directly, and > the model `OpSpec` provides a list of only the argument-like attributes. In > addition to convenience, this should aid consistency between generated code in > each target language._ The *Controller* is in the ***common/*** directory. It is the workhorse used by the language generators; it digests the Op registry and API definitions to build the model and provides utilities for the language generators. The *View* and rendering classes map the language-independent Model classes (`OpSpec`, `ArgSpec`, `AttrSpec`, etc.) to language-specific `SourceCode`. The framework does not impose any design on the language-specific generators, but provides some utilities, and the C++ generator is a complete example. ### C++ Generator The `CppGenerator` class is the interface to the `cpp/` language directory. Given a config, it can generate source code for a .cc or .h file as a string or write it to a target file. The `CppFileRenderer` is the main renderer used by the generator; it renders an entire file. The `CppConfig` defines if it is operating in header or source mode. "Views" are stateless and intended to be low-level building blocks: a direct language-specific representation of the model classes. For example, an `ArgView` is initialized from an `ArgSpec` (which was created initially from an `ArgDef` proto message). Where they may have some similar methods between the model and view, the view methods are language-specific. For instance, the C++ generator's `ArgView::VariableName()` method is an language-formatted name usable as a variable representing the model `ArgSpec` object. In contrast, the `ArgSpec::name()` method in the model refers to the canonical name of the object in the proto. Where views are a representation of the *input* model, in the C++ generator, "renderers" then use these views to build the *output* `SourceCode`; Renderers understand the language at the statement/directive level and target a functional section of the output, such as a block comment or an entire method or file. Other differences between views and renderers: * Renderers are stateful, modifying a referenced SourceCode. Views are stateless and their public methods are all const, returning strings. * Renderers are context-dependent, e.g. a method signature will include default values when in "declaration" mode but not "definition" mode. A view of some argument object simply knows its default value and does not care the context. * In terms of dependencies, `Renderers` use `Views` and other `Renderers`. However, `Renderers` do **not** reference the model directly (e.g. `OpSpec`). This is because if a renderer needs to reference part of the model, it should get a language specific representation. ### Extending to Additional Languages The design for the C++ generator should apply to other languages, and the underlying generator framework (the model and controller) try to be agnostic. In fact, some elements of the C++ design could be formalized (such as the rendering/view framework) or re-used (e.g. `cpp:Renderer` could likely be shared with C and Java as a common C-style language renderer base class). Abstracted and condensed from the C++ generator, the overall control flow could be described as follows: From main() in *generate_lang_main.cc*: * Call `tensorflow::port::InitMain` and parse any flags * Initialize config objects (e.g. `PathConfig`, `LangConfig` from flags) * Initialize a new `LangGenerator` from these config objects * Call this generator to create/write `SourceCode` to a file In class `LangGenerator` in *lang_generator.cc*: * Initialize a new `Controller` from the config objects * Call this controller to build the Op models (`OpSpec`) * Initialize a new language-specific `View` for each model object * Create a blank `SourceCode` rendering target (for each output file) * Initialize a new `LangFileRenderer` from this target source code, the model `View` objects, and config objects * Call this renderer to generate the target `SourceCode` The dependencies are as follows: * `lang::Generator` depends on `Controller`, `Model`, `lang::Renderers`, `lang::Views` * `lang::Renderer` depends on `lang::View` (and `lang::Renderer` peers) * `lang::View` depends on the model (e.g. `OpSpec`) (and `lang::View` peers)