2 * Copyright 2014 Facebook, Inc.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 #ifndef FOLLY_VERSIONCHECK_H_
18 #define FOLLY_VERSIONCHECK_H_
24 #include <folly/Portability.h>
25 #include <folly/Preprocessor.h>
28 * Check if the currently loaded version of a library is what you expect.
30 * It is possible for multiple versions of the same shared library to end up
31 * being loaded simultaneously in the same address space, usually with
34 * For example, let's say you have a shared library (foo) that doesn't keep
35 * binary compatbility between releases, and so each version is distributed as
36 * a SO with different SONAME. Let's say you build another shared library, bar
37 * that depends on version 1 of foo: libbar.so depends on libfoo1.so.
38 * Your main executable now (baz) depends on version 2 of foo, and also
39 * depends on bar: baz depends on libfoo2.so and libbar.so.
41 * At load time, baz loads libfoo2.so first, then libbar.so; libbar.so will
42 * load libfoo1.so, but, as this is normal dynamic loading (and not explicit
43 * dlopen calls with RTLD_DEEPBIND), any symbols from libfoo1.so that are
44 * also present in libfoo2.so will be satisfied from the (already loaded)
47 * But foo does not preserve binary compatibility between versions, so all
48 * hell breaks loose (the symbols from libfoo2.so are not necessarily direct
49 * replacements of the identically-named symbols in libfoo1.so).
51 * It is better to crash with a helpful error message instead, which is what
52 * this macro provides. FOLLY_VERSION_CHECK verifies at load time that
53 * the compiled-in version is the same as the currently loaded version.
55 * Usage: use this macro at namespace scope in a .cpp file (IMPORTANT: NOT
56 * in the unnamed namespace):
58 * FOLLY_VERSION_CHECK(mylib, "1")
60 * The first argument identifies your library; the second argument is a
61 * string literal containing the desired version string.
63 * In order to avoid changing the file for each version, the version string
64 * could be provided on the compiler command line with -D:
66 * FOLLY_VERSION_CHECK(mylib, MYLIB_VERSION)
68 * ... and then commpile your file with -DMYLIB_VERSION=\"1\"
72 // OS X doesn't support constructor priorities. Just pray it works, I guess.
73 #define FOLLY_VERSION_CHECK_PRIORITY __attribute__((__constructor__))
75 #define FOLLY_VERSION_CHECK_PRIORITY __attribute__((__constructor__(101)))
78 // Note that this is carefully crafted: PRODUCT##Version must have external
79 // linkage (so it collides among versions), versionCheck must have internal
80 // linkage (so it does NOT collide between versions); if we're trying to have
81 // multiple versions loaded at the same time, they must each run their copy
82 // of versionCheck, but share the PRODUCT##Version variable.
83 #define FOLLY_VERSION_CHECK(PRODUCT, VERSION) \
84 const char* PRODUCT##Version = VERSION; \
86 FOLLY_VERSION_CHECK_PRIORITY void versionCheck() { \
87 if (strcmp(PRODUCT##Version, VERSION)) { \
89 "Invalid %s version: desired [%s], currently loaded [%s]\n", \
90 FB_STRINGIZE(PRODUCT), PRODUCT##Version, VERSION); \
96 #endif /* FOLLY_VERSIONCHECK_H_ */