mirror of
https://github.com/pytorch/pytorch.git
synced 2025-10-20 21:14:14 +08:00
Summary: (Note: previous revert was due to a race condition between D4657831 and D4659953 that I failed to catch.) After this, we should have contbuild guarding the Windows build both with and without CUDA. This includes a series of changes that are needed to make Windows build, specifically: (1) Various flags that are needed in the cmake system, specially dealing with /MD, /MT, cuda, cudnn, whole static linking, etc. (2) Contbuild scripts based on appveyo. (3) For Windows build, note that one will need to use "cmake --build" to build stuff so that the build type is consistent between configuration and actual build. see scripts\build_windows.bat for details. (4) In logging.h, ERROR is already defined by Windows. I don't have a good solution now, and as a result, LOG(ERROR) on windows is going to be LOG(INFO). (5) variable length array is not supported by MSVC (and it is not part of C++ standard). As a result I replaced them with vectors. (6) sched.h is not available on Windows, so akyrola 's awesome simple async net might encounter some slowdown due to no affinity setting on Windows. (7) MSVC has a bug that does not work very well with template calls inide a templated function call, which is a known issue that should be fixed in MSVC 2017. However for now this means changes to conv_op_impl.h and recurrent_net_op.h. No actual functionalities are changed. (8) std host function calls are not supported in CUDA8+MSVC, so I changed lp_pool (and maybe a few others) to use cuda device functions. (9) The current Scale and Axpy has heavy templating that does not work well with MSVC. As a result I reverted azzolini 's changes to the Scale and Axpy interface, moved the fixed-length version to ScaleFixedSize and AxpyFixedSize. (10) CUDA + MSVC does not deal with Eigen well, so I guarded all Eigen parts to only the non-CUDA part. (11) In conclusion, it is fun but painful to deal with visual c++. Differential Revision: D4666745 fbshipit-source-id: 3c9035083067bdb19a16d9c345c1ce66b6a86600
426 lines
15 KiB
CMake
426 lines
15 KiB
CMake
################################################################################################
|
|
# Command alias for debugging messages
|
|
# Usage:
|
|
# dmsg(<message>)
|
|
function(dmsg)
|
|
message(STATUS ${ARGN})
|
|
endfunction()
|
|
|
|
################################################################################################
|
|
# Removes duplicates from list(s)
|
|
# Usage:
|
|
# caffe_list_unique(<list_variable> [<list_variable>] [...])
|
|
macro(caffe_list_unique)
|
|
foreach(__lst ${ARGN})
|
|
if(${__lst})
|
|
list(REMOVE_DUPLICATES ${__lst})
|
|
endif()
|
|
endforeach()
|
|
endmacro()
|
|
|
|
################################################################################################
|
|
# Clears variables from list
|
|
# Usage:
|
|
# caffe_clear_vars(<variables_list>)
|
|
macro(caffe_clear_vars)
|
|
foreach(_var ${ARGN})
|
|
unset(${_var})
|
|
endforeach()
|
|
endmacro()
|
|
|
|
################################################################################################
|
|
# Removes duplicates from string
|
|
# Usage:
|
|
# caffe_string_unique(<string_variable>)
|
|
function(caffe_string_unique __string)
|
|
if(${__string})
|
|
set(__list ${${__string}})
|
|
separate_arguments(__list)
|
|
list(REMOVE_DUPLICATES __list)
|
|
foreach(__e ${__list})
|
|
set(__str "${__str} ${__e}")
|
|
endforeach()
|
|
set(${__string} ${__str} PARENT_SCOPE)
|
|
endif()
|
|
endfunction()
|
|
|
|
################################################################################################
|
|
# Prints list element per line
|
|
# Usage:
|
|
# caffe_print_list(<list>)
|
|
function(caffe_print_list)
|
|
foreach(e ${ARGN})
|
|
message(STATUS ${e})
|
|
endforeach()
|
|
endfunction()
|
|
|
|
################################################################################################
|
|
# Function merging lists of compiler flags to single string.
|
|
# Usage:
|
|
# caffe_merge_flag_lists(out_variable <list1> [<list2>] [<list3>] ...)
|
|
function(caffe_merge_flag_lists out_var)
|
|
set(__result "")
|
|
foreach(__list ${ARGN})
|
|
foreach(__flag ${${__list}})
|
|
string(STRIP ${__flag} __flag)
|
|
set(__result "${__result} ${__flag}")
|
|
endforeach()
|
|
endforeach()
|
|
string(STRIP ${__result} __result)
|
|
set(${out_var} ${__result} PARENT_SCOPE)
|
|
endfunction()
|
|
|
|
################################################################################################
|
|
# Converts all paths in list to absolute
|
|
# Usage:
|
|
# caffe_convert_absolute_paths(<list_variable>)
|
|
function(caffe_convert_absolute_paths variable)
|
|
set(__dlist "")
|
|
foreach(__s ${${variable}})
|
|
get_filename_component(__abspath ${__s} ABSOLUTE)
|
|
list(APPEND __list ${__abspath})
|
|
endforeach()
|
|
set(${variable} ${__list} PARENT_SCOPE)
|
|
endfunction()
|
|
|
|
################################################################################################
|
|
# Reads set of version defines from the header file
|
|
# Usage:
|
|
# caffe_parse_header(<file> <define1> <define2> <define3> ..)
|
|
macro(caffe_parse_header FILENAME FILE_VAR)
|
|
set(vars_regex "")
|
|
set(__parnet_scope OFF)
|
|
set(__add_cache OFF)
|
|
foreach(name ${ARGN})
|
|
if("${name}" STREQUAL "PARENT_SCOPE")
|
|
set(__parnet_scope ON)
|
|
elseif("${name}" STREQUAL "CACHE")
|
|
set(__add_cache ON)
|
|
elseif(vars_regex)
|
|
set(vars_regex "${vars_regex}|${name}")
|
|
else()
|
|
set(vars_regex "${name}")
|
|
endif()
|
|
endforeach()
|
|
if(EXISTS "${FILENAME}")
|
|
file(STRINGS "${FILENAME}" ${FILE_VAR} REGEX "#define[ \t]+(${vars_regex})[ \t]+[0-9]+" )
|
|
else()
|
|
unset(${FILE_VAR})
|
|
endif()
|
|
foreach(name ${ARGN})
|
|
if(NOT "${name}" STREQUAL "PARENT_SCOPE" AND NOT "${name}" STREQUAL "CACHE")
|
|
if(${FILE_VAR})
|
|
if(${FILE_VAR} MATCHES ".+[ \t]${name}[ \t]+([0-9]+).*")
|
|
string(REGEX REPLACE ".+[ \t]${name}[ \t]+([0-9]+).*" "\\1" ${name} "${${FILE_VAR}}")
|
|
else()
|
|
set(${name} "")
|
|
endif()
|
|
if(__add_cache)
|
|
set(${name} ${${name}} CACHE INTERNAL "${name} parsed from ${FILENAME}" FORCE)
|
|
elseif(__parnet_scope)
|
|
set(${name} "${${name}}" PARENT_SCOPE)
|
|
endif()
|
|
else()
|
|
unset(${name} CACHE)
|
|
endif()
|
|
endif()
|
|
endforeach()
|
|
endmacro()
|
|
|
|
################################################################################################
|
|
# Reads single version define from the header file and parses it
|
|
# Usage:
|
|
# caffe_parse_header_single_define(<library_name> <file> <define_name>)
|
|
function(caffe_parse_header_single_define LIBNAME HDR_PATH VARNAME)
|
|
set(${LIBNAME}_H "")
|
|
if(EXISTS "${HDR_PATH}")
|
|
file(STRINGS "${HDR_PATH}" ${LIBNAME}_H REGEX "^#define[ \t]+${VARNAME}[ \t]+\"[^\"]*\".*$" LIMIT_COUNT 1)
|
|
endif()
|
|
|
|
if(${LIBNAME}_H)
|
|
string(REGEX REPLACE "^.*[ \t]${VARNAME}[ \t]+\"([0-9]+).*$" "\\1" ${LIBNAME}_VERSION_MAJOR "${${LIBNAME}_H}")
|
|
string(REGEX REPLACE "^.*[ \t]${VARNAME}[ \t]+\"[0-9]+\\.([0-9]+).*$" "\\1" ${LIBNAME}_VERSION_MINOR "${${LIBNAME}_H}")
|
|
string(REGEX REPLACE "^.*[ \t]${VARNAME}[ \t]+\"[0-9]+\\.[0-9]+\\.([0-9]+).*$" "\\1" ${LIBNAME}_VERSION_PATCH "${${LIBNAME}_H}")
|
|
set(${LIBNAME}_VERSION_MAJOR ${${LIBNAME}_VERSION_MAJOR} ${ARGN} PARENT_SCOPE)
|
|
set(${LIBNAME}_VERSION_MINOR ${${LIBNAME}_VERSION_MINOR} ${ARGN} PARENT_SCOPE)
|
|
set(${LIBNAME}_VERSION_PATCH ${${LIBNAME}_VERSION_PATCH} ${ARGN} PARENT_SCOPE)
|
|
set(${LIBNAME}_VERSION_STRING "${${LIBNAME}_VERSION_MAJOR}.${${LIBNAME}_VERSION_MINOR}.${${LIBNAME}_VERSION_PATCH}" PARENT_SCOPE)
|
|
|
|
# append a TWEAK version if it exists:
|
|
set(${LIBNAME}_VERSION_TWEAK "")
|
|
if("${${LIBNAME}_H}" MATCHES "^.*[ \t]${VARNAME}[ \t]+\"[0-9]+\\.[0-9]+\\.[0-9]+\\.([0-9]+).*$")
|
|
set(${LIBNAME}_VERSION_TWEAK "${CMAKE_MATCH_1}" ${ARGN} PARENT_SCOPE)
|
|
endif()
|
|
if(${LIBNAME}_VERSION_TWEAK)
|
|
set(${LIBNAME}_VERSION_STRING "${${LIBNAME}_VERSION_STRING}.${${LIBNAME}_VERSION_TWEAK}" ${ARGN} PARENT_SCOPE)
|
|
else()
|
|
set(${LIBNAME}_VERSION_STRING "${${LIBNAME}_VERSION_STRING}" ${ARGN} PARENT_SCOPE)
|
|
endif()
|
|
endif()
|
|
endfunction()
|
|
|
|
########################################################################################################
|
|
# An option that the user can select. Can accept condition to control when option is available for user.
|
|
# Usage:
|
|
# caffe_option(<option_variable> "doc string" <initial value or boolean expression> [IF <condition>])
|
|
function(caffe_option variable description value)
|
|
set(__value ${value})
|
|
set(__condition "")
|
|
set(__varname "__value")
|
|
foreach(arg ${ARGN})
|
|
if(arg STREQUAL "IF" OR arg STREQUAL "if")
|
|
set(__varname "__condition")
|
|
else()
|
|
list(APPEND ${__varname} ${arg})
|
|
endif()
|
|
endforeach()
|
|
unset(__varname)
|
|
if("${__condition}" STREQUAL "")
|
|
set(__condition 2 GREATER 1)
|
|
endif()
|
|
|
|
if(${__condition})
|
|
if("${__value}" MATCHES ";")
|
|
if(${__value})
|
|
option(${variable} "${description}" ON)
|
|
else()
|
|
option(${variable} "${description}" OFF)
|
|
endif()
|
|
elseif(DEFINED ${__value})
|
|
if(${__value})
|
|
option(${variable} "${description}" ON)
|
|
else()
|
|
option(${variable} "${description}" OFF)
|
|
endif()
|
|
else()
|
|
option(${variable} "${description}" ${__value})
|
|
endif()
|
|
else()
|
|
unset(${variable} CACHE)
|
|
endif()
|
|
endfunction()
|
|
|
|
################################################################################################
|
|
# Utility macro for comparing two lists. Used for CMake debugging purposes
|
|
# Usage:
|
|
# caffe_compare_lists(<list_variable> <list2_variable> [description])
|
|
function(caffe_compare_lists list1 list2 desc)
|
|
set(__list1 ${${list1}})
|
|
set(__list2 ${${list2}})
|
|
list(SORT __list1)
|
|
list(SORT __list2)
|
|
list(LENGTH __list1 __len1)
|
|
list(LENGTH __list2 __len2)
|
|
|
|
if(NOT ${__len1} EQUAL ${__len2})
|
|
message(FATAL_ERROR "Lists are not equal. ${__len1} != ${__len2}. ${desc}")
|
|
endif()
|
|
|
|
foreach(__i RANGE 1 ${__len1})
|
|
math(EXPR __index "${__i}- 1")
|
|
list(GET __list1 ${__index} __item1)
|
|
list(GET __list2 ${__index} __item2)
|
|
if(NOT ${__item1} STREQUAL ${__item2})
|
|
message(FATAL_ERROR "Lists are not equal. Differ at element ${__index}. ${desc}")
|
|
endif()
|
|
endforeach()
|
|
endfunction()
|
|
|
|
################################################################################################
|
|
# Command for disabling warnings for different platforms (see below for gcc and VisualStudio)
|
|
# Usage:
|
|
# caffe_warnings_disable(<CMAKE_[C|CXX]_FLAGS[_CONFIGURATION]> -Wshadow /wd4996 ..,)
|
|
macro(caffe_warnings_disable)
|
|
set(_flag_vars "")
|
|
set(_msvc_warnings "")
|
|
set(_gxx_warnings "")
|
|
|
|
foreach(arg ${ARGN})
|
|
if(arg MATCHES "^CMAKE_")
|
|
list(APPEND _flag_vars ${arg})
|
|
elseif(arg MATCHES "^/wd")
|
|
list(APPEND _msvc_warnings ${arg})
|
|
elseif(arg MATCHES "^-W")
|
|
list(APPEND _gxx_warnings ${arg})
|
|
endif()
|
|
endforeach()
|
|
|
|
if(NOT _flag_vars)
|
|
set(_flag_vars CMAKE_C_FLAGS CMAKE_CXX_FLAGS)
|
|
endif()
|
|
|
|
if(MSVC AND _msvc_warnings)
|
|
foreach(var ${_flag_vars})
|
|
foreach(warning ${_msvc_warnings})
|
|
set(${var} "${${var}} ${warning}")
|
|
endforeach()
|
|
endforeach()
|
|
elseif((CMAKE_COMPILER_IS_GNUCXX OR CMAKE_COMPILER_IS_CLANGXX) AND _gxx_warnings)
|
|
foreach(var ${_flag_vars})
|
|
foreach(warning ${_gxx_warnings})
|
|
if(NOT warning MATCHES "^-Wno-")
|
|
string(REPLACE "${warning}" "" ${var} "${${var}}")
|
|
string(REPLACE "-W" "-Wno-" warning "${warning}")
|
|
endif()
|
|
set(${var} "${${var}} ${warning}")
|
|
endforeach()
|
|
endforeach()
|
|
endif()
|
|
caffe_clear_vars(_flag_vars _msvc_warnings _gxx_warnings)
|
|
endmacro()
|
|
|
|
################################################################################################
|
|
# Helper function get current definitions
|
|
# Usage:
|
|
# caffe_get_current_definitions(<definitions_variable>)
|
|
function(caffe_get_current_definitions definitions_var)
|
|
get_property(current_definitions DIRECTORY PROPERTY COMPILE_DEFINITIONS)
|
|
set(result "")
|
|
|
|
foreach(d ${current_definitions})
|
|
list(APPEND result -D${d})
|
|
endforeach()
|
|
|
|
caffe_list_unique(result)
|
|
set(${definitions_var} ${result} PARENT_SCOPE)
|
|
endfunction()
|
|
|
|
################################################################################################
|
|
# Helper function get current includes/definitions
|
|
# Usage:
|
|
# caffe_get_current_cflags(<cflagslist_variable>)
|
|
function(caffe_get_current_cflags cflags_var)
|
|
get_property(current_includes DIRECTORY PROPERTY INCLUDE_DIRECTORIES)
|
|
caffe_convert_absolute_paths(current_includes)
|
|
caffe_get_current_definitions(cflags)
|
|
|
|
foreach(i ${current_includes})
|
|
list(APPEND cflags "-I${i}")
|
|
endforeach()
|
|
|
|
caffe_list_unique(cflags)
|
|
set(${cflags_var} ${cflags} PARENT_SCOPE)
|
|
endfunction()
|
|
|
|
################################################################################################
|
|
# Helper function to parse current linker libs into link directories, libflags and osx frameworks
|
|
# Usage:
|
|
# caffe_parse_linker_libs(<Caffe_LINKER_LIBS_var> <directories_var> <libflags_var> <frameworks_var>)
|
|
function(caffe_parse_linker_libs Caffe_LINKER_LIBS_variable folders_var flags_var frameworks_var)
|
|
|
|
set(__unspec "")
|
|
set(__debug "")
|
|
set(__optimized "")
|
|
set(__framework "")
|
|
set(__varname "__unspec")
|
|
|
|
# split libs into debug, optimized, unspecified and frameworks
|
|
foreach(list_elem ${${Caffe_LINKER_LIBS_variable}})
|
|
if(list_elem STREQUAL "debug")
|
|
set(__varname "__debug")
|
|
elseif(list_elem STREQUAL "optimized")
|
|
set(__varname "__optimized")
|
|
elseif(list_elem MATCHES "^-framework[ \t]+([^ \t].*)")
|
|
list(APPEND __framework -framework ${CMAKE_MATCH_1})
|
|
else()
|
|
list(APPEND ${__varname} ${list_elem})
|
|
set(__varname "__unspec")
|
|
endif()
|
|
endforeach()
|
|
|
|
# attach debug or optimized libs to unspecified according to current configuration
|
|
if(CMAKE_BUILD_TYPE MATCHES "Debug")
|
|
set(__libs ${__unspec} ${__debug})
|
|
else()
|
|
set(__libs ${__unspec} ${__optimized})
|
|
endif()
|
|
|
|
set(libflags "")
|
|
set(folders "")
|
|
|
|
# convert linker libraries list to link flags
|
|
foreach(lib ${__libs})
|
|
if(TARGET ${lib})
|
|
list(APPEND folders $<TARGET_LINKER_FILE_DIR:${lib}>)
|
|
list(APPEND libflags -l${lib})
|
|
elseif(lib MATCHES "^-l.*")
|
|
list(APPEND libflags ${lib})
|
|
elseif(IS_ABSOLUTE ${lib})
|
|
get_filename_component(folder ${lib} PATH)
|
|
get_filename_component(filename ${lib} NAME)
|
|
string(REGEX REPLACE "\\.[^.]*$" "" filename_without_shortest_ext ${filename})
|
|
|
|
string(REGEX MATCH "^lib(.*)" __match ${filename_without_shortest_ext})
|
|
list(APPEND libflags -l${CMAKE_MATCH_1})
|
|
list(APPEND folders ${folder})
|
|
else()
|
|
message(FATAL_ERROR "Logic error. Need to update cmake script")
|
|
endif()
|
|
endforeach()
|
|
|
|
caffe_list_unique(libflags folders)
|
|
|
|
set(${folders_var} ${folders} PARENT_SCOPE)
|
|
set(${flags_var} ${libflags} PARENT_SCOPE)
|
|
set(${frameworks_var} ${__framework} PARENT_SCOPE)
|
|
endfunction()
|
|
|
|
################################################################################################
|
|
# Helper function to detect Darwin version, i.e. 10.8, 10.9, 10.10, ....
|
|
# Usage:
|
|
# caffe_detect_darwin_version(<version_variable>)
|
|
function(caffe_detect_darwin_version output_var)
|
|
if(APPLE)
|
|
execute_process(COMMAND /usr/bin/sw_vers -productVersion
|
|
RESULT_VARIABLE __sw_vers OUTPUT_VARIABLE __sw_vers_out
|
|
ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE)
|
|
|
|
set(${output_var} ${__sw_vers_out} PARENT_SCOPE)
|
|
else()
|
|
set(${output_var} "" PARENT_SCOPE)
|
|
endif()
|
|
endfunction()
|
|
|
|
function(caffe_add_whole_archive_flag lib output_var)
|
|
if("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")
|
|
set(${output_var} -Wl,-force_load,$<TARGET_FILE:${lib}> PARENT_SCOPE)
|
|
elseif(MSVC)
|
|
# In MSVC, we will add whole archive in default.
|
|
set(${output_var} -WHOLEARCHIVE:$<TARGET_FILE:${lib}> PARENT_SCOPE)
|
|
else()
|
|
# Assume everything else is like gcc
|
|
set(${output_var} -Wl,--whole-archive ${lib} -Wl,--no-whole-archive PARENT_SCOPE)
|
|
endif()
|
|
endfunction()
|
|
|
|
##############################################################################
|
|
# Helper function to automatically generate __init__.py files where python
|
|
# sources reside but there are no __init__.py present.
|
|
function(caffe_autogen_init_py_files)
|
|
file(GLOB_RECURSE all_python_files RELATIVE ${PROJECT_SOURCE_DIR}
|
|
"${PROJECT_SOURCE_DIR}/caffe2/*.py")
|
|
set(python_paths_need_init_py)
|
|
foreach(python_file ${all_python_files})
|
|
get_filename_component(python_path ${python_file} PATH)
|
|
string(REPLACE "/" ";" path_parts ${python_path})
|
|
set(rebuilt_path ${CMAKE_BINARY_DIR})
|
|
foreach(path_part ${path_parts})
|
|
set(rebuilt_path "${rebuilt_path}/${path_part}")
|
|
list(APPEND python_paths_need_init_py ${rebuilt_path})
|
|
endforeach()
|
|
endforeach()
|
|
list(REMOVE_DUPLICATES python_paths_need_init_py)
|
|
# Since the _pb2.py files are yet to be created, we will need to manually
|
|
# add them to the list.
|
|
list(APPEND python_paths_need_init_py ${CMAKE_BINARY_DIR}/caffe)
|
|
list(APPEND python_paths_need_init_py ${CMAKE_BINARY_DIR}/caffe/proto)
|
|
list(APPEND python_paths_need_init_py ${CMAKE_BINARY_DIR}/caffe2/proto)
|
|
|
|
foreach(tmp ${python_paths_need_init_py})
|
|
if(NOT EXISTS ${tmp}/__init__.py)
|
|
# message(STATUS "Generate " ${tmp}/__init__.py)
|
|
file(WRITE ${tmp}/__init__.py "")
|
|
endif()
|
|
endforeach()
|
|
endfunction()
|