A common init function for binaries and a default main function for tests
authorDenis Samoylov <den@fb.com>
Thu, 28 Jan 2016 19:18:54 +0000 (11:18 -0800)
committerfacebook-github-bot-1 <folly-bot@fb.com>
Thu, 28 Jan 2016 20:20:22 +0000 (12:20 -0800)
Summary: Added initialization routines to test main function that can help with debugging tests

Reviewed By: markisaa, yfeldblum

Differential Revision: D2839759

fb-gh-sync-id: 71cad45f3747336c8c7f8706db139cd060e1442b

README.md
folly/Makefile.am
folly/configure.ac
folly/experimental/Makefile.am [new file with mode: 0644]
folly/experimental/symbolizer/Makefile.am [new file with mode: 0644]
folly/init/Init.cpp [new file with mode: 0644]
folly/init/Init.h [new file with mode: 0644]
folly/init/Makefile.am [new file with mode: 0644]
folly/test/Makefile.am
folly/test/common/TestMain.cpp [new file with mode: 0644]

index fb6c124331f6fa2f94ac671ed7fd3046c721bdbf..ad8f49b7cd9ffd65ac7a53d8dab40c39a5611ca0 100644 (file)
--- a/README.md
+++ b/README.md
@@ -50,7 +50,10 @@ sudo apt-get install \
     zlib1g-dev \
     binutils-dev \
     libjemalloc-dev \
-    libssl-dev
+    libssl-dev \
+    libunwind8-dev \
+    libelf-dev \
+    libdwarf-dev
 ```
 
 Ubuntu 14.04 LTS
@@ -163,3 +166,6 @@ Other Linux distributions
     - double-conversion-devel
     - openssl-devel
     - libevent-devel
+    - libdwarf-dev
+    - libelf-dev
+    - libunwind8-dev
index e5427199551f2a858cf8e69092cf1a44027bc10a..63edfd8188f29ad7cdb6f8b3dc5d02f37556a674 100644 (file)
@@ -1,4 +1,8 @@
+if HAVE_LINUX
+SUBDIRS = . experimental init test
+else
 SUBDIRS = . test
+endif
 
 ACLOCAL_AMFLAGS = -I m4
 
@@ -119,6 +123,13 @@ nobase_follyinclude_HEADERS = \
        experimental/NestedCommandLineApp.h \
        experimental/ProgramOptions.h \
        experimental/ReadMostlySharedPtr.h \
+       experimental/symbolizer/Elf.h \
+       experimental/symbolizer/ElfCache.h \
+       experimental/symbolizer/Dwarf.h \
+       experimental/symbolizer/LineReader.h \
+       experimental/symbolizer/SignalHandler.h \
+       experimental/symbolizer/StackTrace.cpp \
+       experimental/symbolizer/Symbolizer.h \
        experimental/Select64.h \
        experimental/StringKeyedCommon.h \
        experimental/StringKeyedUnorderedMap.h \
@@ -184,6 +195,7 @@ nobase_follyinclude_HEADERS = \
        IPAddressV6.h \
        IPAddressException.h \
        IndexedMemPool.h \
+       init/Init.h \
        IntrusiveList.h \
        io/Compression.h \
        io/Cursor.h \
index a60af3c5b5c5715ea4807deb3fd07695cf564c60..d7ddb657299fc9e7a8f6ca83fa3b8c04aeb8a2a6 100644 (file)
@@ -468,6 +468,9 @@ AC_CHECK_HEADER([snappy.h], AC_CHECK_LIB([snappy], [main]))
 AC_CHECK_HEADER([zlib.h], AC_CHECK_LIB([z], [main]))
 AC_CHECK_HEADER([lzma.h], AC_CHECK_LIB([lzma], [main]))
 AC_CHECK_HEADER([zstd.h], AC_CHECK_LIB([zstd], [main]))
+AC_CHECK_HEADERS([libdwarf.h dwarf.h],, AC_MSG_ERROR([Please install libdwarf development package]))
+AC_CHECK_HEADERS([libelf.h elf.h],, AC_MSG_ERROR([Please install libelf development package]))
+AC_CHECK_HEADERS(libunwind.h, ac_cv_have_libunwind_h=1, ac_cv_have_libunwind_h=0)
 
 # Include directory that contains "folly" so #include <folly/Foo.h> works
 AM_CPPFLAGS='-I$(top_srcdir)/..'
@@ -494,5 +497,8 @@ AM_CONDITIONAL([HAVE_EXTRANDOM_SFMT19937],
 # Output
 AC_CONFIG_FILES([Makefile
                  test/Makefile
-                 test/function_benchmark/Makefile])
+                 test/function_benchmark/Makefile
+                 experimental/Makefile
+                 experimental/symbolizer/Makefile
+                 init/Makefile])
 AC_OUTPUT
diff --git a/folly/experimental/Makefile.am b/folly/experimental/Makefile.am
new file mode 100644 (file)
index 0000000..4cdff7e
--- /dev/null
@@ -0,0 +1 @@
+SUBDIRS = symbolizer
diff --git a/folly/experimental/symbolizer/Makefile.am b/folly/experimental/symbolizer/Makefile.am
new file mode 100644 (file)
index 0000000..8473959
--- /dev/null
@@ -0,0 +1,15 @@
+SUBDIRS = .
+
+lib_LTLIBRARIES = libfollysymbolizer.la
+
+libfollysymbolizer_la_SOURCES = \
+       Elf.cpp \
+       ElfCache.cpp \
+       Dwarf.cpp \
+       LineReader.cpp \
+       SignalHandler.cpp \
+       StackTrace.cpp \
+       Symbolizer.cpp
+
+libfollysymbolizer_la_LIBADD = $(top_builddir)/libfolly.la
+libfollysymbolizer_la_LDFLAGS = $(AM_LDFLAGS) -version-info $(LT_VERSION)
diff --git a/folly/init/Init.cpp b/folly/init/Init.cpp
new file mode 100644 (file)
index 0000000..46d30a0
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2016 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/init/Init.h>
+#include <folly/Singleton.h>
+#include <folly/experimental/symbolizer/SignalHandler.h>
+
+#include <glog/logging.h>
+#include <gflags/gflags.h>
+
+namespace folly {
+
+void init(int* argc, char*** argv, bool removeFlags) {
+  // Install the handler now, to trap errors received during startup.
+  // The callbacks, if any, can be installed later
+  folly::symbolizer::installFatalSignalHandler();
+
+  google::ParseCommandLineFlags(argc, argv, removeFlags);
+
+  auto programName = argc && argv && *argc > 0 ? (*argv)[0] : "unknown";
+  google::InitGoogleLogging(programName);
+
+  // Don't use glog's DumpStackTraceAndExit; rely on our signal handler.
+  google::InstallFailureFunction(abort);
+
+  // Move from the registration phase to the "you can actually instantiate
+  // things now" phase.
+  folly::SingletonVault::singleton()->registrationComplete();
+
+  // Actually install the callbacks into the handler.
+  folly::symbolizer::installFatalSignalCallbacks();
+}
+} //!folly
diff --git a/folly/init/Init.h b/folly/init/Init.h
new file mode 100644 (file)
index 0000000..8c1bc7e
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2016 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 INIT_LIGHT_BASE_H
+#define INIT_LIGHT_BASE_H
+
+/*
+ * Calls common init functions in the necessary order
+ * Among other things, this ensures that folly::Singletons are initialized
+ * correctly and installs signal handlers for a superior debugging experience.
+ * It also initializes gflags and glog.
+ *
+ * @param argc, argv   arguments to your main
+ * @param removeFlags  if true, will update argc,argv to remove recognized
+ *                     gflags passed on the command line
+ */
+namespace folly {
+
+void init(int* argc, char*** argv, bool removeFlags = true);
+
+} // folly
+
+#endif
diff --git a/folly/init/Makefile.am b/folly/init/Makefile.am
new file mode 100644 (file)
index 0000000..40320ac
--- /dev/null
@@ -0,0 +1,7 @@
+SUBDIRS = .
+
+lib_LTLIBRARIES = libfollyinit.la
+
+libfollyinit_la_SOURCES = Init.cpp
+libfollyinit_la_LIBADD = $(top_builddir)/libfolly.la $(top_builddir)/experimental/symbolizer/libfollysymbolizer.la
+libfollyinit_la_LDFLAGS = $(AM_LDFLAGS) -version-info $(LT_VERSION)
index c9dec17318c2832cadc28122b7ac92b097ab6cbe..11d68151be5491ff9053bd9a38bca66ee4282d82 100644 (file)
@@ -14,182 +14,189 @@ TESTS= \
        bits_test \
        bit_iterator_test
 
-check_LTLIBRARIES = libgtestmain.la libgtest.la
+check_LTLIBRARIES = libfollytestmain.la libgtest.la
 check_PROGRAMS =
 
-libgtestmain_la_CPPFLAGS = -Igtest-1.7.0 -Igtest-1.7.0/src
-libgtestmain_la_SOURCES = gtest-1.7.0/src/gtest-all.cc gtest-1.7.0/src/gtest_main.cc
-
 libgtest_la_CPPFLAGS = -Igtest-1.7.0 -Igtest-1.7.0/src
 libgtest_la_SOURCES = gtest-1.7.0/src/gtest-all.cc
 
+if HAVE_LINUX
+libfollytestmain_la_CPPFLAGS = $(AM_CPPFLAGS) $(libgtest_la_CPPFLAGS)
+libfollytestmain_la_SOURCES = $(libgtest_la_SOURCES) common/TestMain.cpp
+libfollytestmain_la_LIBADD = $(top_builddir)/init/libfollyinit.la $(top_builddir)/libfolly.la
+else
+libfollytestmain_la_CPPFLAGS = $(libgtest_la_CPPFLAGS)
+libfollytestmain_la_SOURCES = $(libgtest_la_SOURCES) gtest-1.7.0/src/gtest_main.cc
+libfollytestmain_la_LIBADD = $(top_builddir)/libfolly.la
+endif
+
 noinst_HEADERS = FBStringTestBenchmarks.cpp.h \
-                FBVectorTestBenchmarks.cpp.h
+       FBVectorTestBenchmarks.cpp.h
 
 spin_lock_test_SOURCES = SpinLockTest.cpp
-spin_lock_test_LDADD = libgtestmain.la $(top_builddir)/libfolly.la
+spin_lock_test_LDADD = libfollytestmain.la
 TESTS += spin_lock_test
 
 if RUN_ARCH_SPECIFIC_TESTS
 small_locks_test_SOURCES = SmallLocksTest.cpp
-small_locks_test_LDADD = libgtestmain.la $(top_builddir)/libfolly.la
+small_locks_test_LDADD = libfollytestmain.la
 TESTS += small_locks_test
 
 # Fails with WARNING: Logging before InitGoogleLogging() is written to STDERR
 packed_sync_ptr_test_SOURCES = PackedSyncPtrTest.cpp
-packed_sync_ptr_test_LDADD = libgtestmain.la $(top_builddir)/libfolly.la
+packed_sync_ptr_test_LDADD = libfollytestmain.la
 TESTS += packed_sync_ptr_test
 
 small_vector_test_SOURCES = small_vector_test.cpp
-small_vector_test_LDADD = libgtestmain.la $(top_builddir)/libfolly.la
+small_vector_test_LDADD = libfollytestmain.la
 TESTS += small_vector_test
 
 discriminated_ptr_test_SOURCES = DiscriminatedPtrTest.cpp
-discriminated_ptr_test_LDADD = libgtestmain.la $(top_builddir)/libfolly.la
+discriminated_ptr_test_LDADD = libfollytestmain.la
 TESTS += discriminated_ptr_test
 
 if !HAVE_PPC64
 cpuid_test_SOURCES = CpuIdTest.cpp
-cpuid_test_LDADD = libgtestmain.la $(top_builddir)/libfolly.la
+cpuid_test_LDADD = libfollytestmain.la
 TESTS += cpuid_test
 endif
 endif
 
 sorted_vector_types_test_SOURCES = sorted_vector_test.cpp
-sorted_vector_types_test_LDADD = libgtestmain.la $(top_builddir)/libfolly.la
+sorted_vector_types_test_LDADD = libfollytestmain.la
 
 
 foreach_test_SOURCES = ForeachTest.cpp
-foreach_test_LDADD = libgtestmain.la $(top_builddir)/libfollybenchmark.la $(top_builddir)/libfolly.la
+foreach_test_LDADD = libfollytestmain.la $(top_builddir)/libfollybenchmark.la
 
 hash_test_SOURCES = HashTest.cpp
-hash_test_LDADD = libgtestmain.la $(top_builddir)/libfolly.la
+hash_test_LDADD = libfollytestmain.la
 
 
 fbstring_test_using_jemalloc_SOURCES = FBStringTest.cpp
-fbstring_test_using_jemalloc_LDADD = libgtestmain.la $(top_builddir)/libfollybenchmark.la $(top_builddir)/libfolly.la
+fbstring_test_using_jemalloc_LDADD = libfollytestmain.la $(top_builddir)/libfollybenchmark.la
 TESTS += fbstring_test_using_jemalloc
 
 thread_cached_int_test_SOURCES = ThreadCachedIntTest.cpp
-thread_cached_int_test_LDADD = libgtestmain.la $(top_builddir)/libfollybenchmark.la $(top_builddir)/libfolly.la
+thread_cached_int_test_LDADD = libfollytestmain.la $(top_builddir)/libfollybenchmark.la
 
 thread_local_test_SOURCES = ThreadLocalTest.cpp
-thread_local_test_LDADD = libgtestmain.la $(top_builddir)/libfollybenchmark.la $(top_builddir)/libfolly.la
+thread_local_test_LDADD = libfollytestmain.la $(top_builddir)/libfollybenchmark.la
 thread_local_test_LDFLAGS = -ldl
 TESTS += thread_cached_int_test thread_local_test
 
 fbvector_test_SOURCES = FBVectorTest.cpp
-fbvector_test_LDADD = libgtestmain.la $(top_builddir)/libfollybenchmark.la $(top_builddir)/libfolly.la
+fbvector_test_LDADD = libfollytestmain.la $(top_builddir)/libfollybenchmark.la
 TESTS += fbvector_test
 
 # fails due to cout
 dynamic_test_SOURCES = DynamicTest.cpp
-dynamic_test_LDADD = libgtestmain.la $(top_builddir)/libfollybenchmark.la $(top_builddir)/libfolly.la $(top_builddir)/libfolly.la
+dynamic_test_LDADD = libfollytestmain.la $(top_builddir)/libfollybenchmark.la
 TESTS += dynamic_test
 
 # fails due to cout
 json_test_SOURCES = JsonTest.cpp
-json_test_LDADD = libgtestmain.la $(top_builddir)/libfollybenchmark.la $(top_builddir)/libfolly.la  $(top_builddir)/libfolly.la
+json_test_LDADD = libfollytestmain.la $(top_builddir)/libfollybenchmark.la
 TESTS += json_test
 
 benchmark_test_SOURCES = BenchmarkTest.cpp
-benchmark_test_LDADD = libgtestmain.la $(top_builddir)/libfollybenchmark.la $(top_builddir)/libfolly.la
+benchmark_test_LDADD = libfollytestmain.la $(top_builddir)/libfollybenchmark.la
 check_PROGRAMS += benchmark_test
 
 # fails due to destructor
 scope_guard_test_SOURCES = ScopeGuardTest.cpp
-scope_guard_test_LDADD = libgtestmain.la $(top_builddir)/libfolly.la
+scope_guard_test_LDADD = libfollytestmain.la
 TESTS += scope_guard_test
 
 timeout_queue_test_SOURCES = TimeoutQueueTest.cpp
-timeout_queue_test_LDADD = libgtestmain.la $(top_builddir)/libfolly.la
+timeout_queue_test_LDADD = libfollytestmain.la
 
 conv_test_SOURCES = ConvTest.cpp
-conv_test_LDADD = libgtestmain.la $(top_builddir)/libfollybenchmark.la $(top_builddir)/libfolly.la
+conv_test_LDADD = libfollytestmain.la $(top_builddir)/libfollybenchmark.la
 
 range_test_SOURCES = RangeTest.cpp
-range_test_LDADD = libgtestmain.la $(top_builddir)/libfolly.la
+range_test_LDADD = libfollytestmain.la
 
 bits_test_SOURCES = BitsTest.cpp
-bits_test_LDADD = libgtestmain.la $(top_builddir)/libfollybenchmark.la $(top_builddir)/libfolly.la
+bits_test_LDADD = libfollytestmain.la $(top_builddir)/libfollybenchmark.la
 
 bit_iterator_test_SOURCES = BitIteratorTest.cpp
-bit_iterator_test_LDADD = libgtestmain.la $(top_builddir)/libfollybenchmark.la $(top_builddir)/libfolly.la
+bit_iterator_test_LDADD = libfollytestmain.la $(top_builddir)/libfollybenchmark.la
 
 endian_test_SOURCES = EndianTest.cpp
-endian_test_LDADD = libgtestmain.la $(top_builddir)/libfolly.la
+endian_test_LDADD = libfollytestmain.la
 TESTS += endian_test
 
 rw_spinlock_test_SOURCES = RWSpinLockTest.cpp
-rw_spinlock_test_LDADD = libgtestmain.la $(top_builddir)/libfollybenchmark.la $(top_builddir)/libfolly.la
+rw_spinlock_test_LDADD = libfollytestmain.la $(top_builddir)/libfollybenchmark.la
 TESTS += rw_spinlock_test
 
 synchronized_test_SOURCES = SynchronizedTest.cpp
-synchronized_test_LDADD = libgtestmain.la $(top_builddir)/libfolly.la
+synchronized_test_LDADD = libfollytestmain.la
 TESTS += synchronized_test
 
 concurrent_skiplist_test_SOURCES = ConcurrentSkipListTest.cpp
-concurrent_skiplist_test_LDADD = libgtest.la $(top_builddir)/libfolly.la
+concurrent_skiplist_test_LDADD = libfollytestmain.la
 TESTS += concurrent_skiplist_test
 
 concurrent_skiplist_benchmark_SOURCES = ConcurrentSkipListBenchmark.cpp
-concurrent_skiplist_benchmark_LDADD = libgtestmain.la $(top_builddir)/libfollybenchmark.la $(top_builddir)/libfolly.la
+concurrent_skiplist_benchmark_LDADD = libfollytestmain.la $(top_builddir)/libfollybenchmark.la
 check_PROGRAMS += concurrent_skiplist_benchmark
 
 histogram_test_SOURCES = HistogramTest.cpp
-histogram_test_LDADD = libgtestmain.la $(top_builddir)/libfolly.la
+histogram_test_LDADD = libfollytestmain.la
 TESTS += histogram_test
 
 group_varint_test_SOURCES = GroupVarintTest.cpp
-group_varint_test_LDADD = libgtestmain.la $(top_builddir)/libfolly.la
+group_varint_test_LDADD = libfollytestmain.la
 TESTS += group_varint_test
 
 map_util_test_SOURCES = MapUtilTest.cpp
-map_util_test_LDADD = libgtestmain.la $(top_builddir)/libfolly.la
+map_util_test_LDADD = libfollytestmain.la
 TESTS += map_util_test
 
 string_test_SOURCES = StringTest.cpp
-string_test_LDADD = libgtest.la $(top_builddir)/libfolly.la
+string_test_LDADD = libfollytestmain.la
 TESTS += string_test
 
 producer_consumer_queue_test_SOURCES = ProducerConsumerQueueTest.cpp
-producer_consumer_queue_test_LDADD = libgtestmain.la $(top_builddir)/libfolly.la
+producer_consumer_queue_test_LDADD = libfollytestmain.la
 TESTS += producer_consumer_queue_test
 
 atomic_hash_array_test_SOURCES = AtomicHashArrayTest.cpp
-atomic_hash_array_test_LDADD = libgtestmain.la $(top_builddir)/libfolly.la
+atomic_hash_array_test_LDADD = libfollytestmain.la
 TESTS += atomic_hash_array_test
 
 atomic_hash_map_test_SOURCES = AtomicHashMapTest.cpp
-atomic_hash_map_test_LDADD = libgtest.la $(top_builddir)/libfolly.la $(top_builddir)/libfollybenchmark.la
+atomic_hash_map_test_LDADD = libfollytestmain.la $(top_builddir)/libfollybenchmark.la
 TESTS += atomic_hash_map_test
 
 format_test_SOURCES = FormatTest.cpp
-format_test_LDADD = libgtest.la $(top_builddir)/libfolly.la $(top_builddir)/libfollybenchmark.la
+format_test_LDADD = libfollytestmain.la $(top_builddir)/libfollybenchmark.la
 TESTS += format_test
 
 fingerprint_test_SOURCES = FingerprintTest.cpp
-fingerprint_test_LDADD = libgtest.la $(top_builddir)/libfolly.la $(top_builddir)/libfollybenchmark.la
+fingerprint_test_LDADD = libfollytestmain.la $(top_builddir)/libfollybenchmark.la
 TESTS += fingerprint_test
 
 portability_test_SOURCES = PortabilityTest.cpp
-portability_test_LDADD = libgtestmain.la $(top_builddir)/libfolly.la
+portability_test_LDADD = libfollytestmain.la
 TESTS += portability_test
 
 spooky_hash_v1_test_SOURCES = SpookyHashV1Test.cpp
-spooky_hash_v1_test_LDADD = libgtestmain.la $(top_builddir)/libfolly.la $(top_builddir)/libfollybenchmark.la
+spooky_hash_v1_test_LDADD = libfollytestmain.la  $(top_builddir)/libfollybenchmark.la
 TESTS += spooky_hash_v1_test
 
 spooky_hash_v2_test_SOURCES = SpookyHashV2Test.cpp
-spooky_hash_v2_test_LDADD = libgtestmain.la $(top_builddir)/libfolly.la $(top_builddir)/libfollybenchmark.la
+spooky_hash_v2_test_LDADD = libfollytestmain.la  $(top_builddir)/libfollybenchmark.la
 TESTS += spooky_hash_v2_test
 
 token_bucket_test_SOURCES = TokenBucketTest.cpp
-token_bucket_test_LDADD = libgtestmain.la $(top_builddir)/libfolly.la $(top_builddir)/libfollybenchmark.la
+token_bucket_test_LDADD = libfollytestmain.la  $(top_builddir)/libfollybenchmark.la
 TESTS += token_bucket_test
 
 thread_name_test_SOURCES = ThreadNameTest.cpp
-thread_name_test_LDADD = libgtestmain.la $(top_builddir)/libfolly.la
+thread_name_test_LDADD = libfollytestmain.la
 TESTS += thread_name_test
 
 
@@ -225,7 +232,7 @@ futures_test_SOURCES = \
     ../futures/test/WhenTest.cpp \
     ../futures/test/WhileDoTest.cpp
 
-futures_test_LDADD = libgtestmain.la $(top_builddir)/libfolly.la
+futures_test_LDADD = libfollytestmain.la
 TESTS += futures_test
 
 check_PROGRAMS += $(TESTS)
diff --git a/folly/test/common/TestMain.cpp b/folly/test/common/TestMain.cpp
new file mode 100644 (file)
index 0000000..c8e08d8
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2016 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/init/Init.h>
+
+#include <gtest/gtest.h>
+
+/*
+ * This is the recommended main function for all tests.
+ * The Makefile links it into all of the test programs so that tests do not need
+ * to - and indeed should typically not - define their own main() functions
+ */
+int main(int argc, char** argv) __attribute__((__weak__));
+
+int main(int argc, char** argv) {
+  ::testing::InitGoogleTest(&argc, argv);
+  folly::init(&argc, &argv);
+  return RUN_ALL_TESTS();
+}