Repository: Project-MONAI/MONAI

Issue:
Failed to build from the latest source cloned from git 
I cloned the latest source code from git and tried to build with python setup.py develop as suggested in the doc, but the following errors occured. Could anyone point out what is the problem?

setup.py with torch 1.5.1
running develop
running egg_info
writing monai.egg-info\PKG-INFO
writing dependency_links to monai.egg-info\dependency_links.txt
writing requirements to monai.egg-info\requires.txt
writing top-level names to monai.egg-info\top_level.txt
reading manifest file 'monai.egg-info\SOURCES.txt'
reading manifest template 'MANIFEST.in'
writing manifest file 'monai.egg-info\SOURCES.txt'
running build_ext
C:\Users\Admin\anaconda3\envs\pytorch\lib\site-packages\torch\utils\cpp_extension.py:238: UserWarning: Error checking compiler version for cl: [WinError 2] The system cannot find the file specified
  warnings.warn('Error checking compiler version for {}: {}'.format(compiler, error))
building 'monai._C' extension
Emitting ninja build file D:\Projects\MONAI\build\temp.win-amd64-3.6\Release\build.ninja...
Compiling objects...
Allowing ninja to set a default number of workers... (overridable by setting the environment variable MAX_JOBS=N)
[1/1] cl /showIncludes /nologo /Ox /W3 /GL /DNDEBUG /MD /MD /wd4819 /EHsc -IC:\Users\Admin\anaconda3\envs\pytorch\lib\site-packages\torch\include -IC:\Users\Admin\anaconda3\envs\pytorch\lib\site-packages\torch\include\torch\csrc\api\include -IC:\Users\Admin\anaconda3\envs\pytorch\lib\site-packages\torch\include\TH -IC:\Users\Admin\anaconda3\envs\pytorch\lib\site-packages\torch\include\THC -IC:\Users\Admin\anaconda3\envs\pytorch\include -IC:\Users\Admin\anaconda3\envs\pytorch\include "-IC:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\INCLUDE" "-IC:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\ATLMFC\INCLUDE" "-IC:\Program Files (x86)\Windows Kits\10\include\10.0.10240.0\ucrt" "-IC:\Program Files (x86)\Windows Kits\NETFXSDK\4.6.1\include\um" "-IC:\Program Files (x86)\Windows Kits\8.1\include\\shared" "-IC:\Program Files (x86)\Windows Kits\8.1\include\\um" "-IC:\Program Files (x86)\Windows Kits\8.1\include\\winrt" -c D:\Projects\MONAI\monai\networks\extensions\lltm\lltm.cpp /FoD:\Projects\MONAI\build\temp.win-amd64-3.6\Release\monai/networks/extensions/lltm/lltm.obj -DTORCH_API_INCLUDE_EXTENSION_H -DTORCH_EXTENSION_NAME=_C -D_GLIBCXX_USE_CXX11_ABI=0 /std:c++14
FAILED: D:/Projects/MONAI/build/temp.win-amd64-3.6/Release/monai/networks/extensions/lltm/lltm.obj
cl /showIncludes /nologo /Ox /W3 /GL /DNDEBUG /MD /MD /wd4819 /EHsc -IC:\Users\Admin\anaconda3\envs\pytorch\lib\site-packages\torch\include -IC:\Users\Admin\anaconda3\envs\pytorch\lib\site-packages\torch\include\torch\csrc\api\include -IC:\Users\Admin\anaconda3\envs\pytorch\lib\site-packages\torch\include\TH -IC:\Users\Admin\anaconda3\envs\pytorch\lib\site-packages\torch\include\THC -IC:\Users\Admin\anaconda3\envs\pytorch\include -IC:\Users\Admin\anaconda3\envs\pytorch\include "-IC:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\INCLUDE" "-IC:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\ATLMFC\INCLUDE" "-IC:\Program Files (x86)\Windows Kits\10\include\10.0.10240.0\ucrt" "-IC:\Program Files (x86)\Windows Kits\NETFXSDK\4.6.1\include\um" "-IC:\Program Files (x86)\Windows Kits\8.1\include\\shared" "-IC:\Program Files (x86)\Windows Kits\8.1\include\\um" "-IC:\Program Files (x86)\Windows Kits\8.1\include\\winrt" -c D:\Projects\MONAI\monai\networks\extensions\lltm\lltm.cpp /FoD:\Projects\MONAI\build\temp.win-amd64-3.6\Release\monai/networks/extensions/lltm/lltm.obj -DTORCH_API_INCLUDE_EXTENSION_H -DTORCH_EXTENSION_NAME=_C -D_GLIBCXX_USE_CXX11_ABI=0 /std:c++14
CreateProcess failed: The system cannot find the file specified.
ninja: build stopped: subcommand failed.
Traceback (most recent call last):
  File "C:\Users\Admin\anaconda3\envs\pytorch\lib\site-packages\torch\utils\cpp_extension.py", line 1423, in _run_ninja_build
    check=True)
  File "C:\Users\Admin\anaconda3\envs\pytorch\lib\subprocess.py", line 438, in run
    output=stdout, stderr=stderr)
subprocess.CalledProcessError: Command '['ninja', '-v']' returned non-zero exit status 1.

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "setup.py", line 58, in <module>
    ext_modules=get_extensions(),
  File "C:\Users\Admin\anaconda3\envs\pytorch\lib\site-packages\setuptools\__init__.py", line 161, in setup
    return distutils.core.setup(**attrs)
  File "C:\Users\Admin\anaconda3\envs\pytorch\lib\distutils\core.py", line 148, in setup
    dist.run_commands()
  File "C:\Users\Admin\anaconda3\envs\pytorch\lib\distutils\dist.py", line 955, in run_commands
    self.run_command(cmd)
  File "C:\Users\Admin\anaconda3\envs\pytorch\lib\distutils\dist.py", line 974, in run_command
    cmd_obj.run()
  File "C:\Users\Admin\anaconda3\envs\pytorch\lib\site-packages\setuptools\command\develop.py", line 38, in run
    self.install_for_development()
  File "C:\Users\Admin\anaconda3\envs\pytorch\lib\site-packages\setuptools\command\develop.py", line 140, in install_for_development
    self.run_command('build_ext')
  File "C:\Users\Admin\anaconda3\envs\pytorch\lib\distutils\cmd.py", line 313, in run_command
    self.distribution.run_command(command)
  File "C:\Users\Admin\anaconda3\envs\pytorch\lib\distutils\dist.py", line 974, in run_command
    cmd_obj.run()
  File "C:\Users\Admin\anaconda3\envs\pytorch\lib\site-packages\setuptools\command\build_ext.py", line 87, in run
    _build_ext.run(self)
  File "C:\Users\Admin\anaconda3\envs\pytorch\lib\distutils\command\build_ext.py", line 339, in run
    self.build_extensions()
  File "C:\Users\Admin\anaconda3\envs\pytorch\lib\site-packages\torch\utils\cpp_extension.py", line 603, in build_extensions
    build_ext.build_extensions(self)
  File "C:\Users\Admin\anaconda3\envs\pytorch\lib\distutils\command\build_ext.py", line 448, in build_extensions
    self._build_extensions_serial()
  File "C:\Users\Admin\anaconda3\envs\pytorch\lib\distutils\command\build_ext.py", line 473, in _build_extensions_serial
    self.build_extension(ext)
  File "C:\Users\Admin\anaconda3\envs\pytorch\lib\site-packages\setuptools\command\build_ext.py", line 208, in build_extension
    _build_ext.build_extension(self, ext)
  File "C:\Users\Admin\anaconda3\envs\pytorch\lib\distutils\command\build_ext.py", line 533, in build_extension
    depends=ext.depends)
  File "C:\Users\Admin\anaconda3\envs\pytorch\lib\site-packages\torch\utils\cpp_extension.py", line 585, in win_wrap_ninja_compile
    with_cuda=with_cuda)
  File "C:\Users\Admin\anaconda3\envs\pytorch\lib\site-packages\torch\utils\cpp_extension.py", line 1163, in _write_ninja_file_and_compile_objects
    error_prefix='Error compiling objects for extension')
  File "C:\Users\Admin\anaconda3\envs\pytorch\lib\site-packages\torch\utils\cpp_extension.py", line 1436, in _run_ninja_build
    raise RuntimeError(message)
RuntimeError: Error compiling objects for extension


Discussion:

Resolving patch:
diff --git a/monai/networks/layers/simplelayers.py b/monai/networks/layers/simplelayers.py
--- a/monai/networks/layers/simplelayers.py
+++ b/monai/networks/layers/simplelayers.py
@@ -21,7 +21,6 @@
 from monai.utils import ensure_tuple_rep, optional_import
 
 _C, _ = optional_import("monai._C")
-_C_CUDA, _ = optional_import("monai._C_CUDA")
 
 __all__ = ["SkipConnection", "Flatten", "GaussianFilter", "LLTM"]
 
@@ -123,8 +122,7 @@ def _conv(input_: torch.Tensor, d: int) -> torch.Tensor:
 class LLTMFunction(Function):
     @staticmethod
     def forward(ctx, input, weights, bias, old_h, old_cell):
-        ext = _C_CUDA if weights.is_cuda else _C
-        outputs = ext.lltm_forward(input, weights, bias, old_h, old_cell)
+        outputs = _C.lltm_forward(input, weights, bias, old_h, old_cell)
         new_h, new_cell = outputs[:2]
         variables = outputs[1:] + [weights]
         ctx.save_for_backward(*variables)
@@ -133,12 +131,8 @@ def forward(ctx, input, weights, bias, old_h, old_cell):
 
     @staticmethod
     def backward(ctx, grad_h, grad_cell):
-        if grad_h.is_cuda:
-            outputs = _C_CUDA.lltm_backward(grad_h.contiguous(), grad_cell.contiguous(), *ctx.saved_tensors)
-            d_old_h, d_input, d_weights, d_bias, d_old_cell, d_gates = outputs
-        else:
-            outputs = _C.lltm_backward(grad_h.contiguous(), grad_cell.contiguous(), *ctx.saved_tensors)
-            d_old_h, d_input, d_weights, d_bias, d_old_cell = outputs
+        outputs = _C.lltm_backward(grad_h.contiguous(), grad_cell.contiguous(), *ctx.saved_tensors)
+        d_old_h, d_input, d_weights, d_bias, d_old_cell = outputs[:5]
 
         return d_input, d_weights, d_bias, d_old_h, d_old_cell
 
diff --git a/setup.py b/setup.py
--- a/setup.py
+++ b/setup.py
@@ -9,43 +9,80 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+import glob
+import os
 import warnings
 
 from setuptools import find_packages, setup
 
 import versioneer
 
+# TODO: debug mode -g -O0, compile test cases
+
+FORCE_CUDA = os.getenv("FORCE_CUDA", "0") == "1"
+SKIP_BUILD = os.getenv("SKIP_MONAI_BUILD", "0") == "1"
+
+BUILD_CPP = BUILD_CUDA = False
+try:
+    import torch
+
+    print(f"setup.py with torch {torch.__version__}")
+    from torch.utils.cpp_extension import BuildExtension, CppExtension
+
+    BUILD_CPP = True
+    from torch.utils.cpp_extension import CUDA_HOME, CUDAExtension
+
+    BUILD_CUDA = (torch.cuda.is_available() and (CUDA_HOME is not None)) or FORCE_CUDA
+except ImportError:
+    warnings.warn("extension build skipped.")
+finally:
+    if SKIP_BUILD:
+        BUILD_CPP = BUILD_CUDA = False
+    print(f"BUILD_MONAI_CPP={BUILD_CPP}, BUILD_MONAI_CUDA={BUILD_CUDA}")
+
 
 def get_extensions():
+    this_dir = os.path.dirname(os.path.abspath(__file__))
+    ext_dir = os.path.join(this_dir, "monai", "csrc")
+    include_dirs = [ext_dir]
+
+    main_src = glob.glob(os.path.join(ext_dir, "*.cpp"))
+    source_cpu = glob.glob(os.path.join(ext_dir, "**", "*.cpp"))
+    source_cuda = glob.glob(os.path.join(ext_dir, "**", "*.cu"))
 
-    try:
-        import torch
-        from torch.utils.cpp_extension import CUDA_HOME, CppExtension, CUDAExtension
-
-        print(f"setup.py with torch {torch.__version__}")
-    except ImportError:
-        warnings.warn("torch cpp/cuda building skipped.")
-        return []
-
-    ext_modules = [CppExtension("monai._C", ["monai/networks/extensions/lltm/lltm.cpp"])]
-    if torch.cuda.is_available() and (CUDA_HOME is not None):
-        ext_modules.append(
-            CUDAExtension(
-                "monai._C_CUDA",
-                ["monai/networks/extensions/lltm/lltm_cuda.cpp", "monai/networks/extensions/lltm/lltm_cuda_kernel.cu"],
-            )
+    extension = None
+    define_macros = []
+    extra_compile_args = {}
+    sources = main_src + source_cpu
+    if BUILD_CPP:
+        extension = CppExtension
+    if BUILD_CUDA:
+        extension = CUDAExtension
+        sources += source_cuda
+        define_macros += [("WITH_CUDA", None)]
+        extra_compile_args = {"cxx": [], "nvcc": []}
+    if extension is None or not sources:
+        return []  # compile nothing
+
+    ext_modules = [
+        extension(
+            name="monai._C",
+            sources=sources,
+            include_dirs=include_dirs,
+            define_macros=define_macros,
+            extra_compile_args=extra_compile_args,
         )
+    ]
     return ext_modules
 
 
 def get_cmds():
     cmds = versioneer.get_cmdclass()
-    try:
-        from torch.utils.cpp_extension import BuildExtension
 
-        cmds.update({"build_ext": BuildExtension})
-    except ImportError:
-        warnings.warn("torch cpp_extension module not found.")
+    if not (BUILD_CPP or BUILD_CUDA):
+        return cmds
+
+    cmds.update({"build_ext": BuildExtension.with_options(no_python_abi_suffix=True)})
     return cmds
 
 


Test patch:
diff --git a/tests/min_tests.py b/tests/min_tests.py
--- a/tests/min_tests.py
+++ b/tests/min_tests.py
@@ -75,6 +75,7 @@ def run_testsuit():
         "test_load_image",
         "test_load_imaged",
         "test_smartcachedataset",
+        "test_lltm",
     ]
 
     files = glob.glob(os.path.join(os.path.dirname(__file__), "test_*.py"))