1# Contributor's Guidelines to ADIOS 2 2 3This guide will walk you through how to submit changes to ADIOS 2 and interact 4with the project as a developer. Information found on ADIOS 2 wiki: https://github.com/ornladios/ADIOS2/wiki under the Contributing to ADIOS section. 5 6Table of Contents 7================= 8 9 * [Contributor's Guide](#contributors-guide) 10 * [Table of Contents](#table-of-contents) 11 * [Workflow](#workflow) 12 * [Setup](#setup) 13 * [Making a change and submitting a pull request](#making-a-change-and-submitting-a-pull-request) 14 * [Create the topic branch](#create-the-topic-branch) 15 * [Do I need to merge master into my branch first?](#do-i-need-to-merge-master-into-my-branch-first) 16 * [Submit a pull request](#submit-a-pull-request) 17 * [Template implementation separation](#template-implementation-separation) 18 * [Example](#example) 19 * [Before separation of public and private template implementation](#before-separation-of-public-and-private-template-implementation) 20 * [Foo.h](#fooh-containing-all-implementation) 21 * [After separation of public and private template implementation](#after-separation-of-public-and-private-template-implementation) 22 * [Foo.h](#fooh-containing-only-prototypes-and-explicit-instantiation-declarations) 23 * [Foo.inl](#fooinl-containing-template-implementations-that-always-need-to-be-included) 24 * [Foo.tcc](#footcc-containing-template-implementations-that-should-be-restricted-to-only-known-types) 25 * [Foo.cpp](#foocpp-containing-non-template-implementations-and-explicit-instantiations-definitions-for-known-types) 26 * [Code formatting and style](#code-formatting-and-style) 27 28## Workflow 29ADIOS uses the GitHub fork-and-branch model. In this, the project "lives" in it's main repository located at https://github.com/ornladios/adios2.git, while each individual developer has their own copy of the repo to work in. Changes are then submitted to the main repository via pull-requests made with branches from your fork. 30 31## Setup 32To setup your local repository for development: 33 34 1. Fork the main repository on GitHub: 35 1. Navigate to https://github.com/ornladios/adios2 in your browser. 36 1. Click the `[Fork]` button in the upper right-hand side of the page. 37 2. Clone the upstream repository to your local machine: 38``` 39$ mkdir adios 40$ cd adios 41$ git clone https://github.com/ornladios/adios2.git source 42Cloning into 'source'... 43remote: Counting objects: 4632, done. 44remote: Compressing objects: 100% (80/80), done. 45remote: Total 4632 (delta 33), reused 0 (delta 0), pack-reused 4549 46Receiving objects: 100% (4632/4632), 1.23 MiB | 224.00 KiB/s, done. 47Resolving deltas: 100% (2738/2738), done. 48Checking connectivity... done. 49$ 50``` 51 3. Run the `scripts/development/setup.sh` script. The script will configure an `upstream` remote and link your local master branch to the upstream. 52``` 53$ cd source/ 54$ ./scripts/developer/setup.sh 55Enter your GitHub username: chuckatkins 56Setup SSH push access? [(y)/n] y 57Re-configuring local master branch to use upstream 58Fetching origin 59remote: Counting objects: 6, done. 60remote: Compressing objects: 100% (6/6), done. 61remote: Total 6 (delta 0), reused 0 (delta 0), pack-reused 0 62Unpacking objects: 100% (6/6), done. 63From https://github.com/chuckatkins/adios2 64Fetching upstream 65From https://github.com/ornladios/adios2 66 * [new branch] master -> upstream/master 67 * [new branch] dashboard -> upstream/dashboard 68 * [new branch] hooks -> upstream/hooks 69Setting up git aliases... 70Setting up git hooks... 71$ 72``` 73 74## Making a change and submitting a pull request 75At this point you are ready to get to work. The first thing to do is to create a branch. ADIOS uses a "branchy" workflow where all changes are committed through self-contained "topic branches". This helps ensure a clean traceable git history and reduce conflicts. 76 77### Create the topic branch 78 791. Make sure you are starting from a current master: 80``` 81$ git checkout master 82$ git pull 83``` 842. Create a branch for your change: 85``` 86$ git checkout -b <your-topic-branch-name> 87``` 883. Make your changes and commits to the branch. 894. Push the branch to your fork: 90``` 91$ git push -u origin HEAD 92Counting objects: 189, done. 93Delta compression using up to 8 threads. 94Compressing objects: 100% (134/134), done. 95Writing objects: 100% (189/189), 70.30 KiB | 0 bytes/s, done. 96Total 189 (delta 128), reused 102 (delta 44) 97remote: Resolving deltas: 100% (128/128), completed with 82 local objects. 98To git@github.com:<your-GitHub-username-here>/adios2.git 99 * [new branch] HEAD -> <your-topic-branch-name> 100Branch <your-topic-branch-name> set up to track remote branch <your-topic-branch-name> from origin. 101$ 102``` 103 104#### Do I need to merge master into my branch first? 105Not usually. The only time to do that is to resolve conflicts. You're pull request will be automatically rejected if merge-conflicts exist, in which case you can then resolve them by either re-basing your branch the current master (preferable): 106``` 107$ git fetch --all -p 108... 109$ git rebase upstream/master 110$ git push -f 111``` 112or if necessary or re-basing is not a viable option then you can always fall back to merging in master but it should be generally discouraged as it tends to make the git history difficult to follow: 113``` 114$ git fetch --all -p 115... 116$ git merge upstream/master 117$ git push -f 118``` 119 120### Submit a pull request 1211. Log in to your GitHub fork. 1222. You should see a message at the top that informs you of your recently pushed branch, something like: `<your-topic-branch-name> (2 minutes ago)`. On the right side, select the `[Compare & pull request]` button. 1233. Fill in the appropriate information for the name of the branch and a brief summary of the changes it contains. 124 * The default configuration will be for the topic branch to be merged into the upstream's master branch. You can change this if you want to submit to a different branch. 1254. Click `[Create pull request]`. 126 127You have now created a pull request (PR) that is pending several status checks before it can be merged. Currently, the only check being performed is for source code formatting and style. In the future, however, the will be a more in depth continuous integration system tied to the pull requests that tests for build and test failures every time a PR is submitted or updated. Once the status checks pass, the PR will be eligible for merging by one of the project maintainers. 128 129## Template implementation separation 130The ADIOS C++ classes try to explicitly separate class declarations from their implementation. Typically this is done by having a separate .h and .cpp file, however it get's more complicated when templates are involved. To maintain the distinct separation between definition and implementation, we use explicit instantiation with 4 different source file types: 131* ClassName.h 132 * The main header file containing *only* the class and member declarations with no implementation. This also contains the declarations for explicitly instantiated members. 133* ClassName.inl 134 * A file containing inline function implementations that need to be made public. This is to be included at the bottom of ClassName.h and should *only* contain implementations that need to be made public. 135* ClassName.tcc 136 * A file containing most of the template implementations that can be hidden through explicit instantiation. 137* ClassName.cpp 138 * A file containing the non-template implementations and the explicit instation of any template members. 139 140### Example 141Here is an example of a simple class `Foo` with template member functions `Bar1` and `Bar2` 142 143#### Before separation of public and private template implementation 144##### Foo.h containing all implementation 145```cpp 146#ifndef FOO_H_ 147#define FOO_H_ 148 149namespace adios 150{ 151 152class Foo 153{ 154public: 155 Foo() 156 : m_Bar1Calls(0), m_Bar2Calls(0), m_Bar3Calls(0); 157 { 158 } 159 160 virtual ~Foo() = default; 161 162 template<typename T> 163 void Bar1() 164 { 165 Bar1Helper<T>(); 166 } 167 168 template<typename T> 169 void Bar2() 170 { 171 Bar2Helper<T>(); 172 } 173 174 void Bar3() 175 { 176 Bar3Helper(); 177 } 178 179private: 180 template<typename T> 181 void Bar1Helper() 182 { 183 ++m_Bar1Calls; 184 } 185 186 template<typename T> 187 void Bar2Helper() 188 { 189 ++m_Bar2Calls; 190 } 191 192 void Bar3Helper() 193 { 194 ++m_Bar3Calls; 195 } 196 197 size_t m_Bar1Calls; 198 size_t m_Bar2Calls; 199 size_t m_Bar3Calls; 200}; 201 202} // end namespace adios 203#endif // FOO_H_ 204``` 205 206#### After separation of public and private template implementation 207 208In this example, we want to hide the template implementation from the header. We will implement this such that `Bar1` is only callable from the core numeric types, i.e. ints, floats, and complex, while `Bar2` is callable from all types. This will necessitate that `Bar1` and it's helper function is implemented in a .tcc file with explicit instantiation for the allowed types while `Bar2` and it's helper function will need to be inlined in the .inl file to be accessible for all types. We will also use a helper macro ADIOS provides to iterate over the core numeric types for the explicit instantiation of `Bar1`. 209 210##### Foo.h containing only prototypes and explicit instantiation declarations 211```cpp 212#ifndef FOO_H_ 213#define FOO_H_ 214 215#include "ADIOSMacros.h" 216 217namespace adios 218{ 219class Foo 220{ 221public: 222 Foo(); 223 virtual ~Foo() = default; 224 225 template<typename T> 226 void Bar1(); 227 228 template<typename T> 229 void Bar2(); 230 231 void Bar3(); 232private: 233 template<typename T> 234 void Bar1Helper(); 235 236 template<typename T> 237 void Bar2Helper(); 238 239 void Bar3Helper; 240 241 size_t m_Bar1Calls; 242 size_t m_Bar2Calls; 243 size_t m_Bar3Calls; 244}; 245 246// Create declarations for explicit instantiations 247#define declare_explicit_instantiation(T) \ 248 extern template void Foo::Bar1<T>(); 249 250ADIOS_FOREACH_STDTYPE_1ARG(declare_explicit_instantiation) 251#undef(declare_explicit_instantiation) 252} // end namespace adios 253 254#include "Foo.inl" 255#endif // FOO_H_ 256``` 257Note here that Bar1Helper does not need an explicit instantiation because it's not a visible funtion in the callable interface. It's implementaion will be available to Bar1 inside the tcc file where it's called from. 258 259##### Foo.inl containing template implementations that always need to be included 260```cpp 261#ifndef FOO_INL_ 262#define FOO_INL_ 263#ifndef FOO_H_ 264#error "Inline file should only be included from it's header, never on it's own" 265#endif 266 267// No need to include Foo.h since it's where this is include from 268 269namespace adios 270{ 271 272template<typename T> 273void Foo::Bar2() 274{ 275 Bar2Helper<T>(); 276} 277 278template<typename T> 279void Foo::Bar2Helper() 280{ 281 ++m_Bar2Calls; 282} 283 284} // end namespace adios 285 286#endif // FOO_INL_ 287``` 288 289##### Foo.tcc containing template implementations that should be restricted to only known types 290```cpp 291#ifndef FOO_TCC_ 292#define FOO_TCC_ 293 294#include "Foo.h" 295namespace adios 296{ 297 298template<typename T> 299void Foo::Bar1() 300{ 301 Bar1Helper<T>(); 302} 303 304template<typename T> 305void Foo::Bar1Helper() 306{ 307 ++m_Bar1Calls; 308} 309 310} // end namespace adios 311 312#endif // FOO_TCC_ 313``` 314 315##### Foo.cpp containing non-template implementations and explicit instantiations definitions for known types. 316```cpp 317#include "Foo.h" 318#include "Foo.tcc" 319 320namespace adios 321{ 322 323Foo::Foo() 324: m_Bar1Calls(0), m_Bar2Calls(0), m_Bar3Calls(0) 325{ 326} 327 328void Foo::Bar3() 329{ 330 Bar3Helper(); 331} 332 333void Foo::Bar3Helper() 334{ 335 ++m_Bar3Calls; 336} 337 338// Create explicit instantiations of existing definitions 339#define define_explicit_instantiation(T) \ 340 template void Foo::Bar1<T>(); 341 342ADIOS_FOREACH_STDTYPE_1ARG(define_explicit_instantiation) 343#undef(define_explicit_instantiation) 344 345} // end namespace adios 346``` 347 348## Code formatting and style using clang-format 7 349ADIOS uses the [clang-format version 7](https://releases.llvm.org/7.0.0/tools/clang/docs/ClangFormat.html) tool to automatically enforce source code style and formatting rules. There are various ways to integrate the clang-format tool into your IDE / Code Editor depending on if you use Emacs, Vim, Eclipse, KDevelop, Microsoft Visual Studio, etc. that are a bit outside the scope of this document. A quick google search for "integrate <insert-editor-here> clang-format" should point you in the right direction. However, you can always reformat the code manually by running: 350 351``` 352clang-format -i SourceFile.cpp SourceFile.h 353``` 354 355That will apply the formatting rules used by the ADIOS project. 356 357While some of the formatting rules are fairly detailed, the main points are: 358 3591. Lines no longer than 80 characters. 3601. Always use braces { and }, even for 1 line if blocks. 3611. Use 4 spaces for indentation. 362 363There are more formatting rules but these three should at least get you close and prevent any drastic re-writes from the re-formatting tools. More details can be found by looking at the `.clang-format` config file in the root of the repository and by looking at the [clang-format documentation](https://releases.llvm.org/7.0.0/tools/clang/docs/ClangFormat.html). 364