aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--mesonbuild/compilers.py66
-rw-r--r--mesonbuild/interpreter.py8
-rw-r--r--test cases/common/126 llvm ir and assembly/main.c9
-rw-r--r--test cases/common/126 llvm ir and assembly/main.cpp8
-rw-r--r--test cases/common/126 llvm ir and assembly/meson.build53
-rw-r--r--test cases/common/126 llvm ir and assembly/square-x86.S23
-rw-r--r--test cases/common/126 llvm ir and assembly/square-x86_64.S25
-rw-r--r--test cases/common/126 llvm ir and assembly/symbol-underscore.h2
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