Repository: mesonbuild/meson

Issue:
CMake subproject fails with "Tried to form an absolute path to a source dir"
**Describe the bug**
I have a simple Meson project that uses a CMake subproject. I pass an additional CMake option in using `cmake_options`, specifying `BOOST_ROOT`.

When configuring, I see the subproject getting configured with CMake correctly, but as soon as the configuration succeeds, Meson quits with an error:

> subprojects/mySubproject/meson.build:0:0: ERROR: Tried to form an absolute path to a source dir. You should not do that but use relative paths instead.

(The error message is followed by an explanation on how to use `include_directories`.)
Note that the error message points to a nonexistent file `subprojects/mySubproject/meson.build` in line 0.

**To Reproduce**

Here's my `meson.build`:

```
project(
    'myApp',
    'cpp',
    version : '0.0.1'
)

cmake = import('cmake')

boost_root = meson.source_root() + '/myBoost'

message('Configuring mySubproject with BOOST_ROOT = ' + boost_root)
proj = cmake.subproject('mySubproject', cmake_options : [ '-DBOOST_ROOT=' + boost_root ])
```

**Expected behavior**
It should either provide better diagnostics, or not fail.

**system parameters**
* Native build
* OS: Oracle Linux 7.7 (based on CentOS)
* Python: 3.7.4
* Meson version: 0.53.1
* Ninja version: 1.9.0



Discussion:
This use case is not supposed to work since subprojects are not allowed to access anything from the root project or other subprojects. The only thing I can "fix" here, is to ignore all paths that are inside the project root but not inside the subproject. However, this will likely cause your build to fail.

The propper fix would be to distribute yout boost root seperately, outside your main project.

Resolving patch:
diff --git a/mesonbuild/cmake/interpreter.py b/mesonbuild/cmake/interpreter.py
--- a/mesonbuild/cmake/interpreter.py
+++ b/mesonbuild/cmake/interpreter.py
@@ -399,7 +399,19 @@ def rel_path(x: str, is_header: bool, is_generated: bool) -> T.Optional[str]:
             if not os.path.isabs(x):
                 x = os.path.normpath(os.path.join(self.src_dir, x))
             if not os.path.exists(x) and not any([x.endswith(y) for y in obj_suffixes]) and not is_generated:
-                mlog.warning('CMake: path', mlog.bold(x), 'does not exist. Ignoring. This can lead to build errors')
+                mlog.warning('CMake: path', mlog.bold(x), 'does not exist.')
+                mlog.warning(' --> Ignoring. This can lead to build errors.')
+                return None
+            if (
+                os.path.isabs(x)
+                    and os.path.commonpath([x, self.env.get_source_dir()]) == self.env.get_source_dir()
+                    and not (
+                        os.path.commonpath([x, root_src_dir]) == root_src_dir or
+                        os.path.commonpath([x, self.env.get_build_dir()]) == self.env.get_build_dir()
+                    )
+                ):
+                mlog.warning('CMake: path', mlog.bold(x), 'is inside the root project but', mlog.bold('not'), 'inside the subproject.')
+                mlog.warning(' --> Ignoring. This can lead to build errors.')
                 return None
             if os.path.isabs(x) and os.path.commonpath([x, self.env.get_build_dir()]) == self.env.get_build_dir():
                 if is_header:


Test patch:
diff --git a/test cases/failing build/4 cmake subproject isolation/incDir/fileA.hpp b/test cases/failing build/4 cmake subproject isolation/incDir/fileA.hpp
new file mode 100644
--- /dev/null
+++ b/test cases/failing build/4 cmake subproject isolation/incDir/fileA.hpp	
@@ -0,0 +1,3 @@
+#pragma once
+
+#define SOME_DEFINE " World"
diff --git a/test cases/failing build/4 cmake subproject isolation/main.cpp b/test cases/failing build/4 cmake subproject isolation/main.cpp
new file mode 100644
--- /dev/null
+++ b/test cases/failing build/4 cmake subproject isolation/main.cpp	
@@ -0,0 +1,10 @@
+#include <iostream>
+#include <cmMod.hpp>
+
+using namespace std;
+
+int main(void) {
+  cmModClass obj("Hello");
+  cout << obj.getStr() << endl;
+  return 0;
+}
diff --git a/test cases/failing build/4 cmake subproject isolation/meson.build b/test cases/failing build/4 cmake subproject isolation/meson.build
new file mode 100644
--- /dev/null
+++ b/test cases/failing build/4 cmake subproject isolation/meson.build	
@@ -0,0 +1,17 @@
+project('subproject isolation', ['c', 'cpp'])
+
+if not find_program('cmake', required: false).found()
+  error('MESON_SKIP_TEST CMake is not installed')
+endif
+
+incdir = meson.source_root() / 'incDir'
+
+cm = import('cmake')
+
+# This should generate a warning and the include dir should be skipped.
+sub_pro = cm.subproject('cmMod', cmake_options : [ '-DMESON_INC_DIR=' + incdir ])
+sub_dep = sub_pro.dependency('cmModLib++')
+
+# Since the include dir is skipped, the compilation of this project should fail.
+exe1 = executable('main', ['main.cpp'], dependencies: [sub_dep])
+test('test1', exe1)
diff --git a/test cases/failing build/4 cmake subproject isolation/subprojects/cmMod/CMakeLists.txt b/test cases/failing build/4 cmake subproject isolation/subprojects/cmMod/CMakeLists.txt
new file mode 100644
--- /dev/null
+++ b/test cases/failing build/4 cmake subproject isolation/subprojects/cmMod/CMakeLists.txt	
@@ -0,0 +1,10 @@
+cmake_minimum_required(VERSION 3.5)
+
+project(cmMod)
+set (CMAKE_CXX_STANDARD 14)
+
+include_directories(${CMAKE_CURRENT_BINARY_DIR} ${MESON_INC_DIR})
+
+add_library(cmModLib++ SHARED cmMod.cpp)
+include(GenerateExportHeader)
+generate_export_header(cmModLib++)
diff --git a/test cases/failing build/4 cmake subproject isolation/subprojects/cmMod/cmMod.cpp b/test cases/failing build/4 cmake subproject isolation/subprojects/cmMod/cmMod.cpp
new file mode 100644
--- /dev/null
+++ b/test cases/failing build/4 cmake subproject isolation/subprojects/cmMod/cmMod.cpp	
@@ -0,0 +1,12 @@
+#include "cmMod.hpp"
+#include "fileA.hpp"
+
+using namespace std;
+
+cmModClass::cmModClass(string foo) {
+  str = foo + SOME_DEFINE;
+}
+
+string cmModClass::getStr() const {
+  return str;
+}
diff --git a/test cases/failing build/4 cmake subproject isolation/subprojects/cmMod/cmMod.hpp b/test cases/failing build/4 cmake subproject isolation/subprojects/cmMod/cmMod.hpp
new file mode 100644
--- /dev/null
+++ b/test cases/failing build/4 cmake subproject isolation/subprojects/cmMod/cmMod.hpp	
@@ -0,0 +1,14 @@
+#pragma once
+
+#include "cmmodlib++_export.h"
+#include <string>
+
+class CMMODLIB___EXPORT cmModClass {
+private:
+  std::string str;
+
+public:
+  cmModClass(std::string foo);
+
+  std::string getStr() const;
+};