Repository: mesonbuild/meson

Issue:
compiler.compiles and compiler.links do not accept files generated by configure_file
**Describe the bug**

Trying to use a file generated by `configure_file` with `compiler.compiles` or `compiler.links` results in the following wall:

```
Traceback (most recent call last):
  File "/usr/local/lib/python3.11/site-packages/mesonbuild/mesonmain.py", line 194, in run
    return options.run_func(options)
           ^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/mesonbuild/msetup.py", line 318, in run
    app.generate()
  File "/usr/local/lib/python3.11/site-packages/mesonbuild/msetup.py", line 194, in generate
    self._generate(env)
  File "/usr/local/lib/python3.11/site-packages/mesonbuild/msetup.py", line 239, in _generate
    intr.run()
  File "/usr/local/lib/python3.11/site-packages/mesonbuild/interpreter/interpreter.py", line 2971, in run
    super().run()
  File "/usr/local/lib/python3.11/site-packages/mesonbuild/interpreterbase/interpreterbase.py", line 164, in run
    self.evaluate_codeblock(self.ast, start=1)
  File "/usr/local/lib/python3.11/site-packages/mesonbuild/interpreterbase/interpreterbase.py", line 190, in evaluate_codeblock
    raise e
  File "/usr/local/lib/python3.11/site-packages/mesonbuild/interpreterbase/interpreterbase.py", line 182, in evaluate_codeblock
    self.evaluate_statement(cur)
  File "/usr/local/lib/python3.11/site-packages/mesonbuild/interpreterbase/interpreterbase.py", line 228, in evaluate_statement
    self.evaluate_foreach(cur)
  File "/usr/local/lib/python3.11/site-packages/mesonbuild/interpreterbase/interpreterbase.py", line 472, in evaluate_foreach
    self.evaluate_codeblock(node.block)
  File "/usr/local/lib/python3.11/site-packages/mesonbuild/interpreterbase/interpreterbase.py", line 190, in evaluate_codeblock
    raise e
  File "/usr/local/lib/python3.11/site-packages/mesonbuild/interpreterbase/interpreterbase.py", line 182, in evaluate_codeblock
    self.evaluate_statement(cur)
  File "/usr/local/lib/python3.11/site-packages/mesonbuild/interpreterbase/interpreterbase.py", line 206, in evaluate_statement
    return self.evaluate_if(cur)
           ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/mesonbuild/interpreterbase/interpreterbase.py", line 301, in evaluate_if
    self.evaluate_codeblock(i.block)
  File "/usr/local/lib/python3.11/site-packages/mesonbuild/interpreterbase/interpreterbase.py", line 190, in evaluate_codeblock
    raise e
  File "/usr/local/lib/python3.11/site-packages/mesonbuild/interpreterbase/interpreterbase.py", line 182, in evaluate_codeblock
    self.evaluate_statement(cur)
  File "/usr/local/lib/python3.11/site-packages/mesonbuild/interpreterbase/interpreterbase.py", line 200, in evaluate_statement
    return self.method_call(cur)
           ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/mesonbuild/interpreterbase/interpreterbase.py", line 537, in method_call
    (h_args, h_kwargs) = self.reduce_arguments(node.args)
                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/mesonbuild/interpreterbase/interpreterbase.py", line 593, in reduce_arguments
    reduced_pos = [self.evaluate_statement(arg) for arg in args.arguments]
                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/mesonbuild/interpreterbase/interpreterbase.py", line 593, in <listcomp>
    reduced_pos = [self.evaluate_statement(arg) for arg in args.arguments]
                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/mesonbuild/interpreterbase/interpreterbase.py", line 200, in evaluate_statement
    return self.method_call(cur)
           ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/mesonbuild/interpreterbase/interpreterbase.py", line 550, in method_call
    res = obj.method_call(method_name, args, kwargs)
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/mesonbuild/interpreterbase/baseobjects.py", line 94, in method_call
    return method(args, kwargs)
           ^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/mesonbuild/interpreterbase/decorators.py", line 277, in wrapper
    return f(*nargs, **wrapped_kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/mesonbuild/interpreterbase/decorators.py", line 596, in wrapper
    return f(*wrapped_args, **wrapped_kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/mesonbuild/interpreter/compiler.py", line 457, in compiles_method
    result, cached = self.compiler.compiles(code, self.environment,
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/mesonbuild/compilers/compilers.py", line 1287, in compiles
    with self._build_wrapper(code, env, extra_args, dependencies, mode, disable_cache=disable_cache) as p:
  File "/usr/local/Cellar/python@3.11/3.11.4_1/Frameworks/Python.framework/Versions/3.11/lib/python3.11/contextlib.py", line 137, in __enter__
    return next(self.gen)
           ^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/mesonbuild/compilers/compilers.py", line 1279, in _build_wrapper
    with self.cached_compile(code, env.coredata, extra_args=args, mode=mode, temp_dir=env.scratch_dir) as r:
  File "/usr/local/Cellar/python@3.11/3.11.4_1/Frameworks/Python.framework/Versions/3.11/lib/python3.11/contextlib.py", line 137, in __enter__
    return next(self.gen)
           ^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/mesonbuild/compilers/compilers.py", line 887, in cached_compile
    with self.compile(code, extra_args=extra_args, mode=mode, want_output=False, temp_dir=temp_dir) as p:
  File "/usr/local/Cellar/python@3.11/3.11.4_1/Frameworks/Python.framework/Versions/3.11/lib/python3.11/contextlib.py", line 137, in __enter__
    return next(self.gen)
           ^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/mesonbuild/compilers/compilers.py", line 826, in compile
    with open(code.fname, encoding='utf-8') as f:
         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
FileNotFoundError: [Errno 2] No such file or directory: 'armv8_external.S'
```

**To Reproduce**

```meson
project('test', 'c')

python3 = import('python').find_installation()

cc = meson.get_compiler('c')

f = configure_file(
      command: [python3, '-c', 'import sys; print(sys.argv[1])', '@0@'.format('prfm   pldl1strm, [x0]')], 
      input: 'meson.build',
      output: 'armv8_external.S',
      capture: true,
)

cc.compiles(
      f,
      args: ['-x', 'assembler'],
      name: 'should succeed under arm64' 
)
```

This should be easy to fix by replacing the following:

https://github.com/mesonbuild/meson/blob/b92858a5beba687478e56850269bc89bc61b3954/mesonbuild/interpreter/compiler.py#L288-L291

with

```py
        if isinstance(code, mesonlib.File):
            self.interpreter.add_build_def_file(code)
            code = mesonlib.File.from_absolute_file(
                code.absolute_path(self.environment.source_dir, self.environment.build_dir))
```

**Expected behavior**

The check should run against the supplied file.

**system parameters**
* Is this a [cross build](https://mesonbuild.com/Cross-compilation.html) or just a plain native build (for the same computer)? **Cross build**
* what operating system (e.g. MacOS Catalina, Windows 10, CentOS 8.0, Ubuntu 18.04, etc.) **macOS Big Sur 11.7.8**
* what Python version are you using e.g. 3.8.0 **3.8.11**
* what `meson --version` **1.1.1**
* what `ninja --version` if it's a Ninja build **1.11.1**

cc @eli-schwartz  for reference



Discussion:

Resolving patch:
diff --git a/mesonbuild/interpreter/compiler.py b/mesonbuild/interpreter/compiler.py
--- a/mesonbuild/interpreter/compiler.py
+++ b/mesonbuild/interpreter/compiler.py
@@ -448,9 +448,12 @@ def get_define_method(self, args: T.Tuple[str], kwargs: 'CommonKW') -> str:
     def compiles_method(self, args: T.Tuple['mesonlib.FileOrString'], kwargs: 'CompileKW') -> bool:
         code = args[0]
         if isinstance(code, mesonlib.File):
+            if code.is_built:
+                FeatureNew.single_use('compiler.compiles with file created at setup time', '1.2.0', self.subproject,
+                                      'It was broken and either errored or returned false.', self.current_node)
             self.interpreter.add_build_def_file(code)
             code = mesonlib.File.from_absolute_file(
-                code.rel_to_builddir(self.environment.source_dir))
+                code.absolute_path(self.environment.source_dir, self.environment.build_dir))
         testname = kwargs['name']
         extra_args = functools.partial(self._determine_args, kwargs['no_builtin_args'], kwargs['include_directories'], kwargs['args'])
         deps, msg = self._determine_dependencies(kwargs['dependencies'], endl=None)
@@ -472,9 +475,12 @@ def links_method(self, args: T.Tuple['mesonlib.FileOrString'], kwargs: 'CompileK
         code = args[0]
         compiler = None
         if isinstance(code, mesonlib.File):
+            if code.is_built:
+                FeatureNew.single_use('compiler.links with file created at setup time', '1.2.0', self.subproject,
+                                      'It was broken and either errored or returned false.', self.current_node)
             self.interpreter.add_build_def_file(code)
             code = mesonlib.File.from_absolute_file(
-                code.rel_to_builddir(self.environment.source_dir))
+                code.absolute_path(self.environment.source_dir, self.environment.build_dir))
             suffix = code.suffix
             if suffix not in self.compiler.file_suffixes:
                 for_machine = self.compiler.for_machine


Test patch:
diff --git a/test cases/common/28 try compile/meson.build b/test cases/common/28 try compile/meson.build
--- a/test cases/common/28 try compile/meson.build	
+++ b/test cases/common/28 try compile/meson.build	
@@ -8,20 +8,27 @@ breakcode = '''#include<nonexisting.h>
 void func(void) { printf("This won't work.\n"); }
 '''
 
-foreach compiler : [meson.get_compiler('c'), meson.get_compiler('cpp')]
-  if compiler.compiles(code, name : 'should succeed') == false
+foreach lang : ['c', 'cpp']
+  compiler = meson.get_compiler(lang)
+
+  if compiler.compiles(code, name : 'code should succeed') == false
+    error('Compiler ' + compiler.get_id() + ' is fail.')
+  endif
+
+  if compiler.compiles(files('valid.c'), name : 'file should succeed') == false
     error('Compiler ' + compiler.get_id() + ' is fail.')
   endif
 
-  if compiler.compiles(files('valid.c'), name : 'should succeed') == false
+  copied = configure_file(input: 'valid.c', output: lang + '-valid-copy.c', copy: true)
+  if compiler.compiles(copied, name : 'built file should succeed') == false
     error('Compiler ' + compiler.get_id() + ' is fail.')
   endif
 
-  if compiler.compiles(breakcode, name : 'should fail')
+  if compiler.compiles(breakcode, name : 'code should fail')
     error('Compiler ' + compiler.get_id() + ' returned true on broken code.')
   endif
 
-  if compiler.compiles(files('invalid.c'), name : 'should fail')
+  if compiler.compiles(files('invalid.c'), name : 'file should fail')
     error('Compiler ' + compiler.get_id() + ' returned true on broken code.')
   endif
 endforeach