Repository: cupy/cupy

Issue:
Introduce `CUPY_INSTALL_LIBRARY_PATH` and `CUPY_INSTALL_INCLUDE_PATH`
When building from source, currently we allow users to directly specify `CUTENSOR_PATH` and `CUGRAPH_PATH` but does not support other libraries.

I think it's better to have `CUPY_INSTALL_LIBRARY_PATH` and `CUPY_INSTALL_INCLUDE_PATH` so that users don't have to specify `LDFLAGS`, `CFLAGS`, etc.


Discussion:
I overlooked the code and noticed it's working 🤦 ... 

I still think `CUPY_INSTALL_LIBRARY_PATH` and `CUPY_INSTALL_INCLUDE_PATH` are valuable though.
I rescoped this issue as the original issue was based on my misunderstanding. Updated the title and the whole contents of the issue. 

Resolving patch:
diff --git a/install/cupy_builder/_context.py b/install/cupy_builder/_context.py
--- a/install/cupy_builder/_context.py
+++ b/install/cupy_builder/_context.py
@@ -10,6 +10,13 @@ def _get_env_bool(name: str, default: bool, env: Mapping[str, str]) -> bool:
     return env[name] != '0' if name in env else default
 
 
+def _get_env_path(name: str, env: Mapping[str, str]) -> List[str]:
+    paths = env.get(name, None)
+    if paths is None:
+        return []
+    return [x for x in paths.split(os.pathsep) if len(x) != 0]
+
+
 class Context:
     def __init__(
             self, source_root: str, *,
@@ -21,6 +28,8 @@ def __init__(
             'CUPY_USE_CUDA_PYTHON', False, _env)
         self.use_hip = _get_env_bool(
             'CUPY_INSTALL_USE_HIP', False, _env)
+        self.include_dirs = _get_env_path('CUPY_INCLUDE_PATH', _env)
+        self.library_dirs = _get_env_path('CUPY_LIBRARY_PATH', _env)
 
         cmdopts, _argv[:] = parse_args(_argv)
         self.package_name: str = cmdopts.cupy_package_name
diff --git a/install/cupy_builder/cupy_setup_build.py b/install/cupy_builder/cupy_setup_build.py
--- a/install/cupy_builder/cupy_setup_build.py
+++ b/install/cupy_builder/cupy_setup_build.py
@@ -261,7 +261,7 @@ def make_extensions(ctx: Context, compiler, use_cython):
 
     no_cuda = ctx.use_stub
     use_hip = not no_cuda and ctx.use_hip
-    settings = build.get_compiler_setting(use_hip)
+    settings = build.get_compiler_setting(ctx, use_hip)
 
     include_dirs = settings['include_dirs']
 
diff --git a/install/cupy_builder/install_build.py b/install/cupy_builder/install_build.py
--- a/install/cupy_builder/install_build.py
+++ b/install/cupy_builder/install_build.py
@@ -13,6 +13,7 @@
 import cupy_builder
 import cupy_builder.install_utils as utils
 from cupy_builder import _environment
+from cupy_builder._context import Context
 
 
 PLATFORM_LINUX = sys.platform.startswith('linux')
@@ -125,7 +126,7 @@ def get_hipcc_path() -> List[str]:
         return None
 
 
-def get_compiler_setting(use_hip):
+def get_compiler_setting(ctx: Context, use_hip):
     cuda_path = None
     rocm_path = None
 
@@ -134,8 +135,8 @@ def get_compiler_setting(use_hip):
     else:
         cuda_path = get_cuda_path()
 
-    include_dirs = []
-    library_dirs = []
+    include_dirs = ctx.include_dirs.copy()
+    library_dirs = ctx.library_dirs.copy()
     define_macros = []
     extra_compile_args = []
 


Test patch:
diff --git a/tests/install_tests/test_build.py b/tests/install_tests/test_build.py
--- a/tests/install_tests/test_build.py
+++ b/tests/install_tests/test_build.py
@@ -5,6 +5,7 @@
 
 import pytest
 
+from cupy_builder._context import Context
 from cupy_builder import install_build as build
 
 
@@ -14,9 +15,10 @@
 class TestCheckVersion(unittest.TestCase):
 
     def setUp(self):
+        ctx = Context('.', _env={}, _argv=[])
         self.compiler = ccompiler.new_compiler()
         sysconfig.customize_compiler(self.compiler)
-        self.settings = build.get_compiler_setting(False)
+        self.settings = build.get_compiler_setting(ctx, False)
 
     @pytest.mark.gpu
     @pytest.mark.skipif(not test_hip, reason='For ROCm/HIP environment')
diff --git a/tests/install_tests/test_cupy_builder/test_context.py b/tests/install_tests/test_cupy_builder/test_context.py
--- a/tests/install_tests/test_cupy_builder/test_context.py
+++ b/tests/install_tests/test_cupy_builder/test_context.py
@@ -1,4 +1,7 @@
-from cupy_builder._context import _get_env_bool, Context, parse_args
+import os
+
+from cupy_builder._context import (
+    _get_env_bool, _get_env_path, Context, parse_args)
 
 
 class TestGetEnvBool:
@@ -13,6 +16,13 @@ def test_false(self):
         assert not _get_env_bool('V', True, {'V': '0'})
 
 
+class TestGetEnvPath:
+    def test(self):
+        assert _get_env_path('P', {}) == []
+        assert _get_env_path('P', {'P': f'1{os.pathsep}'}) == ['1']
+        assert _get_env_path('P', {'P': f'1{os.pathsep}2'}) == ['1', '2']
+
+
 class TestContext:
     def test_default(self):
         ctx = Context('.', _env={}, _argv=[])
@@ -21,6 +31,8 @@ def test_default(self):
 
         assert not ctx.use_cuda_python
         assert not ctx.use_hip
+        assert ctx.include_dirs == []
+        assert ctx.library_dirs == []
 
         assert ctx.package_name == 'cupy'
         assert ctx.long_description_path is None
@@ -33,6 +45,19 @@ def test_default(self):
         assert not ctx.annotate
         assert not ctx.use_stub
 
+    def test_env(self):
+        ctx = Context('.', _env={
+            'CUPY_USE_CUDA_PYTHON': '1',
+            'CUPY_INSTALL_USE_HIP': '1',
+            'CUPY_INCLUDE_PATH': f'/tmp/include{os.pathsep}/tmp2/include',
+            'CUPY_LIBRARY_PATH': f'/tmp/lib{os.pathsep}/tmp2/lib',
+        }, _argv=[])
+
+        assert ctx.use_cuda_python
+        assert ctx.use_hip
+        assert ctx.include_dirs == ['/tmp/include', '/tmp2/include']
+        assert ctx.library_dirs == ['/tmp/lib', '/tmp2/lib']
+
 
 class TestParseArgs:
     def test_args(self):
diff --git a/tests/install_tests/test_cupy_builder/test_features.py b/tests/install_tests/test_cupy_builder/test_features.py
--- a/tests/install_tests/test_cupy_builder/test_features.py
+++ b/tests/install_tests/test_cupy_builder/test_features.py
@@ -10,10 +10,11 @@
 
 
 def get_compiler_settings():
+    ctx = Context('.', _env={}, _argv=[])
     sysconfig.get_config_vars()
     compiler = ccompiler.new_compiler()
     sysconfig.customize_compiler(compiler)
-    settings = build.get_compiler_setting(False)
+    settings = build.get_compiler_setting(ctx, False)
     return compiler, settings