Add a guard function to check Caffe2 linking setup.
Summary:
This helps diagnosing issues like #346
Closes https://github.com/caffe2/caffe2/pull/354
Differential Revision: D4928347
Pulled By: Yangqing
fbshipit-source-id: b45685f1da18cbc49be293260b1fc2268fe5cd4c
diff --git a/caffe2/core/init.cc b/caffe2/core/init.cc
index bac6766..c7c0732 100644
--- a/caffe2/core/init.cc
+++ b/caffe2/core/init.cc
@@ -1,4 +1,5 @@
#include "caffe2/core/init.h"
+#include "caffe2/core/operator.h" // for StaticLinkingProtector
#ifndef CAFFE2_BUILD_STRING
#define CAFFE2_BUILD_STRING "build_version_not_set"
@@ -14,6 +15,7 @@
bool GlobalInit(int* pargc, char*** pargv) {
static bool global_init_was_already_run = false;
+ static StaticLinkingProtector g_protector;
if (global_init_was_already_run) {
VLOG(1) << "GlobalInit has already been called: did you double-call?";
return true;
diff --git a/caffe2/core/operator.cc b/caffe2/core/operator.cc
index 5706360..63a9317 100644
--- a/caffe2/core/operator.cc
+++ b/caffe2/core/operator.cc
@@ -54,10 +54,12 @@
return nullptr;
}
}
+
} // namespace
unique_ptr<OperatorBase> CreateOperator(
const OperatorDef& operator_def, Workspace* ws) {
+ static StaticLinkingProtector g_protector;
// first, check with OpSchema if the operator is legal.
auto* schema = OpSchemaRegistry::Schema(operator_def.type());
if (schema) {
diff --git a/caffe2/core/operator.h b/caffe2/core/operator.h
index faa957f..47b4ab3 100644
--- a/caffe2/core/operator.h
+++ b/caffe2/core/operator.h
@@ -449,6 +449,32 @@
#define REGISTER_CUDNN_OPERATOR(name, ...) \
REGISTER_CUDA_OPERATOR_WITH_ENGINE(name, CUDNN, __VA_ARGS__)
+// StaticLinkingProtector is a helper class that ensures that the Caffe2
+// library is linked correctly with whole archives (in the case of static
+// linking). What happens is that when CreateOperator is called for the first
+// time, it instantiates an OperatorLinkingProtector object to check if the
+// operator registry is empty. If it is empty, this means that we are not
+// properly linking the library.
+//
+// You should not need to use this class.
+struct StaticLinkingProtector {
+ StaticLinkingProtector() {
+ const int registered_ops = CPUOperatorRegistry()->Keys().size();
+ // Note: this is a check failure instead of an exception, because if
+ // the linking is wrong, Caffe2 won't be able to run properly anyway,
+ // so it's better to fail loud.
+ // If Caffe2 is properly linked with whole archive, there should be more
+ // than zero registered ops.
+ if (registered_ops == 0) {
+ LOG(FATAL) <<
+ "You might have made a build error: the Caffe2 library does not seem "
+ "to be linked with whole-static library option. To do so, use "
+ "-Wl,-force_load (clang) or -Wl,--whole-archive (gcc) to link the "
+ "Caffe2 library.";
+ }
+ }
+};
+
// An exception that can be thrown by an operator constructor that notifies
// that it does not support the given setting. This can be usually used for
// specific engines that only implement a subset of the features required by