Skip to content

Commit

Permalink
Add support for windows build
Browse files Browse the repository at this point in the history
Necessary changes to enable widndows build:
Visual studio project files.
Minor code chnages.
3rd party dependencies are resolved through NuGet.
  • Loading branch information
pavlejosipovic committed Feb 11, 2016
1 parent 33f2445 commit 52f7402
Show file tree
Hide file tree
Showing 42 changed files with 2,845 additions and 31 deletions.
63 changes: 63 additions & 0 deletions .gitattributes
@@ -0,0 +1,63 @@
###############################################################################
# Set default behavior to automatically normalize line endings.
###############################################################################
* text=auto

###############################################################################
# Set default behavior for command prompt diff.
#
# This is need for earlier builds of msysgit that does not have it on by
# default for csharp files.
# Note: This is only used by command line
###############################################################################
#*.cs diff=csharp

###############################################################################
# Set the merge driver for project and solution files
#
# Merging from the command prompt will add diff markers to the files if there
# are conflicts (Merging from VS is not affected by the settings below, in VS
# the diff markers are never inserted). Diff markers may cause the following
# file extensions to fail to load in VS. An alternative would be to treat
# these files as binary and thus will always conflict and require user
# intervention with every merge. To do so, just uncomment the entries below
###############################################################################
#*.sln merge=binary
#*.csproj merge=binary
#*.vbproj merge=binary
#*.vcxproj merge=binary
#*.vcproj merge=binary
#*.dbproj merge=binary
#*.fsproj merge=binary
#*.lsproj merge=binary
#*.wixproj merge=binary
#*.modelproj merge=binary
#*.sqlproj merge=binary
#*.wwaproj merge=binary

###############################################################################
# behavior for image files
#
# image files are treated as binary by default.
###############################################################################
#*.jpg binary
#*.png binary
#*.gif binary

###############################################################################
# diff behavior for common document formats
#
# Convert binary document formats to text before diffing them. This feature
# is only available from the command line. Turn it on by uncommenting the
# entries below.
###############################################################################
#*.doc diff=astextplain
#*.DOC diff=astextplain
#*.docx diff=astextplain
#*.DOCX diff=astextplain
#*.dot diff=astextplain
#*.DOT diff=astextplain
#*.pdf diff=astextplain
#*.PDF diff=astextplain
#*.rtf diff=astextplain
#*.RTF diff=astextplain
8 changes: 8 additions & 0 deletions .gitignore
Expand Up @@ -93,3 +93,11 @@ LOCK
LOG*
CURRENT
MANIFEST-*

#Visual Studio files
*.user
*.suo
*.sdf
*.opensdf
*.pdb
*.props
19 changes: 19 additions & 0 deletions appveyor.yml
@@ -0,0 +1,19 @@
version: 1.0.{build}
clone_folder: c:\projects\caffe
build_script:
- cmd: >-
cd C:\projects\caffe\windows
copy CommonSettings.props.example CommonSettings.props
nuget restore Caffe.sln -PackagesDirectory ..\..\NugetPackages -ConfigFile nuget.config
set PATH=%PATH:nuget=hello%
msbuild Caffe.sln /m /v:m /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll" /p:Configuration=Debug;CpuOnlyBuild=true;UseCuDNN=false
msbuild Caffe.sln /m /v:m /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll" /p:Configuration=Release;CpuOnlyBuild=true;UseCuDNN=false
cd ..
Build\x64\Release\test_all.exe --gtest_filter=-*TestTimer*
4 changes: 3 additions & 1 deletion include/caffe/test/test_caffe_main.hpp
Expand Up @@ -10,6 +10,7 @@
#include <cstdlib>

#include "caffe/common.hpp"
#include "caffe/util/io.hpp"

using std::cout;
using std::endl;
Expand All @@ -35,7 +36,8 @@ class MultiDeviceTest : public ::testing::Test {
MultiDeviceTest() {
Caffe::set_mode(TypeParam::device);
}
virtual ~MultiDeviceTest() {}
// Caffe tests may create some temporary files, here we will do the cleanup.
virtual ~MultiDeviceTest() { RemoveCaffeTempDir(); }
};

typedef ::testing::Types<float, double> TestDtypes;
Expand Down
2 changes: 2 additions & 0 deletions include/caffe/util/cudnn.hpp
Expand Up @@ -17,6 +17,7 @@
<< cudnnGetErrorString(status); \
} while (0)

#if !defined (_MSC_VER)
inline const char* cudnnGetErrorString(cudnnStatus_t status) {
switch (status) {
case CUDNN_STATUS_SUCCESS:
Expand Down Expand Up @@ -44,6 +45,7 @@ inline const char* cudnnGetErrorString(cudnnStatus_t status) {
}
return "Unknown cudnn status";
}
#endif

namespace caffe {

Expand Down
25 changes: 22 additions & 3 deletions include/caffe/util/io.hpp
Expand Up @@ -23,8 +23,12 @@ using ::boost::filesystem::path;

inline void MakeTempDir(string* temp_dirname) {
temp_dirname->clear();
const path& model =
boost::filesystem::temp_directory_path()/"caffe_test.%%%%-%%%%";
// Place all temp directories under temp_root, to be able to delete all of
// them at once, without knowing their name.
const path& temp_root =
boost::filesystem::temp_directory_path() / "caffe_test";
boost::filesystem::create_directory(temp_root);
const path& model = temp_root / "%%%%-%%%%";
for ( int i = 0; i < CAFFE_TMP_DIR_RETRIES; i++ ) {
const path& dir = boost::filesystem::unique_path(model).string();
bool done = boost::filesystem::create_directory(dir);
Expand All @@ -37,7 +41,7 @@ inline void MakeTempDir(string* temp_dirname) {
}

inline void MakeTempFilename(string* temp_filename) {
static path temp_files_subpath;
path temp_files_subpath;
static uint64_t next_temp_file = 0;
temp_filename->clear();
if ( temp_files_subpath.empty() ) {
Expand All @@ -49,6 +53,21 @@ inline void MakeTempFilename(string* temp_filename) {
(temp_files_subpath/caffe::format_int(next_temp_file++, 9)).string();
}

#ifdef _MSC_VER

inline void RemoveCaffeTempDir() {
boost::system::error_code err;
boost::filesystem::remove_all(
boost::filesystem::temp_directory_path() / "caffe_test", err);
}

#else

inline void RemoveCaffeTempDir() {
}

#endif

bool ReadProtoFromTextFile(const char* filename, Message* proto);

inline bool ReadProtoFromTextFile(const string& filename, Message* proto) {
Expand Down
4 changes: 4 additions & 0 deletions python/caffe/test/test_python_layer.py
Expand Up @@ -131,6 +131,10 @@ def test_parameter(self):
self.assertEqual(layer.blobs[0].data[0], -1)
net.copy_from(caffemodel_file)
self.assertEqual(layer.blobs[0].data[0], 1)
if os.name == 'nt':
# On Windows, attempting to remove a file that is in use
# causes an exception to be raised."
os.close(h)
os.remove(caffemodel_file)

# Test weight sharing
Expand Down
5 changes: 4 additions & 1 deletion python/caffe/test/test_solver.py
Expand Up @@ -13,7 +13,10 @@ def setUp(self):
self.num_output = 13
net_f = simple_net_file(self.num_output)
f = tempfile.NamedTemporaryFile(mode='w+', delete=False)
f.write("""net: '""" + net_f + """'
net_f_mod = net_f
if os.name == 'nt':
net_f_mod = net_f_mod.replace("\\", "/")
f.write("""net: '""" + net_f_mod + """'
test_iter: 10 test_interval: 10 base_lr: 0.01 momentum: 0.9
weight_decay: 0.0005 lr_policy: 'inv' gamma: 0.0001 power: 0.75
display: 100 max_iter: 100 snapshot_after_train: false
Expand Down
9 changes: 9 additions & 0 deletions src/caffe/common.cpp
@@ -1,3 +1,8 @@
#if defined(_MSC_VER)
#include <process.h>
#define getpid() _getpid()
#endif

#include <boost/thread.hpp>
#include <glog/logging.h>
#include <cmath>
Expand Down Expand Up @@ -46,7 +51,11 @@ void GlobalInit(int* pargc, char*** pargv) {
// Google logging.
::google::InitGoogleLogging(*(pargv)[0]);
// Provide a backtrace on segfault.

// Windows port of glogs doesn't have this function built
#if !defined(_MSC_VER)
::google::InstallFailureSignalHandler();
#endif
}

#ifdef CPU_ONLY // CPU-only Caffe.
Expand Down
2 changes: 1 addition & 1 deletion src/caffe/layers/bnll_layer.cu
Expand Up @@ -5,7 +5,7 @@

namespace caffe {

const float kBNLL_THRESHOLD = 50.;
__constant__ float kBNLL_THRESHOLD = 50.;

template <typename Dtype>
__global__ void BNLLForward(const int n, const Dtype* in, Dtype* out) {
Expand Down
2 changes: 2 additions & 0 deletions src/caffe/test/test_blob.cpp
Expand Up @@ -35,12 +35,14 @@ TYPED_TEST(BlobSimpleTest, TestInitialization) {
EXPECT_EQ(this->blob_->count(), 0);
}

#if !defined(CPU_ONLY)
TYPED_TEST(BlobSimpleTest, TestPointersCPUGPU) {
EXPECT_TRUE(this->blob_preshaped_->gpu_data());
EXPECT_TRUE(this->blob_preshaped_->cpu_data());
EXPECT_TRUE(this->blob_preshaped_->mutable_gpu_data());
EXPECT_TRUE(this->blob_preshaped_->mutable_cpu_data());
}
#endif

TYPED_TEST(BlobSimpleTest, TestReshape) {
this->blob_->Reshape(2, 3, 4, 5);
Expand Down
15 changes: 9 additions & 6 deletions src/caffe/test/test_gradient_based_solver.cpp
Expand Up @@ -177,6 +177,9 @@ class GradientBasedSolverTest : public MultiDeviceTest<TypeParam> {
proto << "momentum: " << momentum << " ";
}
MakeTempDir(&snapshot_prefix_);
#if defined(_MSC_VER)
std::replace(snapshot_prefix_.begin(), snapshot_prefix_.end(), '\\', '/');
#endif
proto << "snapshot_prefix: '" << snapshot_prefix_ << "/' ";
if (snapshot) {
proto << "snapshot: " << num_iters << " ";
Expand Down Expand Up @@ -508,9 +511,8 @@ class GradientBasedSolverTest : public MultiDeviceTest<TypeParam> {
for (int i = 0; i < orig_params.size(); ++i) {
param_copies[i].reset(new Blob<Dtype>());
const bool kReshape = true;
for (int copy_diff = false; copy_diff <= true; ++copy_diff) {
param_copies[i]->CopyFrom(*orig_params[i], copy_diff, kReshape);
}
param_copies[i]->CopyFrom(*orig_params[i], false/*copy data*/, kReshape);
param_copies[i]->CopyFrom(*orig_params[i], true/*copy diff*/, kReshape);
}

// Save the solver history
Expand All @@ -520,9 +522,10 @@ class GradientBasedSolverTest : public MultiDeviceTest<TypeParam> {
for (int i = 0; i < orig_history.size(); ++i) {
history_copies[i].reset(new Blob<Dtype>());
const bool kReshape = true;
for (int copy_diff = false; copy_diff <= true; ++copy_diff) {
history_copies[i]->CopyFrom(*orig_history[i], copy_diff, kReshape);
}
history_copies[i]->CopyFrom(*orig_history[i],
false/*copy data*/, kReshape);
history_copies[i]->CopyFrom(*orig_history[i],
true/*copy diff*/, kReshape);
}

// Run the solver for num_iters iterations and snapshot.
Expand Down
9 changes: 4 additions & 5 deletions src/caffe/test/test_lrn_layer.cpp
Expand Up @@ -279,11 +279,10 @@ class CuDNNLRNLayerTest : public GPUDeviceTest<Dtype> {
vector<Blob<Dtype>*> blob_top_vec_;
};

template <typename TypeParam>
void CuDNNLRNLayerTest<TypeParam>::ReferenceLRNForward(
const Blob<TypeParam>& blob_bottom, const LayerParameter& layer_param,
Blob<TypeParam>* blob_top) {
typedef TypeParam Dtype;
template <typename Dtype>
void CuDNNLRNLayerTest<Dtype>::ReferenceLRNForward(
const Blob<Dtype>& blob_bottom, const LayerParameter& layer_param,
Blob<Dtype>* blob_top) {
blob_top->Reshape(blob_bottom.num(), blob_bottom.channels(),
blob_bottom.height(), blob_bottom.width());
Dtype* top_data = blob_top->mutable_cpu_data();
Expand Down
14 changes: 14 additions & 0 deletions src/caffe/util/db_lmdb.cpp
@@ -1,13 +1,27 @@
#ifdef USE_LMDB
#include "caffe/util/db_lmdb.hpp"

#if defined(_MSC_VER)
#include <direct.h>
#define mkdir(X, Y) _mkdir(X)
#endif

#include <sys/stat.h>

#include <string>

namespace caffe { namespace db {

#ifdef _MSC_VER
// On Windows lmdb creates file with the full size causing test failures due
// to insufficient disk space. We will reduce lmdb size to make tests pass.
const size_t LMDB_MAP_SIZE = 104857600; // 100 MB
// Constant will overflow on 32-bit build, assert that we are using correct
// build.
static_assert(sizeof(size_t) >= 8, "LMDB size overflow.");
#else
const size_t LMDB_MAP_SIZE = 1099511627776; // 1 TB
#endif

void LMDB::Open(const string& source, Mode mode) {
MDB_CHECK(mdb_env_create(&mdb_env_));
Expand Down
55 changes: 41 additions & 14 deletions src/caffe/util/hdf5.cpp
Expand Up @@ -29,31 +29,58 @@ void hdf5_load_nd_dataset_helper(
CHECK_GE(status, 0) << "Failed to get dataset info for " << dataset_name_;
switch (class_) {
case H5T_FLOAT:
LOG_FIRST_N(INFO, 1) << "Datatype class: H5T_FLOAT";
break;
// In VC++ declaring and initializing variables in case statement without
// curly braces (new scope), cause compiler error C2360
// https://msdn.microsoft.com/en-us/library/61af7cx3.aspx
{
LOG_FIRST_N(INFO, 1) << "Datatype class: H5T_FLOAT";
break;
}
case H5T_INTEGER:
LOG_FIRST_N(INFO, 1) << "Datatype class: H5T_INTEGER";
break;
{
LOG_FIRST_N(INFO, 1) << "Datatype class: H5T_INTEGER";
break;
}
case H5T_TIME:
LOG(FATAL) << "Unsupported datatype class: H5T_TIME";
{
LOG(FATAL) << "Unsupported datatype class: H5T_TIME";
}
case H5T_STRING:
LOG(FATAL) << "Unsupported datatype class: H5T_STRING";
{
LOG(FATAL) << "Unsupported datatype class: H5T_STRING";
}
case H5T_BITFIELD:
LOG(FATAL) << "Unsupported datatype class: H5T_BITFIELD";
{
LOG(FATAL) << "Unsupported datatype class: H5T_BITFIELD";
}
case H5T_OPAQUE:
LOG(FATAL) << "Unsupported datatype class: H5T_OPAQUE";
{
LOG(FATAL) << "Unsupported datatype class: H5T_OPAQUE";
}
case H5T_COMPOUND:
LOG(FATAL) << "Unsupported datatype class: H5T_COMPOUND";
{
LOG(FATAL) << "Unsupported datatype class: H5T_COMPOUND";
}
case H5T_REFERENCE:
LOG(FATAL) << "Unsupported datatype class: H5T_REFERENCE";
{
LOG(FATAL) << "Unsupported datatype class: H5T_REFERENCE";
}
case H5T_ENUM:
LOG(FATAL) << "Unsupported datatype class: H5T_ENUM";
{
LOG(FATAL) << "Unsupported datatype class: H5T_ENUM";
}
case H5T_VLEN:
LOG(FATAL) << "Unsupported datatype class: H5T_VLEN";
{
LOG(FATAL) << "Unsupported datatype class: H5T_VLEN";
}
case H5T_ARRAY:
LOG(FATAL) << "Unsupported datatype class: H5T_ARRAY";
{
LOG(FATAL) << "Unsupported datatype class: H5T_ARRAY";
}
default:
LOG(FATAL) << "Datatype class unknown";
{
LOG(FATAL) << "Datatype class unknown";
}
}

vector<int> blob_dims(dims.size());
Expand Down

0 comments on commit 52f7402

Please sign in to comment.