Skip to content

Commit

Permalink
Reapply Windows fix
Browse files Browse the repository at this point in the history
Summary:
Last fix was uncommitted due to a bug in internal build (CAFFE2_API causing error). This one re-applies it as well as a few more, especially enabling gtest.

Earlier commit message: Basically, this should make windows {static_lib, shared_lib} * {static_runtime, shared_runtime} * {cpu, gpu} work other than gpu shared_lib, which willyd kindly pointed out a symbol limit problem. A few highlights:
(1) Updated newest protobuf.
(2) use protoc dllexport command to ensure proper symbol export for windows.
(3) various code updates to make sure that C2 symbols are properly shown
(4) cmake file changes to make build proper
(5) option to choose static runtime and shared runtime similar to protobuf
(6) revert to visual studio 2015 as current cuda and msvc 2017 do not play well together.
(7) enabled gtest and fixed testing bugs.

Earlier PR is pytorch#1793

Closes facebookarchive/caffe2#1827

Differential Revision: D6832086

Pulled By: Yangqing

fbshipit-source-id: 85f86e9a992ee5c53c70b484b761c9d6aed721df
  • Loading branch information
Yangqing authored and facebook-github-bot committed Jan 29, 2018
1 parent 6572145 commit 91d76f5
Show file tree
Hide file tree
Showing 38 changed files with 402 additions and 240 deletions.
24 changes: 20 additions & 4 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,14 @@ set(CAFFE2_VERSION
# ---[ Options.
# Note to developers: if you add an option below, make sure you also add it to
# cmake/Summary.cmake so that the summary prints out the option values.
include(CMakeDependentOption)
option(BUILD_BINARY "Build C++ binaries" ON)
option(BUILD_DOCS "Build documentation" OFF)
option(BUILD_PYTHON "Build Python binaries" ON)
option(BUILD_SHARED_LIBS "Build libcaffe2.so" ON)
cmake_dependent_option(
CAFFE2_USE_MSVC_STATIC_RUNTIME "Using MSVC static runtime libraries" ON
"NOT BUILD_SHARED_LIBS" OFF)
option(BUILD_OBSERVERS "Build performance observers/loggers in caffe2/share/observers directory" OFF)
option(BUILD_TEST "Build C++ test binaries (need gtest and gbenchmark)" ON)
option(USE_ATEN "Use ATen" OFF)
Expand Down Expand Up @@ -49,10 +53,13 @@ option(USE_ZMQ "Use ZMQ" OFF)
option(USE_ZSTD "Use ZSTD" OFF)
option(DEPRIORITIZE_ANACONDA "Search system include directories before Anaconda include directories" OFF)


# ---[ CMake scripts + modules
list(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake/Modules)

if (MSVC AND ${BUILD_SHARED_LIBS})
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
endif()

# ---[ CMake build directories
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
Expand Down Expand Up @@ -101,10 +108,14 @@ else()
foreach(flag_var
CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE
CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELWITHDEBINFO)
if (NOT ${BUILD_SHARED_LIBS})
if (${CAFFE2_USE_MSVC_STATIC_RUNTIME})
if(${flag_var} MATCHES "/MD")
string(REGEX REPLACE "/MD" "/MT" ${flag_var} "${${flag_var}}")
endif(${flag_var} MATCHES "/MD")
else()
if(${flag_var} MATCHES "/MT")
string(REGEX REPLACE "/MT" "/MD" ${flag_var} "${${flag_var}}")
endif()
endif()
set(${flag_var} "${${flag_var}} /MP /bigobj")
endforeach(flag_var)
Expand Down Expand Up @@ -172,13 +183,13 @@ caffe2_print_configuration_summary()

# ---[ CMake related files
# Uninistall option.
if(NOT TARGET uninstall)
if(NOT TARGET caffe2_uninstall)
configure_file(
${CMAKE_CURRENT_SOURCE_DIR}/cmake/cmake_uninstall.cmake.in
${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake
IMMEDIATE @ONLY)

add_custom_target(uninstall
add_custom_target(caffe2_uninstall
COMMAND ${CMAKE_COMMAND} -P
${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake)
endif()
Expand All @@ -197,6 +208,11 @@ if (USE_GFLAGS)
endif()
if (NOT CAFFE2_USE_CUSTOM_PROTOBUF)
list(APPEND CAFFE2_INTERFACE_LIBS ${PROTOBUF_LIBRARIES})
else()
# TODO(jiayq): this is not ideal, as during installation one will not
# have the libprotobuf target ready. It is here only so that we can
# make in-house cmake builds run (link) properly.
list(APPEND CAFFE2_INTERFACE_LIBS libprotobuf)
endif()
if (USE_OPENCV)
list(APPEND CAFFE2_INTERFACE_LIBS ${OpenCV_LIBS})
Expand Down
4 changes: 4 additions & 0 deletions caffe/proto/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,8 @@ file(GLOB Caffe_PROTOBUF_FILES "${CMAKE_CURRENT_SOURCE_DIR}/*.proto")
caffe2_protobuf_generate_cpp_py(Caffe_PROTO_SRCS Caffe_PROTO_HEADERS Caffe_PROTO_PY ${Caffe_PROTOBUF_FILES})

add_library(Caffe_PROTO OBJECT ${Caffe_PROTO_HEADERS} ${Caffe_PROTO_SRCS})
if (MSVC)
target_compile_definitions(
Caffe_PROTO PRIVATE "-DCAFFE2_API=__declspec(dllexport)")
endif()
install(FILES ${Caffe_PROTO_HEADERS} DESTINATION include/caffe/proto)
14 changes: 12 additions & 2 deletions caffe2/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ add_library(caffe2 ${Caffe2_CPU_SRCS} $<TARGET_OBJECTS:Caffe_PROTO> $<TARGET_OBJ
target_link_libraries(caffe2 PRIVATE ${Caffe2_DEPENDENCY_LIBS})
target_include_directories(caffe2 INTERFACE $<INSTALL_INTERFACE:include>)
target_compile_options(caffe2 INTERFACE "-std=c++11")
target_compile_options(caffe2 PRIVATE "-DCAFFE2_BUILD_MAIN_LIB")
install(TARGETS caffe2 EXPORT Caffe2Targets DESTINATION lib)
caffe_add_linker_flag(caffe2 Caffe2_CPU_LINK)
list(APPEND Caffe2_MAIN_LIBS_ORDER caffe2 Caffe2_PROTO)
Expand All @@ -124,13 +125,22 @@ if(USE_CUDA)
# one cannot use PUBLIC/PRIVATE/INTERFACE for the target anymore. This
# hack adds the PRIVATE keywords to CUDA_LIBRARIES so we can deal with
# it.

#set(__tmp ${CUDA_LIBRARIES})
#set(CUDA_LIBRARIES PRIVATE ${CUDA_LIBRARIES})
#CUDA_ADD_LIBRARY(caffe2_gpu ${Caffe2_GPU_SRCS})
#set(CUDA_LIBRARIES ${__tmp})

# Note: the above misses transitive cuda dependencies, as we have not
# sorted out the interface library for cuda related libs. As a result,
# we will first put all CUDA_LIBRARIES as the dependency.
set(__tmp ${CUDA_LIBRARIES})
set(CUDA_LIBRARIES PRIVATE ${CUDA_LIBRARIES})
set(CUDA_LIBRARIES PUBLIC ${CUDA_LIBRARIES})
CUDA_ADD_LIBRARY(caffe2_gpu ${Caffe2_GPU_SRCS})
set(CUDA_LIBRARIES ${__tmp})

target_include_directories(
caffe2_gpu INTERFACE $<INSTALL_INTERFACE:include>)
target_compile_options(caffe2 INTERFACE "-std=c++11")
list(APPEND Caffe2_MAIN_LIBS_ORDER caffe2_gpu)
add_dependencies(caffe2_gpu Caffe2_PROTO)
if (BUILD_SHARED_LIBS)
Expand Down
18 changes: 17 additions & 1 deletion caffe2/core/common.cc
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,26 @@
* limitations under the License.
*/

#include <atomic>

#include "caffe2/core/common.h"

namespace caffe2 {
bool g_caffe2_has_cuda_linked = false;

// A global variable to mark if Caffe2 has cuda linked to the current runtime.
// Do not directly use this variable, but instead use the HasCudaRuntime()
// function below.
std::atomic<bool> g_caffe2_has_cuda_linked{false};

bool HasCudaRuntime() {
return g_caffe2_has_cuda_linked.load();
}

namespace internal {
void SetCudaRuntimeFlag() {
g_caffe2_has_cuda_linked.store(true);
}
} // namespace internal

const std::map<string, string>& GetBuildOptions() {
#ifndef CAFFE2_BUILD_STRINGS
Expand Down
45 changes: 36 additions & 9 deletions caffe2/core/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,18 @@ private: \
#endif
#endif

// Defines CAFFE2_EXPORT and CAFFE2_IMPORT. On Windows, this corresponds to
// different declarations (dllexport and dllimport). On Linux/Mac, it just
// resolves to the same "default visibility" setting.
#if defined(_MSC_VER)
#if defined(CAFFE2_BUILD_SHARED_LIBS)
#define CAFFE2_EXPORT __declspec(dllexport)
#define CAFFE2_IMPORT __declspec(dllimport)
#else
#define CAFFE2_EXPORT
#define CAFFE2_IMPORT
#endif
#else
#if defined(__GNUC__)
#if __GNUC_PREREQ(4, 9)
#define CAFFE2_EXPORT [[gnu::visibility("default")]]
Expand All @@ -132,6 +144,23 @@ private: \
#else
#define CAFFE2_EXPORT
#endif
#define CAFFE2_IMPORT CAFFE2_EXPORT
#endif

// CAFFE2_API is a macro that, depends on whether you are building the
// main caffe2 library or not, resolves to either CAFFE2_EXPORT or
// CAFFE2_IMPORT.
//
// This is used in e.g. Caffe2's protobuf files: when building the main library,
// it is defined as CAFFE2_EXPORT to fix a Windows global-variable-in-dll
// issue, and for anyone dependent on Caffe2 it will be defined as
// CAFFE2_IMPORT.

#ifdef CAFFE2_BUILD_MAIN_LIB
#define CAFFE2_API CAFFE2_EXPORT
#else
#define CAFFE2_API CAFFE2_IMPORT
#endif

// make_unique is a C++14 feature. If we don't have 14, we will emulate
// its behavior. This is copied from folly/Memory.h
Expand Down Expand Up @@ -190,7 +219,7 @@ inline double stod(const string& str, std::size_t* pos = 0) {
double val = 0;
ss >> val;
if (pos) {
if (ss.tellg() == -1) {
if (ss.tellg() == std::streampos(-1)) {
*pos = str.size();
} else {
*pos = ss.tellg();
Expand Down Expand Up @@ -244,19 +273,17 @@ class SkipIndices<> {
}
};

// A global variable to mark if Caffe2 has cuda linked to the current runtime.
// Do not directly use this variable, but instead use the HasCudaRuntime()
// function below.
extern bool g_caffe2_has_cuda_linked;

// HasCudaRuntime() tells the program whether the binary has Cuda runtime
// linked. This function should not be used in static initialization functions
// as the underlying boolean variable is going to be switched on when one
// loads libcaffe2_gpu.so.
inline bool HasCudaRuntime() {
return g_caffe2_has_cuda_linked;
bool HasCudaRuntime();
namespace internal {
// Sets the Cuda Runtime flag that is used by HasCudaRuntime(). You should
// never use this function - it is only used by the Caffe2 gpu code to notify
// Caffe2 core that cuda runtime has been loaded.
void SetCudaRuntimeFlag();
}

// Returns which setting Caffe2 was configured and built with (exported from
// CMake)
const std::map<string, string>& GetBuildOptions();
Expand Down
6 changes: 3 additions & 3 deletions caffe2/core/common_gpu.cc
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,13 @@
*/

#include "caffe2/core/common_gpu.h"
#include "caffe2/core/asan.h"

#include <atomic>
#include <cstdlib>
#include <sstream>

#include "caffe2/core/asan.h"
#include "caffe2/core/common.h"
#include "caffe2/core/init.h"
#include "caffe2/core/logging.h"

Expand Down Expand Up @@ -328,12 +329,11 @@ const char* curandGetErrorString(curandStatus_t error) {

// Turn on the flag g_caffe2_has_cuda_linked to true for HasCudaRuntime()
// function.
extern bool g_caffe2_has_cuda_linked;
namespace {
class CudaRuntimeFlagFlipper {
public:
CudaRuntimeFlagFlipper() {
g_caffe2_has_cuda_linked = true;
internal::SetCudaRuntimeFlag();
}
};
static CudaRuntimeFlagFlipper g_flipper;
Expand Down
2 changes: 1 addition & 1 deletion caffe2/core/context.h
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ class CPUContext final {
// TODO(jiayq): instead of hard-coding a generator, make it more flexible.
int random_seed_{1701};
std::unique_ptr<rand_gen_type> random_generator_;
static MemoryAllocationReporter reporter_;
CAFFE2_API static MemoryAllocationReporter reporter_;

private:
static void ReportAndDelete(void* ptr) {
Expand Down
2 changes: 1 addition & 1 deletion caffe2/core/context_gpu.h
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ class CUDAContext final {

~CUDAContext() {
if (curand_generator_) {
CURAND_ENFORCE(curandDestroyGenerator(curand_generator_));
CURAND_CHECK(curandDestroyGenerator(curand_generator_));
}
FinishDeviceComputation();
}
Expand Down
4 changes: 2 additions & 2 deletions caffe2/core/context_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@

#include <random>

#include "caffe2/proto/caffe2.pb.h"
#include "caffe2/core/context.h"
#include <gtest/gtest.h>
#include "caffe2/core/context.h"
#include "caffe2/proto/caffe2.pb.h"

namespace caffe2 {

Expand Down
21 changes: 12 additions & 9 deletions caffe2/core/event.cc
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,18 @@

namespace caffe2 {

EventCreateFunction Event::event_creator_[MaxDeviceTypes];
EventRecordFunction Event::event_recorder_[MaxDeviceTypes];
EventWaitFunction Event::event_waiter_[MaxDeviceTypes][MaxDeviceTypes];
EventFinishFunction Event::event_finisher_[MaxDeviceTypes];

EventQueryFunction Event::event_querier_[MaxDeviceTypes];
EventErrorMessageFunction Event::event_err_msg_getter_[MaxDeviceTypes];
EventSetFinishedFunction Event::event_finished_setter_[MaxDeviceTypes];
EventResetFunction Event::event_resetter_[MaxDeviceTypes];
CAFFE2_API EventCreateFunction Event::event_creator_[MaxDeviceTypes];
CAFFE2_API EventRecordFunction Event::event_recorder_[MaxDeviceTypes];
CAFFE2_API EventWaitFunction
Event::event_waiter_[MaxDeviceTypes][MaxDeviceTypes];
CAFFE2_API EventFinishFunction Event::event_finisher_[MaxDeviceTypes];

CAFFE2_API EventQueryFunction Event::event_querier_[MaxDeviceTypes];
CAFFE2_API EventErrorMessageFunction
Event::event_err_msg_getter_[MaxDeviceTypes];
CAFFE2_API EventSetFinishedFunction
Event::event_finished_setter_[MaxDeviceTypes];
CAFFE2_API EventResetFunction Event::event_resetter_[MaxDeviceTypes];

namespace {
const std::string kNoError = "No error";
Expand Down
21 changes: 12 additions & 9 deletions caffe2/core/event.h
Original file line number Diff line number Diff line change
Expand Up @@ -172,15 +172,18 @@ class Event {
int type_;
DeviceOption option_;

static EventCreateFunction event_creator_[MaxDeviceTypes];
static EventRecordFunction event_recorder_[MaxDeviceTypes];
static EventWaitFunction event_waiter_[MaxDeviceTypes][MaxDeviceTypes];
static EventFinishFunction event_finisher_[MaxDeviceTypes];

static EventQueryFunction event_querier_[MaxDeviceTypes];
static EventErrorMessageFunction event_err_msg_getter_[MaxDeviceTypes];
static EventSetFinishedFunction event_finished_setter_[MaxDeviceTypes];
static EventResetFunction event_resetter_[MaxDeviceTypes];
CAFFE2_API static EventCreateFunction event_creator_[MaxDeviceTypes];
CAFFE2_API static EventRecordFunction event_recorder_[MaxDeviceTypes];
CAFFE2_API static EventWaitFunction event_waiter_[MaxDeviceTypes]
[MaxDeviceTypes];
CAFFE2_API static EventFinishFunction event_finisher_[MaxDeviceTypes];

CAFFE2_API static EventQueryFunction event_querier_[MaxDeviceTypes];
CAFFE2_API static EventErrorMessageFunction
event_err_msg_getter_[MaxDeviceTypes];
CAFFE2_API static EventSetFinishedFunction
event_finished_setter_[MaxDeviceTypes];
CAFFE2_API static EventResetFunction event_resetter_[MaxDeviceTypes];

template <int d>
friend struct EventCreateFunctionRegisterer;
Expand Down
39 changes: 20 additions & 19 deletions caffe2/core/flags.h
Original file line number Diff line number Diff line change
Expand Up @@ -133,21 +133,22 @@ CAFFE_DECLARE_REGISTRY(Caffe2FlagsRegistry, Caffe2FlagParser, const string&);
// write the CAFFE2_DEFINE_* and CAFFE2_DECLARE_* macros outside any namespace
// as well.

#define CAFFE2_DEFINE_typed_var(type, name, default_value, help_str) \
namespace caffe2 { \
type FLAGS_##name = default_value; \
namespace { \
class Caffe2FlagParser_##name : public Caffe2FlagParser { \
public: \
explicit Caffe2FlagParser_##name(const string& content) { \
success_ = Caffe2FlagParser::Parse<type>(content, &FLAGS_##name); \
} \
}; \
} \
RegistererCaffe2FlagsRegistry g_Caffe2FlagsRegistry_##name( \
#name, Caffe2FlagsRegistry(), \
RegistererCaffe2FlagsRegistry::DefaultCreator<Caffe2FlagParser_##name>, \
"(" #type ", default " #default_value ") " help_str); \
#define CAFFE2_DEFINE_typed_var(type, name, default_value, help_str) \
namespace caffe2 { \
CAFFE2_EXPORT type FLAGS_##name = default_value; \
namespace { \
class Caffe2FlagParser_##name : public Caffe2FlagParser { \
public: \
explicit Caffe2FlagParser_##name(const string& content) { \
success_ = Caffe2FlagParser::Parse<type>(content, &FLAGS_##name); \
} \
}; \
} \
RegistererCaffe2FlagsRegistry g_Caffe2FlagsRegistry_##name( \
#name, \
Caffe2FlagsRegistry(), \
RegistererCaffe2FlagsRegistry::DefaultCreator<Caffe2FlagParser_##name>, \
"(" #type ", default " #default_value ") " help_str); \
}

#define CAFFE2_DEFINE_int(name, default_value, help_str) \
Expand All @@ -162,10 +163,10 @@ CAFFE_DECLARE_REGISTRY(Caffe2FlagsRegistry, Caffe2FlagParser, const string&);
CAFFE2_DEFINE_typed_var(string, name, default_value, help_str)

// DECLARE_typed_var should be used in header files and in the global namespace.
#define CAFFE2_DECLARE_typed_var(type, name) \
namespace caffe2 { \
extern type FLAGS_##name; \
} // namespace caffe2
#define CAFFE2_DECLARE_typed_var(type, name) \
namespace caffe2 { \
CAFFE2_IMPORT extern type FLAGS_##name; \
} // namespace caffe2

#define CAFFE2_DECLARE_int(name) CAFFE2_DECLARE_typed_var(int, name)
#define CAFFE2_DECLARE_int64(name) CAFFE2_DECLARE_typed_var(int64_t, name)
Expand Down
Loading

0 comments on commit 91d76f5

Please sign in to comment.