|
| 1 | +# How-to Guide: `clang-format` |
| 2 | + |
| 3 | +This guide is for developers who wish to apply `clang-format` on their chosen |
| 4 | +development machine, whether that be their personal machine or a multi-user |
| 5 | +cluster. |
| 6 | +In this guide, we will describe how to configure/run `clang-format` on EAMxx |
| 7 | +code and also how to install it if necessary. |
| 8 | + |
| 9 | +## Configure and Run `clang-format` |
| 10 | + |
| 11 | +Running `clang-format` according to the defined EAMxx standard ***can*** be |
| 12 | +done using only command line arguments; however, the command is quite long. |
| 13 | +The easier route is to reference the configuration file |
| 14 | +(`$EAMXX_ROOT/.clang-format`). |
| 15 | +In this case the command is |
| 16 | + |
| 17 | +```bash {.copy} |
| 18 | +clang-format [-i] --style="file:${EAMXX_ROOT}/.clang-format" <path/to/c++/source/file(s)> |
| 19 | +``` |
| 20 | + |
| 21 | +where the `-i` (`--in-place`) argument controls whether the formatting edits |
| 22 | +are conducted and change the source file(s) ("in place") or the required edits |
| 23 | +are printed to `stdout` (flag omitted). |
| 24 | +Also, note that the `--style` flag can also fully define the options without |
| 25 | +the configuration file as follows, but this is not recommended as the |
| 26 | +configuration could change before this guide is updated to reflect as such. |
| 27 | + |
| 28 | +<!-- markdownlint-disable MD046 MD013 --> |
| 29 | +??? Danger "Terminal One-(long-)liner" |
| 30 | + |
| 31 | + ```bash {.copy} |
| 32 | + clang-format [-i] --style="{BasedOnStyle: llvm, ColumnLimit: 100, AlignConsecutiveAssignments: true, AlignConsecutiveBitFields: true, AlignConsecutiveMacros: true, AlignEscapedNewlines: true, AlignTrailingComments: true}" <path/to/c++/source/file(s)> |
| 33 | + ``` |
| 34 | +<!-- markdownlint-enable MD046 MD013 --> |
| 35 | + |
| 36 | +## Installing `clang-format` |
| 37 | + |
| 38 | +On a personal machine, which we will consider to be one for which you have |
| 39 | +`sudo` privileges, installation can be conducted via package manager or by |
| 40 | +building `llvm v14` from scratch. |
| 41 | +If you are a non-admin user of a multi-user cluster, HPC platform, etc., then |
| 42 | +it is likely to be an ***easy*** process, though potentially not immediate. |
| 43 | + |
| 44 | +<!-- markdownlint-disable MD046 --> |
| 45 | +??? Note "If you require or already have multiple versions of `clang-format` installed" |
| 46 | + |
| 47 | + Note that, depending on your requirements, this could be placed in your shell |
| 48 | + config file (`.bashrc`, `.zshrc`), or if only needed for a shell session, it |
| 49 | + can be done directly from the command line. |
| 50 | + |
| 51 | + The other option is to add a versioned symbolic link to your `PATH`. |
| 52 | + This is sometimes included in the package's `bin/` directory by default and, |
| 53 | + if not, can be added there after of placed somewhere that is already on your |
| 54 | + `PATH`. |
| 55 | + |
| 56 | + ```c++ |
| 57 | + $ cd /opt/homebrew/opt/llvm@14/bin |
| 58 | + $ ls clang-format* |
| 59 | + clang-format |
| 60 | + // no versioned binary so we create symlink |
| 61 | + $ ln -s ./clang-format ./clang-format-14 |
| 62 | + $ which clang-format |
| 63 | + /opt/homebrew/opt/llvm@14/bin/clang-format-14 |
| 64 | + ``` |
| 65 | + |
| 66 | + **OR** |
| 67 | + |
| 68 | + ```c++ |
| 69 | + $ cd /opt/homebrew/opt/llvm@14/bin |
| 70 | + $ ls clang-format* |
| 71 | + clang-format |
| 72 | + // no versioned binary so we create symlink in a directory already on PATH |
| 73 | + $ echo $PATH |
| 74 | + /usr/bin:/usr/local/bin |
| 75 | + $ ln -s ./clang-format /usr/local/bin/clang-format-14 |
| 76 | + $ which clang-format |
| 77 | + /usr/local/bin/clang-format-14 |
| 78 | + ``` |
| 79 | +<!-- markdownlint-enable MD046 --> |
| 80 | + |
| 81 | +=== "Personal Machine" |
| 82 | + |
| 83 | + <!-- markdownlint-disable MD046 --> |
| 84 | + === "Mac Users (Homebrew Package Manager)" |
| 85 | + |
| 86 | + For Mac users, the [Homebrew](https://brew.sh) |
| 87 | + package manager (`brew`) is the quickest and most straightforward way |
| 88 | + to get `clang-format` installed. |
| 89 | + Since `clang-format` v14 is not available to install directly from |
| 90 | + Homebrew, we install the entire LLVM package at version 14, and this |
| 91 | + is as simple as |
| 92 | + |
| 93 | + ```bash {.copy} |
| 94 | + brew install llvm@14 |
| 95 | + ``` |
| 96 | + |
| 97 | + It it likely that Homebrew will issue a message about not linking the |
| 98 | + `clang`-related tools by default, so next we add the binary to our `PATH`. |
| 99 | + |
| 100 | + ```bash {.copy} |
| 101 | + $ export PATH="/opt/homebrew/opt/llvm@14/bin/clang-format:$PATH" |
| 102 | + # Note: this is the default location for a recent Mac running Apple silicon. |
| 103 | + # It may be different on another system. |
| 104 | + # You can confirm where yours is installed via 'brew info llvm@14' |
| 105 | + $ which clang-format |
| 106 | + /opt/homebrew/opt/llvm@14/bin/clang-format |
| 107 | + ``` |
| 108 | + |
| 109 | + Note also, that if your system has multiple version of `clang-format` installed, |
| 110 | + it may be preferable to instead set a versioned alias to `clang-format` |
| 111 | + (`clang-format-14`) as in |
| 112 | + |
| 113 | + ```c++ |
| 114 | + // create a shell-alias |
| 115 | + alias clang-format-14="/opt/homebrew/opt/llvm@14/bin/clang-format" |
| 116 | + ``` |
| 117 | + |
| 118 | + === "Linux Users (Package Manager)" |
| 119 | + |
| 120 | + Given the many flavors of Linux, it is difficult to generalize, but there |
| 121 | + is a high probability the proper version of `clang-format` or `llvm` is |
| 122 | + provided by the built-in package manager. |
| 123 | + The commands will differ based on your Linux distribution, but using the |
| 124 | + Debian/Ubuntu `apt` syntax, it could be accomplished via something like |
| 125 | + |
| 126 | + ```bash {.copy} |
| 127 | + $ apt search clang-format |
| 128 | + [...] |
| 129 | + clang-format-14/... |
| 130 | + $ apt install clang-format-14 |
| 131 | + ``` |
| 132 | + |
| 133 | + === "Build from Source" |
| 134 | + |
| 135 | + If you do not succeed in the above, `clang-format` can also be fully built |
| 136 | + from the [LLVM Compiler Infrastructure](https://github.com/llvm/llvm-project). |
| 137 | + It will begin with something like |
| 138 | + |
| 139 | + ```bash {.copy} |
| 140 | + git clone git@github.com:llvm/llvm-project.git |
| 141 | + git checkout llvmorg-14.0.6 # version tag |
| 142 | + ``` |
| 143 | + |
| 144 | + Also, if you only need `clang-format` and not any of the other tooling, |
| 145 | + it will build faster/smaller if you use the CMake flag |
| 146 | + `-DLLVM_ENABLE_PROJECTS="clang"` to only build `clang` and it's friends, |
| 147 | + rather than all of `llvm`. |
| 148 | + And finally, the README for [LLVM version 14.0.6](https://github.com/llvm/llvm-project/tree/llvmorg-14.0.6) |
| 149 | + is far more comprehensive that the one for the latest version, and it contains |
| 150 | + instructions specific to that build. |
| 151 | + |
| 152 | +=== "Multi-user System" |
| 153 | + |
| 154 | + In many cases `llvm`, `clang`, or `clang-format` will be available as a module, |
| 155 | + though whether version 14 is an option could be less likely. |
| 156 | + In the optimistic case, it could be as simple as (using Lmod syntax) |
| 157 | + |
| 158 | + ```bash {.copy} |
| 159 | + $ module avail llvm # [clang, clang-format] |
| 160 | + [... list ] |
| 161 | + $ module load llvm/14.0.6 |
| 162 | + ``` |
| 163 | + |
| 164 | + If it is not available, you will probably need to reach out to a system |
| 165 | + administrator to get an official version installed.[^but-conda] |
| 166 | +<!-- markdownlint-enable MD046 --> |
| 167 | + |
| 168 | +--- |
| 169 | + |
| 170 | +<!-- markdownlint-disable MD046 --> |
| 171 | +??? Tip "Unnecessary but Convenient Workflow Customization (`direnv`)" |
| 172 | + |
| 173 | + If you'd like to add a layer of automation/complexity to ensure you only use |
| 174 | + `clang-format v14` on `EAMxx` and/or want to use a newer version on the rest |
| 175 | + of your system, there is a very handy terminal tool called |
| 176 | + [direnv](https://direnv.net/) |
| 177 | + (`brew install direnv`) that allows you to automatically load and unload |
| 178 | + environment variables based on `$PWD` using a `.envrc` file. |
| 179 | + As an example, here's my `.envrc` that adds `clang-format v14` to the path |
| 180 | + when I'm working on `EAMxx`. |
| 181 | + |
| 182 | + ```bash {.copy} |
| 183 | + PATH_add /opt/homebrew/opt/llvm@14/bin/clang-format |
| 184 | + |
| 185 | + # also, since I often forget to load a python environment that's required for |
| 186 | + # running ctest, this creates or loads a python 3 virtual environment with numpy |
| 187 | + layout python3 |
| 188 | + pip install --upgrade pip |
| 189 | + # the upgrade isn't strictly necessary but trades a little extra setup on |
| 190 | + # the front end to avoid pip endlessly reminding you to update |
| 191 | + pip install numpy |
| 192 | + ``` |
| 193 | + |
| 194 | + This file can be placed in the top-level `EAMxx` directory, and running |
| 195 | + `direnv allow` enables the functionality. |
| 196 | + Namely, executing `cd EAMxx` loads the defined environment that stays loaded |
| 197 | + in any subdirectories, and resets the standard environment when exiting to a |
| 198 | + directory above/outside of `EAMxx`. |
| 199 | + |
| 200 | + For the `conda` fans, this tool can also be used to auto-load a |
| 201 | + pre-configured `conda` environment since the `.envrc` is essentially a bash |
| 202 | + script with a few bells and whistles tacked on. |
| 203 | +<!-- markdownlint-enable MD046 --> |
| 204 | + |
| 205 | +<!-- markdownlint-disable MD053 --> |
| 206 | +[^but-conda]: There are rumors of using `conda` creatively to do a user-install, |
| 207 | +but that is not an option we support or suggest. |
| 208 | +<!-- markdownlint-enable MD053 --> |
0 commit comments