| <!DOCTYPE html> |
| <html lang="en"> |
| <head> |
| <meta charset="utf-8"> |
| <meta name="viewport" content="width=device-width,initial-scale=1"> |
| <title>Code Generation :: PLC4X</title> |
| <meta name="generator" content="Antora 3.1.14"> |
| <!-- |
| Licensed to the Apache Software Foundation (ASF) under one |
| or more contributor license agreements. See the NOTICE file |
| distributed with this work for additional information |
| regarding copyright ownership. The ASF licenses this file |
| to you under the Apache License, Version 2.0 (the |
| "License"); you may not use this file except in compliance |
| with the License. You may obtain a copy of the License at |
| |
| https://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, |
| software distributed under the License is distributed on an |
| "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| KIND, either express or implied. See the License for the |
| specific language governing permissions and limitations |
| under the License. |
| --> |
| <link rel="stylesheet" href="/_/css/site.css"> |
| <link rel="stylesheet" href="/_/css/header.css"> |
| <link rel="stylesheet" href="/_/css/vars.css"> |
| <link rel="stylesheet" href="/_/css/all.min.css" type="text/css"/> |
| <script src="https://www.apachecon.com/event-images/snippet.js" type="text/javascript"></script> |
| <link rel="icon" type="image/x-icon" href="/images/favicon.ico"> </head> |
| <body class="article"> |
| <header class="header"> |
| <nav class="navbar"> |
| <div class="navbar-brand"> |
| <a class="navbar-item" href="../../../.."> |
| <img src="../../../../plc4x/pre-release/_images/apache-plc4x-oakleaf-dark-small.png" alt="Apache PLC4X"> |
| </a> |
| <div class="navbar-item search hide-for-print"> |
| <div id="search-field" class="field"> |
| <input id="search-input" type="text" placeholder="Search the docs"> |
| </div> |
| </div> |
| <button class="navbar-burger" aria-controls="topbar-nav" aria-expanded="false" aria-label="Toggle main menu"> |
| <span></span> |
| <span></span> |
| <span></span> |
| </button> |
| </div> |
| <div id="topbar-nav" class="navbar-menu"> |
| <div class="navbar-end justify-content-center"> |
| <a class="navbar-item" href="../../../../">Home</a> |
| <a class="navbar-item" href="../../../../plc4x/pre-release/users">Users</a> |
| <a class="navbar-item" href="../../../../plc4x/pre-release/developers">Developers</a> |
| <div class="navbar-item has-dropdown is-hoverable"> |
| <a class="navbar-link" href="https://www.apache.org">Apache</a> |
| <div class="navbar-dropdown"> |
| <a class="navbar-item" href="https://www.apache.org">Apache Homepage</a> |
| <a class="navbar-item" href="https://www.apache.org/licenses/">License</a> |
| <a class="navbar-item" href="https://www.apache.org/foundation/sponsorship.html">Sponsorship</a> |
| <a class="navbar-item" href="https://www.apache.org/foundation/thanks.html">Thanks</a> |
| <a class="navbar-item" href="https://www.apache.org/security/">Security</a> |
| <a class="navbar-item" href="https://privacy.apache.org/policies/privacy-policy-public.html">Privacy</a> |
| <a class="navbar-item" href="https://www.apache.org/foundation/policies/conduct">Code of Conduct</a> |
| <a class="navbar-item" href="https://events.apache.org/">Upcoming Events</a> |
| </div> |
| </div> |
| <div class="navbar-item"> |
| <span class="control"> |
| <a class="fa-brands fa-github" href="https://github.com/apache/plc4x"></a> |
| </span> |
| </div> |
| <div class="navbar-item"> |
| <span class="control"> |
| <a class="button is-primary" href="../../../../plc4x/pre-release/users/download.html">Download</a> |
| </span> |
| </div> |
| <a class="acevent" data-format="wide"></a> |
| </div> |
| </div> |
| </nav> |
| </header> |
| <div class="body"> |
| <div class="nav-container" data-component="plc4x" data-version="pre-release"> |
| <aside class="nav"> |
| <div class="panels"> |
| <div class="nav-panel-menu is-active" data-panel="menu"> |
| <nav class="nav-menu"> |
| <button class="nav-menu-toggle" aria-label="Toggle expand/collapse all" style="display: none"></button> |
| <h3 class="title"><a href="../../users/index.html">PLC4X</a></h3> |
| <ul class="nav-list"> |
| <li class="nav-item" data-depth="0"> |
| <ul class="nav-list"> |
| <li class="nav-item" data-depth="1"> |
| <button class="nav-item-toggle"></button> |
| <a class="nav-link" href="../../users/index.html">Users</a> |
| <ul class="nav-list"> |
| <li class="nav-item" data-depth="2"> |
| <a class="nav-link" href="../../users/download.html">Download</a> |
| </li> |
| <li class="nav-item" data-depth="2"> |
| <a class="nav-link" href="../../users/adopters.html">Adopters</a> |
| </li> |
| <li class="nav-item" data-depth="2"> |
| <a class="nav-link" href="../../users/issues.html">Bug & Issue Tracker</a> |
| </li> |
| <li class="nav-item" data-depth="2"> |
| <a class="nav-link" href="../../users/commercial-support.html">Commercial Support</a> |
| </li> |
| <li class="nav-item" data-depth="2"> |
| <button class="nav-item-toggle"></button> |
| <a class="nav-link" href="../../users/getting-started/index.html">Getting Started</a> |
| <ul class="nav-list"> |
| <li class="nav-item" data-depth="3"> |
| <a class="nav-link" href="../../users/getting-started/plc4c.html">Getting Started with C</a> |
| </li> |
| <li class="nav-item" data-depth="3"> |
| <a class="nav-link" href="../../users/getting-started/plc4cs.html">Getting Started with C#</a> |
| </li> |
| <li class="nav-item" data-depth="3"> |
| <a class="nav-link" href="../../users/getting-started/plc4go.html">Getting Started with Go</a> |
| </li> |
| <li class="nav-item" data-depth="3"> |
| <a class="nav-link" href="../../users/getting-started/plc4j.html">Getting Started with Java</a> |
| </li> |
| <li class="nav-item" data-depth="3"> |
| <a class="nav-link" href="../../users/getting-started/plc4py.html">Getting Started with Python</a> |
| </li> |
| <li class="nav-item" data-depth="3"> |
| <a class="nav-link" href="../../users/getting-started/using-snapshots.html">Using SNAPSHOT versions</a> |
| </li> |
| <li class="nav-item" data-depth="3"> |
| <a class="nav-link" href="../../users/getting-started/general-concepts.html">General Concepts</a> |
| </li> |
| <li class="nav-item" data-depth="3"> |
| <a class="nav-link" href="../../users/getting-started/virtual-modbus.html">Virtual Modbus</a> |
| </li> |
| <li class="nav-item" data-depth="3"> |
| <a class="nav-link" href="../../users/getting-started/opcua-client-certificate.html">OPC UA : Client certificate creation</a> |
| </li> |
| </ul> |
| </li> |
| <li class="nav-item" data-depth="2"> |
| <a class="nav-link" href="../../users/blogs-videos-and-slides.html">Blogs, Videos and Slides on Apache PLC4X</a> |
| </li> |
| <li class="nav-item" data-depth="2"> |
| <button class="nav-item-toggle"></button> |
| <a class="nav-link" href="../../users/protocols/index.html">Protocols</a> |
| <ul class="nav-list"> |
| <li class="nav-item" data-depth="3"> |
| <a class="nav-link" href="../../users/protocols/ab-eth.html">AB-ETH</a> |
| </li> |
| <li class="nav-item" data-depth="3"> |
| <a class="nav-link" href="../../users/protocols/ads.html">ADS (Automation Device Specification)</a> |
| </li> |
| <li class="nav-item" data-depth="3"> |
| <a class="nav-link" href="../../users/protocols/bacnet.html">BACnet/IP</a> |
| </li> |
| <li class="nav-item" data-depth="3"> |
| <a class="nav-link" href="../../users/protocols/c-bus.html">C-Bus</a> |
| </li> |
| <li class="nav-item" data-depth="3"> |
| <a class="nav-link" href="../../users/protocols/canopen.html">CANopen</a> |
| </li> |
| <li class="nav-item" data-depth="3"> |
| <a class="nav-link" href="../../users/protocols/ctrlx.html">CtlrX</a> |
| </li> |
| <li class="nav-item" data-depth="3"> |
| <a class="nav-link" href="../../users/protocols/deltav.html">DeltaV</a> |
| </li> |
| <li class="nav-item" data-depth="3"> |
| <a class="nav-link" href="../../users/protocols/df1.html">DF1</a> |
| </li> |
| <li class="nav-item" data-depth="3"> |
| <a class="nav-link" href="../../users/protocols/eip.html">EtherNet/IP</a> |
| </li> |
| <li class="nav-item" data-depth="3"> |
| <a class="nav-link" href="../../users/protocols/firmata.html">Firmata</a> |
| </li> |
| <li class="nav-item" data-depth="3"> |
| <a class="nav-link" href="../../users/protocols/genericcan.html">Generic CAN</a> |
| </li> |
| <li class="nav-item" data-depth="3"> |
| <a class="nav-link" href="../../users/protocols/iec-60870.html">IEC-60870</a> |
| </li> |
| <li class="nav-item" data-depth="3"> |
| <a class="nav-link" href="../../users/protocols/knxnetip.html">KNXnet/IP</a> |
| </li> |
| <li class="nav-item" data-depth="3"> |
| <a class="nav-link" href="../../users/protocols/logix.html">Logix</a> |
| </li> |
| <li class="nav-item" data-depth="3"> |
| <a class="nav-link" href="../../users/protocols/modbus.html">Modbus (TCP/UDP/Serial)</a> |
| </li> |
| <li class="nav-item" data-depth="3"> |
| <a class="nav-link" href="../../users/protocols/opcua.html">OPC UA</a> |
| </li> |
| <li class="nav-item" data-depth="3"> |
| <a class="nav-link" href="../../users/protocols/open-protocol.html">Open-Protocol (Torque-Tools)</a> |
| </li> |
| <li class="nav-item" data-depth="3"> |
| <a class="nav-link" href="../../users/protocols/plc4x.html">PLC4X (Proxy) (TCP)</a> |
| </li> |
| <li class="nav-item" data-depth="3"> |
| <a class="nav-link" href="../../users/protocols/profinet.html">Profinet (In Development)</a> |
| </li> |
| <li class="nav-item" data-depth="3"> |
| <a class="nav-link" href="../../users/protocols/s7.html">S7 (Step7)</a> |
| </li> |
| <li class="nav-item" data-depth="3"> |
| <a class="nav-link" href="../../users/protocols/s7-light.html">S7-Light (Step7)</a> |
| </li> |
| <li class="nav-item" data-depth="3"> |
| <a class="nav-link" href="../../users/protocols/simulated.html">Simulated</a> |
| </li> |
| <li class="nav-item" data-depth="3"> |
| <a class="nav-link" href="../../users/protocols/umas.html">UMAS (Schneider Electric PLCs)</a> |
| </li> |
| </ul> |
| </li> |
| <li class="nav-item" data-depth="2"> |
| <button class="nav-item-toggle"></button> |
| <a class="nav-link" href="../../users/transports/index.html">Transports</a> |
| <ul class="nav-list"> |
| <li class="nav-item" data-depth="3"> |
| <a class="nav-link" href="../../users/transports/tcp.html">TCP</a> |
| </li> |
| <li class="nav-item" data-depth="3"> |
| <a class="nav-link" href="../../users/transports/udp.html">UDP</a> |
| </li> |
| <li class="nav-item" data-depth="3"> |
| <a class="nav-link" href="../../users/transports/serial.html">Serial Port</a> |
| </li> |
| <li class="nav-item" data-depth="3"> |
| <a class="nav-link" href="../../users/transports/socketcan.html">SocketCAN</a> |
| </li> |
| <li class="nav-item" data-depth="3"> |
| <a class="nav-link" href="../../users/transports/raw-socket.html">Raw Socket</a> |
| </li> |
| <li class="nav-item" data-depth="3"> |
| <a class="nav-link" href="../../users/transports/pcap-replay.html">PCAP Replay</a> |
| </li> |
| </ul> |
| </li> |
| <li class="nav-item" data-depth="2"> |
| <button class="nav-item-toggle"></button> |
| <a class="nav-link" href="../../users/integrations/index.html">Integrations</a> |
| <ul class="nav-list"> |
| <li class="nav-item" data-depth="3"> |
| <a class="nav-link" href="../../users/integrations/apache-calcite.html">Apache Calcite</a> |
| </li> |
| <li class="nav-item" data-depth="3"> |
| <a class="nav-link" href="../../users/integrations/apache-camel.html">Apache Camel</a> |
| </li> |
| <li class="nav-item" data-depth="3"> |
| <a class="nav-link" href="../../users/integrations/apache-iotdb.html">Apache IotDB</a> |
| </li> |
| <li class="nav-item" data-depth="3"> |
| <a class="nav-link" href="../../users/integrations/apache-kafka.html">Apache Kafka</a> |
| </li> |
| <li class="nav-item" data-depth="3"> |
| <a class="nav-link" href="../../users/integrations/apache-nifi.html">Apache NiFi</a> |
| </li> |
| <li class="nav-item" data-depth="3"> |
| <a class="nav-link" href="../../users/integrations/apache-streampipes.html">Apache StreamPipes</a> |
| </li> |
| <li class="nav-item" data-depth="3"> |
| <a class="nav-link" href="../../users/integrations/eclipse-ditto.html">Eclipse Ditto</a> |
| </li> |
| <li class="nav-item" data-depth="3"> |
| <a class="nav-link" href="../../users/integrations/eclipse-milo.html">Eclipse Milo (OPC UA Server)</a> |
| </li> |
| </ul> |
| </li> |
| <li class="nav-item" data-depth="2"> |
| <button class="nav-item-toggle"></button> |
| <a class="nav-link" href="../../users/tools/index.html">Tools</a> |
| <ul class="nav-list"> |
| <li class="nav-item" data-depth="3"> |
| <a class="nav-link" href="../../users/tools/capture-replay.html">Capture Replay</a> |
| </li> |
| <li class="nav-item" data-depth="3"> |
| <a class="nav-link" href="../../users/tools/connection-cache.html">The Connection Cache concept</a> |
| </li> |
| <li class="nav-item" data-depth="3"> |
| <a class="nav-link" href="../../users/tools/opm.html">Object PLC Mapping</a> |
| </li> |
| <li class="nav-item" data-depth="3"> |
| <a class="nav-link" href="../../users/tools/scraper.html">Scraper</a> |
| </li> |
| <li class="nav-item" data-depth="3"> |
| <a class="nav-link" href="../../users/tools/testing.html">Testing (or using PLC4X without a PLC)</a> |
| </li> |
| </ul> |
| </li> |
| <li class="nav-item" data-depth="2"> |
| <a class="nav-link" href="../../users/industry40.html">Industry 4.0 with Apache</a> |
| </li> |
| <li class="nav-item" data-depth="2"> |
| <a class="nav-link" href="../../users/security.html">Security Vulnerabilities</a> |
| </li> |
| </ul> |
| </li> |
| </ul> |
| </li> |
| <li class="nav-item" data-depth="0"> |
| <ul class="nav-list"> |
| <li class="nav-item" data-depth="1"> |
| <button class="nav-item-toggle"></button> |
| <a class="nav-link" href="../index.html">Developers</a> |
| <ul class="nav-list"> |
| <li class="nav-item" data-depth="2"> |
| <button class="nav-item-toggle"></button> |
| <a class="nav-link" href="../preparing/index.html">Preparing your Computer</a> |
| <ul class="nav-list"> |
| <li class="nav-item" data-depth="3"> |
| <a class="nav-link" href="../preparing/linux.html">Linux</a> |
| </li> |
| <li class="nav-item" data-depth="3"> |
| <a class="nav-link" href="../preparing/macos.html">Mac OS</a> |
| </li> |
| <li class="nav-item" data-depth="3"> |
| <a class="nav-link" href="../preparing/windows.html">Windows</a> |
| </li> |
| </ul> |
| </li> |
| <li class="nav-item" data-depth="2"> |
| <a class="nav-link" href="../building.html">Building PLC4X</a> |
| </li> |
| <li class="nav-item" data-depth="2"> |
| <a class="nav-link" href="../contributing.html">Contributing</a> |
| </li> |
| <li class="nav-item" data-depth="2"> |
| <button class="nav-item-toggle"></button> |
| <a class="nav-link" href="../tutorials/index.html">Tutorials</a> |
| <ul class="nav-list"> |
| <li class="nav-item" data-depth="3"> |
| <a class="nav-link" href="../tutorials/writing-driver.html">Strategy for creating a new Driver</a> |
| </li> |
| <li class="nav-item" data-depth="3"> |
| <a class="nav-link" href="../tutorials/testing-serializers-and-parsers.html">Testing Serializers and Parsers</a> |
| </li> |
| </ul> |
| </li> |
| <li class="nav-item is-current-page" data-depth="2"> |
| <button class="nav-item-toggle"></button> |
| <a class="nav-link" href="index.html">Code Generation</a> |
| <ul class="nav-list"> |
| <li class="nav-item" data-depth="3"> |
| <a class="nav-link" href="protocol/mspec.html">The MSpec format</a> |
| </li> |
| <li class="nav-item" data-depth="3"> |
| <a class="nav-link" href="language/freemarker.html">Apache Freemarker</a> |
| </li> |
| <li class="nav-item" data-depth="3"> |
| <a class="nav-link" href="protocol/df1.html">Example: DF1 MSpec</a> |
| </li> |
| </ul> |
| </li> |
| <li class="nav-item" data-depth="2"> |
| <button class="nav-item-toggle"></button> |
| <a class="nav-link" href="../protocols/index.html">Usage of protocols</a> |
| <ul class="nav-list"> |
| <li class="nav-item" data-depth="3"> |
| <a class="nav-link" href="../protocols/ads/protocol.html">Beckhoff ADS Protocol</a> |
| </li> |
| <li class="nav-item" data-depth="3"> |
| <a class="nav-link" href="../protocols/eip/protocol.html">EIP Protocol</a> |
| </li> |
| </ul> |
| </li> |
| <li class="nav-item" data-depth="2"> |
| <button class="nav-item-toggle"></button> |
| <a class="nav-link" href="../infrastructure/index.html">Infrastructure</a> |
| <ul class="nav-list"> |
| <li class="nav-item" data-depth="3"> |
| <a class="nav-link" href="../infrastructure/ci.html">Continuous Integration</a> |
| </li> |
| <li class="nav-item" data-depth="3"> |
| <a class="nav-link" href="../infrastructure/issues.html">Bug & Issue Tracker</a> |
| </li> |
| <li class="nav-item" data-depth="3"> |
| <a class="nav-link" href="../infrastructure/sonar.html">Code Analysis</a> |
| </li> |
| <li class="nav-item" data-depth="3"> |
| <a class="nav-link" href="../infrastructure/wiki.html">WIKI</a> |
| </li> |
| <li class="nav-item" data-depth="3"> |
| <a class="nav-link" href="../infrastructure/vm.html">The PLC4X Project VM</a> |
| </li> |
| <li class="nav-item" data-depth="3"> |
| <a class="nav-link" href="../infrastructure/website.html">Generating the Website</a> |
| </li> |
| </ul> |
| </li> |
| <li class="nav-item" data-depth="2"> |
| <button class="nav-item-toggle"></button> |
| <a class="nav-link" href="../release/index.html">Releasing and Validating Releases</a> |
| <ul class="nav-list"> |
| <li class="nav-item" data-depth="3"> |
| <a class="nav-link" href="../release/release.html">Releasing PLC4X</a> |
| </li> |
| <li class="nav-item" data-depth="3"> |
| <a class="nav-link" href="../release/extras.html">Releasing PLC4X-Extras</a> |
| </li> |
| <li class="nav-item" data-depth="3"> |
| <a class="nav-link" href="../release/validation.html">Validating a staged release</a> |
| </li> |
| <li class="nav-item" data-depth="3"> |
| <a class="nav-link" href="../release/build-tools.html">Releasing PLC4X Build-Tools</a> |
| </li> |
| </ul> |
| </li> |
| <li class="nav-item" data-depth="2"> |
| <a class="nav-link" href="../testing/index.html">Setup for testing</a> |
| </li> |
| <li class="nav-item" data-depth="2"> |
| <a class="nav-link" href="../tools.html">Tools</a> |
| </li> |
| <li class="nav-item" data-depth="2"> |
| <a class="nav-link" href="../team.html">Team</a> |
| </li> |
| <li class="nav-item" data-depth="2"> |
| <a class="nav-link" href="../decisions.html">Decision Making</a> |
| </li> |
| <li class="nav-item" data-depth="2"> |
| <a class="nav-link" href="../maturity.html">Apache Maturity Model Assessment for PLC4X</a> |
| </li> |
| </ul> |
| </li> |
| </ul> |
| </li> |
| </ul> |
| </nav> |
| </div> |
| <div class="nav-panel-explore" data-panel="explore"> |
| <div class="context"> |
| <span class="title">PLC4X</span> |
| <span class="version">pre-release</span> |
| </div> |
| <ul class="components"> |
| <li class="component is-current"> |
| <div class="title"><a href="../../../latest/users/index.html">PLC4X</a></div> |
| <ul class="versions"> |
| <li class="version is-current"> |
| <a href="../../users/index.html">pre-release</a> |
| </li> |
| <li class="version is-latest"> |
| <a href="../../../latest/users/index.html">latest</a> |
| </li> |
| <li class="version"> |
| <a href="../../../0.12.0/users/index.html">0.12.0</a> |
| </li> |
| </ul> |
| </li> |
| </ul> |
| </div> |
| </div> |
| </aside> |
| </div> |
| <main class="article"> |
| <div class="toolbar" role="navigation"> |
| <button class="nav-toggle"></button> |
| <nav class="breadcrumbs" aria-label="breadcrumbs"> |
| <ul> |
| <li><a href="../../users/index.html">PLC4X</a></li> |
| <li><a href="../index.html">Developers</a></li> |
| <li><a href="index.html">Code Generation</a></li> |
| </ul> |
| </nav> |
| <div class="page-versions"> |
| <button class="version-menu-toggle" title="Show other versions of page">pre-release</button> |
| <div class="version-menu"> |
| <a class="version is-current" href="index.html">pre-release</a> |
| <a class="version" href="../../../latest/developers/code-gen/index.html">latest</a> |
| <a class="version" href="../../../0.12.0/developers/code-gen/index.html">0.12.0</a> |
| </div> |
| </div> |
| <div class="edit-this-page"><a href="https://github.com/apache/plc4x/edit/develop/website/asciidoc/modules/developers/pages/code-gen/index.adoc">Edit this Page</a></div> |
| </div> |
| <div class="content"> |
| <aside class="toc sidebar" data-title="Contents" data-levels="2"> |
| <div class="toc-menu"></div> |
| </aside> |
| <article class="doc"> |
| <h1 class="page">Code Generation</h1> |
| <div id="preamble"> |
| <div class="sectionbody"> |
| <div class="paragraph"> |
| <p>As hand-writing code for a lot of drivers in multiple languages would be quite a nightmare, we have invested a very large amount of time into finding a way to automate this.</p> |
| </div> |
| <div class="paragraph"> |
| <p>So in the end we need 3 parts:</p> |
| </div> |
| <div class="olist arabic"> |
| <ol class="arabic"> |
| <li> |
| <p>Protocol definition</p> |
| </li> |
| <li> |
| <p>Language template</p> |
| </li> |
| <li> |
| <p>A maven plugin which generates the code</p> |
| </li> |
| </ol> |
| </div> |
| <div class="paragraph"> |
| <p>This maven plugin uses a given protocol definition as well as a language template and generates code for reading/writing data in that protocol with the given language.</p> |
| </div> |
| <div class="imageblock kroki"> |
| <div class="content"> |
| <img src="https://kroki.io/ditaa/svg/eNpTUEAH2rpIQJsLQ16hJtnA1BHOwaZAQcEnMS-9NDE9FUkBwly7GhDfKbE4Fawaq301KMbh4mBRjep8ZNVlXLjlFPAbgBYmqCGAwxxsitBcD-KGVBakFuM1B4gDfJxNIvCbgwhPPOb4Jpal5iECHRIRzvkpqUjmEPQXyD05pemZeTjdQ61wJiV247ClHJzxVIM9nQUU5ZfkJ-fn4FJNWhommGxxhgYAqeGcyA==" alt="code-generation-intro"> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>The <code>Types Base</code> module provides all the structures the <code>Protocol</code> modules output which are then used in the <code>Language</code> templates to generate code.</p> |
| </div> |
| <div class="paragraph"> |
| <p><code>Protocol Base</code> and <code>Language Base</code> hereby just provide the interfaces that reference these types and provide the API for the <code>plc4x-maven-plugin</code> to use.</p> |
| </div> |
| <div class="paragraph"> |
| <p>These modules are also maintained in a <a href="https://github.com/apache/plc4x-build-tools/tree/develop/code-generation">repository</a> which is separate from the rest of the PLC4X code.</p> |
| </div> |
| <div class="paragraph"> |
| <p>This is generally only due to some restrictions in the Maven build system. If you are interested in understanding the reasons - please read the chapter on <code>Problems with Maven</code> near the end of this page.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Concrete <a href="https://github.com/apache/plc4x/tree/develop/code-generation/protocol-base-mspec">protocol spec parsers</a>, <a href="https://github.com/apache/plc4x/tree/develop/code-generation/language-base-freemarker">code generators</a> as well as <a href="https://github.com/apache/plc4x/tree/develop/code-generation/language-java">templates</a> that actually generate code are implemented in derived modules all located under the <a href="https://github.com/apache/plc4x/tree/develop/code-generation">code-generation</a> part of the main project repository.</p> |
| </div> |
| <div class="paragraph"> |
| <p>We didn’t want to tie ourselves to only one way to specify protocols and to generate code. Generally multiple types of formats for specifying drivers are thinkable and the same way, multiple ways of generating code are possible. Currently, however we only have one parser: <code>MSpec</code> and one generator: <code>Freemarker</code>.</p> |
| </div> |
| <div class="paragraph"> |
| <p>These add more layers to the hierarchy.</p> |
| </div> |
| <div class="paragraph"> |
| <p>So for example in case of generating a <code>Siemens S7</code> Driver for <code>Java</code> this would look like this:</p> |
| </div> |
| <div class="imageblock kroki"> |
| <div class="content"> |
| <img src="https://kroki.io/ditaa/svg/eNpTUEAB2rpIQJsLVVKhJtnA1BHOwZAF4pDKgtRiFFmYiSBZBafE4lSwLIYVNWg0KqcGXRmqOzGUlSngA2Vc2LXjCARUXyvgDxOgfEBRfkl-cn4ONsUKCj6JeemliempUMVIYYJFMZIsF_aQwSpQQ5oHcZmJagGJyqgdBU54o8CJblHgG1yQmoxDsVtRampuYlF2atFoFABBsDmetOqVWJZIbnwNnVxAZHlVg7Uwwa0MiAN8nE0isCuDWmYHTq6JZal5YFkbnKU6yLSc0vTMPGylOv4aAVddQEC8jDRb0FIX1kiHJTYu_IkNm6xzfkqqAmG_AwAU9DjG" alt="code-generation-intro-s7-java"> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>The dark blue parts are the ones released externally, the turquoise ones are part of the main PLC4X repo.</p> |
| </div> |
| </div> |
| </div> |
| <div class="sect1"> |
| <h2 id="_introduction"><a class="anchor" href="#_introduction"></a>Introduction</h2> |
| <div class="sectionbody"> |
| <div class="paragraph"> |
| <p>The maven plugin is built up very modular.</p> |
| </div> |
| <div class="paragraph"> |
| <p>So in general it is possible to add new forms of providing protocol definitions as well as language templates.</p> |
| </div> |
| <div class="paragraph"> |
| <p>For the formats of specifying a protocol we have tried out numerous tools and frameworks, however the results were never quite satisfying.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Usually using them required a large amount of workarounds, which made the solution quite complicated. |
| This is mainly the result, that tools like Thrift, Avro, GRPc, …​ all are made for transferring an object structure from A to B. They lay focus on keeping the structure of the object in takt and not offer ways to control the format for transferring them.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Existing industry standards, such as <code>ASN.1</code> unfortunately mostly relied on large portions of text to describe part of the parsing or serializing logic, which made it pretty much useless for a fully automated code genration.</p> |
| </div> |
| <div class="paragraph"> |
| <p>In the end only <code>DFDL</code> and the corresponding Apache project <a href="https://daffodil.apache.org">Apache Daffodil</a> seemed to provide what we were looking for.</p> |
| </div> |
| <div class="paragraph"> |
| <p>With this we were able to provide first driver versions fully specified in XML.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The downside was, that the PLC4X community regarded this XML format as pretty complicated and when implementing an experimental code generator we quickly noticed that generating a nice object model would not be possible, due to the lack of an ability to model inheritance of types into a DFDL schema.</p> |
| </div> |
| <div class="paragraph"> |
| <p>In the end we came up with our own format which we called <code>MSpec</code> and is described in the <a href="protocol/mspec.html">MSpec Format description</a>.</p> |
| </div> |
| </div> |
| </div> |
| <div class="sect1"> |
| <h2 id="_configuration"><a class="anchor" href="#_configuration"></a>Configuration</h2> |
| <div class="sectionbody"> |
| <div class="paragraph"> |
| <p>The <code>plc4x-maven-plugin</code> has a very limited set of configuration options.</p> |
| </div> |
| <div class="paragraph"> |
| <p>In general all you need to specify, is the <code>protocolName</code> and the <code>languageName</code>.</p> |
| </div> |
| <div class="paragraph"> |
| <p>An additional option <code>outputFlavor</code> allows generating multiple versions of a driver for a given language. |
| This can come in handy if we want to be able to generate <code>read-only</code> or <code>passive mode</code> driver variants.</p> |
| </div> |
| <div class="paragraph"> |
| <p>In order to be able to refactor and improve protocol specifications without having to update all drivers for a given protocol, we recently added a <code>protocolVersion</code> attribute, that allows us to provide and use multiple versions of one protocol. |
| So in case of us updating the fictional <code>wombat-protocol</code>, we could add a <code>version 2</code> <code>mspec</code> for that, then use the version 2 in the java-driver and continue to use version 1 in all other languages. |
| Once all drivers are updated we could eliminate the version again.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Last, not least, we have a pretty generic <code>options</code> config option, which is a Map type.</p> |
| </div> |
| <div class="paragraph"> |
| <p>With options is it possible to pass generic options to the code-generation. |
| So if a driver or language requires further customization, these options can be used. |
| For a list of all supported options for a given language template, please refer to the corresponding language page.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Currently, the <code>Java</code> module makes use of such an option for specifying the Java <code>package</code> the generated code uses. |
| If no <code>package</code> option is provided, the default package <code>org.apache.plc4x.{language-name}.{protocol-name}.{output-flavor}</code> is used, but especially when generating custom drivers, which are not part of the Apache PLC4X project, different package names are better suited. |
| So in these cases, the user can simply override the default package name.</p> |
| </div> |
| <div class="paragraph"> |
| <p>There is also an additional parameter: <code>outputDir</code>, which defaults to <code>${project.build.directory}/generated-sources/plc4x/</code> and usually shouldn’t require being changed in case of a <code>Java</code> project, but usually requires tweaking when generating code for other languages.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Here’s an example of a driver pom for building a <code>S7</code> driver for <code>java</code>:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre><?xml version="1.0" encoding="UTF-8"?> |
| <!-- |
| Licensed to the Apache Software Foundation (ASF) under one |
| or more contributor license agreements. See the NOTICE file |
| distributed with this work for additional information |
| regarding copyright ownership. The ASF licenses this file |
| to you under the Apache License, Version 2.0 (the |
| "License"); you may not use this file except in compliance |
| with the License. You may obtain a copy of the License at |
| |
| https://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, |
| software distributed under the License is distributed on an |
| "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| KIND, either express or implied. See the License for the |
| specific language governing permissions and limitations |
| under the License. |
| --> |
| <project xmlns="http://maven.apache.org/POM/4.0.0" |
| xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
| xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> |
| <modelVersion>4.0.0</modelVersion> |
| |
| <parent> |
| <groupId>org.apache.plc4x.plugins</groupId> |
| <artifactId>plc4x-code-generation</artifactId> |
| <version>0.14.0-SNAPSHOT</version> |
| </parent> |
| |
| <artifactId>test-java-s7-driver</artifactId> |
| |
| <build> |
| <plugins> |
| <plugin> |
| <groupId>org.apache.plc4x.plugins</groupId> |
| <artifactId>plc4x-maven-plugin</artifactId> |
| <executions> |
| <execution> |
| <id>test</id> |
| <phase>generate-sources</phase> |
| <goals> |
| <goal>generate-driver</goal> |
| </goals> |
| <configuration> |
| <protocolName>s7</protocolName> |
| <languageName>java</languageName> |
| <outputFlavor>read-write</outputFlavor> |
| </configuration> |
| </execution> |
| </executions> |
| </plugin> |
| </plugins> |
| </build> |
| |
| <dependencies> |
| <dependency> |
| <groupId>org.apache.plc4x.plugins</groupId> |
| <artifactId>plc4x-code-generation-driver-base-java</artifactId> |
| <version>0.14.0-SNAPSHOT</version> |
| </dependency> |
| |
| <dependency> |
| <groupId>org.apache.plc4x.plugins</groupId> |
| <artifactId>plc4x-code-generation-language-java</artifactId> |
| <version>0.14.0-SNAPSHOT</version> |
| <!-- Scope is 'provided' as this way it's not shipped with the driver --> |
| <scope>provided</scope> |
| </dependency> |
| |
| <dependency> |
| <groupId>org.apache.plc4x.plugins</groupId> |
| <artifactId>plc4x-code-generation-protocol-s7</artifactId> |
| <version>0.14.0-SNAPSHOT</version> |
| <!-- Scope is 'provided' as this way it's not shipped with the driver --> |
| <scope>provided</scope> |
| </dependency> |
| </dependencies> |
| |
| </project></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>So the plugin configuration is pretty straight forward, all that is specified, is the <code>protocolName</code>, <code>languageName</code> and the <code>output-flavor</code>.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The dependency:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre> <dependency> |
| <groupId>org.apache.plc4x.plugins</groupId> |
| <artifactId>plc4x-code-generation-driver-base-java</artifactId> |
| <version>0.14.0-SNAPSHOT</version> |
| </dependency></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>For example contains all classes the generated code relies on.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The definitions of both the <code>s7</code> protocol and <code>java</code> language are provided by the two dependencies:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre> <dependency> |
| <groupId>org.apache.plc4x.plugins</groupId> |
| <artifactId>plc4x-code-generation-language-java</artifactId> |
| <version>0.14.0-SNAPSHOT</version> |
| <!-- Scope is 'provided' as this way it's not shipped with the driver --> |
| <scope>provided</scope> |
| </dependency></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>and:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre> <dependency> |
| <groupId>org.apache.plc4x.plugins</groupId> |
| <artifactId>plc4x-code-generation-protocol-s7</artifactId> |
| <version>0.14.0-SNAPSHOT</version> |
| <!-- Scope is 'provided' as this way it's not shipped with the driver --> |
| <scope>provided</scope> |
| </dependency></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>The reason for why the dependencies are added as code-dependencies and why the scope is set the way it is, is described in the <a href="#_why_are_the_protocol_and_language_dependencies_done_so_strangely">Why are the protocol and language dependencies done so strangely?</a> section.</p> |
| </div> |
| </div> |
| </div> |
| <div class="sect1"> |
| <h2 id="_custom_modules"><a class="anchor" href="#_custom_modules"></a>Custom Modules</h2> |
| <div class="sectionbody"> |
| <div class="paragraph"> |
| <p>The plugin uses the <a href="https://docs.oracle.com/javase/7/docs/api/java/util/ServiceLoader.html">Java Serviceloader</a> mechanism to find modules.</p> |
| </div> |
| <div class="sect2"> |
| <h3 id="_protocol_modules"><a class="anchor" href="#_protocol_modules"></a>Protocol Modules</h3> |
| <div class="paragraph"> |
| <p>In order to provide a new protocol module, all that is required, it so create a module containing a <code>META-INF/services/org.apache.plc4x.plugins.codegenerator.protocol.Protocol</code> file referencing an implementation of the <code>org.apache.plc4x.plugins.codegenerator.protocol.Protocol</code> interface.</p> |
| </div> |
| <div class="paragraph"> |
| <p>This interface is located in the <code>org.apache.plc4x.plugins:plc4x-code-generation-protocol-base</code> module and generally only defines three methods:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>package org.apache.plc4x.plugins.codegenerator.protocol; |
| |
| import org.apache.plc4x.plugins.codegenerator.types.exceptions.GenerationException; |
| |
| import java.util.Optional; |
| |
| public interface Protocol { |
| |
| /** |
| * The name of the protocol what the plugin will use to select the correct protocol module. |
| * |
| * @return the name of the protocol. |
| */ |
| String getName(); |
| |
| /** |
| * Returns a map of type definitions for which code has to be generated. |
| * |
| * @return the Map of types that need to be generated. |
| * @throws GenerationException if anything goes wrong parsing. |
| */ |
| TypeContext getTypeContext() throws GenerationException; |
| |
| |
| /** |
| * @return the protocolVersion is applicable |
| */ |
| default Optional<String> getVersion() { |
| return Optional.empty(); |
| } |
| |
| }</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>The <code>name</code> is being used for the module to find the right language module, so the result of <code>getName()</code> needs to match the value provided in the maven config-option <code>protocolName</code>.</p> |
| </div> |
| <div class="paragraph"> |
| <p>As mentioned before, we support multiple versions of a protocol, so if <code>getVersions()</code> returns a non-empty version, this is used to select the version.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The most important method for the actual code-generation however is the <code>getTypeContext()</code> method, which returns a <code>TypeContext</code> type which generally contains a list of all parsed types for this given protocol.</p> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="_language_modules"><a class="anchor" href="#_language_modules"></a>Language Modules</h3> |
| <div class="paragraph"> |
| <p>Analog to the <a href="#_protocol_modules">Protocol Modules</a> the Language modules are constructed very similar.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The <code>LanguageOutput</code> interface is very simplistic too and is located in the <code>org.apache.plc4x.plugins:plc4x-code-generation-language-base</code> module and generally only defines four methods:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>package org.apache.plc4x.plugins.codegenerator.language; |
| |
| import org.apache.plc4x.plugins.codegenerator.types.definitions.ComplexTypeDefinition; |
| import org.apache.plc4x.plugins.codegenerator.types.exceptions.GenerationException; |
| |
| import java.io.File; |
| import java.util.Map; |
| |
| public interface LanguageOutput { |
| |
| /** |
| * The name of the template is what the plugin will use to select the correct language module. |
| * |
| * @return the name of the template. |
| */ |
| String getName(); |
| |
| List<String> supportedOutputFlavors(); |
| |
| /** |
| * An additional method which allows generator to have a hint which options are supported by it. |
| * This method might be used to improve user experience and warn, if set options are ones generator does not support. |
| * |
| * @return Set containing names of options this language output can accept. |
| */ |
| Set<String> supportedOptions(); |
| |
| void generate(File outputDir, String version, String languageName, String protocolName, String outputFlavor, |
| Map<String, TypeDefinition> types, Map<String, String> options) throws GenerationException; |
| |
| }</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>The file for registering Language modules is located at: <code>META-INF/services/org.apache.plc4x.plugins.codegenerator.language.LanguageOutput</code></p> |
| </div> |
| <div class="paragraph"> |
| <p>The <code>name</code> being used by the plugin to find the language output module defined by the maven config option <code>languageName</code>.</p> |
| </div> |
| <div class="paragraph"> |
| <p><code>supportedOutputFlavors</code> provides a possible list of flavors, that can be referred to by the maven config option <code>outputFlavor</code>.</p> |
| </div> |
| <div class="paragraph"> |
| <p><code>supportedOptions</code> provides a list of <code>options</code> that the current language module is able to use and which can be passed in to the maven configuration using the <code>options</code> settings.</p> |
| </div> |
| </div> |
| </div> |
| </div> |
| <div class="sect1"> |
| <h2 id="_problems_with_maven"><a class="anchor" href="#_problems_with_maven"></a>Problems with Maven</h2> |
| <div class="sectionbody"> |
| <div class="sect2"> |
| <h3 id="_why_are_the_4_modules_released_separately"><a class="anchor" href="#_why_are_the_4_modules_released_separately"></a>Why are the 4 modules released separately?</h3> |
| <div class="paragraph"> |
| <p>We mentioned in the introduction, that the first 4 modules are maintained and released from outside the main PLC4X repository.</p> |
| </div> |
| <div class="paragraph"> |
| <p>This is due to some restrictions in Maven, which result from the way Maven generally works.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The main problem is that when starting a build, in the <code>validate</code>-phase, Maven goes through the configuration, downloads the plugins and configures these. |
| This means that Maven also tries to download the dependencies of the plugins too.</p> |
| </div> |
| <div class="paragraph"> |
| <p>In case of using a Maven plugin in a project which also builds the maven plugin itself, this is guaranteed to fail - Especially during releases. |
| While during normal development, Maven will probably just download the latest <code>SNAPSHOT</code> from our Maven repository and will be happy with this and not complain even if this version will be overwritten later on in the build. |
| It will just use the new version as soon as it has to.</p> |
| </div> |
| <div class="paragraph"> |
| <p>During releases however the release plugin changes the version to a release version and then spawns a build. |
| In this case the build will fail because there is no Plugin with that version to download from anywhere. |
| In this case the only option would be to manually build and deploy the plugin in the release version and to re-start the release (Which is not a nice thing for the release manager).</p> |
| </div> |
| <div class="paragraph"> |
| <p>For this reason we have stripped down the plugin and its dependencies to an absolute minimum and have released that separately from the rest, hoping due to the minimality of the dependencies that we will not have to do it very often.</p> |
| </div> |
| <div class="paragraph"> |
| <p>As soon as the tooling is released, the version is updated in the PLC4X build and the release version is used without any complications.</p> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="_why_are_the_protocol_and_language_dependencies_done_so_strangely"><a class="anchor" href="#_why_are_the_protocol_and_language_dependencies_done_so_strangely"></a>Why are the protocol and language dependencies done so strangely?</h3> |
| <div class="paragraph"> |
| <p>It would certainly be a lot cleaner, if we provided the dependencies to protocol and language modules as plugin dependencies.</p> |
| </div> |
| <div class="paragraph"> |
| <p>However, as we mentioned in the previous subchapter, Maven tries to download and configure the plugins prior to running the build. |
| So during a release the new versions of the modules wouldn’t exist, this would cause the build to fail.</p> |
| </div> |
| <div class="paragraph"> |
| <p>We could release the protocol- and the language modules separately too, but we want the language and protocol modules to be part of the project, to not over-complicate things - especially during a release.</p> |
| </div> |
| <div class="paragraph"> |
| <p>In order to keep the build and the release as simple as possible, we built the Maven plugin in a way, that it uses the modules dependencies and creates its own Classloader to contain all of these modules at runtime.</p> |
| </div> |
| <div class="paragraph"> |
| <p>This brings the benefit of being able to utilize Maven’s capability of determining the build order and dynamically creating the modules build classpath.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Adding a normal dependency however would make Maven deploy the artifacts with the rest of the modules.</p> |
| </div> |
| <div class="paragraph"> |
| <p>We don’t want that as both the protocol as well as the language-modules are useless as soon as they have been used to generate the code.</p> |
| </div> |
| <div class="paragraph"> |
| <p>So we use a trick that is usually used in Web applications, for example: |
| Here the vendor of a Servlet engine is expected to provide an implementation of the <code>Servlet API</code>. |
| It is forbidden for an application to bring this along, but it is required to build the application.</p> |
| </div> |
| <div class="paragraph"> |
| <p>For this the Maven scope <code>provided</code>, which tells Maven to provide it during the build, but to exclude it from any applications it builds, because it will be provided by the system running the application.</p> |
| </div> |
| <div class="paragraph"> |
| <p>This is not quite true, but it does the trick.</p> |
| </div> |
| </div> |
| </div> |
| </div> |
| </article> |
| </div> |
| </main> |
| </div> |
| <!-- |
| Licensed to the Apache Software Foundation (ASF) under one |
| or more contributor license agreements. See the NOTICE file |
| distributed with this work for additional information |
| regarding copyright ownership. The ASF licenses this file |
| to you under the Apache License, Version 2.0 (the |
| "License"); you may not use this file except in compliance |
| with the License. You may obtain a copy of the License at |
| |
| https://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, |
| software distributed under the License is distributed on an |
| "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| KIND, either express or implied. See the License for the |
| specific language governing permissions and limitations |
| under the License. |
| --> |
| <footer class="container-flex footer col-6" style="text-align:center;"> |
| <div class="col"></div> |
| <div class="col-6"> |
| Copyright © 2017-2026 <a href="https://www.apache.org/">The Apache Software Foundation.</a> All rights reserved.<br/> |
| Apache PLC4X, PLC4X, Apache, the Apache feather logo, and the Apache PLC4X project logo are either registered |
| trademarks or trademarks of The Apache Software Foundation in the United States and other countries. All other marks |
| mentioned may be trademarks or registered trademarks of their respective owners. |
| <br/> |
| </div> |
| <div>Home screen image taken from <a |
| href="https://flic.kr/p/chEftd">Flickr</a>, "Tesla Robot Dance" by Steve Jurvetson, licensed |
| under <a href="https://creativecommons.org/licenses/by/2.0/">CC BY 2.0 Generic</a>, image cropped |
| and blur effect added. |
| </div> |
| <div class="col"></div> |
| </footer> |
| <script id="site-script" src="../../../../_/js/site.js" data-ui-root-path="../../../../_"></script> |
| <script async src="../../../../_/js/vendor/highlight.js"></script> |
| <script src="../../../../_/js/vendor/lunr.js"></script> |
| <script src="../../../../_/js/search-ui.js" id="search-ui-script" data-site-root-path="../../../.." data-snippet-length="100" data-stylesheet="../../../../_/css/search.css"></script> |
| <script async src="../../../../search-index.js"></script> |
| </body> |
| </html> |