|
| 1 | +# [≡](#contents) [C++ submodule manager](#) |
| 2 | + |
| 3 | +Poor man's submodule management, build scripts, and CI integration for simple, |
| 4 | +"conventional" C++ libraries, executable tests, and executable programs on top |
| 5 | +of |
| 6 | + |
| 7 | +- [CMake](https://cmake.org/), |
| 8 | +- [git](https://git-scm.com/), |
| 9 | +- [Travis CI](https://travis-ci.org/), and |
| 10 | +- [Codecov](https://codecov.io/). |
| 11 | + |
| 12 | +The idea is to minimize boilerplate by relying on simple conventions over |
| 13 | +excessive configuration. |
| 14 | + |
| 15 | +See |
| 16 | +[GitHub repositories with the `#cppsm` topic](https://github.com/topics/cppsm). |
| 17 | + |
| 18 | +[C++ submodule manager GitHub organization](https://github.com/cppsm) |
| 19 | +subprojects: |
| 20 | + |
| 21 | +- [C++ submodule manager documentation](https://github.com/cppsm/cppsm.github.io) |
| 22 | +- [C++ submodule manager command-line interface](https://github.com/cppsm/cppsm-cli) |
| 23 | +- [C++ submodule manager boilerplate](https://github.com/cppsm/cppsm-boilerplate) |
| 24 | + |
| 25 | +## <a id="contents"></a> [≡](#contents) [Contents](#contents) |
| 26 | + |
| 27 | +- [Install](#install) |
| 28 | +- [Synopsis](#synopsis) |
| 29 | +- [Project structure](#project-structure) |
| 30 | +- [CMake](#cmake) |
| 31 | + - [`conventional.cmake`](#conventional-cmake) |
| 32 | + - [`add_conventional_executable(name)`](#add_conventional_executable) |
| 33 | + - [`add_conventional_executable_tests(...)`](#add_conventional_executable_tests) |
| 34 | + - [`add_conventional_library(name)`](#add_conventional_library) |
| 35 | +- [Travis](#travis) |
| 36 | + - [Configuration](#configuration) |
| 37 | + - [`CODECOV`](#codecov) |
| 38 | + - [`XTRACE`](#xtrace) |
| 39 | + |
| 40 | +## <a id="install"></a> [≡](#contents) [Install](#install) |
| 41 | + |
| 42 | +Clone the `cppsm-cli` somewhere: |
| 43 | + |
| 44 | +```bash |
| 45 | +git clone https://github.com/cppsm/cppsm-cli.git |
| 46 | +``` |
| 47 | + |
| 48 | +Add to your `.bash_profile`: |
| 49 | + |
| 50 | +```bash |
| 51 | +CPPSM="path to cppsm-cli directory" |
| 52 | +export PATH="$CPPSM/bin:$PATH" |
| 53 | +. "$CPPSM/bash_completion" |
| 54 | +``` |
| 55 | + |
| 56 | +For code formatting you need to have both |
| 57 | +[`clang-format`](https://clang.llvm.org/docs/ClangFormat.html) and |
| 58 | +[`prettier`](https://prettier.io/) commands in path. |
| 59 | + |
| 60 | +For the optional auto completion of git urls you must have both |
| 61 | +[`curl`](https://curl.haxx.se/) and [`jq`](https://stedolan.github.io/jq/) |
| 62 | +commands in path. |
| 63 | + |
| 64 | +## <a id="synopsis"></a> [≡](#contents) [Synopsis](#synopsis) |
| 65 | + |
| 66 | +Create a new project: |
| 67 | + |
| 68 | +```bash |
| 69 | +mkdir PROJECT && cd "$_" |
| 70 | +git init |
| 71 | +cppsm init |
| 72 | +``` |
| 73 | + |
| 74 | +Try the hello world example (after `init`): |
| 75 | + |
| 76 | +```bash |
| 77 | +cppsm hello |
| 78 | +cppsm test |
| 79 | +.build*/internals/hello |
| 80 | +``` |
| 81 | + |
| 82 | +Start hacking: |
| 83 | + |
| 84 | +```bash |
| 85 | +emacs internals/program/hello.cpp & |
| 86 | +cppsm test-watch |
| 87 | +``` |
| 88 | + |
| 89 | +Format project files inplace: |
| 90 | + |
| 91 | +```bash |
| 92 | +cppsm format |
| 93 | +``` |
| 94 | + |
| 95 | +Clone an existing project: |
| 96 | + |
| 97 | +```bash |
| 98 | +cppsm clone URL BRANCH |
| 99 | +``` |
| 100 | + |
| 101 | +Or clone an existing project using plain git: |
| 102 | + |
| 103 | +```bash |
| 104 | +git clone -b BRANCH URL/NAME.git |
| 105 | +cd NAME |
| 106 | +git submodule update --init # NOTE: non-recursive |
| 107 | +``` |
| 108 | + |
| 109 | +Add a required library: |
| 110 | + |
| 111 | +```bash |
| 112 | +cppsm add requires URL/NAME.git BRANCH |
| 113 | +``` |
| 114 | + |
| 115 | +Remove a previously required library: |
| 116 | + |
| 117 | +```bash |
| 118 | +cppsm remove requires/NAME/BRANCH |
| 119 | +``` |
| 120 | + |
| 121 | +Upgrade all required libraries: |
| 122 | + |
| 123 | +```bash |
| 124 | +cppsm upgrade |
| 125 | +``` |
| 126 | + |
| 127 | +## <a id="project-structure"></a> [≡](#contents) [Project structure](#project-structure) |
| 128 | + |
| 129 | +At the root of a project there are three directories as follows: |
| 130 | + |
| 131 | +- The `equipment` directory may contain any number of _project submodules_ that |
| 132 | + the project internally depends upon. |
| 133 | +- The `internals` directory may contain one or more _target directories_ that |
| 134 | + are internal to the project. |
| 135 | +- The `provides` directory may contain one or more _target directories_ that are |
| 136 | + provided for dependant projects. |
| 137 | +- The `requires` directory may contain any number of _project submodules_ that |
| 138 | + the provided targets depend upon. |
| 139 | + |
| 140 | +In other words, both `internals` and `provides` may contain one or more target |
| 141 | +directories. In case only a single `internal` or `provides` target directory is |
| 142 | +needed, there is no need to create a nested directory. |
| 143 | + |
| 144 | +A single _target directory_ may simultaneously contain |
| 145 | + |
| 146 | +- a library in the `include/${name}` and `library` directories, |
| 147 | +- an executable test in the `testing` directory, and |
| 148 | +- an executable program in the `program` directory. |
| 149 | + |
| 150 | +Try the `cppsm hello` script. It generates a simple example project that has |
| 151 | +essentially the following structure: |
| 152 | + |
| 153 | + CMakeLists.txt |
| 154 | + equipment/ |
| 155 | + testing.cpp/ |
| 156 | + v1/ |
| 157 | + provides/ |
| 158 | + CMakeLists.txt |
| 159 | + include/ |
| 160 | + testing_v1/ |
| 161 | + test_synopsis.hpp |
| 162 | + test.hpp |
| 163 | + library/ |
| 164 | + test.cpp |
| 165 | + internals/ |
| 166 | + CMakeLists.txt |
| 167 | + testing/ |
| 168 | + message_test.cpp |
| 169 | + program/ |
| 170 | + hello.cpp |
| 171 | + provides/ |
| 172 | + CMakeLists.txt |
| 173 | + include/ |
| 174 | + message_v1/ |
| 175 | + hello.hpp |
| 176 | + library/ |
| 177 | + hello.cpp |
| 178 | + |
| 179 | +Note that the include directories are versioned as are CMake target names and |
| 180 | +C++ namespace names. This allows multiple major versions of a library to be used |
| 181 | +simultaneously. |
| 182 | + |
| 183 | +## <a id="cmake"></a> [≡](#contents) [CMake](#cmake) |
| 184 | + |
| 185 | +CMake boilerplate is provided for simple libraries, tests, and executables. |
| 186 | + |
| 187 | +### <a id="conventional-cmake"></a> [≡](#contents) [`conventional.cmake`](#conventional-cmake) |
| 188 | + |
| 189 | +#### <a id="add_conventional_executable"></a> [≡](#contents) [`add_conventional_executable(name)`](#add_conventional_executable) |
| 190 | + |
| 191 | +Adds an executable target. Assumes that the target directory has the following |
| 192 | +structure: |
| 193 | + |
| 194 | + CMakeLists.txt |
| 195 | + program/ |
| 196 | + *.(cpp|hpp) |
| 197 | + |
| 198 | +Add dependencies using `target_link_libraries` separately. |
| 199 | + |
| 200 | +#### <a id="add_conventional_executable_tests"></a> [≡](#contents) [`add_conventional_executable_tests(...)`](#add_conventional_executable_tests) |
| 201 | + |
| 202 | +Adds an executable test target per `.cpp` file. Assumes that the target |
| 203 | +directory has the following structure: |
| 204 | + |
| 205 | + CMakeLists.txt |
| 206 | + testing/ |
| 207 | + *.cpp |
| 208 | + |
| 209 | +The arguments given to `add_conventional_executable_tests` are passed to |
| 210 | +`target_link_libraries` for each added test target. |
| 211 | + |
| 212 | +#### <a id="add_conventional_library"></a> [≡](#contents) [`add_conventional_library(name)`](#add_conventional_library) |
| 213 | + |
| 214 | +Adds a library target. Assumes that the target directory has the following |
| 215 | +structure: |
| 216 | + |
| 217 | + CMakeLists.txt |
| 218 | + include/ |
| 219 | + ${name}/ |
| 220 | + *.hpp |
| 221 | + library/ |
| 222 | + *.(cpp|hpp) |
| 223 | + |
| 224 | +Note that inside `include` there is a directory with the target `${name}` (which |
| 225 | +should also include the major version) to differentiate between the header files |
| 226 | +of different targets (and their major versions). |
| 227 | + |
| 228 | +Add dependencies using `target_link_libraries` separately. |
| 229 | + |
| 230 | +## <a id="travis"></a> [≡](#contents) [Travis](#travis) |
| 231 | + |
| 232 | +A [Travis CI](https://travis-ci.org/) configuration file is provided to build |
| 233 | +and test both `Debug` and `Release` builds on various OS and compiler |
| 234 | +configurations: |
| 235 | + |
| 236 | +- Linux |
| 237 | + - GCC (8) |
| 238 | + - Clang (7) |
| 239 | +- OS X |
| 240 | + - GCC (8) |
| 241 | + - Apple Clang (10) |
| 242 | +- Windows |
| 243 | + - Visual Studio (2017) |
| 244 | + - MinGW GCC (8) |
| 245 | + |
| 246 | +Just add your project to Travis CI. |
| 247 | + |
| 248 | +### <a id="configuration"></a> [≡](#contents) [Configuration](#configuration) |
| 249 | + |
| 250 | +#### <a id="codecov"></a> [≡](#contents) [`CODECOV`](#codecov) |
| 251 | + |
| 252 | +By default the CI scripts do not generate and push code coverage results to |
| 253 | +[Codecov](https://codecov.io/). Set `CODECOV=1` to enable code coverage. |
| 254 | + |
| 255 | +#### <a id="xtrace"></a> [≡](#contents) [`XTRACE`](#xtrace) |
| 256 | + |
| 257 | +By default the CI scripts do not `set -x` to enable Bash xtrace to avoid |
| 258 | +unnecessary verbosity. Set `XTRACE=1` to enable Bash xtrace. |
0 commit comments