Abseil Team | b832dce | 2020-02-25 22:27:31 +0100 | [diff] [blame] | 1 | # Abseil FAQ |
| 2 | |
| 3 | ## Is Abseil the right home for my utility library? |
| 4 | |
| 5 | Most often the answer to the question is "no." As both the [About |
| 6 | Abseil](https://abseil.io/about/) page and our [contributing |
| 7 | guidelines](https://github.com/abseil/abseil-cpp/blob/master/CONTRIBUTING.md#contribution-guidelines) |
| 8 | explain, Abseil contains a variety of core C++ library code that is widely used |
| 9 | at [Google](https://www.google.com/). As such, Abseil's primary purpose is to be |
| 10 | used as a dependency by Google's open source C++ projects. While we do hope that |
| 11 | Abseil is also useful to the C++ community at large, this added constraint also |
| 12 | means that we are unlikely to accept a contribution of utility code that isn't |
| 13 | already widely used by Google. |
| 14 | |
| 15 | ## How to I set the C++ dialect used to build Abseil? |
| 16 | |
| 17 | The short answer is that whatever mechanism you choose, you need to make sure |
| 18 | that you set this option consistently at the global level for your entire |
| 19 | project. If, for example, you want to set the C++ dialect to C++17, with |
| 20 | [Bazel](https://bazel/build/) as the build system and `gcc` or `clang` as the |
| 21 | compiler, there several ways to do this: |
| 22 | * Pass `--cxxopt=-std=c++17` on the command line (for example, `bazel build |
| 23 | --cxxopt=-std=c++17 ...`) |
| 24 | * Set the environment variable `BAZEL_CXXOPTS` (for example, |
| 25 | `BAZEL_CXXOPTS=-std=c++17`) |
| 26 | * Add `build --cxxopt=-std=c++17` to your [`.bazelrc` |
| 27 | file](https://docs.bazel.build/versions/master/guide.html#bazelrc) |
| 28 | |
| 29 | If you are using CMake as the build system, you'll need to add a line like |
| 30 | `set(CMAKE_CXX_STANDARD 17)` to your top level `CMakeLists.txt` file. See the |
| 31 | [CMake build |
| 32 | instructions](https://github.com/abseil/abseil-cpp/blob/master/CMake/README.md) |
| 33 | for more information. |
| 34 | |
| 35 | For a longer answer to this question and to understand why some other approaches |
| 36 | don't work, see the answer to ["What is ABI and why don't you recommend using a |
| 37 | pre-compiled version of |
| 38 | Abseil?"](#what-is-abi-and-why-dont-you-recommend-using-a-pre-compiled-version-of-abseil) |
| 39 | |
| 40 | ## What is ABI and why don't you recommend using a pre-compiled version of Abseil? |
| 41 | |
| 42 | For the purposes of this discussion, you can think of |
| 43 | [ABI](https://en.wikipedia.org/wiki/Application_binary_interface) as the |
| 44 | compiled representation of the interfaces in code. This is in contrast to |
| 45 | [API](https://en.wikipedia.org/wiki/Application_programming_interface), which |
| 46 | you can think of as the interfaces as defined by the code itself. [Abseil has a |
| 47 | strong promise of API compatibility, but does not make any promise of ABI |
| 48 | compatibility](https://abseil.io/about/compatibility). Let's take a look at what |
| 49 | this means in practice. |
| 50 | |
| 51 | You might be tempted to do something like this in a |
| 52 | [Bazel](https://bazel.build/) `BUILD` file: |
| 53 | |
| 54 | ``` |
| 55 | # DON'T DO THIS!!! |
| 56 | cc_library( |
| 57 | name = "my_library", |
| 58 | srcs = ["my_library.cc"], |
| 59 | copts = ["-std=c++17"], # May create a mixed-mode compile! |
| 60 | deps = ["@com_google_absl//absl/strings"], |
| 61 | ) |
| 62 | ``` |
| 63 | |
| 64 | Applying `-std=c++17` to an individual target in your `BUILD` file is going to |
| 65 | compile that specific target in C++17 mode, but it isn't going to ensure the |
| 66 | Abseil library is built in C++17 mode, since the Abseil library itself is a |
| 67 | different build target. If your code includes an Abseil header, then your |
| 68 | program may contain conflicting definitions of the same |
| 69 | class/function/variable/enum, etc. As a rule, all compile options that affect |
| 70 | the ABI of a program need to be applied to the entire build on a global basis. |
| 71 | |
| 72 | C++ has something called the [One Definition |
| 73 | Rule](https://en.wikipedia.org/wiki/One_Definition_Rule) (ODR). C++ doesn't |
| 74 | allow multiple definitions of the same class/function/variable/enum, etc. ODR |
| 75 | violations sometimes result in linker errors, but linkers do not always catch |
| 76 | violations. Uncaught ODR violations can result in strange runtime behaviors or |
| 77 | crashes that can be hard to debug. |
| 78 | |
| 79 | If you build the Abseil library and your code using different compile options |
| 80 | that affect ABI, there is a good chance you will run afoul of the One Definition |
| 81 | Rule. Examples of GCC compile options that affect ABI include (but aren't |
| 82 | limited to) language dialect (e.g. `-std=`), optimization level (e.g. `-O2`), |
| 83 | code generation flags (e.g. `-fexceptions`), and preprocessor defines |
| 84 | (e.g. `-DNDEBUG`). |
| 85 | |
| 86 | If you use a pre-compiled version of Abseil, (for example, from your Linux |
| 87 | distribution package manager or from something like |
| 88 | [vcpkg](https://github.com/microsoft/vcpkg)) you have to be very careful to |
| 89 | ensure ABI compatibility across the components of your program. The only way you |
| 90 | can be sure your program is going to be correct regarding ABI is to ensure |
| 91 | you've used the exact same compile options as were used to build the |
| 92 | pre-compiled library. This does not mean that Abseil cannot work as part of a |
| 93 | Linux distribution since a knowledgeable binary packager will have ensured that |
| 94 | all packages have been built with consistent compile options. This is one of the |
| 95 | reasons we warn against - though do not outright reject - using Abseil as a |
| 96 | pre-compiled library. |
| 97 | |
| 98 | Another possible way that you might afoul of ABI issues is if you accidentally |
| 99 | include two versions of Abseil in your program. Multiple versions of Abseil can |
| 100 | end up within the same binary if your program uses the Abseil library and |
| 101 | another library also transitively depends on Abseil (resulting in what is |
| 102 | sometimes called the diamond dependency problem). In cases such as this you must |
| 103 | structure your build so that all libraries use the same version of Abseil. |
| 104 | [Abseil's strong promise of API compatibility between |
| 105 | releases](https://abseil.io/about/compatibility) means the latest "HEAD" release |
| 106 | of Abseil is almost certainly the right choice if you are doing as we recommend |
| 107 | and building all of your code from source. |
| 108 | |
| 109 | For these reasons we recommend you avoid pre-compiled code and build the Abseil |
| 110 | library yourself in a consistent manner with the rest of your code. |
| 111 | |
| 112 | ## What is "live at head" and how do I do it? |
| 113 | |
| 114 | From Abseil's point-of-view, "live at head" means that every Abseil source |
| 115 | release (which happens on an almost daily basis) is either API compatible with |
| 116 | the previous release, or comes with an automated tool that you can run over code |
| 117 | to make it compatible. In practice, the need to use an automated tool is |
| 118 | extremely rare. This means that upgrading from one source release to another |
| 119 | should be a routine practice that can and should be performed often. |
| 120 | |
| 121 | We recommend you update to the [latest commit in the `master` branch of |
| 122 | Abseil](https://github.com/abseil/abseil-cpp/commits/master) as often as |
| 123 | possible. Not only will you pick up bug fixes more quickly, but if you have good |
| 124 | automated testing, you will catch and be able to fix any [Hyrum's |
| 125 | Law](https://www.hyrumslaw.com/) dependency problems on an incremental basis |
| 126 | instead of being overwhelmed by them and having difficulty isolating them if you |
| 127 | wait longer between updates. |
| 128 | |
| 129 | If you are using the [Bazel](https://bazel.build/) build system and its |
| 130 | [external dependencies](https://docs.bazel.build/versions/master/external.html) |
| 131 | feature, updating the |
| 132 | [`http_archive`](https://docs.bazel.build/versions/master/repo/http.html#http_archive) |
| 133 | rule in your |
| 134 | [`WORKSPACE`](https://docs.bazel.build/versions/master/be/workspace.html) for |
| 135 | `com_google_abseil` to point to the [latest commit in the `master` branch of |
| 136 | Abseil](https://github.com/abseil/abseil-cpp/commits/master) is all you need to |
| 137 | do. For example, on February 11, 2020, the latest commit to the master branch |
| 138 | was `98eb410c93ad059f9bba1bf43f5bb916fc92a5ea`. To update to this commit, you |
| 139 | would add the following snippet to your `WORKSPACE` file: |
| 140 | |
| 141 | ``` |
| 142 | http_archive( |
| 143 | name = "com_google_absl", |
| 144 | urls = ["https://github.com/abseil/abseil-cpp/archive/98eb410c93ad059f9bba1bf43f5bb916fc92a5ea.zip"], # 2020-02-11T18:50:53Z |
| 145 | strip_prefix = "abseil-cpp-98eb410c93ad059f9bba1bf43f5bb916fc92a5ea", |
| 146 | sha256 = "aabf6c57e3834f8dc3873a927f37eaf69975d4b28117fc7427dfb1c661542a87", |
| 147 | ) |
| 148 | ``` |
| 149 | |
| 150 | To get the `sha256` of this URL, run `curl -sL --output - |
| 151 | https://github.com/abseil/abseil-cpp/archive/98eb410c93ad059f9bba1bf43f5bb916fc92a5ea.zip |
| 152 | | sha256sum -`. |
| 153 | |
| 154 | You can commit the updated `WORKSPACE` file to your source control every time |
| 155 | you update, and if you have good automated testing, you might even consider |
| 156 | automating this. |
| 157 | |
| 158 | One thing we don't recommend is using GitHub's `master.zip` files (for example |
| 159 | [https://github.com/abseil/abseil-cpp/archive/master.zip](https://github.com/abseil/abseil-cpp/archive/master.zip)), |
| 160 | which are always the latest commit in the `master` branch, to implement live at |
| 161 | head. Since these `master.zip` URLs are not versioned, you will lose build |
| 162 | reproducibility. In addition, some build systems, including Bazel, will simply |
| 163 | cache this file, which means you won't actually be updating to the latest |
| 164 | release until your cache is cleared or invalidated. |