Repository: chainer/chainer

Issue:
Check versions of libraries on install
We need to check version of CUDA and cuDNN on install. We need to check header files or something like that as they don't have pkgconfig.

There are `CUDA_VERIOSN` in `cuda.h` and `CUDNN_VERSION` in `cudnn.h`.



Discussion:

Resolving patch:
diff --git a/chainer_setup_build.py b/chainer_setup_build.py
--- a/chainer_setup_build.py
+++ b/chainer_setup_build.py
@@ -16,6 +16,64 @@
 dummy_extension = setuptools.Extension('chainer', ['chainer.c'])
 
 cython_version = '0.23.0'
+minimum_cuda_version = 6050
+minimum_cudnn_version = 2000
+
+
+def print_warning(*lines):
+    print('**************************************************')
+    for line in lines:
+        print('*** WARNING: %s' % line)
+    print('**************************************************')
+
+
+def check_cuda_version(compiler, settings):
+    out = build_and_run(compiler, '''
+    #include <cuda.h>
+    #include <stdio.h>
+    int main(int argc, char* argv[]) {
+      printf("%d", CUDA_VERSION);
+    }
+    ''', include_dirs=settings['include_dirs'])
+
+    if out is None:
+        print_warning('Cannot check CUDA version')
+        return False
+
+    cuda_version = int(out)
+
+    if cuda_version < minimum_cuda_version:
+        print_warning(
+            'CUDA version is too old: %d' % cuda_version,
+            'CUDA v6.5 or newer is required')
+        return False
+
+    return True
+
+
+def check_cudnn_version(compiler, settings):
+    out = build_and_run(compiler, '''
+    #include <cudnn.h>
+    #include <stdio.h>
+    int main(int argc, char* argv[]) {
+      printf("%d", CUDNN_VERSION);
+    }
+    ''', include_dirs=settings['include_dirs'])
+
+    if out is None:
+        print_warning('Cannot check cuDNN version')
+        return False
+
+    cudnn_version = int(out)
+
+    if cudnn_version < minimum_cudnn_version:
+        print_warnig(
+            'cuDNN version is too old: %d' % cudnn_version,
+            'cuDNN v2 or newer is required')
+        return False
+
+    return True
+
 
 MODULES = [
     {
@@ -44,6 +102,7 @@
             'cudart',
             'curand',
         ],
+        'check_method': check_cuda_version,
     },
     {
         'name': 'cudnn',
@@ -56,6 +115,7 @@
         'libraries': [
             'cudnn',
         ],
+        'check_method': check_cudnn_version,
     }
 ]
 
@@ -64,21 +124,18 @@ def get_compiler_setting():
     nvcc_path = search_on_path(('nvcc', 'nvcc.exe'))
     cuda_path_default = None
     if nvcc_path is None:
-        print('**************************************************************')
-        print('*** WARNING: nvcc not in path.')
-        print('*** WARNING: Please set path to nvcc.')
-        print('**************************************************************')
+        print_warning('nvcc not in path.',
+                      'Please set path to nvcc.')
     else:
         cuda_path_default = path.normpath(
             path.join(path.dirname(nvcc_path), '..'))
 
     cuda_path = os.environ.get('CUDA_PATH', '')  # Nvidia default on Windows
     if len(cuda_path) > 0 and cuda_path != cuda_path_default:
-        print('**************************************************************')
-        print('*** WARNING: nvcc path != CUDA_PATH')
-        print('*** WARNING: nvcc path: %s', cuda_path_default)
-        print('*** WARNING: CUDA_PATH: %s', cuda_path)
-        print('**************************************************************')
+        print_warning(
+            'nvcc path != CUDA_PATH',
+            'nvcc path: %s' % cuda_path_default,
+            'CUDA_PATH: %s' % cuda_path)
 
     if not path.exists(cuda_path):
         cuda_path = cuda_path_default
@@ -169,6 +226,40 @@ def check_library(compiler, includes=[], libraries=[],
         shutil.rmtree(temp_dir, ignore_errors=True)
 
 
+def build_and_run(compiler, source, libraries=[],
+                  include_dirs=[], library_dirs=[]):
+    temp_dir = tempfile.mkdtemp()
+
+    try:
+        fname = os.path.join(temp_dir, 'a.cpp')
+        with open(fname, 'w') as f:
+            f.write(source)
+
+        try:
+            objects = compiler.compile([fname], output_dir=temp_dir,
+                                       include_dirs=include_dirs)
+        except distutils.errors.CompileError:
+            return None
+
+        try:
+            compiler.link_executable(objects,
+                                     os.path.join(temp_dir, 'a'),
+                                     libraries=libraries,
+                                     library_dirs=library_dirs)
+        except (distutils.errors.LinkError, TypeError):
+            return None
+
+        try:
+            out = subprocess.check_output(os.path.join(temp_dir, 'a'))
+            return out
+
+        except Exception:
+            return None
+
+    finally:
+        shutil.rmtree(temp_dir, ignore_errors=True)
+
+
 def make_extensions(options, compiler):
 
     """Produce a list of Extension instances which passed to cythonize()."""
@@ -209,21 +300,23 @@ def make_extensions(options, compiler):
             if not check_library(compiler,
                                  includes=module['include'],
                                  include_dirs=settings['include_dirs']):
-                print('**************************************************')
-                print('*** Include files not found: %s' % module['include'])
-                print('*** Skip installing %s support' % module['name'])
-                print('*** Check your CPATH environment variable')
-                print('**************************************************')
+                print_warning(
+                    'Include files not found: %s' % module['include'],
+                    'Skip installing %s support' % module['name'],
+                    'Check your CPATH environment variable')
                 continue
 
             if not check_library(compiler,
                                  libraries=module['libraries'],
                                  library_dirs=settings['library_dirs']):
-                print('**************************************************')
-                print('*** Cannot link libraries: %s' % module['libraries'])
-                print('*** Skip installing %s support' % module['name'])
-                print('*** Check your LIBRARY_PATH environment variable')
-                print('**************************************************')
+                print_warning(
+                    'Cannot link libraries: %s' % module['libraries'],
+                    'Skip installing %s support' % module['name'],
+                    'Check your LIBRARY_PATH environment variable')
+                continue
+
+            if 'check_method' in module and \
+               not module['check_method'](compiler, settings):
                 continue
 
         s = settings.copy()


Test patch: