Hello,
I am trying to link mxnet to an existing C++ application under windows.
Basically, I only need to be able to use the prediction API (and nothing more), since
the networks will have been trained under python.
So far, I have tested two approaches ;
Use the amalgamation
The amalgamation is intended to provide an easy to compile only the prediction API.
However, a quick analysis of the code (esp. the Makefile) shows that this solution is not ready for windows, and there might be a lot of work in order to get it running.
Did anyone succeed in building it under windows, and is there a documented procedure?
Build mxnet myself under windows as a shared library :
I guess that this is the preferred solution, and I would link my application against it.
So, my goal was to build libmxnet.dll, and then try to build a simple prediction project that would link to it. My project is comprised of a simple cc file, which is a copy of the the image-classification-predict example. It also links to OpenCV.
However I ran into a problem, which is that mxnet (and all its third parties) are configured to use the static runtime library (/MT), whereas the default behavior of Visual Studio and cmake it to use the dynamic runtime library (aka /MD or “MultiThreaded DLL”).
Visual Studio will refuse my project to link to libmxnet since my project uses the /MT flag : this is the de facto norm, as most of the libraries (opencv and others) are compiled with this flag by default.
So far, I have had to patch mxnet as well as most of its third parties’ CMakeLists
).
I was successful, but it was tedious and not pretty. I explain what I had to patch below.
Is there a better solution?
Is my patch interesting, or am I completely out of line?
=============
Below is the list of the modification I have had to make.
I added an option USE_MSVC_MT
:
- if this option is set to “OFF”, then we then compile a library with the
/MD
flag. - if this option is set to “ON”, then we compile as before (this is the default)
Main repository :
add USE_MSVC_MT
option
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 483108a68..2facf17f1 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -9,6 +9,9 @@ endif()
include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/Utils.cmake)
#Some things have order. This must be put in front alone
+if (MSVC)
+ mxnet_option(USE_MSVC_MT "Build with /MT Runtime Library instead of /MD (DLL)" ON)
+endif()
mxnet_option(USE_CUDA "Build with CUDA support" ON)
mxnet_option(USE_OLDCMAKECUDA "Build with old cmake cuda" OFF)
mxnet_option(USE_NCCL "Use NVidia NCCL with CUDA" OFF)
@@ -507,7 +510,7 @@ if (NOT (EXTRA_OPERATORS STREQUAL ""))
list(APPEND SOURCE ${EXTRA_SRC} ${EXTRA_CUSRC})
endif()
-if(MSVC)
+if(MSVC AND USE_MSVC_MT)
foreach(flag_var
CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE
CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELWITHDEBINFO)
3rdparty/tvm
I removed the option USE_MSVC_MT
from here, since it is now placed it in the main CMakeLists file
Entering '3rdparty/tvm'
diff --git a/CMakeLists.txt b/CMakeLists.txt
index e9699b1f..6603f429 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -37,7 +37,7 @@ tvm_option(USE_LLVM "Build with LLVM, can be set to specific llvm-config path" O
tvm_option(USE_GRAPH_RUNTIME "Build with tiny graph runtime" ON)
tvm_option(USE_GRAPH_RUNTIME_DEBUG "Build with tiny graph runtime debug mode" OFF)
tvm_option(USE_RTTI "Build with RTTI" ON)
-tvm_option(USE_MSVC_MT "Build with MT" OFF)
+#tvm_option(USE_MSVC_MT "Build with MT" OFF)
tvm_option(INSTALL_DEV "Install compiler infrastructure" OFF)
# Contrib library options
3rdparty/cub subrepo:
Entering '3rdparty/cub'
diff --git a/common.mk b/common.mk
index 8154850..4a588e8 100644
--- a/common.mk
+++ b/common.mk
@@ -198,7 +198,8 @@ ifeq (WIN_NT, $(findstring WIN_NT, $(OSUPPER)))
CC = cl
# Multithreaded runtime
- NVCCFLAGS += -Xcompiler /MT
+ # NVCCFLAGS += -Xcompiler /MT
+ NVCCFLAGS += -Xcompiler /MD
ifneq ($(force32), 1)
CUDART_CYG = "$(shell dirname $(NVCC))/../lib/Win32/cudart.lib"
dlmc-core :
Take into account the USE_MSVC_MT
option.
I also had to specify the library type (static).
Also, I had to make a difference for the FLAGS_gtest_death_test_style
initialization (gtest is for /MT by default)
Entering '3rdparty/dmlc-core'
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 7839e9f..8e88c88 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -63,13 +63,15 @@ add_definitions(-D__USE_XOPEN2K8)
# compile
if(MSVC)
add_definitions(-DDMLC_USE_CXX11)
- foreach(flag_var
- CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE
- CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELWITHDEBINFO)
- if(${flag_var} MATCHES "/MD")
- string(REGEX REPLACE "/MD" "/MT" ${flag_var} "${${flag_var}}")
- endif(${flag_var} MATCHES "/MD")
- endforeach(flag_var)
+ if (USE_MSVC_MT)
+ foreach(flag_var
+ CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE
+ CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELWITHDEBINFO)
+ if(${flag_var} MATCHES "/MD")
+ string(REGEX REPLACE "/MD" "/MT" ${flag_var} "${${flag_var}}")
+ endif(${flag_var} MATCHES "/MD")
+ endforeach(flag_var)
+ endif()
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /EHsc")
else(MSVC)
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
@@ -144,7 +146,8 @@ if(USE_AZURE)
list(APPEND SOURCE "src/io/azure_filesys.cc")
endif()
-add_library(dmlc ${SOURCE})
+# add_library(dmlc ${SOURCE})
+add_library(dmlc STATIC ${SOURCE})
target_link_libraries(dmlc ${dmlccore_LINKER_LIBS})
# ---[ Install Includes
diff --git a/test/unittest/unittest_main.cc b/test/unittest/unittest_main.cc
index 14525c7..06393c3 100644
--- a/test/unittest/unittest_main.cc
+++ b/test/unittest/unittest_main.cc
@@ -3,6 +3,8 @@
int main(int argc, char ** argv) {
testing::InitGoogleTest(&argc, argv);
+#ifndef _MSC_VER
testing::FLAGS_gtest_death_test_style = "threadsafe";
+#endif
return RUN_ALL_TESTS();
}
openmp
Entering '3rdparty/openmp'
diff --git a/runtime/cmake/config-ix.cmake b/runtime/cmake/config-ix.cmake
index 0375d21..bd839b8 100644
--- a/runtime/cmake/config-ix.cmake
+++ b/runtime/cmake/config-ix.cmake
@@ -86,14 +86,16 @@ if(WIN32)
set(LIBOMP_HAVE_SAFESEH_MASM_FLAG TRUE)
set(LIBOMP_HAVE_COFF_MASM_FLAG TRUE)
# Change Windows flags /MDx to /MTx
- foreach(libomp_lang IN ITEMS C CXX)
- foreach(libomp_btype IN ITEMS DEBUG RELWITHDEBINFO RELEASE MINSIZEREL)
- string(REPLACE "/MD" "/MT"
- CMAKE_${libomp_lang}_FLAGS_${libomp_btype}
- "${CMAKE_${libomp_lang}_FLAGS_${libomp_btype}}"
- )
+ if (USE_MSVC_MT)
+ foreach(libomp_lang IN ITEMS C CXX)
+ foreach(libomp_btype IN ITEMS DEBUG RELWITHDEBINFO RELEASE MINSIZEREL)
+ string(REPLACE "/MD" "/MT"
+ CMAKE_${libomp_lang}_FLAGS_${libomp_btype}
+ "${CMAKE_${libomp_lang}_FLAGS_${libomp_btype}}"
+ )
+ endforeach()
endforeach()
- endforeach()
+ endif()
else()
# It is difficult to create a dummy assembly file that compiles into an
# exectuable for every architecture and then check the C compiler to
ps-lite
Entering '3rdparty/ps-lite'
diff --git a/CMakeLists.txt b/CMakeLists.txt
index ef566e5..c8c28b9 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -34,19 +34,21 @@ list(APPEND pslite_INCLUDE_DIR_L "${PROJECT_BINARY_DIR}/include/")
FILE(GLOB SOURCE "src/*.cc")
if(MSVC)
-set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /EHsc")
-FILE(GLOB getopt_SOURCE "src/windows/getopt.c")
-list(APPEND SOURCE ${getopt_SOURCE})
-add_definitions(-DSTATIC_GETOPT)
-include_directories(pslite "${PROJECT_SOURCE_DIR}/src/windows")
-list(APPEND pslite_LINKER_LIBS_L "ipHlpApi.lib" "ws2_32.lib")
- foreach(flag_var
- CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE
- CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELWITHDEBINFO)
- if(${flag_var} MATCHES "/MD")
- string(REGEX REPLACE "/MD" "/MT" ${flag_var} "${${flag_var}}")
- endif(${flag_var} MATCHES "/MD")
- endforeach(flag_var)
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /EHsc")
+ FILE(GLOB getopt_SOURCE "src/windows/getopt.c")
+ list(APPEND SOURCE ${getopt_SOURCE})
+ add_definitions(-DSTATIC_GETOPT)
+ include_directories(pslite "${PROJECT_SOURCE_DIR}/src/windows")
+ list(APPEND pslite_LINKER_LIBS_L "ipHlpApi.lib" "ws2_32.lib")
+ if (USE_MSVC_MT)
+ foreach(flag_var
+ CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE
+ CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELWITHDEBINFO)
+ if(${flag_var} MATCHES "/MD")
+ string(REGEX REPLACE "/MD" "/MT" ${flag_var} "${${flag_var}}")
+ endif(${flag_var} MATCHES "/MD")
+ endforeach(flag_var)
+ endif()
endif()
list(APPEND SOURCE ${proto_srcs})