aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJussi Pakkanen <jpakkane@gmail.com>2016-05-25 23:44:24 +0300
committerJussi Pakkanen <jpakkane@gmail.com>2016-05-25 23:44:24 +0300
commitdf03f849a8d52bb45677b17b2516f2257ea42dda (patch)
treec92548f1fc649b4993a1e84bca968e816265365b
parentdf90b265336b896e2e956d9454187838703d69d1 (diff)
parentafe7252476290ffb6d26a21bf4ceab9eecc7ca79 (diff)
downloadmeson-df03f849a8d52bb45677b17b2516f2257ea42dda.zip
meson-df03f849a8d52bb45677b17b2516f2257ea42dda.tar.gz
meson-df03f849a8d52bb45677b17b2516f2257ea42dda.tar.bz2
Merge pull request #542 from mesonbuild/ownstdlib
Build transparently with a custom standard library
-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.py6
-rw-r--r--mesonbuild/environment.py6
-rw-r--r--mesonbuild/interpreter.py35
13 files changed, 153 insertions, 0 deletions
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 27a49a7..241192e 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]
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 fb3e601..f269c2f 100644
--- a/mesonbuild/interpreter.py
+++ b/mesonbuild/interpreter.py
@@ -1078,6 +1078,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))))
@@ -1412,6 +1428,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):
@@ -1983,11 +2001,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):