Commit 1274a688 authored by Tudor Bosman's avatar Tudor Bosman Committed by Chip Turner

Enforce that only one version of folly is loaded at the same time

Test Plan: folly/test, OSS build, check the macro in separate file

Reviewed By: dancol@fb.com

FB internal diff: D1448086
parent c52e055c
......@@ -245,6 +245,7 @@ libfolly_la_SOURCES = \
ThreadCachedArena.cpp \
TimeoutQueue.cpp \
Uri.cpp \
Version.cpp \
wangle/InlineExecutor.cpp \
wangle/ManualExecutor.cpp \
wangle/ThreadGate.cpp \
......
/*
* Copyright 2014 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <folly/VersionCheck.h>
namespace folly { namespace detail {
FOLLY_VERSION_CHECK(folly, FOLLY_VERSION)
}} // namespaces
/*
* Copyright 2014 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef FOLLY_VERSIONCHECK_H_
#define FOLLY_VERSIONCHECK_H_
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <folly/Portability.h>
#include <folly/Preprocessor.h>
/**
* Check if the currently loaded version of a library is what you expect.
*
* It is possible for multiple versions of the same shared library to end up
* being loaded simultaneously in the same address space, usually with
* disastrous results.
*
* For example, let's say you have a shared library (foo) that doesn't keep
* binary compatbility between releases, and so each version is distributed as
* a SO with different SONAME. Let's say you build another shared library, bar
* that depends on version 1 of foo: libbar.so depends on libfoo1.so.
* Your main executable now (baz) depends on version 2 of foo, and also
* depends on bar: baz depends on libfoo2.so and libbar.so.
*
* At load time, baz loads libfoo2.so first, then libbar.so; libbar.so will
* load libfoo1.so, but, as this is normal dynamic loading (and not explicit
* dlopen calls with RTLD_DEEPBIND), any symbols from libfoo1.so that are
* also present in libfoo2.so will be satisfied from the (already loaded)
* libfoo2.so.
*
* But foo does not preserve binary compatibility between versions, so all
* hell breaks loose (the symbols from libfoo2.so are not necessarily direct
* replacements of the identically-named symbols in libfoo1.so).
*
* It is better to crash with a helpful error message instead, which is what
* this macro provides. FOLLY_VERSION_CHECK verifies at load time that
* the compiled-in version is the same as the currently loaded version.
*
* Usage: use this macro at namespace scope in a .cpp file (IMPORTANT: NOT
* in the unnamed namespace):
*
* FOLLY_VERSION_CHECK(mylib, "1")
*
* The first argument identifies your library; the second argument is a
* string literal containing the desired version string.
*
* In order to avoid changing the file for each version, the version string
* could be provided on the compiler command line with -D:
*
* FOLLY_VERSION_CHECK(mylib, MYLIB_VERSION)
*
* ... and then commpile your file with -DMYLIB_VERSION=\"1\"
*/
// Note that this is carefully crafted: PRODUCT##Version must have external
// linkage (so it collides among versions), versionCheck must have internal
// linkage (so it does NOT collide between versions); if we're trying to have
// multiple versions loaded at the same time, they must each run their copy
// of versionCheck, but share the PRODUCT##Version variable.
#define FOLLY_VERSION_CHECK(PRODUCT, VERSION) \
const char* PRODUCT##Version = VERSION; \
namespace { \
__attribute__((constructor(101))) void versionCheck() { \
if (strcmp(PRODUCT##Version, VERSION)) { \
fprintf(stderr, \
"Invalid %s version: desired [%s], currently loaded [%s]\n", \
FB_STRINGIZE(PRODUCT), PRODUCT##Version, VERSION); \
abort(); \
} \
} \
}
#endif /* FOLLY_VERSIONCHECK_H_ */
......@@ -3,12 +3,13 @@
# Process this file with autoconf to produce a configure script.
AC_PREREQ(2.59)
AC_INIT(folly, 0.1, folly@fb.com)
m4_define([folly_libtool_current], [1])
m4_define([folly_version_str], m4_esyscmd_s([cat VERSION]))
AC_INIT([folly], m4_translit(folly_version_str, [:], [.]), [folly@fb.com])
# We assume all revisions are backwards incompatible.
LT_VERSION=folly_libtool_current:0:0
LT_VERSION=folly_version_str:0
AC_SUBST(LT_VERSION)
AC_CONFIG_SRCDIR([Likely.h])
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment