diff options
-rw-r--r-- | mesonbuild/compilers.py | 66 | ||||
-rw-r--r-- | mesonbuild/interpreter.py | 8 | ||||
-rw-r--r-- | test cases/common/126 llvm ir and assembly/main.c | 9 | ||||
-rw-r--r-- | test cases/common/126 llvm ir and assembly/main.cpp | 8 | ||||
-rw-r--r-- | test cases/common/126 llvm ir and assembly/meson.build | 53 | ||||
-rw-r--r-- | test cases/common/126 llvm ir and assembly/square-x86.S | 23 | ||||
-rw-r--r-- | test cases/common/126 llvm ir and assembly/square-x86_64.S | 25 | ||||
-rw-r--r-- | test cases/common/126 llvm ir and assembly/symbol-underscore.h | 2 |
8 files changed, 168 insertions, 26 deletions
diff --git a/mesonbuild/compilers.py b/mesonbuild/compilers.py index aa53444..88ea3e2 100644 --- a/mesonbuild/compilers.py +++ b/mesonbuild/compilers.py @@ -446,7 +446,7 @@ class Compiler(): return extra_flags @contextlib.contextmanager - def compile(self, code, extra_args=None): + def compile(self, code, extra_args=None, compile_only=False): if extra_args is None: extra_args = [] @@ -462,20 +462,25 @@ class Compiler(): # Extension only matters if running results; '.exe' is # guaranteed to be executable on every platform. - output = os.path.join(tmpdirname, 'output.exe') + if compile_only: + suffix = 'obj' + else: + suffix = 'exe' + output = os.path.join(tmpdirname, 'output.' + suffix) commands = self.get_exelist() commands.append(srcname) commands += extra_args commands += self.get_output_args(output) + if compile_only: + commands += self.get_compile_only_args() mlog.debug('Running compile:') mlog.debug('Working directory: ', tmpdirname) mlog.debug('Command line: ', ' '.join(commands), '\n') mlog.debug('Code:\n', code) - p, stdo, stde = Popen_safe(commands, cwd=tmpdirname) - mlog.debug('Compiler stdout:\n', stdo) - mlog.debug('Compiler stderr:\n', stde) - + p, p.stdo, p.stde = Popen_safe(commands, cwd=tmpdirname) + mlog.debug('Compiler stdout:\n', p.stdo) + mlog.debug('Compiler stderr:\n', p.stde) p.input_name = srcname p.output_name = output yield p @@ -753,14 +758,13 @@ int main () {{ # Add CFLAGS/CXXFLAGS/OBJCFLAGS/OBJCXXFLAGS from the env # We assume that the user has ensured these are compiler-specific args += env.coredata.external_args[self.language] - # We only want to compile; not link - args += self.get_compile_only_args() # Append extra_args to the compiler check args such that it overrides extra_args = self._override_args(self.get_compiler_check_args(), extra_args) extra_args = self.unix_link_flags_to_native(extra_args) # Append both to the compiler args such that they override them args = self._override_args(args, extra_args) - with self.compile(code, args) as p: + # We only want to compile; not link + with self.compile(code, args, compile_only=True) as p: return p.returncode == 0 def _links_wrapper(self, code, env, extra_args, dependencies): @@ -1063,6 +1067,40 @@ void bar() { ''' return self.compiles(templ % (prefix, typename), env, extra_args, dependencies) + def symbols_have_underscore_prefix(self, env): + ''' + Check if the compiler prefixes an underscore to global C symbols + ''' + symbol_name = b'meson_uscore_prefix' + code = '''#ifdef __cplusplus + extern "C" { + #endif + void ''' + symbol_name.decode() + ''' () {} + #ifdef __cplusplus + } + #endif + ''' + args = self.get_cross_extra_flags(env, compile=True, link=False) + args += self.get_compiler_check_args() + n = 'symbols_have_underscore_prefix' + with self.compile(code, args, compile_only=True) as p: + if p.returncode != 0: + m = 'BUG: Unable to compile {!r} check: {}' + raise RuntimeError(m.format(n, p.stdo)) + if not os.path.isfile(p.output_name): + m = 'BUG: Can\'t find compiled test code for {!r} check' + raise RuntimeError(m.format(n)) + with open(p.output_name, 'rb') as o: + for line in o: + # Check if the underscore form of the symbol is somewhere + # in the output file. + if b'_' + symbol_name in line: + return True + # Else, check if the non-underscored form is present + elif symbol_name in line: + return False + raise RuntimeError('BUG: {!r} check failed unexpectedly'.format(n)) + def find_library(self, libname, env, extra_dirs): # First try if we can just add the library as -l. code = '''int main(int argc, char **argv) { @@ -1379,14 +1417,16 @@ class ValaCompiler(Compiler): def get_output_args(self, target): return ['-o', target] + def get_compile_only_args(self): + return ['-C'] + def get_werror_args(self): return ['--fatal-warnings'] def sanity_check(self, work_dir, environment): code = 'class MesonSanityCheck : Object { }' args = self.get_cross_extra_flags(environment, compile=True, link=False) - args += ['-C'] - with self.compile(code, args) as p: + with self.compile(code, args, compile_only=True) as p: if p.returncode != 0: msg = 'Vala compiler {!r} can not compile programs' \ ''.format(self.name_string()) @@ -1406,8 +1446,8 @@ class ValaCompiler(Compiler): code = 'class MesonFindLibrary : Object { }' vapi_args = ['--pkg', libname] args = self.get_cross_extra_flags(env, compile=True, link=False) - args += ['-C'] + vapi_args - with self.compile(code, args) as p: + args += vapi_args + with self.compile(code, args, compile_only=True) as p: if p.returncode == 0: return vapi_args # Not found? Try to find the vapi file itself. diff --git a/mesonbuild/interpreter.py b/mesonbuild/interpreter.py index 47b8ae6..d65ce6f 100644 --- a/mesonbuild/interpreter.py +++ b/mesonbuild/interpreter.py @@ -624,6 +624,7 @@ class CompilerHolder(InterpreterObject): 'has_multi_arguments' : self.has_multi_arguments_method, 'first_supported_argument' : self.first_supported_argument_method, 'unittest_args' : self.unittest_args_method, + 'symbols_have_underscore_prefix': self.symbols_have_underscore_prefix_method, }) def version_method(self, args, kwargs): @@ -699,6 +700,13 @@ class CompilerHolder(InterpreterObject): def get_id_method(self, args, kwargs): return self.compiler.get_id() + def symbols_have_underscore_prefix_method(self, args, kwargs): + ''' + Check if the compiler prefixes _ (underscore) to global C symbols + See: https://en.wikipedia.org/wiki/Name_mangling#C + ''' + return self.compiler.symbols_have_underscore_prefix(self.environment) + def unittest_args_method(self, args, kwargs): # At time, only D compilers have this feature. if not hasattr(self.compiler, 'get_unittest_args'): diff --git a/test cases/common/126 llvm ir and assembly/main.c b/test cases/common/126 llvm ir and assembly/main.c index edfb29e..97fe723 100644 --- a/test cases/common/126 llvm ir and assembly/main.c +++ b/test cases/common/126 llvm ir and assembly/main.c @@ -1,9 +1,14 @@ +#include <stdio.h> + unsigned square_unsigned (unsigned a); int main (int argc, char * argv[]) { - if (square_unsigned (2) != 4) - return -1; + unsigned int ret = square_unsigned (2); + if (ret != 4) { + printf("Got %u instead of 4\n", ret); + return 1; + } return 0; } diff --git a/test cases/common/126 llvm ir and assembly/main.cpp b/test cases/common/126 llvm ir and assembly/main.cpp index 4f576e7..f2c7de3 100644 --- a/test cases/common/126 llvm ir and assembly/main.cpp +++ b/test cases/common/126 llvm ir and assembly/main.cpp @@ -1,3 +1,4 @@ +#include <stdio.h> extern "C" { unsigned square_unsigned (unsigned a); @@ -6,7 +7,10 @@ extern "C" { int main (int argc, char * argv[]) { - if (square_unsigned (2) != 4) - return -1; + unsigned int ret = square_unsigned (2); + if (ret != 4) { + printf("Got %u instead of 4\n", ret); + return 1; + } return 0; } diff --git a/test cases/common/126 llvm ir and assembly/meson.build b/test cases/common/126 llvm ir and assembly/meson.build index 8b9be33..97cce18 100644 --- a/test cases/common/126 llvm ir and assembly/meson.build +++ b/test cases/common/126 llvm ir and assembly/meson.build @@ -1,17 +1,54 @@ project('llvm-ir', 'c', 'cpp') foreach lang : ['c', 'cpp'] - cc_id = meson.get_compiler(lang).get_id() + cc = meson.get_compiler(lang) + cc_id = cc.get_id() + ## Build a trivial executale with mixed LLVM IR source if cc_id == 'clang' e = executable('square_ir_' + lang, 'square.ll', 'main.' + lang) test('test IR square' + lang, e) endif - # FIXME: msvc does not support passing assembly to cl.exe, but you can pass - # it to ml.exe and get a compiled object. Meson should add support for - # transparently building assembly with ml.exe with MSVC. - if cc_id != 'msvc' - cpu = host_machine.cpu_family() - e = executable('square_asm_' + lang, 'square-' + cpu + '.S', 'main.' + lang) - test('test ASM square' + lang, e, args : [e.full_path()]) + ## Build a trivial executable with mixed assembly source + # This also helps test whether cc.symbols_have_underscore_prefix() is working + # properly. This is done by assembling some assembly into an object that will + # provide the unsigned_squared() symbol to main.c/cpp. This requires the + # C symbol mangling to be known in advance. + if cc.symbols_have_underscore_prefix() + uscore_args = ['-DMESON_TEST__UNDERSCORE_SYMBOL'] + message('underscore is prefixed') + else + uscore_args = [] + message('underscore is NOT prefixed') endif + cpu = host_machine.cpu_family() + square_base = 'square-' + cpu + square_impl = square_base + '.S' + # MSVC cannot directly compile assembly files, so we pass it through the + # cl.exe pre-processor first and then assemble it with the ml.exe assembler. + # Then we can link it into the executable. + if cc_id == 'msvc' + cl = find_program('cl') + if cpu == 'x86' + ml = find_program('ml') + elif cpu == 'x86_64' + ml = find_program('ml64') + else + error('Unsupported cpu family: "' + cpu + '"') + endif + # Preprocess file (ml doesn't support pre-processing) + preproc_name = lang + square_base + '.i' + square_preproc = custom_target(lang + square_impl + 'preproc', + input : square_impl, + output : preproc_name, + command : [cl, '/EP', '/P', '/Fi' + preproc_name, '@INPUT@'] + uscore_args) + # Use assembled object file instead of the original .S assembly source + square_impl = custom_target(lang + square_impl, + input : square_preproc, + output : lang + square_base + '.obj', + command : [ml, '/Fo', '@OUTPUT@', '/c', '@INPUT@']) + + endif + e = executable('square_asm_' + lang, square_impl, 'main.' + lang, + c_args : uscore_args, cpp_args : uscore_args) + test('test ASM square' + lang, e) endforeach diff --git a/test cases/common/126 llvm ir and assembly/square-x86.S b/test cases/common/126 llvm ir and assembly/square-x86.S index f3d67e7..b38da4f 100644 --- a/test cases/common/126 llvm ir and assembly/square-x86.S +++ b/test cases/common/126 llvm ir and assembly/square-x86.S @@ -1,5 +1,26 @@ #include "symbol-underscore.h" +/* This sadly doesn't test the symbol underscore stuff. I can't figure out how + * to not use an automatic stdcall mechanism and do everything manually. */ +#ifdef _MSC_VER + +.386 +.MODEL FLAT, C + +PUBLIC square_unsigned +_TEXT SEGMENT + +square_unsigned PROC var1:DWORD + mov eax, var1 + imul eax, eax + ret +square_unsigned ENDP + +_TEXT ENDS +END + +#else + .text .globl SYMBOL_NAME(square_unsigned) @@ -7,3 +28,5 @@ SYMBOL_NAME(square_unsigned): movl 4(%esp), %eax imull %eax, %eax retl + +#endif diff --git a/test cases/common/126 llvm ir and assembly/square-x86_64.S b/test cases/common/126 llvm ir and assembly/square-x86_64.S index ea73a9d..4adc31e 100644 --- a/test cases/common/126 llvm ir and assembly/square-x86_64.S +++ b/test cases/common/126 llvm ir and assembly/square-x86_64.S @@ -1,9 +1,34 @@ #include "symbol-underscore.h" +#ifdef _MSC_VER /* MSVC on Windows */ + +PUBLIC SYMBOL_NAME(square_unsigned) +_TEXT SEGMENT + +SYMBOL_NAME(square_unsigned) PROC + mov eax, ecx + imul eax, eax + ret +SYMBOL_NAME(square_unsigned) ENDP + +_TEXT ENDS +END + +#else + .text .globl SYMBOL_NAME(square_unsigned) +# ifdef _WIN32 /* MinGW */ +SYMBOL_NAME(square_unsigned): + imull %ecx, %ecx + movl %ecx, %eax + retq +# else /* Linux and OS X */ SYMBOL_NAME(square_unsigned): imull %edi, %edi movl %edi, %eax retq +# endif + +#endif diff --git a/test cases/common/126 llvm ir and assembly/symbol-underscore.h b/test cases/common/126 llvm ir and assembly/symbol-underscore.h index 508cf50..d0f3ef9 100644 --- a/test cases/common/126 llvm ir and assembly/symbol-underscore.h +++ b/test cases/common/126 llvm ir and assembly/symbol-underscore.h @@ -1,4 +1,4 @@ -#if defined(__WIN32__) || defined(__APPLE__) +#if defined(MESON_TEST__UNDERSCORE_SYMBOL) # define SYMBOL_NAME(name) _##name #else # define SYMBOL_NAME(name) name |