Repository: mesonbuild/meson

Issue:
Cross-drive build is not supported on Windows
```
Stdout:
Traceback (most recent call last):
  File "D:\dev\meson\mesonbuild\mesonmain.py", line 368, in run
    app.generate()
  File "D:\dev\meson\mesonbuild\mesonmain.py", line 150, in generate
    self._generate(env)
  File "D:\dev\meson\mesonbuild\mesonmain.py", line 168, in _generate
    g = ninjabackend.NinjaBackend(b)
  File "D:\dev\meson\mesonbuild\backend\ninjabackend.py", line 143, in __init__
    super().__init__(build)
  File "D:\dev\meson\mesonbuild\backend\backends.py", line 111, in __init__
    self.environment.get_build_dir())
  File "C:\Python36\lib\ntpath.py", line 585, in relpath
    path_drive, start_drive))
ValueError: path is on mount 'D:', start on mount 'C:'
```

A little bit of debugging shows that this happens in `Backend.__init__()`, 
```python
self.build_to_src = os.path.relpath(self.environment.get_source_dir(), # D:\dev\meson\test cases\common\5 linkstatic
                                    self.environment.get_build_dir())  # C:\Users\$NAME\AppData\Local\Temp\tmp1iii95om
```


Discussion:

Resolving patch:
diff --git a/mesonbuild/backend/backends.py b/mesonbuild/backend/backends.py
--- a/mesonbuild/backend/backends.py
+++ b/mesonbuild/backend/backends.py
@@ -132,8 +132,8 @@ def __init__(self, build):
         self.build = build
         self.environment = build.environment
         self.processed_targets = {}
-        self.build_to_src = os.path.relpath(self.environment.get_source_dir(),
-                                            self.environment.get_build_dir())
+        self.build_to_src = mesonlib.relpath(self.environment.get_source_dir(),
+                                             self.environment.get_build_dir())
 
     def get_target_filename(self, t):
         if isinstance(t, build.CustomTarget):
diff --git a/mesonbuild/interpreter.py b/mesonbuild/interpreter.py
--- a/mesonbuild/interpreter.py
+++ b/mesonbuild/interpreter.py
@@ -1540,8 +1540,8 @@ def method_call(self, method_name, args, kwargs):
         # because the Build object contains dicts and lists.
         num_targets = len(self.interpreter.build.targets)
         state = ModuleState(
-            build_to_src=os.path.relpath(self.interpreter.environment.get_source_dir(),
-                                         self.interpreter.environment.get_build_dir()),
+            build_to_src=mesonlib.relpath(self.interpreter.environment.get_source_dir(),
+                                          self.interpreter.environment.get_build_dir()),
             subproject=self.interpreter.subproject,
             subdir=self.interpreter.subdir,
             current_lineno=self.interpreter.current_lineno,
@@ -2182,14 +2182,7 @@ def run_command_impl(self, node, args, kwargs, in_builddir=False):
                 raise InterpreterException('Program or command {!r} not found '
                                            'or not executable'.format(cmd))
             cmd = prog
-        try:
-            cmd_path = os.path.relpath(cmd.get_path(), start=srcdir)
-        except ValueError:
-            # On Windows a relative path can't be evaluated for
-            # paths on two different drives (i.e. c:\foo and f:\bar).
-            # The only thing left to is is to use the original absolute
-            # path.
-            cmd_path = cmd.get_path()
+        cmd_path = mesonlib.relpath(cmd.get_path(), start=srcdir)
         if not cmd_path.startswith('..') and cmd_path not in self.build_def_files:
             self.build_def_files.append(cmd_path)
         expanded_args = []
@@ -2206,7 +2199,7 @@ def run_command_impl(self, node, args, kwargs, in_builddir=False):
             if not os.path.isabs(a):
                 a = os.path.join(builddir if in_builddir else srcdir, self.subdir, a)
             if os.path.isfile(a):
-                a = os.path.relpath(a, start=srcdir)
+                a = mesonlib.relpath(a, start=srcdir)
                 if not a.startswith('..'):
                     if a not in self.build_def_files:
                         self.build_def_files.append(a)
diff --git a/mesonbuild/mesonlib.py b/mesonbuild/mesonlib.py
--- a/mesonbuild/mesonlib.py
+++ b/mesonbuild/mesonlib.py
@@ -1143,3 +1143,12 @@ def __exit__(self, *args):
         elif have_msvcrt:
             msvcrt.locking(self.lockfile.fileno(), msvcrt.LK_UNLCK, 1)
         self.lockfile.close()
+
+def relpath(path, start):
+    # On Windows a relative path can't be evaluated for paths on two different
+    # drives (i.e. c:\foo and f:\bar).  The only thing left to do is to use the
+    # original absolute path.
+    try:
+        return os.path.relpath(path, start)
+    except ValueError:
+        return path


Test patch: