Repository: mesonbuild/meson

Issue:
ccache isn't supported with --cross_file option
To be able to use ccache with a cross compiler I've added the 'ccache' string in the cross_file:

[binaries]
c = ['ccache', '/usr/local/bin/mips-linux-gcc']

Meson fails using the above cross_file:

The Meson build system
Version: 0.38.1
Source dir: /ssd/lte/app-2/tcommon/src/oma-dm/kt_lib
Build dir: /ssd/lte/app-2/tcommon/src/oma-dm/kt_lib/build
Build type: cross build
Project name: kt_lib
Traceback (most recent call last):
  File "/usr/lib/python3.5/site-packages/mesonbuild/mesonmain.py", line 286, in run
    app.generate()
  File "/usr/lib/python3.5/site-packages/mesonbuild/mesonmain.py", line 160, in generate
    intr = interpreter.Interpreter(b, g)
  File "/usr/lib/python3.5/site-packages/mesonbuild/interpreter.py", line 1198, in __init__
    self.parse_project()
  File "/usr/lib/python3.5/site-packages/mesonbuild/interpreterbase.py", line 111, in parse_project
    self.evaluate_codeblock(self.ast, end=1)
  File "/usr/lib/python3.5/site-packages/mesonbuild/interpreterbase.py", line 146, in evaluate_codeblock
    raise e
  File "/usr/lib/python3.5/site-packages/mesonbuild/interpreterbase.py", line 140, in evaluate_codeblock
    self.evaluate_statement(cur)
  File "/usr/lib/python3.5/site-packages/mesonbuild/interpreterbase.py", line 151, in evaluate_statement
    return self.function_call(cur)
  File "/usr/lib/python3.5/site-packages/mesonbuild/interpreterbase.py", line 372, in function_call
    return self.funcs[func_name](node, self.flatten(posargs), kwargs)
  File "/usr/lib/python3.5/site-packages/mesonbuild/interpreterbase.py", line 55, in wrapped
    return f(self, node, args, kwargs)
  File "/usr/lib/python3.5/site-packages/mesonbuild/interpreter.py", line 1611, in func_project
    self.add_languages(args[1:], True)
  File "/usr/lib/python3.5/site-packages/mesonbuild/interpreter.py", line 1727, in add_languages
    (comp, cross_comp) = self.detect_compilers(lang, need_cross_compiler)
  File "/usr/lib/python3.5/site-packages/mesonbuild/interpreter.py", line 1652, in detect_compilers
    cross_comp = self.environment.detect_c_compiler(True)
  File "/usr/lib/python3.5/site-packages/mesonbuild/environment.py", line 371, in detect_c_compiler
    basename = os.path.basename(compiler).lower()
  File "/usr/lib64/python3.5/posixpath.py", line 139, in basename
    i = p.rfind(sep) + 1
AttributeError: 'list' object has no attribute 'rfind'

Any idea how to fix that?

Thanks
Fabio Porcedda


Discussion:
IMHO I've a working solution for this problem, tomorrow i will make a pull request.
The basic issue, as I said on the PR, is that we expect a string there, and we don't actually check that it's a string, and throw a traceback if it's any other object. The solution would be to check if it's a string, and use it as a string, and if it's a list, use it as a list.

If it's anything else, report a proper error instead of spewing traceback.
The function you probably want to use is `mesonlib.stringlistify`.

Resolving patch:
diff --git a/mesonbuild/environment.py b/mesonbuild/environment.py
--- a/mesonbuild/environment.py
+++ b/mesonbuild/environment.py
@@ -19,6 +19,7 @@
 from .compilers import *
 from .mesonlib import EnvironmentException, Popen_safe
 import configparser
+import shlex
 import shutil
 
 build_filename = 'meson.build'
@@ -348,7 +349,9 @@ def get_gnu_compiler_type(defines):
     def detect_c_compiler(self, want_cross):
         evar = 'CC'
         if self.is_cross_build() and want_cross:
-            compilers = [self.cross_info.config['binaries']['c']]
+            compilers = self.cross_info.config['binaries']['c']
+            if not isinstance(compilers, list):
+                compilers = [compilers]
             ccache = []
             is_cross = True
             if self.cross_info.need_exe_wrapper():
@@ -356,7 +359,7 @@ def detect_c_compiler(self, want_cross):
             else:
                 exe_wrap = []
         elif evar in os.environ:
-            compilers = os.environ[evar].split()
+            compilers = shlex.split(os.environ[evar])
             ccache = []
             is_cross = False
             exe_wrap = None
@@ -385,13 +388,13 @@ def detect_c_compiler(self, want_cross):
                     continue
                 gtype = self.get_gnu_compiler_type(defines)
                 version = self.get_gnu_version_from_defines(defines)
-                return GnuCCompiler(ccache + [compiler], version, gtype, is_cross, exe_wrap, defines)
+                return GnuCCompiler(ccache + compilers, version, gtype, is_cross, exe_wrap, defines)
             if 'clang' in out:
                 if 'Apple' in out or for_darwin(want_cross, self):
                     cltype = CLANG_OSX
                 else:
                     cltype = CLANG_STANDARD
-                return ClangCCompiler(ccache + [compiler], version, cltype, is_cross, exe_wrap)
+                return ClangCCompiler(ccache + compilers, version, cltype, is_cross, exe_wrap)
             if 'Microsoft' in out or 'Microsoft' in err:
                 # Visual Studio prints version number to stderr but
                 # everything else to stdout. Why? Lord only knows.
@@ -400,7 +403,7 @@ def detect_c_compiler(self, want_cross):
             if '(ICC)' in out:
                 # TODO: add microsoft add check OSX
                 inteltype = ICC_STANDARD
-                return IntelCCompiler(ccache + [compiler], version, inteltype, is_cross, exe_wrap)
+                return IntelCCompiler(ccache + compilers, version, inteltype, is_cross, exe_wrap)
         errmsg = 'Unknown compiler(s): "' + ', '.join(compilers) + '"'
         if popen_exceptions:
             errmsg += '\nThe follow exceptions were encountered:'


Test patch: