aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.travis.yml12
-rw-r--r--README.md5
-rw-r--r--cross/ownstdlib.txt13
-rw-r--r--manual tests/9 nostdlib/meson.build10
-rw-r--r--manual tests/9 nostdlib/prog.c7
-rw-r--r--manual tests/9 nostdlib/subprojects/mylibc/libc.c35
-rw-r--r--manual tests/9 nostdlib/subprojects/mylibc/meson.build11
-rw-r--r--manual tests/9 nostdlib/subprojects/mylibc/stdio.h5
-rw-r--r--manual tests/9 nostdlib/subprojects/mylibc/stubstart.s8
-rw-r--r--mesonbuild/backend/backends.py1
-rw-r--r--mesonbuild/backend/ninjabackend.py15
-rw-r--r--mesonbuild/build.py1
-rw-r--r--mesonbuild/compilers.py133
-rw-r--r--mesonbuild/environment.py6
-rw-r--r--mesonbuild/interpreter.py37
-rwxr-xr-xrun_tests.py8
-rw-r--r--test cases/common/43 has function/meson.build8
17 files changed, 218 insertions, 97 deletions
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..01d8eb5
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,12 @@
+sudo: required
+
+language: c
+
+services:
+ - docker
+
+before_install:
+ - docker pull jpakkane/mesonci:xenial
+
+script:
+ - docker run jpakkane/mesonci:xenial /bin/sh -c "cd /root && git clone https://github.com/mesonbuild/meson.git && cd meson && ./run_tests.py"
diff --git a/README.md b/README.md
index 82ee3f7..70f67a2 100644
--- a/README.md
+++ b/README.md
@@ -4,6 +4,11 @@
MesonĀ® is a project to create the best possible next-generation
build system.
+####Build status
+
+<a href="https://travis-ci.org/mesonbuild/meson"><img
+src="https://travis-ci.org/mesonbuild/meson.svg?branch=master"></a>
+
####Dependencies
- [Python](http://python.org) (version 3.4 or newer)
diff --git a/cross/ownstdlib.txt b/cross/ownstdlib.txt
new file mode 100644
index 0000000..46e99f7
--- /dev/null
+++ b/cross/ownstdlib.txt
@@ -0,0 +1,13 @@
+# This is a setup for compiling a program that runs natively
+# but uses a custom std lib. This test will only work on
+# x86_64.
+
+[target_machine]
+system = 'linux'
+cpu_family = 'x86_64'
+cpu = 'x86_64'
+endian = 'little'
+
+[properties]
+
+c_stdlib = ['mylibc', 'mylibc_dep'] # Subproject name, dependency name
diff --git a/manual tests/9 nostdlib/meson.build b/manual tests/9 nostdlib/meson.build
new file mode 100644
index 0000000..3ef743e
--- /dev/null
+++ b/manual tests/9 nostdlib/meson.build
@@ -0,0 +1,10 @@
+project('own libc', 'c')
+
+# A simple project that uses its own libc.
+
+# Note that we don't need to specify anything, the flags to use
+# stdlib come from the cross file.
+
+exe = executable('selfcontained', 'prog.c')
+
+test('standalone test', exe)
diff --git a/manual tests/9 nostdlib/prog.c b/manual tests/9 nostdlib/prog.c
new file mode 100644
index 0000000..9414bce
--- /dev/null
+++ b/manual tests/9 nostdlib/prog.c
@@ -0,0 +1,7 @@
+
+#include<stdio.h>
+
+int main() {
+ const char *message = "Hello without stdlib.\n";
+ return simple_print(message, simple_strlen(message));
+}
diff --git a/manual tests/9 nostdlib/subprojects/mylibc/libc.c b/manual tests/9 nostdlib/subprojects/mylibc/libc.c
new file mode 100644
index 0000000..67261cb
--- /dev/null
+++ b/manual tests/9 nostdlib/subprojects/mylibc/libc.c
@@ -0,0 +1,35 @@
+/* Do not use this as the basis of your own libc.
+ * The code is probably unoptimal or wonky, as I
+ * had no prior experience with this, but instead
+ * just fiddled with the code until it worked.
+ */
+
+#include<stdio.h>
+
+#define STDOUT 1
+#define SYS_WRITE 4
+
+int simple_print(const char *msg, const long bufsize) {
+ int count;
+ long total_written = 0;
+ while(total_written < bufsize) {
+ asm(
+ "int $0x80\n\t"
+ : "=a"(count)
+ : "0"(SYS_WRITE), "b"(STDOUT), "c"(msg+total_written), "d"(bufsize-total_written)
+ :);
+ if(count == 0) {
+ return 1;
+ }
+ total_written += count;
+ }
+ return 0;
+}
+
+int simple_strlen(const char *str) {
+ int len = 0;
+ while(str[len] != '\0') {
+ len++;
+ }
+ return len;
+}
diff --git a/manual tests/9 nostdlib/subprojects/mylibc/meson.build b/manual tests/9 nostdlib/subprojects/mylibc/meson.build
new file mode 100644
index 0000000..aa0184e
--- /dev/null
+++ b/manual tests/9 nostdlib/subprojects/mylibc/meson.build
@@ -0,0 +1,11 @@
+project('own libc', 'c')
+
+# A very simple libc implementation
+
+# Do not specify -nostdlib & co. They come from cross specifications.
+
+libc = static_library('c', 'libc.c', 'stubstart.s')
+
+mylibc_dep = declare_dependency(link_with : libc,
+ include_directories : include_directories('.')
+)
diff --git a/manual tests/9 nostdlib/subprojects/mylibc/stdio.h b/manual tests/9 nostdlib/subprojects/mylibc/stdio.h
new file mode 100644
index 0000000..c3f8f56
--- /dev/null
+++ b/manual tests/9 nostdlib/subprojects/mylibc/stdio.h
@@ -0,0 +1,5 @@
+#pragma once
+
+int simple_print(const char *msg, const long bufsize);
+
+int simple_strlen(const char *str);
diff --git a/manual tests/9 nostdlib/subprojects/mylibc/stubstart.s b/manual tests/9 nostdlib/subprojects/mylibc/stubstart.s
new file mode 100644
index 0000000..0a6d972
--- /dev/null
+++ b/manual tests/9 nostdlib/subprojects/mylibc/stubstart.s
@@ -0,0 +1,8 @@
+.globl _start
+
+_start:
+
+ call main
+ movl %eax, %ebx
+ movl $1, %eax
+ int $0x80
diff --git a/mesonbuild/backend/backends.py b/mesonbuild/backend/backends.py
index 7c6caa6..d4a0f99 100644
--- a/mesonbuild/backend/backends.py
+++ b/mesonbuild/backend/backends.py
@@ -286,6 +286,7 @@ class Backend():
def generate_basic_compiler_args(self, target, compiler):
commands = []
+ commands += self.get_cross_stdlib_args(target, compiler)
commands += compiler.get_always_args()
commands += compiler.get_warn_args(self.environment.coredata.get_builtin_option('warning_level'))
commands += compiler.get_option_compile_args(self.environment.coredata.compiler_options)
diff --git a/mesonbuild/backend/ninjabackend.py b/mesonbuild/backend/ninjabackend.py
index bd6f4db..4b85565 100644
--- a/mesonbuild/backend/ninjabackend.py
+++ b/mesonbuild/backend/ninjabackend.py
@@ -1394,6 +1394,13 @@ rule FORTRAN_DEP_HACK
mod_files.append(os.path.join(dirname, mod_name))
return mod_files
+ def get_cross_stdlib_args(self, target, compiler):
+ if not target.is_cross:
+ return []
+ if self.environment.cross_info.has_stdlib(compiler.language):
+ return []
+ return compiler.get_no_stdinc_args()
+
def generate_single_compile(self, target, outfile, src, is_generated=False, header_deps=[], order_deps=[]):
if(isinstance(src, str) and src.endswith('.h')):
raise RuntimeError('Fug')
@@ -1599,6 +1606,13 @@ rule FORTRAN_DEP_HACK
elem.add_item('CROSS', '--cross-host=' + self.environment.cross_info.config['host_machine']['system'])
elem.write(outfile)
+ def get_cross_stdlib_link_args(self, target, linker):
+ if isinstance(target, build.StaticLibrary) or not target.is_cross:
+ return []
+ if not self.environment.cross_info.has_stdlib(linker.language):
+ return []
+ return linker.get_no_stdlib_link_args()
+
def generate_link(self, target, outfile, outname, obj_list, linker, extra_args=[]):
if isinstance(target, build.StaticLibrary):
linker_base = 'STATIC'
@@ -1612,6 +1626,7 @@ rule FORTRAN_DEP_HACK
linker_rule = linker_base + crstr + '_LINKER'
abspath = os.path.join(self.environment.get_build_dir(), target.subdir)
commands = []
+ commands += self.get_cross_stdlib_link_args(target, linker)
commands += linker.get_linker_always_args()
if not isinstance(target, build.StaticLibrary):
commands += compilers.get_base_link_args(self.environment.coredata.base_options,
diff --git a/mesonbuild/build.py b/mesonbuild/build.py
index 1e9a1bb..9de556c 100644
--- a/mesonbuild/build.py
+++ b/mesonbuild/build.py
@@ -101,6 +101,7 @@ class Build:
self.install_dirs = []
self.dep_manifest_name = None
self.dep_manifest = {}
+ self.cross_stdlibs = {}
def has_language(self, language):
for i in self.compilers:
diff --git a/mesonbuild/compilers.py b/mesonbuild/compilers.py
index 25eefc6..1fc936a 100644
--- a/mesonbuild/compilers.py
+++ b/mesonbuild/compilers.py
@@ -311,6 +311,12 @@ class CCompiler(Compiler):
def get_always_args(self):
return []
+ def get_no_stdinc_args(self):
+ return ['-nostdinc']
+
+ def get_no_stdlib_link_args(self):
+ return ['-nostdlib']
+
def get_warn_args(self, level):
return self.warn_args[level]
@@ -414,30 +420,32 @@ class CCompiler(Compiler):
def get_linker_search_args(self, dirname):
return ['-L'+dirname]
- def sanity_check(self, work_dir):
- mlog.debug('Sanity testing C compiler:', ' '.join(self.exelist))
+ def sanity_check_impl(self, work_dir, sname, code):
+ mlog.debug('Sanity testing ' + self.language + ' compiler:', ' '.join(self.exelist))
mlog.debug('Is cross compiler: %s.' % str(self.is_cross))
- source_name = os.path.join(work_dir, 'sanitycheckc.c')
+ extra_flags = []
+ source_name = os.path.join(work_dir, sname)
+ binname = sname.rsplit('.', 1)[0]
if self.is_cross:
- binname = 'sanitycheckc_cross'
- else:
- binname = 'sanitycheckc'
+ binname += '_cross'
+ if self.exe_wrapper is None:
+ # Linking cross built apps is painful. You can't really
+ # tell if you should use -nostdlib or not and for example
+ # on OSX the compiler binary is the same but you need
+ # a ton of compiler flags to differentiate between
+ # arm and x86_64. So just compile.
+ extra_flags = self.get_compile_only_args()
+ # Is a valid executable output for all toolchains and platforms
+ binname += '.exe'
+ # Write binary check source
binary_name = os.path.join(work_dir, binname)
ofile = open(source_name, 'w')
- ofile.write('int main(int argc, char **argv) { int class=0; return class; }\n')
+ ofile.write(code)
ofile.close()
- if self.is_cross and self.exe_wrapper is None:
- # Linking cross built apps is painful. You can't really
- # tell if you should use -nostdlib or not and for example
- # on OSX the compiler binary is the same but you need
- # a ton of compiler flags to differentiate between
- # arm and x86_64. So just compile.
- extra_flags = ['-c']
- else:
- extra_flags = []
- cmdlist = self.exelist + extra_flags + [source_name, '-o', binary_name]
- pc = subprocess.Popen(cmdlist, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ # Compile sanity check
+ cmdlist = self.exelist + extra_flags + [source_name] + self.get_output_args(binary_name)
+ pc = subprocess.Popen(cmdlist, stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=work_dir)
(stdo, stde) = pc.communicate()
stdo = stdo.decode()
stde = stde.decode()
@@ -448,7 +456,8 @@ class CCompiler(Compiler):
mlog.debug(stde)
mlog.debug('-----')
if pc.returncode != 0:
- raise EnvironmentException('Compiler %s can not compile programs.' % self.name_string())
+ raise EnvironmentException('Compiler {0} can not compile programs.'.format(self.name_string()))
+ # Run sanity check
if self.is_cross:
if self.exe_wrapper is None:
# Can't check if the binaries run so we have to assume they do
@@ -460,7 +469,11 @@ class CCompiler(Compiler):
pe = subprocess.Popen(cmdlist)
pe.wait()
if pe.returncode != 0:
- raise EnvironmentException('Executables created by C compiler %s are not runnable.' % self.name_string())
+ raise EnvironmentException('Executables created by {0} compiler {1} are not runnable.'.format(self.language, self.name_string()))
+
+ def sanity_check(self, work_dir):
+ code = 'int main(int argc, char **argv) { int class=0; return class; }\n'
+ return self.sanity_check_impl(work_dir, 'sanitycheckc.c', code)
def has_header(self, hname, extra_args=[]):
templ = '''#include<%s>
@@ -692,6 +705,7 @@ int main(int argc, char **argv) {
# Then, undef the symbol to get rid of it completely.
templ = '''
#define {1} meson_disable_define_of_{1}
+ #include <limits.h>
{0}
#undef {1}
'''
@@ -709,6 +723,8 @@ int main(int argc, char **argv) {
# glibc defines functions that are not available on Linux as stubs that
# fail with ENOSYS (such as e.g. lchmod). In this case we want to fail
# instead of detecting the stub as a valid symbol.
+ # We always include limits.h above to ensure that these are defined for
+ # stub functions.
stubs_fail = '''
#if defined __stub_{1} || defined __stub___{1}
fail fail fail this function is not going to work
@@ -739,7 +755,8 @@ int main(int argc, char **argv) {
# redefines the symbol to be something else. In that case, we want to
# still detect the function. We still want to fail if __stub_foo or
# _stub_foo are defined, of course.
- if self.links('{0}\n' + stubs_fail + '\nint main() {{ {1}; }}'.format(prefix, funcname), extra_args):
+ header_templ = '#include <limits.h>\n{0}\n' + stubs_fail + '\nint main() {{ {1}; }}'
+ if self.links(header_templ.format(prefix, funcname), extra_args):
return True
# Some functions like alloca() are defined as compiler built-ins which
# are inlined by the compiler, so test for that instead. Built-ins are
@@ -808,42 +825,8 @@ class CPPCompiler(CCompiler):
return False
def sanity_check(self, work_dir):
- source_name = os.path.join(work_dir, 'sanitycheckcpp.cc')
- binary_name = os.path.join(work_dir, 'sanitycheckcpp')
- ofile = open(source_name, 'w')
- ofile.write('class breakCCompiler;int main(int argc, char **argv) { return 0; }\n')
- ofile.close()
- if self.is_cross and self.exe_wrapper is None:
- # Skipping link because of the same reason as for C.
- # The comment in CCompiler explains why this is done.
- extra_flags = ['-c']
- else:
- extra_flags = []
- cmdlist = self.exelist + extra_flags + [source_name, '-o', binary_name]
- pc = subprocess.Popen(cmdlist, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
- (stdo, stde) = pc.communicate()
- stdo = stdo.decode()
- stde = stde.decode()
- mlog.debug('Sanity check compiler command line:', ' '.join(cmdlist))
- mlog.debug('Sanity check compile stdout:')
- mlog.debug(stdo)
- mlog.debug('-----\nSanity check compile stderr:')
- mlog.debug(stde)
- mlog.debug('-----')
- pc.wait()
- if pc.returncode != 0:
- raise EnvironmentException('Compiler %s can not compile programs.' % self.name_string())
- if self.is_cross:
- if self.exe_wrapper is None:
- # Can't check if the binaries run so we have to assume they do
- return
- cmdlist = self.exe_wrapper + [binary_name]
- else:
- cmdlist = [binary_name]
- pe = subprocess.Popen(cmdlist)
- pe.wait()
- if pe.returncode != 0:
- raise EnvironmentException('Executables created by C++ compiler %s are not runnable.' % self.name_string())
+ code = 'class breakCCompiler;int main(int argc, char **argv) { return 0; }\n'
+ return self.sanity_check_impl(work_dir, 'sanitycheckcpp.cc', code)
class ObjCCompiler(CCompiler):
def __init__(self, exelist, version, is_cross, exe_wrap):
@@ -1386,24 +1369,6 @@ class VisualStudioCCompiler(CCompiler):
objname = os.path.splitext(pchname)[0] + '.obj'
return (objname, ['/Yc' + header, '/Fp' + pchname, '/Fo' + objname ])
- def sanity_check(self, work_dir):
- source_name = 'sanitycheckc.c'
- binary_name = 'sanitycheckc'
- ofile = open(os.path.join(work_dir, source_name), 'w')
- ofile.write('int main(int argc, char **argv) { return 0; }\n')
- ofile.close()
- pc = subprocess.Popen(self.exelist + [source_name, '/Fe' + binary_name],
- stdout=subprocess.DEVNULL,
- stderr=subprocess.DEVNULL,
- cwd=work_dir)
- pc.wait()
- if pc.returncode != 0:
- raise EnvironmentException('Compiler %s can not compile programs.' % self.name_string())
- pe = subprocess.Popen(os.path.join(work_dir, binary_name))
- pe.wait()
- if pe.returncode != 0:
- raise EnvironmentException('Executables created by C++ compiler %s are not runnable.' % self.name_string())
-
def build_rpath_args(self, build_dir, rpath_paths, install_rpath):
return []
@@ -1468,24 +1433,6 @@ class VisualStudioCPPCompiler(VisualStudioCCompiler):
return True
return False
- def sanity_check(self, work_dir):
- source_name = 'sanitycheckcpp.cpp'
- binary_name = 'sanitycheckcpp'
- ofile = open(os.path.join(work_dir, source_name), 'w')
- ofile.write('class BreakPlainC;int main(int argc, char **argv) { return 0; }\n')
- ofile.close()
- pc = subprocess.Popen(self.exelist + [source_name, '/Fe' + binary_name],
- stdout=subprocess.DEVNULL,
- stderr=subprocess.DEVNULL,
- cwd=work_dir)
- pc.wait()
- if pc.returncode != 0:
- raise EnvironmentException('Compiler %s can not compile programs.' % self.name_string())
- pe = subprocess.Popen(os.path.join(work_dir, binary_name))
- pe.wait()
- if pe.returncode != 0:
- raise EnvironmentException('Executables created by C++ compiler %s are not runnable.' % self.name_string())
-
def get_options(self):
return {'cpp_eh' : coredata.UserComboOption('cpp_eh',
'C++ exception handling type.',
diff --git a/mesonbuild/environment.py b/mesonbuild/environment.py
index 41e8531..5096320 100644
--- a/mesonbuild/environment.py
+++ b/mesonbuild/environment.py
@@ -759,6 +759,12 @@ class CrossBuildInfo():
def has_target(self):
return 'target_machine' in self.config
+ def has_stdlib(self, language):
+ return language + '_stdlib' in self.config['properties']
+
+ def get_stdlib(self, language):
+ return self.config['properties'][language + '_stdlib']
+
# Wehn compiling a cross compiler we use the native compiler for everything.
# But not when cross compiling a cross compiler.
def need_cross_compiler(self):
diff --git a/mesonbuild/interpreter.py b/mesonbuild/interpreter.py
index adcdd7a..bf11439 100644
--- a/mesonbuild/interpreter.py
+++ b/mesonbuild/interpreter.py
@@ -876,7 +876,7 @@ class MesonMain(InterpreterObject):
if self.is_cross_build_method(None, None) and \
'binaries' in self.build.environment.cross_info.config and \
self.build.environment.cross_info.need_exe_wrapper():
- exe_wrap = self.build.environment.cross_info.config['binaries'].get('exe_wrap', None)
+ exe_wrap = self.build.environment.cross_info.config['binaries'].get('exe_wrapper', None)
if exe_wrap is None:
return False
# We return True when exe_wrap is defined, when it's not needed, and
@@ -1077,6 +1077,22 @@ class Interpreter():
if not isinstance(first, mparser.FunctionNode) or first.func_name != 'project':
raise InvalidCode('First statement must be a call to project')
+ def check_cross_stdlibs(self):
+ if self.build.environment.is_cross_build():
+ cross_info = self.build.environment.cross_info
+ for c in self.build.cross_compilers:
+ l = c.language
+ try:
+ di = mesonlib.stringlistify(cross_info.get_stdlib(l))
+ if len(di) != 2:
+ raise InterpreterException('Stdlib definition for %s should have exactly two elements.' \
+ % l)
+ projname, depname = di
+ subproj = self.do_subproject(projname, {})
+ self.build.cross_stdlibs[l] = subproj.get_variable_method([depname], {})
+ except KeyError as e:
+ pass
+
def run(self):
self.evaluate_codeblock(self.ast)
mlog.log('Build targets in project:', mlog.bold(str(len(self.build.targets))))
@@ -1411,6 +1427,8 @@ class Interpreter():
if 'vala' in langs:
if not 'c' in langs:
raise InterpreterException('Compiling Vala requires C. Add C to your project languages and rerun Meson.')
+ if not self.is_subproject():
+ self.check_cross_stdlibs()
@stringArgs
def func_add_languages(self, node, args, kwargs):
@@ -1982,11 +2000,28 @@ class Interpreter():
mlog.debug('Unknown target type:', str(targetholder))
raise RuntimeError('Unreachable code')
target = targetclass(name, self.subdir, self.subproject, is_cross, sources, objs, self.environment, kwargs)
+ if is_cross:
+ self.add_cross_stdlib_info(target)
l = targetholder(target, self)
self.add_target(name, l.held_object)
self.global_args_frozen = True
return l
+ def get_used_languages(self, target):
+ result = {}
+ for i in target.sources:
+ for c in self.build.compilers:
+ if c.can_compile(i):
+ result[c.language] = True
+ break
+ return result
+
+ def add_cross_stdlib_info(self, target):
+ for l in self.get_used_languages(target):
+ if self.environment.cross_info.has_stdlib(l) and \
+ self.subproject != self.environment.cross_info.get_stdlib(l)[0]:
+ target.add_external_deps(self.build.cross_stdlibs[l])
+
def check_sources_exist(self, subdir, sources):
for s in sources:
if not isinstance(s, str):
diff --git a/run_tests.py b/run_tests.py
index ad2450e..1317380 100755
--- a/run_tests.py
+++ b/run_tests.py
@@ -157,7 +157,7 @@ def validate_install(srcdir, installdir):
return ''
def log_text_file(logfile, testdir, stdo, stde):
- global stop
+ global stop, executor, futures
logfile.write('%s\nstdout\n\n---\n' % testdir)
logfile.write(stdo)
logfile.write('\n\n---\n\nstderr\n\n---\n')
@@ -167,6 +167,10 @@ def log_text_file(logfile, testdir, stdo, stde):
print(stdo)
print(stde, file=sys.stderr)
if stop:
+ print("Aborting..")
+ for f in futures:
+ f[2].cancel()
+ executor.shutdown()
raise StopException()
def run_configure_inprocess(commandlist):
@@ -300,7 +304,7 @@ def detect_tests_to_run():
return all_tests
def run_tests(extra_args):
- global passing_tests, failing_tests, stop
+ global passing_tests, failing_tests, stop, executor, futures
all_tests = detect_tests_to_run()
logfile = open('meson-test-run.txt', 'w', encoding="utf_8")
junit_root = ET.Element('testsuites')
diff --git a/test cases/common/43 has function/meson.build b/test cases/common/43 has function/meson.build
index c7fe353..00ca640 100644
--- a/test cases/common/43 has function/meson.build
+++ b/test cases/common/43 has function/meson.build
@@ -9,7 +9,13 @@ endif
# Should also be able to detect it without specifying the header
# We check for a different function here to make sure the result is
# not taken from a cache (ie. the check above)
-assert(cc.has_function('fprintf'), '"fprintf" function not found without include (should always exist).')
+# On MSVC fprintf is defined as an inline function in the header, so it cannot
+# be found without the include.
+if cc.get_id() != 'msvc'
+ assert(cc.has_function('fprintf'), '"fprintf" function not found without include (on !msvc).')
+else
+ assert(cc.has_function('fprintf', prefix : '#include <stdio.h>'), '"fprintf" function not found with include (on msvc).')
+endif
if cc.has_function('hfkerhisadf', prefix : '#include<stdio.h>')
error('Found non-existent function "hfkerhisadf".')