| |
| <!DOCTYPE html> |
| <html lang="en"> |
| <head> |
| <meta charset="utf-8"> |
| <meta name="viewport" content="width=device-width, initial-scale=1"> |
| <meta name="description" content=""> |
| <meta name="author" content=""> |
| |
| <title>Apache Celix Coding Conventions / Apache Celix</title> |
| |
| |
| <link rel="icon" href="/assets/img/favicon.ico"> |
| |
| |
| <link href="/assets/css/bootstrap.min.css" rel="stylesheet"> |
| |
| |
| <link href="/assets/css/style.css" rel="stylesheet"> |
| |
| <style> |
| |
| |
| .card-body img { |
| max-width: 100%; |
| width: 100%; |
| height: auto; |
| } |
| |
| |
| .card-body img + em { |
| text-decoration: underline; |
| } |
| </style> |
| |
| |
| <script> |
| var _paq = window._paq = window._paq || []; |
| |
| _paq.push(['disableCookies']); |
| |
| _paq.push(['trackPageView']); |
| _paq.push(['enableLinkTracking']); |
| (function() { |
| var u="https://analytics.apache.org/"; |
| _paq.push(['setTrackerUrl', u+'matomo.php']); |
| _paq.push(['setSiteId', '9']); |
| var d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0]; |
| g.async=true; g.src=u+'matomo.js'; s.parentNode.insertBefore(g,s); |
| })(); |
| </script> |
| |
| |
| </head> |
| <body class="light-grey"> |
| |
| <a href="https://github.com/apache/celix" class="github-ribbon"> |
| <img src="/assets/img/forkme_right_red_aa0000.png" alt="Fork me on GitHub"> |
| </a> |
| |
| |
| <nav class="navbar navbar-expand-lg navbar-dark bg-primary fixed-top"> |
| <div class="container"> |
| <a class="navbar-brand" href="/"> |
| <img src="/assets/img/celix-white.svg" height="40" class="d-inline-block align-top" alt="Celix Logo"> |
| </a> |
| <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarResponsive" aria-controls="navbarResponsive" aria-expanded="false" aria-label="Toggle navigation"> |
| <span class="navbar-toggler-icon"></span> |
| </button> |
| <div class="collapse navbar-collapse" id="navbarResponsive"> |
| <ul class="navbar-nav ml-auto"> |
| <li class="nav-item"> |
| <a class="nav-link" href="/">Home</a> |
| </li> |
| <li class="nav-item"> |
| <a class="nav-link" href="/download.cgi">Download</a> |
| </li> |
| <li class="nav-item dropdown active"> |
| <a class="nav-link dropdown-toggle" href="#" id="ddDocs" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> |
| Docs |
| </a> |
| <div class="dropdown-menu" aria-labelledby="ddDocs"> |
| <a class="dropdown-item" href="/docs/2.4.0/docs.html">2.4.0 (latest)</a> |
| <a class="dropdown-item" href="/docs/2.3.0/docs.html">2.3.0</a> |
| <a class="dropdown-item" href="/docs/2.2.1/docs.html">2.2.1</a> |
| <a class="dropdown-item" href="/docs/2.1.0/docs.html">2.1.0</a> |
| </div> |
| </li> |
| <li class="nav-item dropdown"> |
| <a class="nav-link dropdown-toggle" href="#" id="ddContributing" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> |
| Contributing |
| </a> |
| <div class="dropdown-menu" aria-labelledby="ddContributing"> |
| <a class="dropdown-item" href="/contributing/youatcelix.html">You at Celix</a> |
| <a class="dropdown-item" href="/contributing/submitting-patches.html">Submitting patches</a> |
| <a class="dropdown-item" href="/contributing/source-and-builds.html">Source code and builds</a> |
| <hr> |
| <a class="dropdown-item" href="/contributing/releasing.html">Releasing</a> |
| <a class="dropdown-item" href="/contributing/volunteers.html">Volunteers</a> |
| <a class="dropdown-item" href="https://whimsy.apache.org/board/minutes/Celix.html">Board Reports</a> |
| </div> |
| </li> |
| <li class="nav-item dropdown"> |
| <a class="nav-link dropdown-toggle" href="#" id="ddSupport" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> |
| Support |
| </a> |
| <div class="dropdown-menu" aria-labelledby="ddSupport"> |
| <a class="dropdown-item" href="/support/mailing-list.html">Mailing Lists</a> |
| <a class="dropdown-item" href="/support/issue-tracking.html">Issue Tracking</a> |
| </div> |
| </li> |
| <li class="nav-item dropdown"> |
| <a class="nav-link dropdown-toggle" href="#" id="ddFoundation" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> |
| ASF |
| </a> |
| <div class="dropdown-menu" aria-labelledby="ddFoundation"> |
| <a class="dropdown-item" href="https://www.apache.org/">ASF Home</a> |
| <a class="dropdown-item" href="https://www.apache.org/foundation/how-it-works.html">How it works</a> |
| <a class="dropdown-item" href="https://www.apache.org/licenses/">License</a> |
| <a class="dropdown-item" href="https://www.apache.org/foundation/sponsorship.html">Sponsorship</a> |
| <a class="dropdown-item" href="https://www.apache.org/foundation/thanks.html">Thanks</a> |
| <a class="dropdown-item" href="https://www.apache.org/security/">Security</a> |
| <a class="dropdown-item" href="https://www.apache.org/foundation/policies/conduct">Code of Conduct</a> |
| </div> |
| </li> |
| </ul> |
| </div> |
| </div> |
| </nav> |
| |
| |
| <div class="section"> |
| <div class="container"> |
| <div class="row py-4"> |
| <div class="col-sm-12 card"> |
| <div class="card-body pt-5"> |
| |
| |
| |
| |
| <a class="edit-on-gh" href="https://github.com/apache/celix/edit/master/documents/development/README.md" title="Edit this page on GitHub">Edit on GitHub</a> |
| |
| |
| |
| |
| |
| <a href="/docs/2.4.0/docs.html" title="back to documentation"><< back to documentation</a> |
| |
| |
| |
| <!-- |
| 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 |
| |
| http://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. |
| --> |
| <h1 id="apache-celix-coding-conventions">Apache Celix Coding Conventions</h1> |
| <p>Adhering to consistent and meaningful coding conventions is crucial for maintaining readable and maintainable code. |
| This document outlines the recommended coding conventions for Apache Celix development, including naming conventions, |
| formatting, comments, control structures, functions and error handling.</p> |
| <p>Note that not all existing code adheres to these conventions. |
| New code should adhere to these conventions and when possible, existing code should be updated to adhere to these |
| conventions.</p> |
| <h2 id="naming-conventions">Naming Conventions</h2> |
| <h3 id="cc-variables">C/C++ Variables</h3> |
| <ul> |
| <li>Use <code>camelCase</code> for variable names.</li> |
| <li>Use descriptive names for variables.</li> |
| <li>Use <code>celix_</code> prefix or <code>celix::</code> (sub)namespace for global variables.</li> |
| <li>Asterisks <code>*</code> and ampersands <code>&</code> should be placed on the variable type name.</li> |
| </ul> |
| <h3 id="c-structures">C Structures</h3> |
| <ul> |
| <li>Use <code>snake_case</code> for structure names.</li> |
| <li>Add a typedef for the structure.</li> |
| <li>Use a <code>_t</code> postfix for structure typedef.</li> |
| <li>Use <code>celix_</code> prefix for structure names.</li> |
| <li>For C objects, use typedef of an opaque struct. E.g. <code>typedef struct celix_<obj> celix_<obj>_t;</code> |
| <ul> |
| <li>This way the implementation details can be hidden from the user.</li> |
| </ul> |
| </li> |
| </ul> |
| <h3 id="c-functions">C Functions</h3> |
| <ul> |
| <li>Use descriptive names for functions.</li> |
| <li>Use a <code>celix_</code> prefix.</li> |
| <li>Use a <code>_<obj>_</code> camelCase infix for the object/module name.</li> |
| <li>Use a postfix <code>camelCase</code> for the function name.</li> |
| <li>Asterisks <code>*</code> should be placed on the variable type name.</li> |
| <li>Use verb as function names when a function has a side effect.</li> |
| <li>Use nouns or getter/setter as function names when a function does not have a side effect.</li> |
| <li>Use getters/setters naming convention for functions which get/set a value: |
| <ul> |
| <li><code>celix_<obj>_is<Value></code> and <code>celix_<obj>_set<Value></code> for boolean values</li> |
| <li><code>celix_<obj>_get<Value></code> and <code>celix_<obj>_set<Value></code> for other values</li> |
| </ul> |
| </li> |
| <li>For C objects: |
| <ul> |
| <li>Use a (opaque) object pointer as the first argument of the function.</li> |
| <li>Ensure that object can be created using a <code>celix_<obj>_create</code> function and destroyed using |
| a <code>celix_<obj>_destroy</code> function.</li> |
| <li>The <code>celix_<obj>_create</code> function should return a pointer to the object.</li> |
| <li>The <code>celix_<obj>_destroy</code> function should return a <code>void</code> and should be able to handle a NULL pointer. |
| <ul> |
| <li>By being able to handle a NULL pointer, the <code>celix_<obj>_destroy</code> function can be more easily used in |
| error handling code.</li> |
| </ul> |
| </li> |
| </ul> |
| </li> |
| </ul> |
| <p>Examples:</p> |
| <ul> |
| <li><code>long celix_bundleContext_installBundle(celix_bundle_context_t* ctx, const char* bundleUrl, bool autoStart)</code></li> |
| <li><code>bool celix_utils_stringEquals(const char* a, const char* b)</code></li> |
| <li><code>celix_status_t celix_utils_createDirectory(const char* path, bool failIfPresent, const char** errorOut)</code></li> |
| </ul> |
| <h3 id="c-constants">C Constants</h3> |
| <ul> |
| <li>Use <code>SNAKE_CASE</code> for constant names.</li> |
| <li>Use a <code>CELIX_</code> prefix for constant names.</li> |
| <li>Use <code>#define</code> for constants.</li> |
| </ul> |
| <h3 id="c-enums">C Enums</h3> |
| <ul> |
| <li>Use <code>snake_case</code> for enum type names.</li> |
| <li>Use a <code>celix_</code> prefix for enum type names.</li> |
| <li>Use <code>SNAKE_CASE</code> for enum value names.</li> |
| <li>Use a <code>CELIX_</code> prefix for enum value names.</li> |
| <li>Add a typedef - with a <code>_e</code> postfix - for the enum</li> |
| </ul> |
| <p>Example:</p> |
| <div class="highlight"><pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-c" data-lang="c"><span style="display:flex;"><span><span style="color:#a2f;font-weight:bold">typedef</span> <span style="color:#a2f;font-weight:bold">enum</span> celix_hash_map_key_type { |
| </span></span><span style="display:flex;"><span> CELIX_HASH_MAP_STRING_KEY, |
| </span></span><span style="display:flex;"><span> CELIX_HASH_MAP_LONG_KEY |
| </span></span><span style="display:flex;"><span>} celix_hash_map_key_type_e; |
| </span></span></code></pre></div><h3 id="macros">Macros</h3> |
| <ul> |
| <li>Use all caps <code>SNAKE_CASE</code> for macro names.</li> |
| <li>Use a <code>CELIX_</code> prefix for macro names.</li> |
| </ul> |
| <h3 id="c-files-and-directories">C files and directories</h3> |
| <ul> |
| <li>Use <code>snake_case</code> for file names.</li> |
| <li>Name header files with a <code>.h</code> extension and source files with a <code>.c</code> extension.</li> |
| <li>Organize files in directories according to their purpose. |
| <ul> |
| <li>Public headers files in a <code>include</code>, <code>api</code> or <code>spi</code> directory.</li> |
| <li>Private header files in a <code>private</code> and <code>src</code> directory.</li> |
| <li>Source files in a <code>src</code> directory.</li> |
| </ul> |
| </li> |
| <li>Google test files should be placed in a <code>gtest</code> directory with its own <code>CMakeLists.txt</code> file and <code>src</code> directory.</li> |
| <li>Use <code>celix_</code> prefix for header file names.</li> |
| <li>Use a header guard.</li> |
| <li>Use a C++ “extern C” block in headers file to ensure C headers are usable in C++.</li> |
| </ul> |
| <h3 id="c-libraries">C Libraries</h3> |
| <ul> |
| <li>Target names should be <code>snake_case</code>.</li> |
| <li>There should be <code>celix::</code> prefixed aliases for the library.</li> |
| <li>C Shared libraries should configure an output name with a <code>celix_</code> prefix.</li> |
| </ul> |
| <h3 id="c-services">C Services</h3> |
| <ul> |
| <li>Service headers should be made available through a CMake INTERFACE header-only api/spi library (i.e. <code>celix::shell_api</code>)</li> |
| <li>C service should be C struct, where the first member is the service handle (<code>void* handle;</code>) and the rest of the members are |
| function pointers.</li> |
| <li>The first argument of the service functions should be the service handle.</li> |
| <li>If memory allocation is needed or another error can occur in a service function, ensure that the return value can |
| be used to check for errors. This can be done by: |
| <ul> |
| <li>Returning a <code>celix_status_t</code> and if needed using an out parameter.</li> |
| <li>Returning a NULL pointer if the function returns a pointer type.</li> |
| <li>Returning a boolean value, where <code>true</code> indicates success and <code>false</code> indicates failure.</li> |
| </ul> |
| </li> |
| <li>In the same header as the C service struct, there should be defines for the service name and version.</li> |
| <li>The service name macro should be all caps <code>SNAKE_CASE</code>, prefixed with <code>CELIX_</code> and postfixed with <code>_NAME</code>.</li> |
| <li>The service version macro should be all caps <code>SNAKE_CASE</code>, prefixed with <code>CELIX_</code> and postfixed with <code>_VERSION</code>.</li> |
| <li>The value of the service name macro should be the service struct (so without a <code>_t</code> postfix</li> |
| <li>The value of the service version macro should be the version of the service.</li> |
| </ul> |
| <p>Example:</p> |
| <div class="highlight"><pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-c" data-lang="c"><span style="display:flex;"><span><span style="color:#080;font-style:italic">//celix_foo.h |
| </span></span></span><span style="display:flex;"><span><span style="color:#080;font-style:italic"></span><span style="color:#080">#include</span> <span style="color:#080">"celix_errno.h"</span><span style="color:#080"> |
| </span></span></span><span style="display:flex;"><span><span style="color:#080"></span> |
| </span></span><span style="display:flex;"><span><span style="color:#080">#define CELIX_FOO_NAME "celix_foo" |
| </span></span></span><span style="display:flex;"><span><span style="color:#080">#define CELIX_FOO_VERSION 1.0.0 |
| </span></span></span><span style="display:flex;"><span><span style="color:#080"></span> |
| </span></span><span style="display:flex;"><span><span style="color:#a2f;font-weight:bold">typedef</span> <span style="color:#a2f;font-weight:bold">struct</span> celix_foo { |
| </span></span><span style="display:flex;"><span> <span style="color:#0b0;font-weight:bold">void</span><span style="color:#666">*</span> handle; |
| </span></span><span style="display:flex;"><span> <span style="color:#0b0;font-weight:bold">celix_status_t</span> (<span style="color:#666">*</span>doFoo)(<span style="color:#0b0;font-weight:bold">void</span><span style="color:#666">*</span> handle, <span style="color:#0b0;font-weight:bold">char</span><span style="color:#666">**</span> outMsg); |
| </span></span><span style="display:flex;"><span>} <span style="color:#0b0;font-weight:bold">celix_foo_t</span>; |
| </span></span></code></pre></div><h3 id="c-bundles">C Bundles</h3> |
| <ul> |
| <li>Use <code>snake_case</code> for C bundle target names.</li> |
| <li>Do <em>not</em> use a <code>celix_</code> prefix for C bundle target names.</li> |
| <li>Use <code>celix::</code> prefixed aliases for C bundle targets.</li> |
| <li>Use <code>snake_case</code> for C bundle symbolic names.</li> |
| <li>Configure at least SYMBOLIC_NAME, NAME, FILENAME, VERSION and GROUP for C bundle targets.</li> |
| <li>Use <code>apache_celix_</code> prefix for C bundle symbolic names.</li> |
| <li>Use <code>Apache Celix </code> prefix for C bundle names.</li> |
| <li>Use a <code>celix_</code> prefix for C bundle filenames.</li> |
| <li>Use a group name starting with <code>celix/</code> for C bundle groups.</li> |
| </ul> |
| <p>Examples:</p> |
| <div class="highlight"><pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-cmake" data-lang="cmake"><span style="display:flex;"><span><span style="color:#a2f">add_celix_bundle</span>(<span style="color:#b44">my_bundle</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#b44">SOURCES</span> <span style="color:#b44">src/my_bundle.c</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#b44">SYMBOLIC_NAME</span> <span style="color:#b44">"apache_celix_my_bundle"</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#b44">NAME</span> <span style="color:#b44">"Apache Celix My Bundle"</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#b44">FILENAME</span> <span style="color:#b44">"celix_my_bundle"</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#b44">VERSION</span> <span style="color:#b44">"1.0.0"</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#b44">GROUP</span> <span style="color:#b44">"celix/my_bundle_group"</span> |
| </span></span><span style="display:flex;"><span>)<span style=""> |
| </span></span></span><span style="display:flex;"><span><span style=""></span><span style="color:#a2f">add_library</span>(<span style="color:#b44">celix::my_bundle</span> <span style="color:#b44">ALIAS</span> <span style="color:#b44">my_bundle</span>)<span style=""> |
| </span></span></span></code></pre></div><h3 id="c-namespaces">C++ Namespaces</h3> |
| <ul> |
| <li>Use <code>snake_case</code> for namespace names.</li> |
| <li>All namespaces should be part of the <code>celix</code> namespace.</li> |
| <li>Aim for a max of 3 levels of namespaces.</li> |
| <li>Use a namespace ending with <code>detail</code> for implementation details.</li> |
| </ul> |
| <h3 id="c-classes">C++ Classes</h3> |
| <ul> |
| <li>Use <code>CamelCase</code> (starting with a capital) for class names.</li> |
| <li>Use descriptive names for classes.</li> |
| <li>Classes should be part of a <code>celix::</code> namespace or sub <code>celix::</code> namespace.</li> |
| </ul> |
| <h3 id="c-functions-1">C++ Functions</h3> |
| <ul> |
| <li>Use <code>camelCase</code> for function names.</li> |
| <li>If a function is not part of a class/struct, it should be part of a <code>celix::</code> namespace or sub <code>celix::</code> namespace.</li> |
| <li>Asterisks <code>*</code> and ampersands <code>&</code> should be placed on the variable type name.</li> |
| <li>Use verb as function names when a function has a side effect.</li> |
| <li>Use nouns or getter/setter as function names when a function does not have a side effect.</li> |
| <li>Use getters/setters naming convention for functions which get/set a value.</li> |
| </ul> |
| <h3 id="c-constants-1">C++ Constants</h3> |
| <ul> |
| <li>Use <code>SNAKE_CASE</code> for constants.</li> |
| <li>Use constexpr for constants.</li> |
| <li>Place constants in a <code>celix::</code> namespace or sub <code>celix::</code> namespace.</li> |
| </ul> |
| <p>example:</p> |
| <div class="highlight"><pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-c++" data-lang="c++"><span style="display:flex;"><span><span style="color:#a2f;font-weight:bold">namespace</span> celix { |
| </span></span><span style="display:flex;"><span> <span style="color:#a2f;font-weight:bold">constexpr</span> <span style="color:#0b0;font-weight:bold">long</span> FRAMEWORK_BUNDLE_ID <span style="color:#666">=</span> <span style="color:#666">0</span>; |
| </span></span><span style="display:flex;"><span> <span style="color:#a2f;font-weight:bold">constexpr</span> <span style="color:#a2f;font-weight:bold">const</span> <span style="color:#0b0;font-weight:bold">char</span><span style="color:#666">*</span> <span style="color:#a2f;font-weight:bold">const</span> SERVICE_ID <span style="color:#666">=</span> <span style="color:#b44">"service.id"</span>; |
| </span></span><span style="display:flex;"><span>} |
| </span></span></code></pre></div><h3 id="c-enums-1">C++ Enums</h3> |
| <ul> |
| <li>Use <code>CamelCase</code> (starting with a capital) for enum types names.</li> |
| <li>Use <code>enum class</code> instead of <code>enum</code> and if possible use <code>std::int8_t</code> as base type.</li> |
| <li>Use <code>SNAKE_CASE</code> for enum values without a celix/class prefix. Note that for enum values no prefix is required |
| because enum class values are scoped.</li> |
| </ul> |
| <p>Example:</p> |
| <div class="highlight"><pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-c++" data-lang="c++"><span style="display:flex;"><span><span style="color:#a2f;font-weight:bold">namespace</span> celix { |
| </span></span><span style="display:flex;"><span> <span style="color:#a2f;font-weight:bold">enum</span> <span style="color:#a2f;font-weight:bold">class</span> <span style="color:#00f">ServiceRegistrationState</span> { |
| </span></span><span style="display:flex;"><span> REGISTERING, |
| </span></span><span style="display:flex;"><span> REGISTERED, |
| </span></span><span style="display:flex;"><span> UNREGISTERING, |
| </span></span><span style="display:flex;"><span> UNREGISTERED |
| </span></span><span style="display:flex;"><span> }; |
| </span></span><span style="display:flex;"><span>} |
| </span></span></code></pre></div><h3 id="c-files-and-directories-1">C++ files and directories</h3> |
| <ul> |
| <li>Use <code>CamelCase</code> (starting with a capital) for file names.</li> |
| <li>Name header files with a <code>.h</code> extension and source files with a <code>.cc</code> extension.</li> |
| <li>Place header files in a directory based on the namespace (e.g. <code>celix/Bundle.h</code>, <code>celix/dm/Component.h</code>).</li> |
| <li>Organize files in directories according to their purpose. |
| <ul> |
| <li>Public headers files in a <code>include</code>, <code>api</code> or <code>spi</code> directory.</li> |
| <li>Private header files in a <code>private</code> and <code>src</code> directory.</li> |
| <li>Source files in a <code>src</code> directory.</li> |
| </ul> |
| </li> |
| <li>Use a <code>#pragma once</code> header guard.</li> |
| </ul> |
| <h3 id="c-libraries-1">C++ Libraries</h3> |
| <ul> |
| <li>Target name should be <code>CamelCase</code> (starting with a capital).</li> |
| <li>There should be <code>celix::</code> prefixed aliases for the library.</li> |
| <li>C++ Libraries should support C++14. |
| <ul> |
| <li>Exception are <code>celix::Promises</code> and <code>celix::PushStreams</code> which requires C++17.</li> |
| </ul> |
| </li> |
| <li>The Apache Celix framework library (<code>Celix::framework</code>) and the Apache Celix utils library (<code>Celix::utils</code>) can only |
| use header-only C++ files. This ensure that the framework and utils library can be used in C only projects and do |
| not introduce a C++ ABI.</li> |
| <li>For other libraries, header-only C++ libraries are preferred but not required.</li> |
| <li>Header-only C++ libraries do not need an export header and do not need to configure symbol visibility.</li> |
| <li>C++ shared libraries (lib with C++ sources), should configure an output name with a <code>celix_</code> prefix.</li> |
| <li>C++ shared libraries (lib with C++ sources), should use an export header and configure symbol visibility. |
| <ul> |
| <li>See the C Libraries section for more information.</li> |
| </ul> |
| </li> |
| </ul> |
| <h3 id="c-services-1">C++ Services</h3> |
| <ul> |
| <li>Use <code>CamelCase</code> (starting with a capital) for service names.</li> |
| <li>Add a ‘I’ prefix to the service interface name.</li> |
| <li>Place service classes in a <code>celix::</code> namespace or sub <code>celix::</code> namespace.</li> |
| <li>Add a <code>static constexpr const char* const NAME</code> to the service class, for the service name.</li> |
| <li>Add a <code>static constexpr const char* const VERSION</code> to the service class, for the service version.</li> |
| </ul> |
| <h3 id="c-bundles-1">C++ Bundles</h3> |
| <ul> |
| <li>Use <code>CamelCase</code> for C++ bundle target names.</li> |
| <li>Do <em>not</em> use a <code>Celix</code> prefix for C++ bundle target names.</li> |
| <li>Use <code>celix::</code> prefixed aliases for C++ bundle targets.</li> |
| <li>Use <code>CamelCase</code> for C++ bundle symbolic names.</li> |
| <li>Configure at least SYMBOLIC_NAME, NAME, FILENAME, VERSION and GROUP for C++ bundle targets.</li> |
| <li>Use <code>Apache_Celix_</code> prefix for C++ bundle symbolic names.</li> |
| <li>Use <code>Apache Celix </code> prefix for C++ bundle names.</li> |
| <li>Use a <code>celix_</code> prefix for C++ bundle filenames.</li> |
| <li>Use a group name starting with <code>celix/</code> for C++ bundle groups.</li> |
| </ul> |
| <p>Examples:</p> |
| <div class="highlight"><pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-cmake" data-lang="cmake"><span style="display:flex;"><span><span style="color:#a2f">add_celix_bundle</span>(<span style="color:#b44">MyBundle</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#b44">SOURCES</span> <span style="color:#b44">src/MyBundle.cc</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#b44">SYMBOLIC_NAME</span> <span style="color:#b44">"Apache_Celix_MyBundle"</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#b44">NAME</span> <span style="color:#b44">"Apache Celix My Bundle"</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#b44">FILENAME</span> <span style="color:#b44">"celix_MyBundle"</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#b44">VERSION</span> <span style="color:#b44">"1.0.0"</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#b44">GROUP</span> <span style="color:#b44">"celix/MyBundleGroup"</span> |
| </span></span><span style="display:flex;"><span>)<span style=""> |
| </span></span></span><span style="display:flex;"><span><span style=""></span><span style="color:#a2f">add_library</span>(<span style="color:#b44">celix::MyBundle</span> <span style="color:#b44">ALIAS</span> <span style="color:#b44">MyBundle</span>)<span style=""> |
| </span></span></span></code></pre></div><h3 id="unit-tests-naming">Unit Tests Naming</h3> |
| <ul> |
| <li>The test fixture should have a<code>TestSuite</code> postfix.</li> |
| <li>The source file should be named after the test fixture name and use a <code>.cc</code> extension.</li> |
| <li>Testcase names should use <code>CamelCase</code> (starting with a capital) and have a <code>Test</code> postfix.</li> |
| <li>When using error injection (one of the <code>error_injector</code> libraries) a separate test suite should be used. |
| <ul> |
| <li>A <code>ErrorInjectionTestSuite</code> postfix should be used for the test fixture.</li> |
| <li>The error injection setup should be reset on the <code>TearDown</code> function or destructor of the test fixture.</li> |
| </ul> |
| </li> |
| </ul> |
| <h2 id="comments-and-documentation">Comments and Documentation</h2> |
| <ul> |
| <li>Use Doxygen documentation, except for inline comments.</li> |
| <li>Write comments that explain the purpose of the code, focusing on the “why” rather than the “how”.</li> |
| <li>Apply doxygen documentation to all public API’s.</li> |
| <li>Use the javadoc style for doxygen documentation.</li> |
| <li>Use <code>@</code> instead of <code>\</code> for doxygen commands.</li> |
| <li>Start with a <code>@brief</code> command and a short description.</li> |
| <li>For <code>@param</code> commands also provide in, out, or in/out information.</li> |
| <li>For <code>@return</code> commands also provide a description of the return value.</li> |
| <li>If a function can return multiple error codes, use a errors section (<code>@section errors_section Errors</code>) to document the |
| possible errors. Use <code>man 2 write</code> as an example for a good errors section.</li> |
| </ul> |
| <h2 id="formatting-and-indentation">Formatting and Indentation</h2> |
| <ul> |
| <li>Use spaces for indentation and use 4 spaces per indentation level.</li> |
| <li>Keep line lengths under 120 characters, if possible, to enhance readability.</li> |
| <li>Place opening braces on the same line as the control statement or function definition,<br> |
| and closing braces on a new line aligned with the control statement or function definition.</li> |
| <li>Use a single space before and after operators and around assignment statements.</li> |
| <li>Add a space after control keywords (<code>if</code>, <code>for</code>, <code>while</code>, etc.) that are followed by a parenthesis.</li> |
| <li>Always use braces ({ }) for control structures, even for single-statement blocks, to prevent errors.</li> |
| <li>Add a space after control keywords (<code>else</code>, <code>do</code>, etc) that are followed by a brace.</li> |
| <li>Do not add a space after the function name and the opening parenthesis.</li> |
| <li>For new files apply clang-format using the project .clang-format file. |
| <ul> |
| <li>Note that this can be done using a plugin for your IDE or by running <code>clang-format -i <file></code>.</li> |
| </ul> |
| </li> |
| </ul> |
| <h2 id="control-structures">Control Structures</h2> |
| <ul> |
| <li>Use <code>if</code>, <code>else if</code>, and <code>else</code> statements to handle multiple conditions.</li> |
| <li>Use <code>switch</code> statements for multiple conditions with a default case.</li> |
| <li>Use <code>while</code> statements for loops that may not execute.</li> |
| <li>Use <code>do</code>/<code>while</code> statements for loops that must execute at least once.</li> |
| <li>Use <code>for</code> statements for loops with a known number of iterations.</li> |
| <li>The use of <code>goto</code> is not allowed, except for error handling in C (for C++ use RAII).</li> |
| <li>For C, try to prevent deeply nested control structures and prefer early returns or error handling <code>goto</code> statements. |
| <ul> |
| <li>To prevent deeply nested control structures, the <code>CELIX_DO_IF</code>, <code>CELIX_GOTO_IF_NULL</code> and <code>CELIX_GOTO_IF_ERR</code> |
| macros can also be used.</li> |
| </ul> |
| </li> |
| </ul> |
| <h2 id="functions-and-methods">Functions and Methods</h2> |
| <ul> |
| <li>Limit functions to a single responsibility or purpose, following the Single Responsibility Principle (SRP).</li> |
| <li>Keep functions short and focused, aiming for a length of fewer than 50 lines.</li> |
| <li>Ensure const correctness.</li> |
| <li>For C functions with a lot of different parameters, consider using an options struct. |
| <ul> |
| <li>An options struct combined with a EMPTY_OPTIONS macro can be used to provide default values and a such |
| options struct can be updated backwards compatible.</li> |
| <li>An options struct ensure that a lot of parameters can be configured, but also direct set on creation.</li> |
| </ul> |
| </li> |
| <li>For C++ functions with a lot of different parameters, consider using a builder pattern. |
| <ul> |
| <li>A builder pattern can be updated backwards compatible.</li> |
| <li>A builder pattern ensure that a lot of parameters can be configured, but also direct set on construction.</li> |
| </ul> |
| </li> |
| </ul> |
| <h2 id="error-handling-and-logging">Error Handling and Logging</h2> |
| <ul> |
| <li>For C++, throw an exception when an error occurs and use RAII to ensure that resources are freed.</li> |
| <li>For C, if memory allocation is needed or another error can occur, ensure that a function returns a value |
| than can be used to check for errors. This can be done by: |
| <ul> |
| <li>Returning a <code>celix_status_t</code> and if needed using an out parameter.</li> |
| <li>Returning a NULL pointer if the function returns a pointer.</li> |
| <li>Returning a boolean value, where <code>true</code> indicates success and <code>false</code> indicates failure.</li> |
| </ul> |
| </li> |
| <li>Use consistent error handling techniques, such as returning error codes or using designated error handling functions.</li> |
| <li>Log errors, warnings, and other important events using the Apache Celix log helper functions or - for libraries - |
| the <code>celix_err</code> functionality.</li> |
| <li>Always check for errors and log them.</li> |
| <li>Error handling should free resources in the reverse order of their allocation/creation.</li> |
| <li>Ensure error handling is correct, using test suite with error injection.</li> |
| </ul> |
| <p>For log levels use the following guidelines:</p> |
| <ul> |
| <li>trace: Use this level for very detailed that you would only want to have while diagnosing problems.</li> |
| <li>debug: This level should be used for information that might be helpful in diagnosing problems or understanding |
| what’s going on, but is too verbose to be enabled by default.</li> |
| <li>info: Use this level for general operational messages that aren’t tied to any specific problem or error condition. |
| They provide insight into the normal behavior of the system. Examples include startup/shutdown messages, |
| configuration assumptions, etc.</li> |
| <li>warning: Use this level to report an issue from which the system can recover, but which might indicate a potential |
| problem.</li> |
| <li>error: This level should be used to report issues that need immediate attention and might prevent the system from |
| functioning correctly. These are problems that are unexpected and affect functionality, but not so severe that the |
| process needs to stop. Examples include runtime errors, inability to connect to a service, etc.</li> |
| <li>fatal: Use this level to report severe errors that prevent the program from continuing to run. |
| After logging a fatal error, the program will typically terminate.</li> |
| </ul> |
| <p>Example of error handling and logging:</p> |
| <div class="highlight"><pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-c" data-lang="c"><span style="display:flex;"><span><span style="color:#0b0;font-weight:bold">celix_foo_t</span><span style="color:#666">*</span> <span style="color:#00a000">celix_foo_create</span>(<span style="color:#0b0;font-weight:bold">celix_log_helper_t</span><span style="color:#666">*</span> logHelper) { |
| </span></span><span style="display:flex;"><span> <span style="color:#0b0;font-weight:bold">celix_foo_t</span><span style="color:#666">*</span> foo <span style="color:#666">=</span> <span style="color:#00a000">calloc</span>(<span style="color:#666">1</span>, <span style="color:#a2f;font-weight:bold">sizeof</span>(<span style="color:#666">*</span>foo)); |
| </span></span><span style="display:flex;"><span> <span style="color:#a2f;font-weight:bold">if</span> (<span style="color:#666">!</span>foo) { |
| </span></span><span style="display:flex;"><span> <span style="color:#a2f;font-weight:bold">goto</span> create_enomem_err; |
| </span></span><span style="display:flex;"><span> } |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> <span style="color:#00a000">CELIX_GOTO_IF_ERR</span>(create_mutex_err, <span style="color:#00a000">celixThreadMutex_create</span>(<span style="color:#666">&</span>foo<span style="color:#666">-></span>mutex, <span style="color:#a2f">NULL</span>)); |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> foo<span style="color:#666">-></span>list <span style="color:#666">=</span> <span style="color:#00a000">celix_arrayList_create</span>(); |
| </span></span><span style="display:flex;"><span> foo<span style="color:#666">-></span>map <span style="color:#666">=</span> <span style="color:#00a000">celix_longHashMap_create</span>(); |
| </span></span><span style="display:flex;"><span> <span style="color:#a2f;font-weight:bold">if</span> (<span style="color:#666">!</span>foo<span style="color:#666">-></span>list <span style="color:#666">||</span> <span style="color:#666">!</span>foo<span style="color:#666">-></span>map) { |
| </span></span><span style="display:flex;"><span> <span style="color:#a2f;font-weight:bold">goto</span> create_enomem_err; |
| </span></span><span style="display:flex;"><span> } |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> <span style="color:#a2f;font-weight:bold">return</span> foo; |
| </span></span><span style="display:flex;"><span><span style="color:#a0a000">create_mutex_err</span>: |
| </span></span><span style="display:flex;"><span> <span style="color:#00a000">celix_logHelper_log</span>(logHelper, CELIX_LOG_LEVEL_ERROR, <span style="color:#b44">"Error creating mutex"</span>); |
| </span></span><span style="display:flex;"><span> <span style="color:#00a000">free</span>(foo); <span style="color:#080;font-style:italic">//mutex not created, do not use celix_foo_destroy to prevent mutex destroy |
| </span></span></span><span style="display:flex;"><span><span style="color:#080;font-style:italic"></span> <span style="color:#a2f;font-weight:bold">return</span> <span style="color:#a2f">NULL</span>; |
| </span></span><span style="display:flex;"><span><span style="color:#a0a000">create_enomem_err</span>: |
| </span></span><span style="display:flex;"><span> <span style="color:#00a000">celix_logHelper_log</span>(logHelper, CELIX_LOG_LEVEL_ERROR, <span style="color:#b44">"Error creating foo, out of memory"</span>); |
| </span></span><span style="display:flex;"><span> <span style="color:#00a000">celix_foo_destroy</span>(foo); <span style="color:#080;font-style:italic">//note celix_foo_destroy can handle NULL |
| </span></span></span><span style="display:flex;"><span><span style="color:#080;font-style:italic"></span> <span style="color:#a2f;font-weight:bold">return</span> <span style="color:#a2f">NULL</span>; |
| </span></span><span style="display:flex;"><span>} |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span><span style="color:#0b0;font-weight:bold">void</span> <span style="color:#00a000">celix_foo_destroy</span>(<span style="color:#0b0;font-weight:bold">celix_foo_t</span><span style="color:#666">*</span> foo) { |
| </span></span><span style="display:flex;"><span> <span style="color:#a2f;font-weight:bold">if</span> (foo <span style="color:#666">!=</span> <span style="color:#a2f">NULL</span>) { |
| </span></span><span style="display:flex;"><span> <span style="color:#080;font-style:italic">//note reverse order of creation |
| </span></span></span><span style="display:flex;"><span><span style="color:#080;font-style:italic"></span> <span style="color:#00a000">celixThreadMutex_destroy</span>(<span style="color:#666">&</span>foo<span style="color:#666">-></span>mutex); |
| </span></span><span style="display:flex;"><span> <span style="color:#00a000">celix_arrayList_destroy</span>(foo<span style="color:#666">-></span>list); |
| </span></span><span style="display:flex;"><span> <span style="color:#00a000">celix_longHashMap_destroy</span>(foo<span style="color:#666">-></span>map); |
| </span></span><span style="display:flex;"><span> <span style="color:#00a000">free</span>(foo); |
| </span></span><span style="display:flex;"><span> } |
| </span></span><span style="display:flex;"><span>} |
| </span></span></code></pre></div><h2 id="error-injection">Error Injection</h2> |
| <ul> |
| <li>Use the Apache Celix error_injector libraries to inject errors in unit tests in a controlled way.</li> |
| <li>Create a separate test suite for error injection tests and place them under a <code>EI_TESTS</code> cmake condition.</li> |
| <li>Reset error injection setup on the <code>TearDown</code> function or destructor of the test fixture.</li> |
| <li>If an - internal or external - function is missing error injection support, add it to the error_injector library. |
| <ul> |
| <li>Try to create small error injector libraries for specific functionality.</li> |
| </ul> |
| </li> |
| </ul> |
| <h2 id="unit-test-approach">Unit Test Approach</h2> |
| <ul> |
| <li>Use the Google Test framework for unit tests.</li> |
| <li>Use the Google Mock framework for mocking.</li> |
| <li>Use the Apache Celix error_injector libraries to inject errors in unit tests in a controlled way.</li> |
| <li>Test bundles by installing them in a programmatically created framework.</li> |
| <li>Test bundles by using their provided services and used services.</li> |
| <li>In most cases, libraries can be tested using a white box approach and bundles can be tested using a black box approach.</li> |
| <li>For libraries that are tested with the Apache Celix error_injector libraries or require access to private/hidden |
| functions (white-box testing), a separate “code under test” static library should be created. |
| This library should not hide its symbols and should have a <code>_cut</code> postfix.</li> |
| </ul> |
| <div class="highlight"><pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-cmake" data-lang="cmake"><span style="display:flex;"><span><span style="color:#a2f">set</span>(<span style="color:#b44">MY_LIB_SOURCES</span> <span style="color:#b44">...</span>)<span style=""> |
| </span></span></span><span style="display:flex;"><span><span style=""></span><span style="color:#a2f">set</span>(<span style="color:#b44">MY_LIB_PUBLIC_LIBS</span> <span style="color:#b44">...</span>)<span style=""> |
| </span></span></span><span style="display:flex;"><span><span style=""></span><span style="color:#a2f">set</span>(<span style="color:#b44">MY_LIB_PRIVATE_LIBS</span> <span style="color:#b44">...</span>)<span style=""> |
| </span></span></span><span style="display:flex;"><span><span style=""></span><span style="color:#a2f">add_library</span>(<span style="color:#b44">my_lib</span> <span style="color:#b44">SHARED</span> <span style="color:#666">${</span><span style="color:#b8860b">MY_LIB_SOURCES</span><span style="color:#666">}</span>)<span style=""> |
| </span></span></span><span style="display:flex;"><span><span style=""></span><span style="color:#a2f">target_link_libraries</span>(<span style="color:#b44">my_lib</span> <span style="color:#b44">PUBLIC</span> <span style="color:#666">${</span><span style="color:#b8860b">MY_LIB_PUBLIC_LIBS</span><span style="color:#666">}</span> <span style="color:#b44">PRIVATE</span> <span style="color:#666">${</span><span style="color:#b8860b">MY_LIB_PRIVATE_LIBS</span><span style="color:#666">}</span>)<span style=""> |
| </span></span></span><span style="display:flex;"><span><span style=""></span><span style="color:#a2f">celix_target_hide_symbols</span>(<span style="color:#b44">my_lib</span>)<span style=""> |
| </span></span></span><span style="display:flex;"><span><span style="">... |
| </span></span></span><span style="display:flex;"><span><span style=""> |
| </span></span></span><span style="display:flex;"><span><span style=""></span><span style="color:#a2f">if</span> (<span style="color:#b44">ENABLE_TESTING</span>)<span style=""> |
| </span></span></span><span style="display:flex;"><span><span style=""></span> <span style="color:#a2f">add_library</span>(<span style="color:#b44">my_lib_cut</span> <span style="color:#b44">STATIC</span> <span style="color:#666">${</span><span style="color:#b8860b">MY_LIB_SOURCES</span><span style="color:#666">}</span>)<span style=""> |
| </span></span></span><span style="display:flex;"><span><span style=""></span> <span style="color:#a2f">target_link_libraries</span>(<span style="color:#b44">my_lib_cut</span> <span style="color:#b44">PUBLIC</span> <span style="color:#666">${</span><span style="color:#b8860b">MY_LIB_PUBLIC_LIBS</span><span style="color:#666">}</span> <span style="color:#666">${</span><span style="color:#b8860b">MY_LIB_PRIVATE_LIBS</span><span style="color:#666">}</span>)<span style=""> |
| </span></span></span><span style="display:flex;"><span><span style=""></span> <span style="color:#a2f">target_include_directories</span>(<span style="color:#b44">my_lib_cut</span> <span style="color:#b44">PUBLIC</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#666">${</span><span style="color:#b8860b">CMAKE_CURRENT_LIST_DIR</span><span style="color:#666">}</span><span style="color:#b44">/src</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#666">${</span><span style="color:#b8860b">CMAKE_CURRENT_LIST_DIR</span><span style="color:#666">}</span><span style="color:#b44">/include</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#666">${</span><span style="color:#b8860b">CMAKE_BINARY_DIR</span><span style="color:#666">}</span><span style="color:#b44">/celix/gen/includes/my_lib</span> |
| </span></span><span style="display:flex;"><span> )<span style=""> |
| </span></span></span><span style="display:flex;"><span><span style=""></span><span style="color:#a2f">endif</span> ()<span style=""> |
| </span></span></span></code></pre></div><h2 id="supported-c-and-c-standards">Supported C and C++ Standards</h2> |
| <ul> |
| <li>C libraries should support C99.</li> |
| <li>C++ libraries should support C++14. |
| <ul> |
| <li>Exception are <code>celix::Promises</code> and <code>celix::PushStreams</code> which requires C++17.</li> |
| </ul> |
| </li> |
| <li>C++ support for <code>celix::framework</code> and <code>celix::utils</code> must be header-only.</li> |
| <li>Unit test code can be written in C++17.</li> |
| </ul> |
| <h2 id="library-target-properties">Library target properties</h2> |
| <p>For C and C++ shared libraries, the following target properties should be set:</p> |
| <ul> |
| <li><code>VERSION</code> should be set to the library version.</li> |
| <li><code>SOVERSION</code> should be set to the library major version.</li> |
| <li><code>OUTPUT_NAME</code> should be set to the library name and should contain a <code>celix_</code> prefix.</li> |
| </ul> |
| <div class="highlight"><pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-cmake" data-lang="cmake"><span style="display:flex;"><span><span style="color:#a2f">add_library</span>(<span style="color:#b44">my_lib</span> <span style="color:#b44">SHARED</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#b44">src/my_lib.c</span>)<span style=""> |
| </span></span></span><span style="display:flex;"><span><span style=""></span><span style="color:#a2f">set_target_properties</span>(<span style="color:#b44">my_lib</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#b44">PROPERTIES</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#b44">VERSION</span> <span style="color:#b44">1.0.0</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#b44">SOVERSION</span> <span style="color:#b44">1</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#b44">OUTPUT_NAME</span> <span style="color:#b44">celix_my_lib</span>)<span style=""> |
| </span></span></span></code></pre></div><p>For C and C++ static libraries, the following target properties should be set:</p> |
| <ul> |
| <li><code>POSITION_INDEPENDENT_CODE</code> should be set to <code>ON</code> for static libraries.</li> |
| <li><code>OUTPUT_NAME</code> should be set to the library name and should contain a <code>celix_</code> prefix.</li> |
| </ul> |
| <div class="highlight"><pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-cmake" data-lang="cmake"><span style="display:flex;"><span><span style="color:#a2f">add_library</span>(<span style="color:#b44">my_lib</span> <span style="color:#b44">STATIC</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#b44">src/my_lib.c</span>)<span style=""> |
| </span></span></span><span style="display:flex;"><span><span style=""></span><span style="color:#a2f">set_target_properties</span>(<span style="color:#b44">my_lib</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#b44">PROPERTIES</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#b44">POSITION_INDEPENDENT_CODE</span> <span style="color:#b44">ON</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#b44">OUTPUT_NAME</span> <span style="color:#b44">celix_my_lib</span>)<span style=""> |
| </span></span></span></code></pre></div><h2 id="symbol-visibility">Symbol Visibility</h2> |
| <ul> |
| <li>Header-only (INTERFACE) libraries should not configure symbol visibility.</li> |
| <li>Shared and static libraries should configure symbol visibility. |
| <ul> |
| <li>Static library meant to be linked as PRIVATE should hide symbols.</li> |
| </ul> |
| </li> |
| <li>Bundles should configure symbol visibility (this is done by default).</li> |
| </ul> |
| <h3 id="configuring-symbol-visibility-for-cc-libraries">Configuring Symbol Visibility for C/C++ Libraries</h3> |
| <p>For Apache Celix shared libraries, symbol visibility should be configured using the CMake target |
| properties <code>C_VISIBILITY_PRESET</code>, <code>CXX_VISIBILITY_PRESET</code> and <code>VISIBILITY_INLINES_HIDDEN</code> and a generated export |
| header.</p> |
| <p>The <code>C_VISIBILITY_PRESET</code> and <code>CXX_VISIBILITY_PRESET</code> target properties can be used to configure the default visibility |
| of symbols in C and C++ code. The <code>VISIBILITY_INLINES_HIDDEN</code> property can be used to configure the visibility of |
| inline functions. The <code>VISIBILITY_INLINES_HIDDEN</code> property is only supported for C++ code.</p> |
| <p>The default visibility should be configured to hidden and symbols should be explicitly exported using the export |
| marcos from a generated export header. The export header can be generated using the CMake function |
| <code>generate_export_header</code>. Every library should have its own export header.</p> |
| <p>For shared libraries, this can be done using the following CMake code:</p> |
| <div class="highlight"><pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-cmake" data-lang="cmake"><span style="display:flex;"><span><span style="color:#a2f">add_library</span>(<span style="color:#b44">my_lib</span> <span style="color:#b44">SHARED</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#b44">src/my_lib.c</span>)<span style=""> |
| </span></span></span><span style="display:flex;"><span><span style=""></span><span style="color:#a2f">set_target_properties</span>(<span style="color:#b44">my_lib</span> <span style="color:#b44">PROPERTIES</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#b44">C_VISIBILITY_PRESET</span> <span style="color:#b44">hidden</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#080;font-style:italic">#For C++ shared libraries also configure CXX_VISIBILITY_PRESET |
| </span></span></span><span style="display:flex;"><span><span style="color:#080;font-style:italic"></span> <span style="color:#b44">CXX_VISIBILITY_PRESET</span> <span style="color:#b44">hidden</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#b44">VISIBILITY_INLINES_HIDDEN</span> <span style="color:#b44">ON</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#b44">OUTPUT_NAME</span> <span style="color:#b44">celix_my_lib</span>)<span style=""> |
| </span></span></span><span style="display:flex;"><span><span style=""></span><span style="color:#a2f">target_include_directories</span>(<span style="color:#b44">my_lib</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#b44">PUBLIC</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#666">$<</span><span style="color:#b8860b">BUILD_INTERFACE:${CMAKE_BINARY_DIR}/celix/gen/includes/my_lib</span><span style="color:#666">></span> |
| </span></span><span style="display:flex;"><span> <span style="color:#b44">PRIVATE</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#b44">src</span>)<span style=""> |
| </span></span></span><span style="display:flex;"><span><span style=""> |
| </span></span></span><span style="display:flex;"><span><span style=""></span><span style="color:#080;font-style:italic">#generate export header |
| </span></span></span><span style="display:flex;"><span><span style="color:#080;font-style:italic"></span><span style="color:#a2f">generate_export_header</span>(<span style="color:#b44">my_lib</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#b44">BASE_NAME</span> <span style="color:#b44">"CELIX_MY_LIB"</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#b44">EXPORT_FILE_NAME</span> <span style="color:#b44">"${CMAKE_BINARY_DIR}/celix/gen/includes/my_lib/celix_my_lib_export.h"</span>)<span style=""> |
| </span></span></span><span style="display:flex;"><span><span style=""> |
| </span></span></span><span style="display:flex;"><span><span style=""></span><span style="color:#080;font-style:italic">#install |
| </span></span></span><span style="display:flex;"><span><span style="color:#080;font-style:italic"></span><span style="color:#a2f">install</span>(<span style="color:#b44">TARGETS</span> <span style="color:#b44">my_lib</span> <span style="color:#b44">EXPORT</span> <span style="color:#b44">celix</span> <span style="color:#b44">LIBRARY</span> <span style="color:#b44">DESTINATION</span> <span style="color:#666">${</span><span style="color:#b8860b">CMAKE_INSTALL_LIBDIR</span><span style="color:#666">}</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#b44">INCLUDES</span> <span style="color:#b44">DESTINATION</span> <span style="color:#666">${</span><span style="color:#b8860b">CMAKE_INSTALL_INCLUDEDIR</span><span style="color:#666">}</span><span style="color:#b44">/celix_my_lib</span>)<span style=""> |
| </span></span></span><span style="display:flex;"><span><span style=""></span><span style="color:#a2f">install</span>(<span style="color:#b44">DIRECTORY</span> <span style="color:#b44">include/</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#b44">DESTINATION</span> <span style="color:#666">${</span><span style="color:#b8860b">CMAKE_INSTALL_INCLUDEDIR</span><span style="color:#666">}</span><span style="color:#b44">/celix_my_lib</span>)<span style=""> |
| </span></span></span><span style="display:flex;"><span><span style=""></span><span style="color:#a2f">install</span>(<span style="color:#b44">DIRECTORY</span> <span style="color:#666">${</span><span style="color:#b8860b">CMAKE_BINARY_DIR</span><span style="color:#666">}</span><span style="color:#b44">/celix/gen/includes/my_lib/</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#b44">DESTINATION</span> <span style="color:#666">${</span><span style="color:#b8860b">CMAKE_INSTALL_INCLUDEDIR</span><span style="color:#666">}</span><span style="color:#b44">/celix_my_lib</span>)<span style=""> |
| </span></span></span></code></pre></div><h3 id="configuring-symbol-visibility-for-cc-bundles">Configuring Symbol Visibility for C/C++ Bundles</h3> |
| <p>For bundle, symbol visibility will default be configured to hidden. This can be default by providing |
| the <code>DO_NOT_CONFIGURE_SYMBOL_VISIBILITY</code> option to the CMake <code>add_celix_bundle</code> function.</p> |
| <p>If symbol visibility is not configured in the <code>add_celix_bundle</code>, symbol visibility should be configured the same |
| way as a shared library.</p> |
| <div class="highlight"><pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-cmake" data-lang="cmake"><span style="display:flex;"><span><span style="color:#a2f">add_celix_bundle</span>(<span style="color:#b44">my_bundle</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#b44">SOURCES</span> <span style="color:#b44">src/my_bundle.c</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#b44">SYMBOLIC_NAME</span> <span style="color:#b44">"apache_celix_my_bundle"</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#b44">NAME</span> <span style="color:#b44">"Apache Celix My Bundle"</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#b44">FILENAME</span> <span style="color:#b44">"celix_my_bundle"</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#b44">VERSION</span> <span style="color:#b44">"1.0.0"</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#b44">GROUP</span> <span style="color:#b44">"celix/my_bundle_group"</span> |
| </span></span><span style="display:flex;"><span>)<span style=""> |
| </span></span></span><span style="display:flex;"><span><span style=""></span><span style="color:#a2f">add_library</span>(<span style="color:#b44">celix::my_bundle</span> <span style="color:#b44">ALIAS</span> <span style="color:#b44">my_bundle</span>)<span style=""> |
| </span></span></span></code></pre></div><h2 id="branch-naming">Branch naming</h2> |
| <ul> |
| <li>Prefix feature branches with <code>feature/</code>, hotfix branches with <code>hotfix/</code>, bugfix branches with <code>bugfix/</code> |
| and release branches with <code>release/</code>.</li> |
| <li>If you are working on an issue, prefix the branch name with the issue number. E.g., <code>feature/1234-add-feature</code>.</li> |
| <li>Hotfix branches are for urgent fixes that need to be applied as soon as possible.</li> |
| <li>Use short and descriptive branch names.</li> |
| </ul> |
| <h2 id="commit-messages">Commit Messages</h2> |
| <ul> |
| <li>Utilize the imperative mood when writing commit messages (e.g., “Add feature” instead of “Adds feature” |
| or “Added feature”). This style aligns with git’s auto-generated messages for merge commits or revert actions.</li> |
| <li>Ensure that commit messages are descriptive and provide meaningful context.</li> |
| <li>Keep the first line of the commit message concise, ideally under 50 characters. |
| This summary line serves as a quick overview of the change and should be easy to read in git logs.</li> |
| <li>If more context is needed, separate the summary line from the body with a blank line. |
| The body can provide additional details, explanations, or reasoning behind the changes. |
| Aim to keep each line of the commit message body wrapped at around 72 characters for optimal readability.</li> |
| <li>Use bullet points, numbered lists, or other formatting conventions when listing multiple changes or points in the |
| commit message body to improve readability.</li> |
| <li>When applicable, reference related issues, bug reports, or pull requests in the commit message body to |
| provide additional context and establish connections between the commit and the larger project. |
| <ul> |
| <li>If your commit fixes, closes, or resolves an issue, use one of these keywords followed by the issue number |
| (e.g., “fixes #42”, “closes #42”, or “resolves #42”).</li> |
| <li>If you want to reference an issue without closing it, simply mention the issue number |
| (e.g., “related to #42” or “#42”).</li> |
| </ul> |
| </li> |
| </ul> |
| <h2 id="benchmarking">Benchmarking</h2> |
| <ul> |
| <li>When needed, use benchmarking to measure performance.</li> |
| <li>Use the Google Benchmark framework for benchmarking.</li> |
| </ul> |
| <h2 id="code-quality">Code Quality</h2> |
| <ul> |
| <li>New code should be reviewed through a pull request and no direct commits on the master branch are allowed. |
| <ul> |
| <li>At least 1 reviewer should review the code.</li> |
| </ul> |
| </li> |
| <li>Hotfix pull request can be merged first and reviewed later, the rest is reviewed first and merged later.</li> |
| <li>Unit tests should be written for all new code.</li> |
| <li>Code coverage should be measured and strive for a minimum of 95% code coverage.</li> |
| <li>For existing code, maintain or increase the code coverage.</li> |
| <li>Code should be checked for memory leaks using AddressSanitizer.</li> |
| <li>Coverity scan are done on the master on a regular basis. Ideally new coverity issues should be fixed as soon as |
| possible.</li> |
| </ul> |
| |
| |
| </div> |
| </div> |
| </div> |
| </div> |
| </div> |
| |
| |
| <footer class="py-3 bg-secondary"> |
| <div class="container"> |
| <div class="row"> |
| <div class="col-md-8 text-center"> |
| <p class="m-0 text-white"> |
| Copyright © 2024 The Apache Software Foundation, Licensed under |
| the <a href="https://www.apache.org/licenses/LICENSE-2.0">Apache License, Version 2.0</a>. |
| <br> |
| Apache Celix, Celix, Apache, the Apache feather logo and the Apache Celix logo are trademarks of The Apache Software Foundation. |
| </p> |
| </div> |
| <div class="col-md-4 text-center"> |
| <a href="https://www.apache.org/events/current-event.html" target="_blank"> |
| <img src="https://www.apache.org/events/current-event-234x60.png" title="Apache Event" width="234" height="60" border="0"> |
| </a> |
| </div> |
| </div> |
| </div> |
| </footer> |
| |
| |
| <script src="/assets/js/jquery.min.js"></script> |
| <script src="/assets/js/bootstrap.bundle.min.js"></script> |
| |
| |
| </body> |
| </html> |