aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.appveyor.yml6
-rw-r--r--.travis.yml4
-rw-r--r--__main__.py20
-rw-r--r--authors.txt1
-rw-r--r--data/macros.meson53
-rw-r--r--man/meson.12
-rw-r--r--man/mesonconf.12
-rw-r--r--man/mesonintrospect.12
-rw-r--r--man/wraptool.12
-rwxr-xr-xmeson.py12
-rw-r--r--mesonbuild/backend/backends.py26
-rw-r--r--mesonbuild/backend/ninjabackend.py156
-rw-r--r--mesonbuild/build.py162
-rw-r--r--mesonbuild/compilers.py364
-rw-r--r--mesonbuild/coredata.py9
-rw-r--r--mesonbuild/dependencies.py25
-rw-r--r--mesonbuild/environment.py195
-rw-r--r--mesonbuild/interpreter.py70
-rw-r--r--mesonbuild/mconf.py2
-rw-r--r--mesonbuild/mesonlib.py3
-rw-r--r--mesonbuild/mesonmain.py18
-rw-r--r--mesonbuild/mintro.py2
-rw-r--r--mesonbuild/modules/gnome.py180
-rw-r--r--mesonbuild/modules/pkgconfig.py18
-rw-r--r--mesonbuild/modules/rpm.py22
-rwxr-xr-x[-rw-r--r--]mesonbuild/scripts/commandrunner.py0
-rwxr-xr-x[-rw-r--r--]mesonbuild/scripts/delwithsuffix.py0
-rwxr-xr-x[-rw-r--r--]mesonbuild/scripts/depfixer.py0
-rwxr-xr-x[-rw-r--r--]mesonbuild/scripts/dirchanger.py0
-rw-r--r--mesonbuild/scripts/gettext.py2
-rwxr-xr-x[-rw-r--r--]mesonbuild/scripts/gtkdochelper.py0
-rwxr-xr-x[-rw-r--r--]mesonbuild/scripts/meson_benchmark.py0
-rwxr-xr-x[-rw-r--r--]mesonbuild/scripts/meson_exe.py0
-rwxr-xr-x[-rw-r--r--]mesonbuild/scripts/meson_install.py0
-rwxr-xr-x[-rw-r--r--]mesonbuild/scripts/meson_test.py0
-rwxr-xr-x[-rw-r--r--]mesonbuild/scripts/regen_checker.py0
-rw-r--r--mesonbuild/scripts/scanbuild.py1
-rwxr-xr-x[-rw-r--r--]mesonbuild/scripts/symbolextractor.py0
-rwxr-xr-x[-rw-r--r--]mesonbuild/scripts/vcstagger.py0
-rwxr-xr-xrun_project_tests.py499
-rwxr-xr-xrun_tests.py494
-rwxr-xr-xrun_unittests.py91
-rw-r--r--setup.py27
-rw-r--r--test cases/common/1 trivial/meson.build5
-rw-r--r--test cases/common/117 custom target capture/meson.build12
-rw-r--r--test cases/common/119 pathjoin/meson.build9
-rw-r--r--test cases/common/62 exe static shared/meson.build9
-rw-r--r--test cases/common/62 exe static shared/prog.c7
-rw-r--r--test cases/common/62 exe static shared/shlib2.c8
-rw-r--r--test cases/common/62 exe static shared/stat2.c3
-rw-r--r--test cases/common/62 exe static shared/subdir/exports.h12
-rw-r--r--test cases/common/62 exe static shared/subdir/shlib.c11
-rw-r--r--test cases/common/95 dep fallback/gensrc.py6
-rw-r--r--test cases/common/95 dep fallback/meson.build11
-rw-r--r--test cases/common/95 dep fallback/subprojects/boblib/bob.c3
-rw-r--r--test cases/common/95 dep fallback/subprojects/boblib/bob.h3
-rw-r--r--test cases/common/95 dep fallback/subprojects/boblib/genbob.py7
-rw-r--r--test cases/common/95 dep fallback/subprojects/boblib/meson.build11
-rw-r--r--test cases/common/95 dep fallback/tester.c1
-rw-r--r--test cases/failing/33 exe static shared/meson.build11
-rw-r--r--test cases/failing/33 exe static shared/prog.c10
-rw-r--r--test cases/failing/33 exe static shared/shlib2.c16
-rw-r--r--test cases/failing/33 exe static shared/stat.c3
-rw-r--r--test cases/frameworks/7 gnome/genmarshal/main.c102
-rw-r--r--test cases/frameworks/7 gnome/genmarshal/marshaller.list3
-rw-r--r--test cases/frameworks/7 gnome/genmarshal/meson.build11
-rw-r--r--test cases/frameworks/7 gnome/gir/meson.build3
-rw-r--r--test cases/frameworks/7 gnome/installed_files.txt4
-rw-r--r--test cases/frameworks/7 gnome/meson.build3
-rw-r--r--test cases/frameworks/7 gnome/mkenums/enums.c.in41
-rw-r--r--test cases/frameworks/7 gnome/mkenums/enums.h.in24
-rw-r--r--test cases/frameworks/7 gnome/mkenums/enums2.c.in41
-rw-r--r--test cases/frameworks/7 gnome/mkenums/enums2.h.in24
-rw-r--r--test cases/frameworks/7 gnome/mkenums/main.c30
-rw-r--r--test cases/frameworks/7 gnome/mkenums/meson-sample.h18
-rw-r--r--test cases/frameworks/7 gnome/mkenums/meson.build119
-rw-r--r--test cases/frameworks/7 gnome/schemas/meson.build4
-rw-r--r--test cases/swift/2 multifile/main.swift4
-rw-r--r--test cases/swift/4 generate/gen/main.swift4
-rw-r--r--test cases/vala/11 mixed sources/bar.vala5
-rw-r--r--test cases/vala/11 mixed sources/foo.c3
-rw-r--r--test cases/vala/11 mixed sources/meson.build5
-rw-r--r--test cases/vala/8 generated source/installed_files.txt1
-rw-r--r--test cases/vala/8 generated source/meson.build7
-rw-r--r--test cases/vala/8 generated source/src/config.vala.in3
-rw-r--r--test cases/vala/8 generated source/src/meson.build5
-rw-r--r--test cases/vala/8 generated source/src/test.vala3
-rw-r--r--test cases/vala/8 generated source/tools/meson.build3
-rwxr-xr-xtools/ac_converter.py5
89 files changed, 2049 insertions, 1054 deletions
diff --git a/.appveyor.yml b/.appveyor.yml
index 09f67e4..38ebe56 100644
--- a/.appveyor.yml
+++ b/.appveyor.yml
@@ -18,4 +18,8 @@ build_script:
- cmd: echo No build step.
test_script:
- - cmd: PATH c:\python34;%PATH% && python3 run_tests.py --backend=ninja
+ - cmd: PATH c:\python34;%PATH%; && python3 run_tests.py --backend=ninja
+
+on_finish:
+ - appveyor PushArtifact meson-test-run.txt -DeploymentName "Text test logs"
+ - appveyor PushArtifact meson-test-run.xml -DeploymentName "XML test logs"
diff --git a/.travis.yml b/.travis.yml
index 2564742..fdf82ef 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -22,5 +22,5 @@ script:
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then echo FROM jpakkane/mesonci:xenial > Dockerfile; fi
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then echo ADD . /root >> Dockerfile; fi
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then docker build -t withgit .; fi
- - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then docker run withgit /bin/sh -c "cd /root && ./run_tests.py"; fi
- - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then ./run_tests.py --backend=ninja ; fi
+ - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then docker run withgit /bin/sh -c "cd /root && TRAVIS=true ./run_tests.py"; fi
+ - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then SDKROOT=$(xcodebuild -version -sdk macosx Path) ./run_tests.py --backend=ninja ; fi
diff --git a/__main__.py b/__main__.py
new file mode 100644
index 0000000..c412e37
--- /dev/null
+++ b/__main__.py
@@ -0,0 +1,20 @@
+#!/usr/bin/env python3
+
+# Copyright 2016 The Meson development team
+
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+
+# http://www.apache.org/licenses/LICENSE-2.0
+
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import meson
+import sys
+
+sys.exit(meson.main())
diff --git a/authors.txt b/authors.txt
index f0c2006..229a2ff 100644
--- a/authors.txt
+++ b/authors.txt
@@ -46,3 +46,4 @@ Patrick Griffis
Iain Lane
Daniel Brendle
Franz Zapata
+Emanuele Aina
diff --git a/data/macros.meson b/data/macros.meson
index c89854b..4b91c70 100644
--- a/data/macros.meson
+++ b/data/macros.meson
@@ -1,21 +1,34 @@
-%__meson /usr/bin/meson
+%__meson %{_bindir}/meson
+%__sourcedir .
+%__builddir %{_target_platform}
-%meson() %{expand:\
- export CFLAGS="%{optflags}" ; \
- export CXXFLAGS="%{optflags}" ; \
- export FFLAGS="%{optflags} -I%{_fmoddir}" ; \
- export FCFLAGS="%{optflags} -I%{_fmoddir}" ; \
- export LDFLAGS="%{__global_ldflags}" ; \
- %__meson %{?1} \\\
- --prefix=%{_prefix} \\\
- --libdir=%{_libdir} \\\
- --libexecdir=%{_libexecdir} \\\
- --bindir=%{_bindir} \\\
- --includedir=%{_includedir} \\\
- --datadir=%{_datadir} \\\
- --mandir=%{_mandir} \\\
- --localedir=%{_datadir}/locale \\\
- --sysconfdir=%{_sysconfdir} \\\
- --buildtype=plain \
- %{nil} \
-}
+%meson \
+ export CFLAGS="%{optflags}" \
+ export CXXFLAGS="%{optflags}" \
+ export FFLAGS="%{optflags} -I%{_fmoddir}" \
+ export FCFLAGS="%{optflags} -I%{_fmoddir}" \
+ export LDFLAGS="%{?__global_ldflags}" \
+ mkdir -p %{__builddir} \
+ pushd %{__builddir} \
+ %{__meson} \\\
+ --buildtype=plain \\\
+ --prefix=%{_prefix} \\\
+ --libdir=%{_libdir} \\\
+ --libexecdir=%{_libexecdir} \\\
+ --bindir=%{_bindir} \\\
+ --includedir=%{_includedir} \\\
+ --datadir=%{_datadir} \\\
+ --mandir=%{_mandir} \\\
+ --localedir=%{_datadir}/locale \\\
+ --sysconfdir=%{_sysconfdir} \\\
+ $OLDPWD/%{__sourcedir} \
+ popd
+
+%meson_build \
+ %ninja_build -C %{__builddir}
+
+%meson_install \
+ %ninja_install -C %{__builddir}
+
+%meson_test \
+ %ninja_test -C %{__builddir}
diff --git a/man/meson.1 b/man/meson.1
index f41a945..cb8420b 100644
--- a/man/meson.1
+++ b/man/meson.1
@@ -1,4 +1,4 @@
-.TH MESON "1" "September 2016" "meson 0.34.0" "User Commands"
+.TH MESON "1" "October 2016" "meson 0.35.0" "User Commands"
.SH NAME
meson - a high productivity build system
.SH DESCRIPTION
diff --git a/man/mesonconf.1 b/man/mesonconf.1
index 4009c58..5b0212f 100644
--- a/man/mesonconf.1
+++ b/man/mesonconf.1
@@ -1,4 +1,4 @@
-.TH MESONCONF "1" "September 2016" "mesonconf 0.34.0" "User Commands"
+.TH MESONCONF "1" "October 2016" "mesonconf 0.35.0" "User Commands"
.SH NAME
mesonconf - a tool to configure Meson builds
.SH DESCRIPTION
diff --git a/man/mesonintrospect.1 b/man/mesonintrospect.1
index 74a006c..5f6a26f 100644
--- a/man/mesonintrospect.1
+++ b/man/mesonintrospect.1
@@ -1,4 +1,4 @@
-.TH MESONCONF "1" "September 2016" "mesonintrospect 0.34.0" "User Commands"
+.TH MESONCONF "1" "October 2016" "mesonintrospect 0.35.0" "User Commands"
.SH NAME
mesonintrospect - a tool to extract information about a Meson build
.SH DESCRIPTION
diff --git a/man/wraptool.1 b/man/wraptool.1
index b2168c3..15958ca 100644
--- a/man/wraptool.1
+++ b/man/wraptool.1
@@ -1,4 +1,4 @@
-.TH WRAPTOOL "1" "September 2016" "meson 0.34.0" "User Commands"
+.TH WRAPTOOL "1" "October 2016" "meson 0.35.0" "User Commands"
.SH NAME
wraptool - source dependency downloader
.SH DESCRIPTION
diff --git a/meson.py b/meson.py
index fbca883..8c223e5 100755
--- a/meson.py
+++ b/meson.py
@@ -18,13 +18,9 @@ from mesonbuild import mesonmain
import sys, os
def main():
- thisfile = __file__
- if not os.path.isabs(thisfile):
- thisfile = os.path.normpath(os.path.join(os.getcwd(), thisfile))
- if __package__ == '':
- thisfile = os.path.dirname(thisfile)
-
- sys.exit(mesonmain.run(thisfile, sys.argv[1:]))
+ # Always resolve the command path so Ninja can find it for regen, tests, etc.
+ launcher = os.path.realpath(sys.argv[0])
+ return mesonmain.run(launcher, sys.argv[1:])
if __name__ == '__main__':
- main()
+ sys.exit(main())
diff --git a/mesonbuild/backend/backends.py b/mesonbuild/backend/backends.py
index 5681f7c..16f7ada 100644
--- a/mesonbuild/backend/backends.py
+++ b/mesonbuild/backend/backends.py
@@ -72,7 +72,6 @@ class Backend():
self.build = build
self.environment = build.environment
self.processed_targets = {}
- self.dep_rules = {}
self.build_to_src = os.path.relpath(self.environment.get_source_dir(),
self.environment.get_build_dir())
for t in self.build.targets:
@@ -238,27 +237,6 @@ class Backend():
self.write_benchmark_file(datafile)
return (test_data, benchmark_data)
- def has_source_suffix(self, target, suffix):
- for s in target.get_sources():
- if s.endswith(suffix):
- return True
- return False
-
- def has_vala(self, target):
- return self.has_source_suffix(target, '.vala')
-
- def has_rust(self, target):
- return self.has_source_suffix(target, '.rs')
-
- def has_cs(self, target):
- return self.has_source_suffix(target, '.cs')
-
- def has_swift(self, target):
- return self.has_source_suffix(target, '.swift')
-
- def has_d(self, target):
- return self.has_source_suffix(target, '.d')
-
def determine_linker(self, target, src):
if isinstance(target, build.StaticLibrary):
if self.build.static_cross_linker is not None:
@@ -363,6 +341,8 @@ class Backend():
commands += compiler.get_werror_args()
if isinstance(target, build.SharedLibrary):
commands += compiler.get_pic_args()
+ if isinstance(target, build.StaticLibrary) and target.pic:
+ commands += compiler.get_pic_args()
for dep in target.get_external_deps():
# Cflags required by external deps might have UNIX-specific flags,
# so filter them out if needed
@@ -641,7 +621,7 @@ class Backend():
final_commands = []
previous = '-fsuch_arguments=woof'
for c in commands:
- if c.startswith(('-I' '-L', '/LIBPATH')):
+ if c.startswith(('-I', '-L', '/LIBPATH')):
if c in includes:
continue
includes[c] = True
diff --git a/mesonbuild/backend/ninjabackend.py b/mesonbuild/backend/ninjabackend.py
index 41f96f1..a29af60 100644
--- a/mesonbuild/backend/ninjabackend.py
+++ b/mesonbuild/backend/ninjabackend.py
@@ -38,6 +38,12 @@ class RawFilename():
def __init__(self, fname):
self.fname = fname
+ def __str__(self):
+ return self.fname
+
+ def __repr__(self):
+ return '<RawFilename: {0}>'.format(self.fname)
+
def split(self, c):
return self.fname.split(c)
@@ -233,23 +239,19 @@ int dummy;
if isinstance(target, build.Jar):
self.generate_jar_target(target, outfile)
return
- if 'rust' in self.environment.coredata.compilers.keys() and self.has_rust(target):
+ if 'rust' in target.compilers:
self.generate_rust_target(target, outfile)
return
- if 'cs' in self.environment.coredata.compilers.keys() and self.has_cs(target):
+ if 'cs' in target.compilers:
self.generate_cs_target(target, outfile)
return
- if 'vala' in self.environment.coredata.compilers.keys() and self.has_vala(target):
- vc = self.environment.coredata.compilers['vala']
- vala_output_files = self.generate_vala_compile(vc, target, outfile)
- gen_src_deps += vala_output_files
- if 'swift' in self.environment.coredata.compilers.keys() and self.has_swift(target):
+ if 'swift' in target.compilers:
self.generate_swift_target(target, outfile)
return
+ if 'vala' in target.compilers:
+ vala_output_files = self.generate_vala_compile(target, outfile)
+ gen_src_deps += vala_output_files
self.scan_fortran_module_outputs(target)
- # The following deals with C/C++ compilation.
- (gen_src, gen_other_deps) = self.process_dep_gens(outfile, target)
- gen_src_deps += gen_src
self.process_target_dependencies(target, outfile)
self.generate_custom_generator_rules(target, outfile)
outname = self.get_target_filename(target)
@@ -260,22 +262,30 @@ int dummy;
pch_objects = self.generate_pch(target, outfile)
else:
pch_objects = []
- header_deps = gen_other_deps
+ header_deps = []
unity_src = []
unity_deps = [] # Generated sources that must be built before compiling a Unity target.
header_deps += self.get_generated_headers(target)
- generator_output_sources = [] # Needed to determine the linker
+ src_list = []
+
+ # Get a list of all generated *sources* (sources files, headers,
+ # objects, etc). Needed to determine the linker.
+ generated_output_sources = []
+ # Get a list of all generated headers that will be needed while building
+ # this target's sources (generated sources and pre-existing sources).
+ # This will be set as dependencies of all the target's sources. At the
+ # same time, also deal with generated sources that need to be compiled.
+ generated_source_files = []
for gensource in target.get_generated_sources():
if isinstance(gensource, build.CustomTarget):
for src in gensource.output:
src = os.path.join(self.get_target_dir(gensource), src)
- generator_output_sources.append(src)
+ generated_output_sources.append(src)
if self.environment.is_source(src) and not self.environment.is_header(src):
if is_unity:
unity_deps.append(os.path.join(self.environment.get_build_dir(), RawFilename(src)))
else:
- obj_list.append(self.generate_single_compile(target, outfile, RawFilename(src), True,
- header_deps))
+ generated_source_files.append(RawFilename(src))
elif self.environment.is_object(src):
obj_list.append(src)
elif self.environment.is_library(src):
@@ -287,7 +297,7 @@ int dummy;
header_deps.append(RawFilename(src))
else:
for src in gensource.get_outfilelist():
- generator_output_sources.append(src)
+ generated_output_sources.append(src)
if self.environment.is_object(src):
obj_list.append(os.path.join(self.get_target_private_dir(target), src))
elif not self.environment.is_header(src):
@@ -300,9 +310,16 @@ int dummy;
abs_src = os.path.join(self.environment.get_build_dir(), rel_src)
unity_src.append(abs_src)
else:
- obj_list.append(self.generate_single_compile(target, outfile, src, True,
- header_deps=header_deps))
- src_list = []
+ generated_source_files.append(src)
+ # These are the generated source files that need to be built for use by
+ # this target. We create the Ninja build file elements for this here
+ # because we need `header_deps` to be fully generated in the above loop.
+ for src in generated_source_files:
+ src_list.append(src)
+ obj_list.append(self.generate_single_compile(target, outfile, src, True,
+ header_deps=header_deps))
+ # Generate compilation targets for sources belonging to this target that
+ # are generated by other rules (this is only used for Vala right now)
for src in gen_src_deps:
src_list.append(src)
if is_unity:
@@ -318,6 +335,7 @@ int dummy;
header_deps.append(src)
else:
obj_list.append(self.generate_single_compile(target, outfile, src, True, [], header_deps))
+ # Generate compile targets for all the pre-existing sources for this target
for src in target.get_sources():
if src.endswith('.vala'):
continue
@@ -333,7 +351,7 @@ int dummy;
if is_unity:
for src in self.generate_unity_files(target, unity_src):
obj_list.append(self.generate_single_compile(target, outfile, src, True, unity_deps + header_deps))
- linker = self.determine_linker(target, src_list + generator_output_sources)
+ linker = self.determine_linker(target, src_list + generated_output_sources)
elem = self.generate_link(target, outfile, outname, obj_list, linker, pch_objects)
self.generate_shlib_aliases(target, self.get_target_dir(target))
elem.write(outfile)
@@ -718,8 +736,7 @@ int dummy;
outname_rel = os.path.join(self.get_target_dir(target), fname)
src_list = target.get_sources()
class_list = []
- compiler = self.get_compiler_for_source(src_list[0], False)
- assert(compiler.get_language() == 'java')
+ compiler = target.compilers['java']
c = 'c'
m = ''
e = ''
@@ -769,8 +786,7 @@ int dummy;
fname = target.get_filename()
outname_rel = os.path.join(self.get_target_dir(target), fname)
src_list = target.get_sources()
- compiler = self.get_compiler_for_source(src_list[0], False)
- assert(compiler.get_language() == 'cs')
+ compiler = target.compilers['cs']
rel_srcs = [s.rel_to_builddir(self.build_to_src) for s in src_list]
deps = []
commands = target.extra_args.get('cs', [])
@@ -823,14 +839,14 @@ int dummy;
outfile.write('\n')
def split_vala_sources(self, sources):
- src = []
+ other_src = []
vapi_src = []
for s in sources:
if s.endswith('.vapi'):
vapi_src.append(s)
else:
- src.append(s)
- return (src, vapi_src)
+ other_src.append(s)
+ return (other_src, vapi_src)
def determine_dep_vapis(self, target):
result = []
@@ -845,17 +861,13 @@ int dummy;
break
return result
- def generate_vala_compile(self, compiler, target, outfile):
+ def generate_vala_compile(self, target, outfile):
"""Vala is compiled into C. Set up all necessary build steps here."""
- valac = self.environment.coredata.compilers['vala']
- (src, vapi_src) = self.split_vala_sources(target.get_sources())
+ valac = target.compilers['vala']
+ (other_src, vapi_src) = self.split_vala_sources(target.get_sources())
vapi_src = [x.rel_to_builddir(self.build_to_src) for x in vapi_src]
extra_dep_files = []
- vala_input_files = []
- for s in src:
- if s.endswith('.vala'):
- vala_input_files.append(s.rel_to_builddir(self.build_to_src))
- if len(src) == 0:
+ if len(other_src) == 0:
raise InvalidArguments('Vala library has no Vala source files.')
namebase = target.name
base_h = namebase + '.h'
@@ -866,8 +878,8 @@ int dummy;
generated_c_files = []
outputs = [vapiname]
args = []
- args += self.build.get_global_args(compiler)
- args += compiler.get_buildtype_args(self.environment.coredata.get_builtin_option('buildtype'))
+ args += self.build.get_global_args(valac)
+ args += valac.get_buildtype_args(self.environment.coredata.get_builtin_option('buildtype'))
args += ['-d', self.get_target_private_dir(target)]
args += ['-C']#, '-o', cname]
if not isinstance(target, build.Executable):
@@ -875,9 +887,23 @@ int dummy;
args += ['-H', hname]
args += ['--library=' + target.name]
args += ['--vapi=' + os.path.join('..', base_vapi)]
- for src in vala_input_files:
- namebase = os.path.splitext(os.path.split(src)[1])[0] + '.c'
- full_c = os.path.join(self.get_target_private_dir(target), namebase)
+ vala_src = []
+ for s in other_src:
+ if not s.endswith('.vala'):
+ continue
+ vala_file = s.rel_to_builddir(self.build_to_src)
+ vala_src.append(vala_file)
+ # Figure out where the Vala compiler will write the compiled C file
+ dirname, basename = os.path.split(vala_file)
+ # If the Vala file is in a subdir of the build dir (in our case
+ # because it was generated/built by something else), the subdir path
+ # components will be preserved in the output path. But if the Vala
+ # file is outside the build directory, the path components will be
+ # stripped and just the basename will be used.
+ c_file = os.path.splitext(basename)[0] + '.c'
+ if s.is_built:
+ c_file = os.path.join(dirname, c_file)
+ full_c = os.path.join(self.get_target_private_dir(target), c_file)
generated_c_files.append(full_c)
outputs.append(full_c)
if self.environment.coredata.get_builtin_option('werror'):
@@ -903,14 +929,14 @@ int dummy;
args += dependency_vapis
element = NinjaBuildElement(self.all_outputs, outputs,
valac.get_language() + '_COMPILER',
- vala_input_files + vapi_src)
+ vala_src + vapi_src)
element.add_item('ARGS', args)
element.add_dep(extra_dep_files)
element.write(outfile)
return generated_c_files
def generate_rust_target(self, target, outfile):
- rustc = self.environment.coredata.compilers['rust']
+ rustc = target.compilers['rust']
relsrc = []
for i in target.get_sources():
if not rustc.can_compile(i):
@@ -1001,7 +1027,7 @@ int dummy;
def generate_swift_target(self, target, outfile):
module_name = self.target_swift_modulename(target)
- swiftc = self.environment.coredata.compilers['swift']
+ swiftc = target.compilers['swift']
abssrc = []
abs_headers = []
header_imports = []
@@ -1801,7 +1827,7 @@ rule FORTRAN_DEP_HACK
soversion = target.soversion
else:
soversion = None
- commands += linker.get_soname_args(target.name, abspath, soversion)
+ commands += linker.get_soname_args(target.prefix, target.name, target.suffix, abspath, soversion)
# This is only visited when using the Visual Studio toolchain
if target.vs_module_defs and hasattr(linker, 'gen_vs_module_defs_args'):
commands += linker.gen_vs_module_defs_args(target.vs_module_defs.rel_to_builddir(self.build_to_src))
@@ -1891,36 +1917,6 @@ rule FORTRAN_DEP_HACK
gcda_elem.add_item('description', 'Deleting gcda files')
gcda_elem.write(outfile)
- def is_compilable_file(self, filename):
- if filename.endswith('.cpp') or\
- filename.endswith('.c') or\
- filename.endswith('.cxx') or\
- filename.endswith('.cc') or\
- filename.endswith('.C'):
- return True
- return False
-
- def process_dep_gens(self, outfile, target):
- src_deps = []
- other_deps = []
- for rule in self.dep_rules.values():
- srcs = target.get_original_kwargs().get(rule.src_keyword, [])
- if isinstance(srcs, str):
- srcs = [srcs]
- for src in srcs:
- plainname = os.path.split(src)[1]
- basename = plainname.split('.')[0]
- outname = rule.name_templ.replace('@BASENAME@', basename).replace('@PLAINNAME@', plainname)
- outfilename = os.path.join(self.get_target_private_dir(target), outname)
- infilename = os.path.join(self.build_to_src, target.get_source_subdir(), src)
- elem = NinjaBuildElement(self.all_outputs, outfilename, rule.name, infilename)
- elem.write(outfile)
- if self.is_compilable_file(outfilename):
- src_deps.append(outfilename)
- else:
- other_deps.append(outfilename)
- return (src_deps, other_deps)
-
# For things like scan-build and other helper tools we might have.
def generate_utils(self, outfile):
cmd = [sys.executable, self.environment.get_build_command(),
@@ -1932,8 +1928,16 @@ rule FORTRAN_DEP_HACK
elem.write(outfile)
def generate_ending(self, outfile):
- targetlist = [self.get_target_filename(t) for t in self.build.get_targets().values()\
- if not isinstance(t, build.RunTarget)]
+ targetlist = []
+ for t in self.build.get_targets().values():
+ # RunTargets are meant to be invoked manually
+ if isinstance(t, build.RunTarget):
+ continue
+ # CustomTargets that aren't installed should only be built if they
+ # are used by something else or are meant to be always built
+ if isinstance(t, build.CustomTarget) and not (t.install or t.build_always):
+ continue
+ targetlist.append(self.get_target_filename(t))
elem = NinjaBuildElement(self.all_outputs, 'all', 'phony', targetlist)
elem.write(outfile)
diff --git a/mesonbuild/build.py b/mesonbuild/build.py
index dce0236..4fc8536 100644
--- a/mesonbuild/build.py
+++ b/mesonbuild/build.py
@@ -44,43 +44,30 @@ known_basic_kwargs = {'install' : True,
'native' : True,
}
-known_shlib_kwargs = known_basic_kwargs.copy()
-known_shlib_kwargs.update({'version' : True,
- 'soversion' : True,
- 'name_prefix' : True,
- 'name_suffix' : True,
- 'vs_module_defs' : True})
-
-def sources_are_suffix(sources, suffix):
- for source in sources:
- if source.endswith('.' + suffix):
- return True
- return False
-
-def compiler_is_msvc(sources, is_cross, env):
+# These contain kwargs supported by both static and shared libraries. These are
+# combined here because a library() call might be shared_library() or
+# static_library() at runtime based on the configuration.
+# FIXME: Find a way to pass that info down here so we can have proper target
+# kwargs checking when specifically using shared_library() or static_library().
+known_lib_kwargs = known_basic_kwargs.copy()
+known_lib_kwargs.update({'version' : True, # Only for shared libs
+ 'soversion' : True, # Only for shared libs
+ 'name_prefix' : True,
+ 'name_suffix' : True,
+ 'vs_module_defs' : True, # Only for shared libs
+ 'pic' : True, # Only for static libs
+ })
+
+def compilers_are_msvc(compilers):
"""
- Since each target does not currently have the compiler information attached
- to it, we must do this detection manually here.
-
- This detection is purposely incomplete and will cause bugs if other code is
- extended and this piece of code is forgotten.
+ Check if all the listed compilers are MSVC. Used by Executable,
+ StaticLibrary, and SharedLibrary for deciding when to use MSVC-specific
+ file naming.
"""
- compiler = None
- if sources_are_suffix(sources, 'c'):
- try:
- compiler = env.detect_c_compiler(is_cross)
- except MesonException:
- return False
- elif sources_are_suffix(sources, 'cxx') or \
- sources_are_suffix(sources, 'cpp') or \
- sources_are_suffix(sources, 'cc'):
- try:
- compiler = env.detect_cpp_compiler(is_cross)
- except MesonException:
+ for compiler in compilers.values():
+ if compiler.get_id() != 'msvc':
return False
- if compiler and compiler.get_id() == 'msvc':
- return True
- return False
+ return True
class InvalidArguments(MesonException):
@@ -234,12 +221,16 @@ class BuildTarget():
self.subdir = subdir
self.subproject = subproject # Can not be calculated from subdir as subproject dirname can be changed per project.
self.is_cross = is_cross
+ self.environment = environment
self.sources = []
+ self.compilers = {}
self.objects = []
self.external_deps = []
self.include_dirs = []
self.link_targets = []
self.link_depends = []
+ self.name_prefix_set = False
+ self.name_suffix_set = False
self.filename = 'no_name'
# The file with debugging symbols
self.debug_filename = None
@@ -256,6 +247,7 @@ class BuildTarget():
len(self.generated) == 0 and \
len(self.objects) == 0:
raise InvalidArguments('Build target %s has no sources.' % name)
+ self.process_compilers()
self.validate_sources()
def __repr__(self):
@@ -320,16 +312,52 @@ class BuildTarget():
msg = 'Bad source of type {!r} in target {!r}.'.format(type(s).__name__, self.name)
raise InvalidArguments(msg)
+ @staticmethod
+ def can_compile_remove_sources(compiler, sources):
+ removed = False
+ for s in sources[:]:
+ if compiler.can_compile(s):
+ sources.remove(s)
+ removed = True
+ return removed
+
+ def process_compilers(self):
+ if len(self.sources) == 0:
+ return
+ sources = list(self.sources)
+ if self.is_cross:
+ compilers = self.environment.coredata.cross_compilers
+ else:
+ compilers = self.environment.coredata.compilers
+ for lang, compiler in compilers.items():
+ if self.can_compile_remove_sources(compiler, sources):
+ self.compilers[lang] = compiler
+
def validate_sources(self):
- if len(self.sources) > 0:
+ if len(self.sources) == 0:
+ return
+ for lang in ('cs', 'java'):
+ if lang in self.compilers:
+ check_sources = list(self.sources)
+ compiler = self.compilers[lang]
+ if not self.can_compile_remove_sources(compiler, check_sources):
+ m = 'No {} sources found in target {!r}'.format(lang, self.name)
+ raise InvalidArguments(m)
+ if check_sources:
+ m = '{0} targets can only contain {0} files:\n'.format(lang.capitalize())
+ m += '\n'.join([repr(c) for c in check_sources])
+ raise InvalidArguments(m)
+ # CSharp and Java targets can't contain any other file types
+ assert(len(self.compilers) == 1)
+ return
+ if 'rust' in self.compilers:
firstname = self.sources[0]
if isinstance(firstname, File):
firstname = firstname.fname
first = os.path.split(firstname)[1]
(base, suffix) = os.path.splitext(first)
- if suffix == '.rs':
- if self.name != base:
- raise InvalidArguments('In Rust targets, the first source file must be named projectname.rs.')
+ if suffix != '.rs' or self.name != base:
+ raise InvalidArguments('In Rust targets, the first source file must be named projectname.rs.')
def get_original_kwargs(self):
return self.kwargs
@@ -484,19 +512,34 @@ class BuildTarget():
name_prefix = kwargs['name_prefix']
if isinstance(name_prefix, list):
if len(name_prefix) != 0:
- raise InvalidArguments('Array must be empty to signify null.')
+ raise InvalidArguments('name_prefix array must be empty to signify null.')
elif not isinstance(name_prefix, str):
- raise InvalidArguments('Name prefix must be a string.')
+ raise InvalidArguments('name_prefix must be a string.')
self.prefix = name_prefix
+ self.name_prefix_set = True
if 'name_suffix' in kwargs:
name_suffix = kwargs['name_suffix']
if isinstance(name_suffix, list):
if len(name_suffix) != 0:
- raise InvalidArguments('Array must be empty to signify null.')
+ raise InvalidArguments('name_suffix array must be empty to signify null.')
else:
if not isinstance(name_suffix, str):
- raise InvalidArguments('Name suffix must be a string.')
+ raise InvalidArguments('name_suffix must be a string.')
self.suffix = name_suffix
+ self.name_suffix_set = True
+ if isinstance(self, StaticLibrary):
+ # You can't disable PIC on OS X. The compiler ignores -fno-PIC.
+ # PIC is always on for Windows (all code is position-independent
+ # since library loading is done differently)
+ if for_darwin(self.is_cross, self.environment) or for_windows(self.is_cross, self.environment):
+ self.pic = True
+ elif '-fPIC' in clist + cpplist:
+ mlog.log(mlog.red('WARNING:'), "Use the 'pic' kwarg instead of passing -fPIC manually to static library {!r}".format(self.name))
+ self.pic = True
+ else:
+ self.pic = kwargs.get('pic', False)
+ if not isinstance(self.pic, bool):
+ raise InvalidArguments('Argument pic to static library {!r} must be boolean'.format(self.name))
def get_subdir(self):
return self.subdir
@@ -598,9 +641,13 @@ by calling get_variable() on the subproject object.''')
if hasattr(t, 'held_object'):
t = t.held_object
if not isinstance(t, (StaticLibrary, SharedLibrary)):
- raise InvalidArguments('Link target is not library.')
+ raise InvalidArguments('Link target {!r} is not library.'.format(t.name))
+ if isinstance(self, SharedLibrary) and isinstance(t, StaticLibrary) and not t.pic:
+ msg = "Can't link non-PIC static library {!r} into shared library {!r}. ".format(t.name, self.name)
+ msg += "Use the 'pic' option to static_library to build with PIC."
+ raise InvalidArguments(msg)
if self.is_cross != t.is_cross:
- raise InvalidArguments('Tried to mix cross built and native libraries in target %s.' % self.name)
+ raise InvalidArguments('Tried to mix cross built and native libraries in target {!r}'.format(self.name))
self.link_targets.append(t)
def set_generated(self, genlist):
@@ -768,7 +815,7 @@ class Executable(BuildTarget):
self.prefix = ''
if not hasattr(self, 'suffix'):
# Executable for Windows or C#/Mono
- if for_windows(is_cross, environment) or sources_are_suffix(self.sources, 'cs'):
+ if for_windows(is_cross, environment) or 'cs' in self.compilers:
self.suffix = 'exe'
else:
self.suffix = ''
@@ -777,8 +824,7 @@ class Executable(BuildTarget):
self.filename += '.' + self.suffix
# See determine_debug_filenames() in build.SharedLibrary
buildtype = environment.coredata.get_builtin_option('buildtype')
- if compiler_is_msvc(self.sources, is_cross, environment) and \
- buildtype.startswith('debug'):
+ if compilers_are_msvc(self.compilers) and buildtype.startswith('debug'):
self.debug_filename = self.prefix + self.name + '.pdb'
def type_suffix(self):
@@ -786,8 +832,10 @@ class Executable(BuildTarget):
class StaticLibrary(BuildTarget):
def __init__(self, name, subdir, subproject, is_cross, sources, objects, environment, kwargs):
+ if 'pic' not in kwargs and 'b_staticpic' in environment.coredata.base_options:
+ kwargs['pic'] = environment.coredata.base_options['b_staticpic'].value
super().__init__(name, subdir, subproject, is_cross, sources, objects, environment, kwargs)
- if sources_are_suffix(self.sources, 'cs'):
+ if 'cs' in self.compilers:
raise InvalidArguments('Static libraries not supported for C#.')
# By default a static library is named libfoo.a even on Windows because
# MSVC does not have a consistent convention for what static libraries
@@ -800,20 +848,22 @@ class StaticLibrary(BuildTarget):
self.prefix = 'lib'
if not hasattr(self, 'suffix'):
# Rust static library crates have .rlib suffix
- if sources_are_suffix(self.sources, 'rs'):
+ if 'rust' in self.compilers:
self.suffix = 'rlib'
else:
self.suffix = 'a'
self.filename = self.prefix + self.name + '.' + self.suffix
# See determine_debug_filenames() in build.SharedLibrary
buildtype = environment.coredata.get_builtin_option('buildtype')
- if compiler_is_msvc(self.sources, is_cross, environment) and \
- buildtype.startswith('debug'):
+ if compilers_are_msvc(self.compilers) and buildtype.startswith('debug'):
self.debug_filename = self.prefix + self.name + '.pdb'
def type_suffix(self):
return "@sta"
+ def check_unknown_kwargs(self, kwargs):
+ self.check_unknown_kwargs_int(kwargs, known_lib_kwargs)
+
class SharedLibrary(BuildTarget):
def __init__(self, name, subdir, subproject, is_cross, sources, objects, environment, kwargs):
self.soversion = None
@@ -864,12 +914,12 @@ class SharedLibrary(BuildTarget):
if self.prefix != None and self.suffix != None:
pass
# C# and Mono
- elif sources_are_suffix(self.sources, 'cs'):
+ elif 'cs' in self.compilers:
prefix = ''
suffix = 'dll'
self.filename_tpl = '{0.prefix}{0.name}.{0.suffix}'
# Rust
- elif sources_are_suffix(self.sources, 'rs'):
+ elif 'rust' in self.compilers:
# Currently, we always build --crate-type=rlib
prefix = 'lib'
suffix = 'rlib'
@@ -881,7 +931,7 @@ class SharedLibrary(BuildTarget):
suffix = 'dll'
self.vs_import_filename = '{0}.lib'.format(self.name)
self.gcc_import_filename = 'lib{0}.dll.a'.format(self.name)
- if compiler_is_msvc(self.sources, is_cross, env):
+ if compilers_are_msvc(self.compilers):
# Shared library is of the form foo.dll
prefix = ''
# Import library is called foo.lib
@@ -928,7 +978,7 @@ class SharedLibrary(BuildTarget):
determine_filenames() above.
"""
buildtype = env.coredata.get_builtin_option('buildtype')
- if compiler_is_msvc(self.sources, is_cross, env) and buildtype.startswith('debug'):
+ if compilers_are_msvc(self.compilers) and buildtype.startswith('debug'):
# Currently we only implement separate debug symbol files for MSVC
# since the toolchain does it for us. Other toolchains embed the
# debugging symbols in the file itself by default.
@@ -971,7 +1021,7 @@ class SharedLibrary(BuildTarget):
self.link_depends.append(path)
def check_unknown_kwargs(self, kwargs):
- self.check_unknown_kwargs_int(kwargs, known_shlib_kwargs)
+ self.check_unknown_kwargs_int(kwargs, known_lib_kwargs)
def get_import_filename(self):
"""
diff --git a/mesonbuild/compilers.py b/mesonbuild/compilers.py
index ec75b76..68157bd 100644
--- a/mesonbuild/compilers.py
+++ b/mesonbuild/compilers.py
@@ -24,12 +24,27 @@ from . import coredata
about. To support a new compiler, add its information below.
Also add corresponding autodetection code in environment.py."""
-header_suffixes = ['h', 'hh', 'hpp', 'hxx', 'H', 'ipp', 'moc', 'vapi', 'di']
-cpp_suffixes = ['cc', 'cpp', 'cxx', 'h', 'hh', 'hpp', 'ipp', 'hxx', 'c++']
-c_suffixes = ['c']
-clike_suffixes = c_suffixes + cpp_suffixes
-obj_suffixes = ['o', 'obj', 'res']
-lib_suffixes = ['a', 'lib', 'dll', 'dylib', 'so']
+header_suffixes = ('h', 'hh', 'hpp', 'hxx', 'H', 'ipp', 'moc', 'vapi', 'di')
+obj_suffixes = ('o', 'obj', 'res')
+lib_suffixes = ('a', 'lib', 'dll', 'dylib', 'so')
+# Mapping of language to suffixes of files that should always be in that language
+# This means we can't include .h headers here since they could be C, C++, ObjC, etc.
+lang_suffixes = {
+ 'c': ('c',),
+ 'cpp': ('cpp', 'cc', 'cxx', 'c++', 'hh', 'hpp', 'ipp', 'hxx'),
+ 'fortran': ('f', 'f90', 'f95'),
+ 'd': ('d', 'di'),
+ 'objc': ('m',),
+ 'objcpp': ('mm',),
+ 'rust': ('rs',),
+ 'vala': ('vala', 'vapi'),
+ 'cs': ('cs',),
+ 'swift': ('swift',),
+ 'java': ('java',),
+}
+cpp_suffixes = lang_suffixes['cpp'] + ('h',)
+c_suffixes = lang_suffixes['c'] + ('h',)
+clike_suffixes = lang_suffixes['c'] + lang_suffixes['cpp'] + ('h',)
def is_header(fname):
if hasattr(fname, 'fname'):
@@ -176,7 +191,10 @@ base_options = {
'always'),
'b_ndebug' : coredata.UserBooleanOption('b_ndebug',
'Disable asserts',
- False)
+ False),
+ 'b_staticpic' : coredata.UserBooleanOption('b_staticpic',
+ 'Build static libraries as position independent',
+ True),
}
def sanitizer_compile_args(value):
@@ -301,9 +319,38 @@ class Compiler():
self.exelist = exelist
else:
raise TypeError('Unknown argument to Compiler')
+ # In case it's been overriden by a child class already
+ if not hasattr(self, 'file_suffixes'):
+ self.file_suffixes = lang_suffixes[self.language]
+ if not hasattr(self, 'can_compile_suffixes'):
+ self.can_compile_suffixes = set(self.file_suffixes)
+ self.default_suffix = self.file_suffixes[0]
self.version = version
self.base_options = []
+ def can_compile(self, src):
+ if hasattr(src, 'fname'):
+ src = src.fname
+ suffix = os.path.splitext(src)[1].lower()
+ if suffix and suffix[1:] in self.can_compile_suffixes:
+ return True
+ return False
+
+ def get_id(self):
+ return self.id
+
+ def get_language(self):
+ return self.language
+
+ def get_exelist(self):
+ return self.exelist[:]
+
+ def get_define(self, *args, **kwargs):
+ raise EnvironmentException('%s does not support get_define.' % self.id)
+
+ def has_define(self, *args, **kwargs):
+ raise EnvironmentException('%s does not support has_define.' % self.id)
+
def get_always_args(self):
return []
@@ -392,11 +439,13 @@ class Compiler():
class CCompiler(Compiler):
def __init__(self, exelist, version, is_cross, exe_wrapper=None):
+ # If a child ObjC or CPP class has already set it, don't set it ourselves
+ if not hasattr(self, 'language'):
+ self.language = 'c'
super().__init__(exelist, version)
- self.language = 'c'
- self.default_suffix = 'c'
self.id = 'unknown'
self.is_cross = is_cross
+ self.can_compile_suffixes.add('h')
if isinstance(exe_wrapper, str):
self.exe_wrapper = [exe_wrapper]
else:
@@ -424,7 +473,7 @@ class CCompiler(Compiler):
def get_warn_args(self, level):
return self.warn_args[level]
- def get_soname_args(self, shlib_name, path, soversion):
+ def get_soname_args(self, prefix, shlib_name, suffix, path, soversion):
return []
def split_shlib_to_parts(self, fname):
@@ -435,9 +484,6 @@ class CCompiler(Compiler):
def build_rpath_args(self, build_dir, rpath_paths, install_rpath):
return build_unix_rpath_args(build_dir, rpath_paths, install_rpath)
- def get_id(self):
- return self.id
-
def get_dependency_gen_args(self, outtarget, outfile):
return ['-MMD', '-MQ', outtarget, '-MF', outfile]
@@ -447,9 +493,6 @@ class CCompiler(Compiler):
def get_depfile_suffix(self):
return 'd'
- def get_language(self):
- return self.language
-
def get_default_suffix(self):
return self.default_suffix
@@ -503,12 +546,6 @@ class CCompiler(Compiler):
return libstr.split(':')
return []
- def can_compile(self, filename):
- suffix = filename.split('.')[-1]
- if suffix == 'c' or suffix == 'h':
- return True
- return False
-
def get_pic_args(self):
return ['-fPIC']
@@ -973,15 +1010,10 @@ void bar() {
class CPPCompiler(CCompiler):
def __init__(self, exelist, version, is_cross, exe_wrap):
+ # If a child ObjCPP class has already set it, don't set it ourselves
+ if not hasattr(self, 'language'):
+ self.language = 'cpp'
CCompiler.__init__(self, exelist, version, is_cross, exe_wrap)
- self.language = 'cpp'
- self.default_suffix = 'cpp'
-
- def can_compile(self, filename):
- suffix = filename.split('.')[-1]
- if suffix in cpp_suffixes:
- return True
- return False
def sanity_check(self, work_dir, environment):
code = 'class breakCCompiler;int main(int argc, char **argv) { return 0; }\n'
@@ -989,15 +1021,8 @@ class CPPCompiler(CCompiler):
class ObjCCompiler(CCompiler):
def __init__(self, exelist, version, is_cross, exe_wrap):
- CCompiler.__init__(self, exelist, version, is_cross, exe_wrap)
self.language = 'objc'
- self.default_suffix = 'm'
-
- def can_compile(self, filename):
- suffix = filename.split('.')[-1]
- if suffix == 'm' or suffix == 'h':
- return True
- return False
+ CCompiler.__init__(self, exelist, version, is_cross, exe_wrap)
def sanity_check(self, work_dir, environment):
# TODO try to use sanity_check_impl instead of duplicated code
@@ -1023,15 +1048,8 @@ class ObjCCompiler(CCompiler):
class ObjCPPCompiler(CPPCompiler):
def __init__(self, exelist, version, is_cross, exe_wrap):
- CPPCompiler.__init__(self, exelist, version, is_cross, exe_wrap)
self.language = 'objcpp'
- self.default_suffix = 'mm'
-
- def can_compile(self, filename):
- suffix = filename.split('.')[-1]
- if suffix == 'mm' or suffix == 'h':
- return True
- return False
+ CPPCompiler.__init__(self, exelist, version, is_cross, exe_wrap)
def sanity_check(self, work_dir, environment):
# TODO try to use sanity_check_impl instead of duplicated code
@@ -1058,9 +1076,8 @@ class ObjCPPCompiler(CPPCompiler):
class MonoCompiler(Compiler):
def __init__(self, exelist, version):
- super().__init__(exelist, version)
self.language = 'cs'
- self.default_suffix = 'cs'
+ super().__init__(exelist, version)
self.id = 'mono'
self.monorunner = 'mono'
@@ -1070,7 +1087,7 @@ class MonoCompiler(Compiler):
def get_link_args(self, fname):
return ['-r:' + fname]
- def get_soname_args(self, shlib_name, path, soversion):
+ def get_soname_args(self, prefix, shlib_name, suffix, path, soversion):
return []
def get_werror_args(self):
@@ -1082,21 +1099,12 @@ class MonoCompiler(Compiler):
def build_rpath_args(self, build_dir, rpath_paths, install_rpath):
return []
- def get_id(self):
- return self.id
-
def get_dependency_gen_args(self, outtarget, outfile):
return []
- def get_language(self):
- return self.language
-
def get_default_suffix(self):
return self.default_suffix
- def get_exelist(self):
- return self.exelist[:]
-
def get_linker_exelist(self):
return self.exelist[:]
@@ -1121,12 +1129,6 @@ class MonoCompiler(Compiler):
def get_std_shared_lib_link_args(self):
return []
- def can_compile(self, filename):
- suffix = filename.split('.')[-1]
- if suffix == 'cs':
- return True
- return False
-
def get_pic_args(self):
return []
@@ -1167,13 +1169,12 @@ class MonoCompiler(Compiler):
class JavaCompiler(Compiler):
def __init__(self, exelist, version):
- super().__init__(exelist, version)
self.language = 'java'
- self.default_suffix = 'java'
+ super().__init__(exelist, version)
self.id = 'unknown'
self.javarunner = 'java'
- def get_soname_args(self, shlib_name, path, soversion):
+ def get_soname_args(self, prefix, shlib_name, suffix, path, soversion):
return []
def get_werror_args(self):
@@ -1185,21 +1186,12 @@ class JavaCompiler(Compiler):
def build_rpath_args(self, build_dir, rpath_paths, install_rpath):
return []
- def get_id(self):
- return self.id
-
def get_dependency_gen_args(self, outtarget, outfile):
return []
- def get_language(self):
- return self.language
-
def get_default_suffix(self):
return self.default_suffix
- def get_exelist(self):
- return self.exelist[:]
-
def get_linker_exelist(self):
return self.exelist[:]
@@ -1229,12 +1221,6 @@ class JavaCompiler(Compiler):
def get_std_shared_lib_link_args(self):
return []
- def can_compile(self, filename):
- suffix = filename.split('.')[-1]
- if suffix == 'java':
- return True
- return False
-
def get_pic_args(self):
return []
@@ -1276,10 +1262,10 @@ class JavaCompiler(Compiler):
class ValaCompiler(Compiler):
def __init__(self, exelist, version):
+ self.language = 'vala'
super().__init__(exelist, version)
self.version = version
- self.id = 'unknown'
- self.language = 'vala'
+ self.id = 'valac'
self.is_cross = False
def name_string(self):
@@ -1288,15 +1274,9 @@ class ValaCompiler(Compiler):
def needs_static_linker(self):
return False # Because compiles into C.
- def get_exelist(self):
- return self.exelist[:]
-
def get_werror_args(self):
return ['--fatal-warnings']
- def get_language(self):
- return self.language
-
def sanity_check(self, work_dir, environment):
src = 'valatest.vala'
source_name = os.path.join(work_dir, src)
@@ -1310,10 +1290,6 @@ class ValaCompiler(Compiler):
if pc.returncode != 0:
raise EnvironmentException('Vala compiler %s can not compile programs.' % self.name_string())
- def can_compile(self, filename):
- suffix = filename.split('.')[-1]
- return suffix in ('vala', 'vapi')
-
def get_buildtype_args(self, buildtype):
if buildtype == 'debug' or buildtype == 'debugoptimized' or buildtype == 'minsize':
return ['--debug']
@@ -1321,9 +1297,9 @@ class ValaCompiler(Compiler):
class RustCompiler(Compiler):
def __init__(self, exelist, version):
- super().__init__(exelist, version)
- self.id = 'unknown'
self.language = 'rust'
+ super().__init__(exelist, version)
+ self.id = 'rustc'
def needs_static_linker(self):
return False
@@ -1331,15 +1307,6 @@ class RustCompiler(Compiler):
def name_string(self):
return ' '.join(self.exelist)
- def get_exelist(self):
- return self.exelist[:]
-
- def get_id(self):
- return self.id
-
- def get_language(self):
- return self.language
-
def sanity_check(self, work_dir, environment):
source_name = os.path.join(work_dir, 'sanity.rs')
output_name = os.path.join(work_dir, 'rusttest')
@@ -1354,9 +1321,6 @@ class RustCompiler(Compiler):
if subprocess.call(output_name) != 0:
raise EnvironmentException('Executables created by Rust compiler %s are not runnable.' % self.name_string())
- def can_compile(self, fname):
- return fname.endswith('.rs')
-
def get_dependency_gen_args(self, outfile):
return ['--dep-info', outfile]
@@ -1365,15 +1329,12 @@ class RustCompiler(Compiler):
class SwiftCompiler(Compiler):
def __init__(self, exelist, version):
+ self.language = 'swift'
super().__init__(exelist, version)
self.version = version
self.id = 'llvm'
- self.language = 'swift'
self.is_cross = False
- def get_id(self):
- return self.id
-
def get_linker_exelist(self):
return self.exelist[:]
@@ -1383,15 +1344,9 @@ class SwiftCompiler(Compiler):
def needs_static_linker(self):
return True
- def get_exelist(self):
- return self.exelist[:]
-
def get_werror_args(self):
return ['--fatal-warnings']
- def get_language(self):
- return self.language
-
def get_dependency_gen_args(self, outtarget, outfile):
return ['-emit-dependencies']
@@ -1452,15 +1407,11 @@ class SwiftCompiler(Compiler):
if subprocess.call(output_name) != 0:
raise EnvironmentException('Executables created by Swift compiler %s are not runnable.' % self.name_string())
- def can_compile(self, filename):
- suffix = filename.split('.')[-1]
- return suffix in ('swift')
-
class DCompiler(Compiler):
def __init__(self, exelist, version, is_cross):
+ self.language = 'd'
super().__init__(exelist, version)
self.id = 'unknown'
- self.language = 'd'
self.is_cross = is_cross
def sanity_check(self, work_dir, environment):
@@ -1483,19 +1434,6 @@ class DCompiler(Compiler):
def name_string(self):
return ' '.join(self.exelist)
- def get_exelist(self):
- return self.exelist
-
- def get_id(self):
- return self.id
-
- def get_language(self):
- return self.language
-
- def can_compile(self, fname):
- suffix = fname.split('.')[-1]
- return suffix in ('d', 'di')
-
def get_linker_exelist(self):
return self.exelist[:]
@@ -1511,7 +1449,7 @@ class DCompiler(Compiler):
def get_std_shared_lib_link_args(self):
return ['-shared']
- def get_soname_args(self, shlib_name, path, soversion):
+ def get_soname_args(self, prefix, shlib_name, suffix, path, soversion):
return []
def get_unittest_args(self):
@@ -1566,7 +1504,7 @@ class GnuDCompiler(DCompiler):
self.warn_args = {'1': ['-Wall', '-Wdeprecated'],
'2': ['-Wall', '-Wextra', '-Wdeprecated'],
'3': ['-Wall', '-Wextra', '-Wdeprecated', '-Wpedantic']}
- self.base_options = ['b_colorout', 'b_sanitize']
+ self.base_options = ['b_colorout', 'b_sanitize', 'b_staticpic']
def get_colorout_args(self, colortype):
if mesonlib.version_compare(self.version, '>=4.9.0'):
@@ -1898,17 +1836,11 @@ class VisualStudioCCompiler(CCompiler):
class VisualStudioCPPCompiler(VisualStudioCCompiler):
def __init__(self, exelist, version, is_cross, exe_wrap):
- VisualStudioCCompiler.__init__(self, exelist, version, is_cross, exe_wrap)
self.language = 'cpp'
+ VisualStudioCCompiler.__init__(self, exelist, version, is_cross, exe_wrap)
self.default_suffix = 'cpp'
self.base_options = ['b_pch'] # FIXME add lto, pgo and the like
- def can_compile(self, filename):
- suffix = filename.split('.')[-1]
- if suffix in cpp_suffixes:
- return True
- return False
-
def get_options(self):
return {'cpp_eh' : coredata.UserComboOption('cpp_eh',
'C++ exception handling type.',
@@ -1938,14 +1870,15 @@ CLANG_OSX = 1
CLANG_WIN = 2
# Possibly clang-cl?
-def get_gcc_soname_args(gcc_type, shlib_name, path, soversion):
+def get_gcc_soname_args(gcc_type, prefix, shlib_name, suffix, path, soversion):
if soversion is None:
sostr = ''
else:
sostr = '.' + soversion
if gcc_type == GCC_STANDARD or gcc_type == GCC_MINGW:
# Might not be correct for mingw but seems to work.
- return ['-Wl,-soname,lib%s.so%s' % (shlib_name, sostr)]
+ return ['-Wl,-soname,%s%s.%s%s' % (prefix, shlib_name, suffix, sostr)]
+ return ['-Wl,-soname,%s%s' % (shlib_name, sostr)]
elif gcc_type == GCC_OSX:
return ['-install_name', os.path.join(path, 'lib' + shlib_name + '.dylib')]
else:
@@ -1954,11 +1887,12 @@ def get_gcc_soname_args(gcc_type, shlib_name, path, soversion):
class GnuCompiler:
# Functionality that is common to all GNU family compilers.
- def __init__(self, gcc_type):
+ def __init__(self, gcc_type, defines):
self.id = 'gcc'
self.gcc_type = gcc_type
+ self.defines = defines or {}
self.base_options = ['b_pch', 'b_lto', 'b_pgo', 'b_sanitize', 'b_coverage',
- 'b_colorout', 'b_ndebug']
+ 'b_colorout', 'b_ndebug', 'b_staticpic']
if self.gcc_type != GCC_OSX:
self.base_options.append('b_lundef')
self.base_options.append('b_asneeded')
@@ -1976,9 +1910,16 @@ class GnuCompiler:
args[args.index('-Wpedantic')] = '-pedantic'
return args
+ def has_define(self, define):
+ return define in self.defines
+
+ def get_define(self, define):
+ if define in self.defines:
+ return defines[define]
+
def get_pic_args(self):
- if self.gcc_type == GCC_MINGW:
- return [] # On Window gcc defaults to fpic being always on.
+ if self.gcc_type in (GCC_MINGW, GCC_OSX):
+ return [] # On Window and OS X, pic is always on.
return ['-fPIC']
def get_buildtype_args(self, buildtype):
@@ -1996,20 +1937,19 @@ class GnuCompiler:
def split_shlib_to_parts(self, fname):
return (os.path.split(fname)[0], fname)
- def get_soname_args(self, shlib_name, path, soversion):
- return get_gcc_soname_args(self.gcc_type, shlib_name, path, soversion)
+ def get_soname_args(self, prefix, shlib_name, suffix, path, soversion):
+ return get_gcc_soname_args(self.gcc_type, prefix, shlib_name, suffix, path, soversion)
class GnuCCompiler(GnuCompiler, CCompiler):
- def __init__(self, exelist, version, gcc_type, is_cross, exe_wrapper=None):
+ def __init__(self, exelist, version, gcc_type, is_cross, exe_wrapper=None, defines=None):
CCompiler.__init__(self, exelist, version, is_cross, exe_wrapper)
- GnuCompiler.__init__(self, gcc_type)
+ GnuCompiler.__init__(self, gcc_type, defines)
+ # Gcc can do asm, too.
+ self.can_compile_suffixes.add('s')
self.warn_args = {'1': ['-Wall', '-Winvalid-pch'],
'2': ['-Wall', '-Wextra', '-Winvalid-pch'],
'3' : ['-Wall', '-Wpedantic', '-Wextra', '-Winvalid-pch']}
- def can_compile(self, filename):
- return super().can_compile(filename) or filename.split('.')[-1].lower() == 's' # Gcc can do asm, too.
-
def get_options(self):
opts = {'c_std' : coredata.UserComboOption('c_std', 'C language standard to use',
['none', 'c89', 'c99', 'c11', 'gnu89', 'gnu99', 'gnu11'],
@@ -2035,9 +1975,9 @@ class GnuCCompiler(GnuCompiler, CCompiler):
class GnuCPPCompiler(GnuCompiler, CPPCompiler):
- def __init__(self, exelist, version, gcc_type, is_cross, exe_wrap):
+ def __init__(self, exelist, version, gcc_type, is_cross, exe_wrap, defines):
CPPCompiler.__init__(self, exelist, version, is_cross, exe_wrap)
- GnuCompiler.__init__(self, gcc_type)
+ GnuCompiler.__init__(self, gcc_type, defines)
self.warn_args = {'1': ['-Wall', '-Winvalid-pch', '-Wnon-virtual-dtor'],
'2': ['-Wall', '-Wextra', '-Winvalid-pch', '-Wnon-virtual-dtor'],
'3': ['-Wall', '-Wpedantic', '-Wextra', '-Winvalid-pch', '-Wnon-virtual-dtor']}
@@ -2073,22 +2013,22 @@ class GnuCPPCompiler(GnuCompiler, CPPCompiler):
class GnuObjCCompiler(GnuCompiler,ObjCCompiler):
- def __init__(self, exelist, version, is_cross, exe_wrapper=None):
+ def __init__(self, exelist, version, is_cross, exe_wrapper=None, defines=None):
ObjCCompiler.__init__(self, exelist, version, is_cross, exe_wrapper)
# Not really correct, but GNU objc is only used on non-OSX non-win. File a bug
# if this breaks your use case.
- GnuCompiler.__init__(self, GCC_STANDARD)
+ GnuCompiler.__init__(self, GCC_STANDARD, defines)
self.warn_args = {'1': ['-Wall', '-Winvalid-pch'],
'2': ['-Wall', '-Wextra', '-Winvalid-pch'],
'3' : ['-Wall', '-Wpedantic', '-Wextra', '-Winvalid-pch']}
class GnuObjCPPCompiler(GnuCompiler, ObjCPPCompiler):
- def __init__(self, exelist, version, is_cross, exe_wrapper=None):
- ObjCCompiler.__init__(self, exelist, version, is_cross, exe_wrapper)
+ def __init__(self, exelist, version, is_cross, exe_wrapper=None, defines=None):
+ ObjCPPCompiler.__init__(self, exelist, version, is_cross, exe_wrapper)
# Not really correct, but GNU objc is only used on non-OSX non-win. File a bug
# if this breaks your use case.
- GnuCompiler.__init__(self, GCC_STANDARD)
+ GnuCompiler.__init__(self, GCC_STANDARD, defines)
self.warn_args = {'1': ['-Wall', '-Winvalid-pch', '-Wnon-virtual-dtor'],
'2': ['-Wall', '-Wextra', '-Winvalid-pch', '-Wnon-virtual-dtor'],
'3' : ['-Wall', '-Wpedantic', '-Wextra', '-Winvalid-pch', '-Wnon-virtual-dtor']}
@@ -2098,11 +2038,16 @@ class ClangCompiler():
self.id = 'clang'
self.clang_type = clang_type
self.base_options = ['b_pch', 'b_lto', 'b_pgo', 'b_sanitize', 'b_coverage',
- 'b_ndebug']
+ 'b_ndebug', 'b_staticpic']
if self.clang_type != CLANG_OSX:
self.base_options.append('b_lundef')
self.base_options.append('b_asneeded')
+ def get_pic_args(self):
+ if self.clang_type in (CLANG_WIN, CLANG_OSX):
+ return [] # On Window and OS X, pic is always on.
+ return ['-fPIC']
+
def get_buildtype_args(self, buildtype):
return gnulike_buildtype_args[buildtype]
@@ -2118,10 +2063,23 @@ class ClangCompiler():
# so it might change semantics at any time.
return ['-include-pch', os.path.join (pch_dir, self.get_pch_name (header))]
+ def get_soname_args(self, prefix, shlib_name, suffix, path, soversion):
+ if self.clang_type == CLANG_STANDARD:
+ gcc_type = GCC_STANDARD
+ elif self.clang_type == CLANG_OSX:
+ gcc_type = GCC_OSX
+ elif self.clang_type == CLANG_WIN:
+ gcc_type = GCC_MINGW
+ else:
+ raise MesonException('Unreachable code when converting clang type to gcc type.')
+ return get_gcc_soname_args(gcc_type, prefix, shlib_name, suffix, path, soversion)
+
class ClangCCompiler(ClangCompiler, CCompiler):
def __init__(self, exelist, version, clang_type, is_cross, exe_wrapper=None):
CCompiler.__init__(self, exelist, version, is_cross, exe_wrapper)
ClangCompiler.__init__(self, clang_type)
+ # Clang can do asm, too.
+ self.can_compile_suffixes.add('s')
self.warn_args = {'1': ['-Wall', '-Winvalid-pch'],
'2': ['-Wall', '-Wextra', '-Winvalid-pch'],
'3' : ['-Wall', '-Wpedantic', '-Wextra', '-Winvalid-pch']}
@@ -2144,9 +2102,6 @@ class ClangCCompiler(ClangCompiler, CCompiler):
def has_argument(self, arg, env):
return super().has_argument(['-Werror=unknown-warning-option', arg], env)
- def can_compile(self, filename):
- return super().can_compile(filename) or filename.split('.')[-1].lower() == 's' # Clang can do asm, too.
-
class ClangCPPCompiler(ClangCompiler, CPPCompiler):
def __init__(self, exelist, version, cltype, is_cross, exe_wrapper=None):
@@ -2174,9 +2129,6 @@ class ClangCPPCompiler(ClangCompiler, CPPCompiler):
def has_argument(self, arg, env):
return super().has_argument(['-Werror=unknown-warning-option', arg], env)
- def can_compile(self, filename):
- return super().can_compile(filename) or filename.split('.')[-1].lower() == 's' # Clang can do asm, too.
-
class ClangObjCCompiler(GnuObjCCompiler):
def __init__(self, exelist, version, cltype, is_cross, exe_wrapper=None):
super().__init__(exelist, version, is_cross, exe_wrapper)
@@ -2199,29 +2151,20 @@ class ClangObjCPPCompiler(GnuObjCPPCompiler):
class FortranCompiler(Compiler):
def __init__(self, exelist, version, is_cross, exe_wrapper=None):
+ self.language = 'fortran'
super().__init__(exelist, version)
self.is_cross = is_cross
self.exe_wrapper = exe_wrapper
- self.language = 'fortran'
# Not really correct but I don't have Fortran compilers to test with. Sorry.
self.gcc_type = GCC_STANDARD
self.id = "IMPLEMENTATION CLASSES MUST SET THIS"
- def get_id(self):
- return self.id
-
def name_string(self):
return ' '.join(self.exelist)
- def get_exelist(self):
- return self.exelist[:]
-
- def get_language(self):
- return self.language
-
def get_pic_args(self):
- if self.gcc_type == GCC_MINGW:
- return [] # On Windows gcc defaults to fpic being always on.
+ if self.gcc_type in (GCC_MINGW, GCC_OSX):
+ return [] # On Window and OS X, pic is always on.
return ['-fPIC']
def get_std_shared_lib_link_args(self):
@@ -2267,8 +2210,8 @@ end program prog
def split_shlib_to_parts(self, fname):
return (os.path.split(fname)[0], fname)
- def get_soname_args(self, shlib_name, path, soversion):
- return get_gcc_soname_args(self.gcc_type, shlib_name, path, soversion)
+ def get_soname_args(self, prefix, shlib_name, suffix, path, soversion):
+ return get_gcc_soname_args(self.gcc_type, prefix, shlib_name, suffix, path, soversion)
def get_dependency_gen_args(self, outtarget, outfile):
# Disabled until this is fixed:
@@ -2288,14 +2231,6 @@ end program prog
def get_linker_output_args(self, outputname):
return ['-o', outputname]
- def can_compile(self, src):
- if hasattr(src, 'fname'):
- src = src.fname
- suffix = os.path.splitext(src)[1].lower()
- if suffix == '.f' or suffix == '.f95' or suffix == '.f90':
- return True
- return False
-
def get_include_args(self, path, is_system):
return ['-I' + path]
@@ -2322,11 +2257,19 @@ end program prog
class GnuFortranCompiler(FortranCompiler):
- def __init__(self, exelist, version, gcc_type, is_cross, exe_wrapper=None):
+ def __init__(self, exelist, version, gcc_type, is_cross, exe_wrapper=None, defines=None):
super().__init__(exelist, version, is_cross, exe_wrapper=None)
self.gcc_type = gcc_type
+ self.defines = defines or {}
self.id = 'gcc'
+ def has_define(self, define):
+ return define in self.defines
+
+ def get_define(self, define):
+ if define in self.defines:
+ return self.defines[define]
+
def get_always_args(self):
return ['-pipe']
@@ -2378,18 +2321,13 @@ class IntelFortranCompiler(FortranCompiler):
std_warn_args = ['-warn', 'all']
def __init__(self, exelist, version, is_cross, exe_wrapper=None):
+ self.file_suffixes = ('f', 'f90')
super().__init__(exelist, version, is_cross, exe_wrapper=None)
self.id = 'intel'
def get_module_outdir_args(self, path):
return ['-module', path]
- def can_compile(self, src):
- suffix = os.path.splitext(src)[1].lower()
- if suffix == '.f' or suffix == '.f90':
- return True
- return False
-
def get_warn_args(self, level):
return IntelFortranCompiler.std_warn_args
@@ -2403,12 +2341,6 @@ class PathScaleFortranCompiler(FortranCompiler):
def get_module_outdir_args(self, path):
return ['-module', path]
- def can_compile(self, src):
- suffix = os.path.splitext(src)[1].lower()
- if suffix == '.f' or suffix == '.f90' or suffix == '.f95':
- return True
- return False
-
def get_std_warn_args(self, level):
return PathScaleFortranCompiler.std_warn_args
@@ -2422,12 +2354,6 @@ class PGIFortranCompiler(FortranCompiler):
def get_module_outdir_args(self, path):
return ['-module', path]
- def can_compile(self, src):
- suffix = os.path.splitext(src)[1].lower()
- if suffix == '.f' or suffix == '.f90' or suffix == '.f95':
- return True
- return False
-
def get_warn_args(self, level):
return PGIFortranCompiler.std_warn_args
@@ -2442,12 +2368,6 @@ class Open64FortranCompiler(FortranCompiler):
def get_module_outdir_args(self, path):
return ['-module', path]
- def can_compile(self, src):
- suffix = os.path.splitext(src)[1].lower()
- if suffix == '.f' or suffix == '.f90' or suffix == '.f95':
- return True
- return False
-
def get_warn_args(self, level):
return Open64FortranCompiler.std_warn_args
@@ -2464,12 +2384,6 @@ class NAGFortranCompiler(FortranCompiler):
def get_always_args(self):
return []
- def can_compile(self, src):
- suffix = os.path.splitext(src)[1].lower()
- if suffix == '.f' or suffix == '.f90' or suffix == '.f95':
- return True
- return False
-
def get_warn_args(self, level):
return NAGFortranCompiler.std_warn_args
diff --git a/mesonbuild/coredata.py b/mesonbuild/coredata.py
index 7a6eada..109bb32 100644
--- a/mesonbuild/coredata.py
+++ b/mesonbuild/coredata.py
@@ -15,7 +15,7 @@
import pickle, os, uuid
from .mesonlib import MesonException, default_libdir, default_libexecdir, default_prefix
-version = '0.35.0.dev1'
+version = '0.36.0.dev1'
backendlist = ['ninja', 'vs2010', 'vs2015', 'xcode']
class UserOption:
@@ -36,11 +36,6 @@ class UserStringOption(UserOption):
def validate(self, value):
if not isinstance(value, str):
raise MesonException('Value "%s" for string option "%s" is not a string.' % (str(value), self.name))
- if self.name == 'prefix' and not os.path.isabs(value):
- raise MesonException('Prefix option value \'{0}\' must be an absolute path.'.format(value))
- if self.name in ('libdir', 'bindir', 'includedir', 'datadir', 'mandir', 'localedir') \
- and os.path.isabs(value):
- raise MesonException('Option %s must not be an absolute path.' % self.name)
def set_value(self, newvalue):
self.validate(newvalue)
@@ -224,7 +219,7 @@ builtin_options = {
'default_library' : [ UserComboOption, 'Default library type.', [ 'shared', 'static' ], 'shared' ],
'backend' : [ UserComboOption, 'Backend to use.', backendlist, 'ninja' ],
'stdsplit' : [ UserBooleanOption, 'Split stdout and stderr in test logs.', True ],
- 'errorlogs' : [ UserBooleanOption, "Whether to print the logs from failing tests.", False ],
+ 'errorlogs' : [ UserBooleanOption, "Whether to print the logs from failing tests.", True ],
}
forbidden_target_names = {'clean': None,
diff --git a/mesonbuild/dependencies.py b/mesonbuild/dependencies.py
index 106273c..ccff7a7 100644
--- a/mesonbuild/dependencies.py
+++ b/mesonbuild/dependencies.py
@@ -25,6 +25,7 @@ import sysconfig
from . mesonlib import MesonException
from . import mlog
from . import mesonlib
+from .environment import detect_cpu_family
class DependencyException(MesonException):
def __init__(self, *args, **kwargs):
@@ -187,6 +188,7 @@ class PkgConfigDependency(Dependency):
p = subprocess.Popen([self.pkgbin, '--variable=%s' % variable_name, self.name],
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
out = p.communicate()[0]
+ variable = ''
if p.returncode != 0:
if self.required:
raise DependencyException('%s dependency %s not found.' %
@@ -474,7 +476,12 @@ class BoostDependency(Dependency):
def __init__(self, environment, kwargs):
Dependency.__init__(self)
self.name = 'boost'
+ self.environment = environment
self.libdir = ''
+ if 'native' in kwargs and environment.is_cross_build():
+ want_cross = not kwargs['native']
+ else:
+ want_cross = environment.is_cross_build()
try:
self.boost_root = os.environ['BOOST_ROOT']
if not os.path.isabs(self.boost_root):
@@ -482,6 +489,8 @@ class BoostDependency(Dependency):
except KeyError:
self.boost_root = None
if self.boost_root is None:
+ if want_cross:
+ raise DependencyException('BOOST_ROOT is needed while cross-compiling')
if mesonlib.is_windows():
self.boost_root = self.detect_win_root()
self.incdir = self.boost_root
@@ -575,11 +584,21 @@ class BoostDependency(Dependency):
return self.detect_lib_modules_nix()
def detect_lib_modules_win(self):
- if mesonlib.is_32bit():
+ arch = detect_cpu_family(self.environment.coredata.compilers)
+ # Guess the libdir
+ if arch == 'x86':
gl = 'lib32*'
- else:
+ elif arch == 'x86_64':
gl = 'lib64*'
- libdir = glob.glob(os.path.join(self.boost_root, gl))
+ else:
+ # Does anyone do Boost cross-compiling to other archs on Windows?
+ gl = None
+ # See if the libdir is valid
+ if gl:
+ libdir = glob.glob(os.path.join(self.boost_root, gl))
+ else:
+ libdir = []
+ # Can't find libdir, bail
if len(libdir) == 0:
return
libdir = libdir[0]
diff --git a/mesonbuild/environment.py b/mesonbuild/environment.py
index 341e5e8..86c23ae 100644
--- a/mesonbuild/environment.py
+++ b/mesonbuild/environment.py
@@ -57,26 +57,89 @@ def detect_ninja():
if p.returncode == 0 and mesonlib.version_compare(version, ">=1.6"):
return n
-def detect_cpu_family():
+def detect_native_windows_arch():
+ """
+ The architecture of Windows itself: x86 or amd64
+ """
+ # These env variables are always available. See:
+ # https://msdn.microsoft.com/en-us/library/aa384274(VS.85).aspx
+ # https://blogs.msdn.microsoft.com/david.wang/2006/03/27/howto-detect-process-bitness/
+ arch = os.environ.get('PROCESSOR_ARCHITEW6432', '').lower()
+ if not arch:
+ try:
+ # If this doesn't exist, something is messing with the environment
+ arch = os.environ['PROCESSOR_ARCHITECTURE'].lower()
+ except KeyError:
+ raise InterpreterException('Unable to detect native OS architecture')
+ return arch
+
+def detect_windows_arch(compilers):
+ """
+ Detecting the 'native' architecture of Windows is not a trivial task. We
+ cannot trust that the architecture that Python is built for is the 'native'
+ one because you can run 32-bit apps on 64-bit Windows using WOW64 and
+ people sometimes install 32-bit Python on 64-bit Windows.
+
+ We also can't rely on the architecture of the OS itself, since it's
+ perfectly normal to compile and run 32-bit applications on Windows as if
+ they were native applications. It's a terrible experience to require the
+ user to supply a cross-info file to compile 32-bit applications on 64-bit
+ Windows. Thankfully, the only way to compile things with Visual Studio on
+ Windows is by entering the 'msvc toolchain' environment, which can be
+ easily detected.
+
+ In the end, the sanest method is as follows:
+ 1. Check if we're in an MSVC toolchain environment, and if so, return the
+ MSVC toolchain architecture as our 'native' architecture.
+ 2. If not, check environment variables that are set by Windows and WOW64 to
+ find out the architecture that Windows is built for, and use that as our
+ 'native' architecture.
+ """
+ os_arch = detect_native_windows_arch()
+ if os_arch != 'amd64':
+ return os_arch
+ # If we're on 64-bit Windows, 32-bit apps can be compiled without
+ # cross-compilation. So if we're doing that, just set the native arch as
+ # 32-bit and pretend like we're running under WOW64. Else, return the
+ # actual Windows architecture that we deduced above.
+ for compiler in compilers.values():
+ # Check if we're using and inside an MSVC toolchain environment
+ if compiler.id == 'msvc' and 'VCINSTALLDIR' in os.environ:
+ # 'Platform' is only set when the target arch is not 'x86'.
+ # It's 'x64' when targetting x86_64 and 'arm' when targetting ARM.
+ platform = os.environ.get('Platform', 'x86').lower()
+ if platform == 'x86':
+ return platform
+ if compiler.id == 'gcc' and compiler.has_define('__i386__'):
+ return 'x86'
+ return os_arch
+
+def detect_cpu_family(compilers):
"""
Python is inconsistent in its platform module.
It returns different values for the same cpu.
For x86 it might return 'x86', 'i686' or somesuch.
Do some canonicalization.
"""
- trial = platform.machine().lower()
+ if mesonlib.is_windows():
+ trial = detect_windows_arch(compilers)
+ else:
+ trial = platform.machine().lower()
if trial.startswith('i') and trial.endswith('86'):
return 'x86'
if trial.startswith('arm'):
return 'arm'
- if trial == 'amd64':
+ if trial in ('amd64', 'x64'):
return 'x86_64'
# Add fixes here as bugs are reported.
return trial
-def detect_cpu():
- trial = platform.machine().lower()
- if trial == 'amd64':
+def detect_cpu(compilers):
+ if mesonlib.is_windows():
+ trial = detect_windows_arch(compilers)
+ else:
+ trial = platform.machine().lower()
+ if trial in ('amd64', 'x64'):
return 'x86_64'
# Add fixes here as bugs are reported.
return trial
@@ -116,12 +179,10 @@ class Environment():
coredata_file = os.path.join(private_dir, 'coredata.dat')
version_regex = '\d+(\.\d+)+(-[a-zA-Z0-9]+)?'
- def __init__(self, source_dir, build_dir, main_script_file, options, original_cmd_line_args):
- assert(os.path.isabs(main_script_file))
- assert(not os.path.islink(main_script_file))
+ def __init__(self, source_dir, build_dir, main_script_launcher, options, original_cmd_line_args):
self.source_dir = source_dir
self.build_dir = build_dir
- self.meson_script_file = main_script_file
+ self.meson_script_launcher = main_script_launcher
self.scratch_dir = os.path.join(build_dir, Environment.private_dir)
self.log_dir = os.path.join(build_dir, Environment.log_dir)
os.makedirs(self.scratch_dir, exist_ok=True)
@@ -135,7 +196,7 @@ class Environment():
# re-initialized with project options by the interpreter during
# build file parsing.
self.coredata = coredata.CoreData(options)
- self.coredata.meson_script_file = self.meson_script_file
+ self.coredata.meson_script_launcher = self.meson_script_launcher
self.first_invocation = True
if self.coredata.cross_file:
self.cross_info = CrossBuildInfo(self.coredata.cross_file)
@@ -190,7 +251,7 @@ class Environment():
return self.coredata
def get_build_command(self):
- return self.meson_script_file
+ return self.meson_script_launcher
def is_header(self, fname):
return is_header(fname)
@@ -225,6 +286,45 @@ class Environment():
if type(oldval) != type(value):
self.coredata.user_options[name] = value
+ @staticmethod
+ def get_gnu_compiler_defines(compiler):
+ """
+ Detect GNU compiler platform type (Apple, MinGW, Unix)
+ """
+ # Arguments to output compiler pre-processor defines to stdout
+ # gcc, g++, and gfortran all support these arguments
+ args = compiler + ['-E', '-dM', '-']
+ p = subprocess.Popen(args, universal_newlines=True,
+ stdin=subprocess.PIPE, stdout=subprocess.PIPE)
+ output = p.communicate('')[0]
+ if p.returncode != 0:
+ raise EnvironmentException('Unable to detect GNU compiler type:\n' + output)
+ # Parse several lines of the type:
+ # `#define ___SOME_DEF some_value`
+ # and extract `___SOME_DEF`
+ defines = {}
+ for line in output.split('\n'):
+ if not line:
+ continue
+ d, *rest = line.split(' ', 2)
+ if d != '#define':
+ continue
+ if len(rest) == 1:
+ defines[rest] = True
+ if len(rest) == 2:
+ defines[rest[0]] = rest[1]
+ return defines
+
+ @staticmethod
+ def get_gnu_compiler_type(defines):
+ # Detect GCC type (Apple, MinGW, Cygwin, Unix)
+ if '__APPLE__' in defines:
+ return GCC_OSX
+ elif '__MINGW32__' in defines or '__MINGW64__' in defines:
+ return GCC_MINGW
+ # We ignore Cygwin for now, and treat it as a standard GCC
+ return GCC_STANDARD
+
def detect_c_compiler(self, want_cross):
evar = 'CC'
if self.is_cross_build() and want_cross:
@@ -266,16 +366,13 @@ class Environment():
version = vmatch.group(0)
else:
version = 'unknown version'
- if 'apple' in out and 'Free Software Foundation' in out:
- return GnuCCompiler(ccache + [compiler], version, GCC_OSX, is_cross, exe_wrap)
- if (out.startswith('cc') or 'gcc' in out.lower()) and \
- 'Free Software Foundation' in out:
- lowerout = out.lower()
- if 'mingw' in lowerout or 'msys' in lowerout or 'mingw' in compiler.lower():
- gtype = GCC_MINGW
- else:
- gtype = GCC_STANDARD
- return GnuCCompiler(ccache + [compiler], version, gtype, is_cross, exe_wrap)
+ if 'Free Software Foundation' in out:
+ defines = self.get_gnu_compiler_defines([compiler])
+ if not defines:
+ popen_exceptions[compiler] = 'no pre-processor defines'
+ continue
+ gtype = self.get_gnu_compiler_type(defines)
+ return GnuCCompiler(ccache + [compiler], version, gtype, is_cross, exe_wrap, defines)
if 'clang' in out:
if 'Apple' in out:
cltype = CLANG_OSX
@@ -331,13 +428,12 @@ class Environment():
version = vmatch.group(0)
if 'GNU Fortran' in out:
- if mesonlib.is_osx():
- gcctype = GCC_OSX
- elif mesonlib.is_windows():
- gcctype = GCC_MINGW
- else:
- gcctype = GCC_STANDARD
- return GnuFortranCompiler([compiler], version, gcctype, is_cross, exe_wrap)
+ defines = self.get_gnu_compiler_defines([compiler])
+ if not defines:
+ popen_exceptions[compiler] = 'no pre-processor defines'
+ continue
+ gtype = self.get_gnu_compiler_type(defines)
+ return GnuFortranCompiler([compiler], version, gtype, is_cross, exe_wrap, defines)
if 'G95' in out:
return G95FortranCompiler([compiler], version, is_cross, exe_wrap)
@@ -419,16 +515,13 @@ class Environment():
version = vmatch.group(0)
else:
version = 'unknown version'
- if 'apple' in out and 'Free Software Foundation' in out:
- return GnuCPPCompiler(ccache + [compiler], version, GCC_OSX, is_cross, exe_wrap)
- if (out.startswith('c++ ') or 'g++' in out or 'GCC' in out) and \
- 'Free Software Foundation' in out:
- lowerout = out.lower()
- if 'mingw' in lowerout or 'msys' in lowerout or 'mingw' in compiler.lower():
- gtype = GCC_MINGW
- else:
- gtype = GCC_STANDARD
- return GnuCPPCompiler(ccache + [compiler], version, gtype, is_cross, exe_wrap)
+ if 'Free Software Foundation' in out:
+ defines = self.get_gnu_compiler_defines([compiler])
+ if not defines:
+ popen_exceptions[compiler] = 'no pre-processor defines'
+ continue
+ gtype = self.get_gnu_compiler_type(defines)
+ return GnuCPPCompiler(ccache + [compiler], version, gtype, is_cross, exe_wrap, defines)
if 'clang' in out:
if 'Apple' in out:
cltype = CLANG_OSX
@@ -469,13 +562,11 @@ class Environment():
version = vmatch.group(0)
else:
version = 'unknown version'
- if (out.startswith('cc ') or 'gcc' in out) and \
- 'Free Software Foundation' in out:
- return GnuObjCCompiler(exelist, version, is_cross, exe_wrap)
+ if 'Free Software Foundation' in out:
+ defines = self.get_gnu_compiler_defines(exelist)
+ return GnuObjCCompiler(exelist, version, is_cross, exe_wrap, defines)
if out.startswith('Apple LLVM'):
return ClangObjCCompiler(exelist, version, CLANG_OSX, is_cross, exe_wrap)
- if 'apple' in out and 'Free Software Foundation' in out:
- return GnuObjCCompiler(exelist, version, is_cross, exe_wrap)
raise EnvironmentException('Unknown compiler "' + ' '.join(exelist) + '"')
def detect_objcpp_compiler(self, want_cross):
@@ -502,13 +593,11 @@ class Environment():
version = vmatch.group(0)
else:
version = 'unknown version'
- if (out.startswith('c++ ') or out.startswith('g++')) and \
- 'Free Software Foundation' in out:
- return GnuObjCPPCompiler(exelist, version, is_cross, exe_wrap)
+ if 'Free Software Foundation' in out:
+ defines = self.get_gnu_compiler_defines(exelist)
+ return GnuObjCPPCompiler(exelist, version, is_cross, exe_wrap, defines)
if out.startswith('Apple LLVM'):
return ClangObjCPPCompiler(exelist, version, CLANG_OSX, is_cross, exe_wrap)
- if 'apple' in out and 'Free Software Foundation' in out:
- return GnuObjCPPCompiler(exelist, version, is_cross, exe_wrap)
raise EnvironmentException('Unknown compiler "' + ' '.join(exelist) + '"')
def detect_java_compiler(self):
@@ -846,10 +935,12 @@ class CrossBuildInfo():
return 'host_machine' in self.config
def need_exe_wrapper(self):
- if self.has_host() and detect_cpu_family() == 'x86_64' and \
+ # Can almost always run 32-bit binaries on 64-bit natively if the host
+ # and build systems are the same. We don't pass any compilers to
+ # detect_cpu_family() here because we always want to know the OS
+ # architecture, not what the compiler environment tells us.
+ if self.has_host() and detect_cpu_family({}) == 'x86_64' and \
self.config['host_machine']['cpu_family'] == 'x86' and \
self.config['host_machine']['system'] == detect_system():
- # Can almost always run 32-bit binaries on 64-bit natively if the
- # host and build systems are the same
return False
return True
diff --git a/mesonbuild/interpreter.py b/mesonbuild/interpreter.py
index 522450b..8435bb1 100644
--- a/mesonbuild/interpreter.py
+++ b/mesonbuild/interpreter.py
@@ -375,7 +375,8 @@ class GeneratedListHolder(InterpreterObject):
self.held_object.add_file(a)
class BuildMachine(InterpreterObject):
- def __init__(self):
+ def __init__(self, compilers):
+ self.compilers = compilers
InterpreterObject.__init__(self)
self.methods.update({'system' : self.system_method,
'cpu_family' : self.cpu_family_method,
@@ -384,10 +385,10 @@ class BuildMachine(InterpreterObject):
})
def cpu_family_method(self, args, kwargs):
- return environment.detect_cpu_family()
+ return environment.detect_cpu_family(self.compilers)
def cpu_method(self, args, kwargs):
- return environment.detect_cpu()
+ return environment.detect_cpu(self.compilers)
def system_method(self, args, kwargs):
return environment.detect_system()
@@ -1111,6 +1112,8 @@ class Interpreter():
def __init__(self, build, backend, subproject='', subdir='', subproject_dir='subprojects'):
self.build = build
+ self.environment = build.environment
+ self.coredata = self.environment.get_coredata()
self.backend = backend
self.subproject = subproject
self.subdir = subdir
@@ -1126,7 +1129,7 @@ class Interpreter():
if not os.path.isfile(mesonfile):
raise InvalidArguments('Missing Meson file in %s' % mesonfile)
with open(mesonfile, encoding='utf8') as mf:
- code = mf.read()
+ code = mf.read()
if len(code.strip()) == 0:
raise InvalidCode('Builder file is empty.')
assert(isinstance(code, str))
@@ -1137,8 +1140,15 @@ class Interpreter():
raise me
self.sanity_check_ast()
self.variables = {}
- self.builtin = {}
- self.builtin['build_machine'] = BuildMachine()
+ self.builtin = {'meson': MesonMain(build, self)}
+ self.generators = []
+ self.visited_subdirs = {}
+ self.global_args_frozen = False
+ self.subprojects = {}
+ self.subproject_stack = []
+ self.build_func_dict()
+ self.parse_project()
+ self.builtin['build_machine'] = BuildMachine(self.coredata.compilers)
if not self.build.environment.is_cross_build():
self.builtin['host_machine'] = self.builtin['build_machine']
self.builtin['target_machine'] = self.builtin['build_machine']
@@ -1152,16 +1162,7 @@ class Interpreter():
self.builtin['target_machine'] = CrossMachineInfo(cross_info.config['target_machine'])
else:
self.builtin['target_machine'] = self.builtin['host_machine']
- self.builtin['meson'] = MesonMain(build, self)
- self.environment = build.environment
- self.build_func_dict()
self.build_def_files = [os.path.join(self.subdir, environment.build_filename)]
- self.coredata = self.environment.get_coredata()
- self.generators = []
- self.visited_subdirs = {}
- self.global_args_frozen = False
- self.subprojects = {}
- self.subproject_stack = []
def build_func_dict(self):
self.funcs = {'project' : self.func_project,
@@ -1206,8 +1207,16 @@ class Interpreter():
'declare_dependency': self.func_declare_dependency,
'assert': self.func_assert,
'environment' : self.func_environment,
+ 'path_join' : self.func_path_join,
}
+ def parse_project(self):
+ """
+ Parses project() and initializes languages, compilers etc. Do this
+ early because we need this before we parse the rest of the AST.
+ """
+ self.evaluate_codeblock(self.ast, end=1)
+
def module_method_callback(self, invalues):
unwrap_single = False
if invalues is None:
@@ -1257,6 +1266,7 @@ 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
@@ -1274,10 +1284,12 @@ class Interpreter():
pass
def run(self):
- self.evaluate_codeblock(self.ast)
+ # Evaluate everything after the first line, which is project() because
+ # we already parsed that in self.parse_project()
+ self.evaluate_codeblock(self.ast, start=1)
mlog.log('Build targets in project:', mlog.bold(str(len(self.build.targets))))
- def evaluate_codeblock(self, node):
+ def evaluate_codeblock(self, node, start=0, end=None):
if node is None:
return
if not isinstance(node, mparser.CodeBlockNode):
@@ -1285,7 +1297,7 @@ class Interpreter():
e.lineno = node.lineno
e.colno = node.colno
raise e
- statements = node.lines
+ statements = node.lines[start:end]
i = 0
while i < len(statements):
cur = statements[i]
@@ -1607,13 +1619,12 @@ class Interpreter():
@stringArgs
def func_project(self, node, args, kwargs):
- if len(args) < 2:
- raise InvalidArguments('Not enough arguments to project(). Needs at least the project name and one language')
-
if not self.is_subproject():
self.build.project_name = args[0]
if self.environment.first_invocation and 'default_options' in kwargs:
self.parse_default_options(kwargs['default_options'])
+ if len(args) < 2:
+ raise InvalidArguments('Not enough arguments to project(). Needs at least the project name and one language')
self.active_projectname = args[0]
self.project_version = kwargs.get('version', 'undefined')
proj_license = mesonlib.stringlistify(kwargs.get('license', 'unknown'))
@@ -1631,7 +1642,7 @@ class Interpreter():
raise InterpreterException('Meson version is %s but project requires %s.' % (cv, pv))
self.build.projects[self.subproject] = args[0]
mlog.log('Project name: ', mlog.bold(args[0]), sep='')
- self.add_languages(node, args[1:], True)
+ self.add_languages(args[1:], True)
langs = self.coredata.compilers.keys()
if 'vala' in langs:
if not 'c' in langs:
@@ -1641,7 +1652,7 @@ class Interpreter():
@stringArgs
def func_add_languages(self, node, args, kwargs):
- return self.add_languages(node, args, kwargs.get('required', True))
+ return self.add_languages(args, kwargs.get('required', True))
@noKwargs
def func_message(self, node, args, kwargs):
@@ -1661,8 +1672,6 @@ class Interpreter():
raise InvalidArguments('Function accepts only strings, integers, lists and lists thereof.')
mlog.log(mlog.bold('Message:'), argstr)
- return
-
@noKwargs
def func_error(self, node, args, kwargs):
@@ -1739,7 +1748,7 @@ class Interpreter():
self.coredata.compiler_options = new_options
return (comp, cross_comp)
- def add_languages(self, node, args, required):
+ def add_languages(self, args, required):
success = True
need_cross_compiler = self.environment.is_cross_build() and self.environment.cross_info.need_cross_compiler()
for lang in args:
@@ -2239,6 +2248,15 @@ class Interpreter():
def func_environment(self, node, args, kwargs):
return EnvironmentVariablesHolder()
+ @stringArgs
+ @noKwargs
+ def func_path_join(self, node, args, kwargs):
+ if isinstance(args, str):
+ st = (args,)
+ else:
+ st = tuple(args)
+ return os.path.join(*args).replace('\\', '/')
+
def flatten(self, args):
if isinstance(args, mparser.StringNode):
return args.value
diff --git a/mesonbuild/mconf.py b/mesonbuild/mconf.py
index afabc62..25f2c6b 100644
--- a/mesonbuild/mconf.py
+++ b/mesonbuild/mconf.py
@@ -1,5 +1,3 @@
-#!/usr/bin/env python3
-
# Copyright 2014-2016 The Meson development team
# Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/mesonbuild/mesonlib.py b/mesonbuild/mesonlib.py
index 7294a54..abb5641 100644
--- a/mesonbuild/mesonlib.py
+++ b/mesonbuild/mesonlib.py
@@ -91,9 +91,6 @@ def is_windows():
platname = platform.system().lower()
return platname == 'windows' or 'mingw' in platname
-def is_32bit():
- return not(sys.maxsize > 2**32)
-
def is_debianlike():
return os.path.isfile('/etc/debian_version')
diff --git a/mesonbuild/mesonmain.py b/mesonbuild/mesonmain.py
index f35d821..7f7ab43 100644
--- a/mesonbuild/mesonmain.py
+++ b/mesonbuild/mesonmain.py
@@ -1,5 +1,3 @@
-#!/usr/bin/env python3
-
# Copyright 2012-2016 The Meson development team
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -56,6 +54,8 @@ add_builtin_argument('werror', action='store_true')
add_builtin_argument('layout')
add_builtin_argument('default-library')
add_builtin_argument('warnlevel', dest='warning_level')
+add_builtin_argument('stdsplit', action='store_false')
+add_builtin_argument('errorlogs', action='store_false')
parser.add_argument('--cross-file', default=None,
help='File describing cross compilation environment.')
@@ -67,10 +67,10 @@ parser.add_argument('directories', nargs='*')
class MesonApp():
- def __init__(self, dir1, dir2, script_file, handshake, options, original_cmd_line_args):
+ def __init__(self, dir1, dir2, script_launcher, handshake, options, original_cmd_line_args):
(self.source_dir, self.build_dir) = self.validate_dirs(dir1, dir2, handshake)
if not os.path.isabs(options.prefix):
- raise RuntimeError('--prefix value \'{0}\' must be an absolute path: '.format(options.prefix))
+ raise RuntimeError('--prefix value must be an absolute path: {!r}'.format(options.prefix))
if options.prefix.endswith('/') or options.prefix.endswith('\\'):
# On Windows we need to preserve the trailing slash if the
# string is of type 'C:\' because 'C:' is not an absolute path.
@@ -78,7 +78,7 @@ class MesonApp():
pass
else:
options.prefix = options.prefix[:-1]
- self.meson_script_file = script_file
+ self.meson_script_launcher = script_launcher
self.options = options
self.original_cmd_line_args = original_cmd_line_args
@@ -126,7 +126,7 @@ itself as required.'''
env.coredata.pkgconf_envvar = curvar
def generate(self):
- env = environment.Environment(self.source_dir, self.build_dir, self.meson_script_file, self.options, self.original_cmd_line_args)
+ env = environment.Environment(self.source_dir, self.build_dir, self.meson_script_launcher, self.options, self.original_cmd_line_args)
mlog.initialize(env.get_log_dir())
mlog.debug('Build started at', datetime.datetime.now().isoformat())
mlog.debug('Python binary:', sys.executable)
@@ -264,12 +264,6 @@ def run(mainfile, args):
dir2 = args[1]
else:
dir2 = '.'
- while os.path.islink(mainfile):
- resolved = os.readlink(mainfile)
- if resolved[0] != '/':
- mainfile = os.path.join(os.path.dirname(mainfile), resolved)
- else:
- mainfile = resolved
try:
app = MesonApp(dir1, dir2, mainfile, handshake, options, sys.argv)
except Exception as e:
diff --git a/mesonbuild/mintro.py b/mesonbuild/mintro.py
index 2086c37..a18912e 100644
--- a/mesonbuild/mintro.py
+++ b/mesonbuild/mintro.py
@@ -1,5 +1,3 @@
-#!/usr/bin/env python3
-
# Copyright 2014-2016 The Meson development team
# Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/mesonbuild/modules/gnome.py b/mesonbuild/modules/gnome.py
index 11abf88..be111ea 100644
--- a/mesonbuild/modules/gnome.py
+++ b/mesonbuild/modules/gnome.py
@@ -45,6 +45,9 @@ class GnomeModule:
if not isinstance(source_dirs, list):
source_dirs = [source_dirs]
+ # Always include current directory, but after paths set by user
+ source_dirs.append(os.path.join(state.environment.get_source_dir(), state.subdir))
+
if len(args) < 2:
raise MesonException('Not enough arguments; The name of the resource and the path to the XML file are required')
@@ -192,6 +195,8 @@ class GnomeModule:
def generate_gir(self, state, args, kwargs):
if len(args) != 1:
raise MesonException('Gir takes one argument')
+ if kwargs.get('install_dir'):
+ raise MesonException('install_dir is not supported with generate_gir(), see "install_dir_gir" and "install_dir_typelib"')
girtarget = args[0]
while hasattr(girtarget, 'held_object'):
girtarget = girtarget.held_object
@@ -220,6 +225,8 @@ class GnomeModule:
extra_args = mesonlib.stringlistify(kwargs.pop('extra_args', []))
scan_command += extra_args
+ scan_command += ['-I' + os.path.join(state.environment.get_source_dir(), state.subdir),
+ '-I' + os.path.join(state.environment.get_build_dir(), state.subdir)]
scan_command += self.get_include_args(state, girtarget.get_include_dirs())
if 'link_with' in kwargs:
@@ -307,7 +314,8 @@ class GnomeModule:
}
if kwargs.get('install'):
scankwargs['install'] = kwargs['install']
- scankwargs['install_dir'] = os.path.join(state.environment.get_datadir(), 'gir-1.0')
+ scankwargs['install_dir'] = kwargs.get('install_dir_gir',
+ os.path.join(state.environment.get_datadir(), 'gir-1.0'))
scan_target = GirTarget(girfile, state.subdir, scankwargs)
typelib_output = '%s-%s.typelib' % (ns, nsversion)
@@ -331,10 +339,15 @@ class GnomeModule:
if girdir:
typelib_cmd += ["--includedir=%s" % (girdir, )]
- kwargs['output'] = typelib_output
- kwargs['command'] = typelib_cmd
- kwargs['install_dir'] = os.path.join(state.environment.get_libdir(), 'girepository-1.0')
- typelib_target = TypelibTarget(typelib_output, state.subdir, kwargs)
+ typelib_kwargs = {
+ 'output': typelib_output,
+ 'command': typelib_cmd,
+ }
+ if kwargs.get('install'):
+ typelib_kwargs['install'] = kwargs['install']
+ typelib_kwargs['install_dir'] = kwargs.get('install_dir_typelib',
+ os.path.join(state.environment.get_libdir(), 'girepository-1.0'))
+ typelib_target = TypelibTarget(typelib_output, state.subdir, typelib_kwargs)
return [scan_target, typelib_target]
def compile_schemas(self, state, args, kwargs):
@@ -473,6 +486,163 @@ class GnomeModule:
}
return build.CustomTarget(namebase + '-gdbus', state.subdir, custom_kwargs)
+ def mkenums(self, state, args, kwargs):
+ if len(args) != 1:
+ raise MesonException('Mkenums requires one positional argument.')
+ basename = args[0]
+
+ if 'sources' not in kwargs:
+ raise MesonException('Missing keyword argument "sources".')
+ sources = kwargs.pop('sources')
+ if isinstance(sources, str):
+ sources = [sources]
+ elif not isinstance(sources, list):
+ raise MesonException(
+ 'Sources keyword argument must be a string or array.')
+
+ cmd = []
+ known_kwargs = ['comments', 'eprod', 'fhead', 'fprod', 'ftail',
+ 'identifier_prefix', 'symbol_prefix', 'template',
+ 'vhead', 'vprod', 'vtail']
+ known_custom_target_kwargs = ['install', 'install_dir', 'build_always',
+ 'depends', 'depend_files']
+ c_template = h_template = None
+ install_header = False
+ for arg, value in kwargs.items():
+ if arg == 'sources':
+ sources = [value] + sources
+ elif arg == 'c_template':
+ c_template = value
+ elif arg == 'h_template':
+ h_template = value
+ elif arg == 'install_header':
+ install_header = value
+ elif arg in known_kwargs:
+ cmd += ['--' + arg.replace('_', '-'), value]
+ elif arg not in known_custom_target_kwargs:
+ raise MesonException(
+ 'Mkenums does not take a %s keyword argument.' % (arg, ))
+ cmd = ['glib-mkenums'] + cmd
+ custom_kwargs = {}
+ for arg in known_custom_target_kwargs:
+ if arg in kwargs:
+ custom_kwargs[arg] = kwargs[arg]
+
+ targets = []
+
+ if h_template is not None:
+ h_output = os.path.splitext(h_template)[0]
+ # We always set template as the first element in the source array
+ # so --template consumes it.
+ h_cmd = cmd + ['--template', '@INPUT@']
+ h_sources = [h_template] + sources
+ custom_kwargs['install'] = install_header
+ if 'install_dir' not in custom_kwargs:
+ custom_kwargs['install_dir'] = \
+ state.environment.coredata.get_builtin_option('includedir')
+ h_target = self.make_mkenum_custom_target(state, h_sources,
+ h_output, h_cmd,
+ custom_kwargs)
+ targets.append(h_target)
+
+ if c_template is not None:
+ c_output = os.path.splitext(c_template)[0]
+ # We always set template as the first element in the source array
+ # so --template consumes it.
+ c_cmd = cmd + ['--template', '@INPUT@']
+ c_sources = [c_template] + sources
+ # Never install the C file. Complain on bug tracker if you need it.
+ custom_kwargs['install'] = False
+ if h_template is not None:
+ if 'depends' in custom_kwargs:
+ custom_kwargs['depends'] += [h_target]
+ else:
+ custom_kwargs['depends'] = h_target
+ c_target = self.make_mkenum_custom_target(state, c_sources,
+ c_output, c_cmd,
+ custom_kwargs)
+ targets.insert(0, c_target)
+
+ if c_template is None and h_template is None:
+ generic_cmd = cmd + ['@INPUT@']
+ custom_kwargs['install'] = install_header
+ if 'install_dir' not in custom_kwargs:
+ custom_kwargs['install_dir'] = \
+ state.environment.coredata.get_builtin_option('includedir')
+ target = self.make_mkenum_custom_target(state, sources, basename,
+ generic_cmd, custom_kwargs)
+ return target
+ elif len(targets) == 1:
+ return targets[0]
+ else:
+ return targets
+
+ def make_mkenum_custom_target(self, state, sources, output, cmd, kwargs):
+ custom_kwargs = {
+ 'input': sources,
+ 'output': output,
+ 'capture': True,
+ 'command': cmd
+ }
+ custom_kwargs.update(kwargs)
+ return build.CustomTarget(output, state.subdir, custom_kwargs)
+
+ def genmarshal(self, state, args, kwargs):
+ if len(args) != 1:
+ raise MesonException(
+ 'Genmarshal requires one positional argument.')
+ output = args[0]
+
+ if 'sources' not in kwargs:
+ raise MesonException('Missing keyword argument "sources".')
+ sources = kwargs.pop('sources')
+ if isinstance(sources, str):
+ sources = [sources]
+ elif not isinstance(sources, list):
+ raise MesonException(
+ 'Sources keyword argument must be a string or array.')
+
+ cmd = ['glib-genmarshal']
+ known_kwargs = ['internal', 'nostdinc', 'skip_source', 'stdinc',
+ 'valist_marshallers']
+ known_custom_target_kwargs = ['build_always', 'depends',
+ 'depend_files', 'install_dir',
+ 'install_header']
+ for arg, value in kwargs.items():
+ if arg == 'prefix':
+ cmd += ['--prefix', value]
+ elif arg in known_kwargs and value:
+ cmd += ['--' + arg.replace('_', '-')]
+ elif arg not in known_custom_target_kwargs:
+ raise MesonException(
+ 'Genmarshal does not take a %s keyword argument.' % (
+ arg, ))
+
+ install_header = kwargs.pop('install_header', False)
+ install_dir = kwargs.pop('install_dir', None)
+
+ custom_kwargs = {
+ 'input': sources,
+ 'capture': True,
+ }
+ for arg in known_custom_target_kwargs:
+ if arg in kwargs:
+ custom_kwargs[arg] = kwargs[arg]
+
+ custom_kwargs['command'] = cmd + ['--header', '--body', '@INPUT@']
+ custom_kwargs['output'] = output + '.c'
+ body = build.CustomTarget(output + '_c', state.subdir, custom_kwargs)
+
+ custom_kwargs['install'] = install_header
+ if install_dir is not None:
+ custom_kwargs['install_dir'] = install_dir
+ custom_kwargs['command'] = cmd + ['--header', '@INPUT@']
+ custom_kwargs['output'] = output + '.h'
+ header = build.CustomTarget(output + '_h', state.subdir, custom_kwargs)
+
+ return [body, header]
+
+
def initialize():
return GnomeModule()
diff --git a/mesonbuild/modules/pkgconfig.py b/mesonbuild/modules/pkgconfig.py
index 3bf7658..daa11ea 100644
--- a/mesonbuild/modules/pkgconfig.py
+++ b/mesonbuild/modules/pkgconfig.py
@@ -14,15 +14,16 @@
from .. import coredata, build
from .. import mesonlib
+from .. import mlog
import os
class PkgConfigModule:
- def generate_pkgconfig_file(self, state, libraries, subdirs, name, description, version, filebase,
+ def generate_pkgconfig_file(self, state, libraries, subdirs, name, description, version, pcfile,
pub_reqs, priv_reqs, priv_libs):
coredata = state.environment.get_coredata()
outdir = state.environment.scratch_dir
- fname = os.path.join(outdir, filebase + '.pc')
+ fname = os.path.join(outdir, pcfile)
with open(fname, 'w') as ofile:
ofile.write('prefix=%s\n' % coredata.get_builtin_option('prefix'))
ofile.write('libdir=${prefix}/%s\n' %
@@ -43,9 +44,20 @@ class PkgConfigModule:
ofile.write(
'Libraries.private: {}\n'.format(' '.join(priv_libs)))
ofile.write('Libs: -L${libdir} ')
+ msg = 'Library target {0!r} has {1!r} set. Compilers ' \
+ 'may not find it from its \'-l{0}\' linker flag in the ' \
+ '{2!r} pkg-config file.'
for l in libraries:
if l.custom_install_dir:
ofile.write('-L${prefix}/%s ' % l.custom_install_dir)
+ # Warn, but not if the filename starts with 'lib'. This can
+ # happen, for instance, if someone really wants to use the
+ # 'lib' prefix on all systems, not just on UNIX, or if the the
+ # target name itself starts with 'lib'.
+ if l.name_prefix_set and not l.filename.startswith('lib'):
+ mlog.log(mlog.red('WARNING:'), msg.format(l.name, 'name_prefix', pcfile))
+ if l.name_suffix_set:
+ mlog.log(mlog.red('WARNING:'), msg.format(l.name, 'name_suffix', pcfile))
ofile.write('-l%s ' % l.name)
ofile.write('\n')
ofile.write('CFlags: ')
@@ -92,7 +104,7 @@ class PkgConfigModule:
pkgroot = os.path.join(state.environment.coredata.get_builtin_option('libdir'), 'pkgconfig')
if not isinstance(pkgroot, str):
raise mesonlib.MesonException('Install_dir must be a string.')
- self.generate_pkgconfig_file(state, libs, subdirs, name, description, version, filebase,
+ self.generate_pkgconfig_file(state, libs, subdirs, name, description, version, pcfile,
pub_reqs, priv_reqs, priv_libs)
return build.Data(False, state.environment.get_scratch_dir(), [pcfile], pkgroot)
diff --git a/mesonbuild/modules/rpm.py b/mesonbuild/modules/rpm.py
index 89194e9..13aa20b 100644
--- a/mesonbuild/modules/rpm.py
+++ b/mesonbuild/modules/rpm.py
@@ -104,7 +104,7 @@ class RPMModule:
mlog.bold('dnf provides %s' % lib.fullpath))
for prog in state.environment.coredata.ext_progs.values():
if not prog.found():
- fn.write('BuildRequires: /usr/bin/%s # FIXME\n' %
+ fn.write('BuildRequires: %{_bindir}/%s # FIXME\n' %
prog.get_name())
else:
fn.write('BuildRequires: %s\n' % ' '.join(prog.fullpath))
@@ -115,32 +115,25 @@ class RPMModule:
if devel_subpkg:
fn.write('%package devel\n')
fn.write('Summary: Development files for %{name}\n')
- fn.write('Requires: %{name}%{?_isa} = %{version}-%{release}\n')
+ fn.write('Requires: %{name}%{?_isa} = %{?epoch:%{epoch}:}{version}-%{release}\n')
fn.write('\n')
fn.write('%description devel\n')
fn.write('Development files for %{name}.\n')
fn.write('\n')
fn.write('%prep\n')
fn.write('%autosetup\n')
- fn.write('rm -rf rpmbuilddir && mkdir rpmbuilddir\n')
fn.write('\n')
fn.write('%build\n')
- fn.write('pushd rpmbuilddir\n')
- fn.write(' %meson ..\n')
- fn.write(' ninja-build -v\n')
- fn.write('popd\n')
+ fn.write('%meson\n')
+ fn.write('%meson_build\n')
fn.write('\n')
fn.write('%install\n')
- fn.write('pushd rpmbuilddir\n')
- fn.write(' DESTDIR=%{buildroot} ninja-build -v install\n')
- fn.write('popd\n')
+ fn.write('%meson_install\n')
if len(to_delete) > 0:
- fn.write('rm -rf %s\n' % ' '.join(to_delete))
+ fn.write('rm -vf %s\n' % ' '.join(to_delete))
fn.write('\n')
fn.write('%check\n')
- fn.write('pushd rpmbuilddir\n')
- fn.write(' ninja-build -v test\n')
- fn.write('popd\n')
+ fn.write('%meson_test\n')
fn.write('\n')
fn.write('%files\n')
for f in files:
@@ -153,7 +146,6 @@ class RPMModule:
fn.write('\n')
if so_installed:
fn.write('%post -p /sbin/ldconfig\n')
- fn.write('\n')
fn.write('%postun -p /sbin/ldconfig\n')
fn.write('\n')
fn.write('%changelog\n')
diff --git a/mesonbuild/scripts/commandrunner.py b/mesonbuild/scripts/commandrunner.py
index 1c37f5c..1c37f5c 100644..100755
--- a/mesonbuild/scripts/commandrunner.py
+++ b/mesonbuild/scripts/commandrunner.py
diff --git a/mesonbuild/scripts/delwithsuffix.py b/mesonbuild/scripts/delwithsuffix.py
index e112101..e112101 100644..100755
--- a/mesonbuild/scripts/delwithsuffix.py
+++ b/mesonbuild/scripts/delwithsuffix.py
diff --git a/mesonbuild/scripts/depfixer.py b/mesonbuild/scripts/depfixer.py
index 7124c6f..7124c6f 100644..100755
--- a/mesonbuild/scripts/depfixer.py
+++ b/mesonbuild/scripts/depfixer.py
diff --git a/mesonbuild/scripts/dirchanger.py b/mesonbuild/scripts/dirchanger.py
index 93a901d..93a901d 100644..100755
--- a/mesonbuild/scripts/dirchanger.py
+++ b/mesonbuild/scripts/dirchanger.py
diff --git a/mesonbuild/scripts/gettext.py b/mesonbuild/scripts/gettext.py
index 1f0a391..ba6b242 100644
--- a/mesonbuild/scripts/gettext.py
+++ b/mesonbuild/scripts/gettext.py
@@ -1,5 +1,3 @@
-#!/usr/bin/env python3
-
# Copyright 2016 The Meson development team
# Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/mesonbuild/scripts/gtkdochelper.py b/mesonbuild/scripts/gtkdochelper.py
index e87a379..e87a379 100644..100755
--- a/mesonbuild/scripts/gtkdochelper.py
+++ b/mesonbuild/scripts/gtkdochelper.py
diff --git a/mesonbuild/scripts/meson_benchmark.py b/mesonbuild/scripts/meson_benchmark.py
index 6d138b0..6d138b0 100644..100755
--- a/mesonbuild/scripts/meson_benchmark.py
+++ b/mesonbuild/scripts/meson_benchmark.py
diff --git a/mesonbuild/scripts/meson_exe.py b/mesonbuild/scripts/meson_exe.py
index d2ae357..d2ae357 100644..100755
--- a/mesonbuild/scripts/meson_exe.py
+++ b/mesonbuild/scripts/meson_exe.py
diff --git a/mesonbuild/scripts/meson_install.py b/mesonbuild/scripts/meson_install.py
index 5cf02e6..5cf02e6 100644..100755
--- a/mesonbuild/scripts/meson_install.py
+++ b/mesonbuild/scripts/meson_install.py
diff --git a/mesonbuild/scripts/meson_test.py b/mesonbuild/scripts/meson_test.py
index acf7cd5..acf7cd5 100644..100755
--- a/mesonbuild/scripts/meson_test.py
+++ b/mesonbuild/scripts/meson_test.py
diff --git a/mesonbuild/scripts/regen_checker.py b/mesonbuild/scripts/regen_checker.py
index ddf4943..ddf4943 100644..100755
--- a/mesonbuild/scripts/regen_checker.py
+++ b/mesonbuild/scripts/regen_checker.py
diff --git a/mesonbuild/scripts/scanbuild.py b/mesonbuild/scripts/scanbuild.py
index f90c3c7..f13a1a4 100644
--- a/mesonbuild/scripts/scanbuild.py
+++ b/mesonbuild/scripts/scanbuild.py
@@ -1,5 +1,4 @@
# Copyright 2016 The Meson development team
-
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
diff --git a/mesonbuild/scripts/symbolextractor.py b/mesonbuild/scripts/symbolextractor.py
index c117301..c117301 100644..100755
--- a/mesonbuild/scripts/symbolextractor.py
+++ b/mesonbuild/scripts/symbolextractor.py
diff --git a/mesonbuild/scripts/vcstagger.py b/mesonbuild/scripts/vcstagger.py
index 3f36e0a..3f36e0a 100644..100755
--- a/mesonbuild/scripts/vcstagger.py
+++ b/mesonbuild/scripts/vcstagger.py
diff --git a/run_project_tests.py b/run_project_tests.py
new file mode 100755
index 0000000..1e094ad
--- /dev/null
+++ b/run_project_tests.py
@@ -0,0 +1,499 @@
+#!/usr/bin/env python3
+
+# Copyright 2012-2016 The Meson development team
+
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+
+# http://www.apache.org/licenses/LICENSE-2.0
+
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from glob import glob
+import os, subprocess, shutil, sys, signal
+from io import StringIO
+from ast import literal_eval
+import sys, tempfile
+from mesonbuild import environment
+from mesonbuild import mesonlib
+from mesonbuild import mlog
+from mesonbuild import mesonmain
+from mesonbuild.mesonlib import stringlistify
+from mesonbuild.scripts import meson_test, meson_benchmark
+import argparse
+import xml.etree.ElementTree as ET
+import time
+import multiprocessing
+import concurrent.futures as conc
+
+from mesonbuild.coredata import backendlist
+
+class TestResult:
+ def __init__(self, msg, stdo, stde, mlog, conftime=0, buildtime=0, testtime=0):
+ self.msg = msg
+ self.stdo = stdo
+ self.stde = stde
+ self.mlog = mlog
+ self.conftime = conftime
+ self.buildtime = buildtime
+ self.testtime = testtime
+
+class AutoDeletedDir():
+ def __init__(self, d):
+ self.dir = d
+ def __enter__(self):
+ os.makedirs(self.dir, exist_ok=True)
+ return self.dir
+ def __exit__(self, _type, value, traceback):
+ # On Windows, shutil.rmtree fails sometimes, because 'the directory is not empty'.
+ # Retrying fixes this.
+ # That's why we don't use tempfile.TemporaryDirectory, but wrap the deletion in the AutoDeletedDir class.
+ retries = 5
+ for i in range(0, retries):
+ try:
+ shutil.rmtree(self.dir)
+ return
+ except OSError:
+ if i == retries-1:
+ raise
+ time.sleep(0.1 * (2**i))
+
+passing_tests = 0
+failing_tests = 0
+skipped_tests = 0
+failing_logs = []
+print_debug = 'MESON_PRINT_TEST_OUTPUT' in os.environ
+do_debug = not {'MESON_PRINT_TEST_OUTPUT', 'TRAVIS', 'APPVEYOR'}.isdisjoint(os.environ)
+
+meson_command = os.path.join(os.getcwd(), 'meson')
+if not os.path.exists(meson_command):
+ meson_command += '.py'
+ if not os.path.exists(meson_command):
+ raise RuntimeError('Could not find main Meson script to run.')
+
+class StopException(Exception):
+ def __init__(self):
+ super().__init__('Stopped by user')
+
+stop = False
+def stop_handler(signal, frame):
+ global stop
+ stop = True
+signal.signal(signal.SIGINT, stop_handler)
+signal.signal(signal.SIGTERM, stop_handler)
+
+#unity_flags = ['--unity']
+unity_flags = []
+
+backend_flags = None
+compile_commands = None
+test_commands = None
+install_commands = None
+
+def setup_commands(backend):
+ global backend_flags, compile_commands, test_commands, install_commands
+ msbuild_exe = shutil.which('msbuild')
+ if backend == 'vs2010' or (backend is None and msbuild_exe is not None):
+ backend_flags = ['--backend=vs2010']
+ compile_commands = ['msbuild']
+ test_commands = ['msbuild', 'RUN_TESTS.vcxproj']
+ install_commands = []
+ elif backend == 'vs2015':
+ backend_flags = ['--backend=vs2015']
+ compile_commands = ['msbuild']
+ test_commands = ['msbuild', 'RUN_TESTS.vcxproj']
+ install_commands = []
+ elif backend == 'xcode' or (backend is None and mesonlib.is_osx()):
+ backend_flags = ['--backend=xcode']
+ compile_commands = ['xcodebuild']
+ test_commands = ['xcodebuild', '-target', 'RUN_TESTS']
+ install_commands = []
+ else:
+ backend_flags = []
+ ninja_command = environment.detect_ninja()
+ if ninja_command is None:
+ raise RuntimeError('Could not find Ninja v1.6 or newer')
+ if do_debug:
+ compile_commands = [ninja_command, '-v']
+ else:
+ compile_commands = [ninja_command]
+ compile_commands += ['-w', 'dupbuild=err']
+ test_commands = [ninja_command, 'test', 'benchmark']
+ install_commands = [ninja_command, 'install']
+
+def get_relative_files_list_from_dir(fromdir):
+ paths = []
+ for (root, _, files) in os.walk(fromdir):
+ reldir = os.path.relpath(root, start=fromdir)
+ for f in files:
+ path = os.path.join(reldir, f).replace('\\', '/')
+ if path.startswith('./'):
+ path = path[2:]
+ paths.append(path)
+ return paths
+
+def platform_fix_exe_name(fname):
+ if not fname.endswith('?exe'):
+ return fname
+ fname = fname[:-4]
+ if mesonlib.is_windows():
+ return fname + '.exe'
+ return fname
+
+def validate_install(srcdir, installdir):
+ # List of installed files
+ info_file = os.path.join(srcdir, 'installed_files.txt')
+ # If this exists, the test does not install any other files
+ noinst_file = 'usr/no-installed-files'
+ expected = {}
+ found = {}
+ ret_msg = ''
+ # Generate list of expected files
+ if os.path.exists(os.path.join(installdir, noinst_file)):
+ expected[noinst_file] = False
+ elif os.path.exists(info_file):
+ with open(info_file) as f:
+ for line in f:
+ expected[platform_fix_exe_name(line.strip())] = False
+ # Check if expected files were found
+ for fname in expected:
+ if os.path.exists(os.path.join(installdir, fname)):
+ expected[fname] = True
+ for (fname, found) in expected.items():
+ if not found:
+ ret_msg += 'Expected file {0} missing.\n'.format(fname)
+ # Check if there are any unexpected files
+ found = get_relative_files_list_from_dir(installdir)
+ for fname in found:
+ if fname not in expected and not fname.endswith('.pdb'):
+ ret_msg += 'Extra file {0} found.\n'.format(fname)
+ return ret_msg
+
+def log_text_file(logfile, testdir, stdo, stde):
+ global stop, executor, futures
+ logfile.write('%s\nstdout\n\n---\n' % testdir)
+ logfile.write(stdo)
+ logfile.write('\n\n---\n\nstderr\n\n---\n')
+ logfile.write(stde)
+ logfile.write('\n\n---\n\n')
+ if print_debug:
+ 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):
+ old_stdout = sys.stdout
+ sys.stdout = mystdout = StringIO()
+ old_stderr = sys.stderr
+ sys.stderr = mystderr = StringIO()
+ try:
+ returncode = mesonmain.run(commandlist[0], commandlist[1:])
+ finally:
+ sys.stdout = old_stdout
+ sys.stderr = old_stderr
+ return (returncode, mystdout.getvalue(), mystderr.getvalue())
+
+def run_test_inprocess(testdir):
+ old_stdout = sys.stdout
+ sys.stdout = mystdout = StringIO()
+ old_stderr = sys.stderr
+ sys.stderr = mystderr = StringIO()
+ old_cwd = os.getcwd()
+ os.chdir(testdir)
+ try:
+ returncode_test = meson_test.run(['meson-private/meson_test_setup.dat'])
+ returncode_benchmark = meson_benchmark.run(['meson-private/meson_benchmark_setup.dat'])
+ finally:
+ sys.stdout = old_stdout
+ sys.stderr = old_stderr
+ os.chdir(old_cwd)
+ return (max(returncode_test, returncode_benchmark), mystdout.getvalue(), mystderr.getvalue())
+
+def parse_test_args(testdir):
+ args = []
+ try:
+ with open(os.path.join(testdir, 'test_args.txt'), 'r') as f:
+ content = f.read()
+ try:
+ args = literal_eval(content)
+ except Exception:
+ raise Exception('Malformed test_args file.')
+ args = stringlistify(args)
+ except FileNotFoundError:
+ pass
+ return args
+
+def run_test(skipped, testdir, extra_args, flags, compile_commands, install_commands, should_succeed):
+ if skipped:
+ return None
+ with AutoDeletedDir(tempfile.mkdtemp(prefix='b ', dir='.')) as build_dir:
+ with AutoDeletedDir(tempfile.mkdtemp(prefix='i ', dir=os.getcwd())) as install_dir:
+ try:
+ return _run_test(testdir, build_dir, install_dir, extra_args, flags, compile_commands, install_commands, should_succeed)
+ finally:
+ mlog.shutdown() # Close the log file because otherwise Windows wets itself.
+
+def _run_test(testdir, test_build_dir, install_dir, extra_args, flags, compile_commands, install_commands, should_succeed):
+ test_args = parse_test_args(testdir)
+ gen_start = time.time()
+ gen_command = [meson_command, '--prefix', '/usr', '--libdir', 'lib', testdir, test_build_dir]\
+ + flags + test_args + extra_args
+ (returncode, stdo, stde) = run_configure_inprocess(gen_command)
+ try:
+ logfile = os.path.join(test_build_dir, 'meson-logs/meson-log.txt')
+ with open(logfile, errors='ignore') as f:
+ mesonlog = f.read()
+ except Exception:
+ mesonlog = 'No meson-log.txt found.'
+ gen_time = time.time() - gen_start
+ if not should_succeed:
+ if returncode != 0:
+ return TestResult('', stdo, stde, mesonlog, gen_time)
+ return TestResult('Test that should have failed succeeded', stdo, stde, mesonlog, gen_time)
+ if returncode != 0:
+ return TestResult('Generating the build system failed.', stdo, stde, mesonlog, gen_time)
+ if 'msbuild' in compile_commands[0]:
+ sln_name = glob(os.path.join(test_build_dir, '*.sln'))[0]
+ comp = compile_commands + [os.path.split(sln_name)[-1]]
+ else:
+ comp = compile_commands
+ build_start = time.time()
+ pc = subprocess.Popen(comp, cwd=test_build_dir,
+ stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ (o, e) = pc.communicate()
+ build_time = time.time() - build_start
+ stdo += o.decode(sys.stdout.encoding)
+ stde += e.decode(sys.stdout.encoding)
+ if pc.returncode != 0:
+ return TestResult('Compiling source code failed.', stdo, stde, mesonlog, gen_time, build_time)
+ test_start = time.time()
+ # Note that we don't test that running e.g. 'ninja test' actually
+ # works. One hopes that this is a common enough happening that
+ # it is picked up immediately on development.
+ (returncode, tstdo, tstde) = run_test_inprocess(test_build_dir)
+ test_time = time.time() - test_start
+ stdo += tstdo
+ stde += tstde
+ if returncode != 0:
+ return TestResult('Running unit tests failed.', stdo, stde, mesonlog, gen_time, build_time, test_time)
+ if len(install_commands) == 0:
+ return TestResult('', '', '', gen_time, build_time, test_time)
+ else:
+ env = os.environ.copy()
+ env['DESTDIR'] = install_dir
+ pi = subprocess.Popen(install_commands, cwd=test_build_dir, env=env,
+ stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ (o, e) = pi.communicate()
+ stdo += o.decode(sys.stdout.encoding)
+ stde += e.decode(sys.stdout.encoding)
+ if pi.returncode != 0:
+ return TestResult('Running install failed.', stdo, stde, mesonlog, gen_time, build_time, test_time)
+ return TestResult(validate_install(testdir, install_dir), stdo, stde, mesonlog, gen_time, build_time, test_time)
+
+def gather_tests(testdir):
+ tests = [t.replace('\\', '/').split('/', 2)[2] for t in glob(os.path.join(testdir, '*'))]
+ testlist = [(int(t.split()[0]), t) for t in tests]
+ testlist.sort()
+ tests = [os.path.join(testdir, t[1]) for t in testlist]
+ return tests
+
+def have_d_compiler():
+ if shutil.which("ldc2"):
+ return True
+ elif shutil.which("ldc"):
+ return True
+ elif shutil.which("gdc"):
+ return True
+ elif shutil.which("dmd"):
+ return True
+ return False
+
+def detect_tests_to_run():
+ all_tests = []
+ all_tests.append(('common', gather_tests('test cases/common'), False))
+ all_tests.append(('failing', gather_tests('test cases/failing'), False))
+ all_tests.append(('prebuilt', gather_tests('test cases/prebuilt'), False))
+
+ all_tests.append(('platform-osx', gather_tests('test cases/osx'), False if mesonlib.is_osx() else True))
+ all_tests.append(('platform-windows', gather_tests('test cases/windows'), False if mesonlib.is_windows() else True))
+ all_tests.append(('platform-linux', gather_tests('test cases/linuxlike'), False if not (mesonlib.is_osx() or mesonlib.is_windows()) else True))
+ all_tests.append(('framework', gather_tests('test cases/frameworks'), False if not mesonlib.is_osx() and not mesonlib.is_windows() else True))
+ all_tests.append(('java', gather_tests('test cases/java'), False if not mesonlib.is_osx() and shutil.which('javac') else True))
+ all_tests.append(('C#', gather_tests('test cases/csharp'), False if shutil.which('mcs') else True))
+ all_tests.append(('vala', gather_tests('test cases/vala'), False if shutil.which('valac') else True))
+ all_tests.append(('rust', gather_tests('test cases/rust'), False if shutil.which('rustc') else True))
+ all_tests.append(('d', gather_tests('test cases/d'), False if have_d_compiler() else True))
+ all_tests.append(('objective c', gather_tests('test cases/objc'), False if not mesonlib.is_windows() else True))
+ all_tests.append(('fortran', gather_tests('test cases/fortran'), False if shutil.which('gfortran') else True))
+ all_tests.append(('swift', gather_tests('test cases/swift'), False if shutil.which('swiftc') else True))
+ all_tests.append(('python3', gather_tests('test cases/python3'), False if shutil.which('python3') else True))
+ return all_tests
+
+def run_tests(extra_args):
+ 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')
+ conf_time = 0
+ build_time = 0
+ test_time = 0
+
+ executor = conc.ProcessPoolExecutor(max_workers=multiprocessing.cpu_count())
+
+ for name, test_cases, skipped in all_tests:
+ current_suite = ET.SubElement(junit_root, 'testsuite', {'name' : name, 'tests' : str(len(test_cases))})
+ if skipped:
+ print('\nNot running %s tests.\n' % name)
+ else:
+ print('\nRunning %s tests.\n' % name)
+ futures = []
+ for t in test_cases:
+ # Jenkins screws us over by automatically sorting test cases by name
+ # and getting it wrong by not doing logical number sorting.
+ (testnum, testbase) = os.path.split(t)[-1].split(' ', 1)
+ testname = '%.3d %s' % (int(testnum), testbase)
+ result = executor.submit(run_test, skipped, t, extra_args, unity_flags + backend_flags, compile_commands, install_commands, name != 'failing')
+ futures.append((testname, t, result))
+ for (testname, t, result) in futures:
+ result = result.result()
+ if result is None:
+ print('Skipping:', t)
+ current_test = ET.SubElement(current_suite, 'testcase', {'name' : testname,
+ 'classname' : name})
+ ET.SubElement(current_test, 'skipped', {})
+ global skipped_tests
+ skipped_tests += 1
+ else:
+ without_install = "" if len(install_commands) > 0 else " (without install)"
+ if result.msg != '':
+ print('Failed test%s: %s' % (without_install, t))
+ print('Reason:', result.msg)
+ failing_tests += 1
+ failing_logs.append(result.stdo)
+ failing_logs.append(result.stde)
+ else:
+ print('Succeeded test%s: %s' % (without_install, t))
+ passing_tests += 1
+ conf_time += result.conftime
+ build_time += result.buildtime
+ test_time += result.testtime
+ total_time = conf_time + build_time + test_time
+ log_text_file(logfile, t, result.stdo, result.stde)
+ current_test = ET.SubElement(current_suite, 'testcase', {'name' : testname,
+ 'classname' : name,
+ 'time' : '%.3f' % total_time})
+ if result.msg != '':
+ ET.SubElement(current_test, 'failure', {'message' : result.msg})
+ stdoel = ET.SubElement(current_test, 'system-out')
+ stdoel.text = result.stdo
+ stdeel = ET.SubElement(current_test, 'system-err')
+ stdeel.text = result.stde
+ print("\nTotal configuration time: %.2fs" % conf_time)
+ print("Total build time: %.2fs" % build_time)
+ print("Total test time: %.2fs" % test_time)
+ ET.ElementTree(element=junit_root).write('meson-test-run.xml', xml_declaration=True, encoding='UTF-8')
+
+def check_file(fname):
+ linenum = 1
+ with open(fname, 'rb') as f:
+ lines = f.readlines()
+ for line in lines:
+ if b'\t' in line:
+ print("File %s contains a literal tab on line %d. Only spaces are permitted." % (fname, linenum))
+ sys.exit(1)
+ if b'\r' in line:
+ print("File %s contains DOS line ending on line %d. Only unix-style line endings are permitted." % (fname, linenum))
+ sys.exit(1)
+ linenum += 1
+
+def check_format():
+ for (root, _, files) in os.walk('.'):
+ for file in files:
+ if file.endswith('.py') or file.endswith('.build') or file == 'meson_options.txt':
+ fullname = os.path.join(root, file)
+ check_file(fullname)
+
+def pbcompile(compiler, source, objectfile):
+ if compiler == 'cl':
+ cmd = [compiler, '/nologo', '/Fo'+objectfile, '/c', source]
+ else:
+ cmd = [compiler, '-c', source, '-o', objectfile]
+ subprocess.check_call(cmd, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
+
+def generate_pb_object(compiler, object_suffix):
+ source = 'test cases/prebuilt/1 object/source.c'
+ objectfile = 'test cases/prebuilt/1 object/prebuilt.' + object_suffix
+ pbcompile(compiler, source, objectfile)
+ return objectfile
+
+def generate_pb_static(compiler, object_suffix, static_suffix):
+ source = 'test cases/prebuilt/2 static/libdir/best.c'
+ objectfile = 'test cases/prebuilt/2 static/libdir/best.' + object_suffix
+ stlibfile = 'test cases/prebuilt/2 static/libdir/libbest.' + static_suffix
+ pbcompile(compiler, source, objectfile)
+ if compiler == 'cl':
+ linker = ['lib', '/NOLOGO', '/OUT:' + stlibfile, objectfile]
+ else:
+ linker = ['ar', 'csr', stlibfile, objectfile]
+ subprocess.check_call(linker)
+ os.unlink(objectfile)
+ return stlibfile
+
+def generate_prebuilt():
+ static_suffix = 'a'
+ if shutil.which('cl'):
+ compiler = 'cl'
+ static_suffix = 'lib'
+ elif shutil.which('cc'):
+ compiler = 'cc'
+ elif shutil.which('gcc'):
+ compiler = 'gcc'
+ else:
+ raise RuntimeError("Could not find C compiler.")
+ if mesonlib.is_windows():
+ object_suffix = 'obj'
+ else:
+ object_suffix = 'o'
+ objectfile = generate_pb_object(compiler, object_suffix)
+ stlibfile = generate_pb_static(compiler, object_suffix, static_suffix)
+ return (objectfile, stlibfile)
+
+if __name__ == '__main__':
+ parser = argparse.ArgumentParser(description="Run the test suite of Meson.")
+ parser.add_argument('extra_args', nargs='*',
+ help='arguments that are passed directly to Meson (remember to have -- before these).')
+ parser.add_argument('--backend', default=None, dest='backend',
+ choices = backendlist)
+ options = parser.parse_args()
+ setup_commands(options.backend)
+
+ script_dir = os.path.split(__file__)[0]
+ if script_dir != '':
+ os.chdir(script_dir)
+ check_format()
+ pbfiles = generate_prebuilt()
+ try:
+ run_tests(options.extra_args)
+ except StopException:
+ pass
+ for f in pbfiles:
+ os.unlink(f)
+ print('\nTotal passed tests:', passing_tests)
+ print('Total failed tests:', failing_tests)
+ print('Total skipped tests:', skipped_tests)
+ if failing_tests > 0 and ('TRAVIS' in os.environ or 'APPVEYOR' in os.environ):
+ print('\nMesonlogs of failing tests\n')
+ for l in failing_logs:
+ print(l, '\n')
+ sys.exit(failing_tests)
+
diff --git a/run_tests.py b/run_tests.py
index b57dd39..ec8970a 100755
--- a/run_tests.py
+++ b/run_tests.py
@@ -14,484 +14,22 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-from glob import glob
-import os, subprocess, shutil, sys, signal
-from io import StringIO
-from ast import literal_eval
-import sys, tempfile
-from mesonbuild import environment
+import subprocess, sys, os
+import shutil
from mesonbuild import mesonlib
-from mesonbuild import mlog
-from mesonbuild import mesonmain
-from mesonbuild.mesonlib import stringlistify
-from mesonbuild.scripts import meson_test, meson_benchmark
-import argparse
-import xml.etree.ElementTree as ET
-import time
-import multiprocessing
-import concurrent.futures as conc
-
-from mesonbuild.coredata import backendlist
-
-class TestResult:
- def __init__(self, msg, stdo, stde, mlog, conftime=0, buildtime=0, testtime=0):
- self.msg = msg
- self.stdo = stdo
- self.stde = stde
- self.mlog = mlog
- self.conftime = conftime
- self.buildtime = buildtime
- self.testtime = testtime
-
-class AutoDeletedDir():
- def __init__(self, d):
- self.dir = d
- def __enter__(self):
- os.makedirs(self.dir, exist_ok=True)
- return self.dir
- def __exit__(self, _type, value, traceback):
- # On Windows, shutil.rmtree fails sometimes, because 'the directory is not empty'.
- # Retrying fixes this.
- # That's why we don't use tempfile.TemporaryDirectory, but wrap the deletion in the AutoDeletedDir class.
- retries = 5
- for i in range(0, retries):
- try:
- shutil.rmtree(self.dir)
- return
- except OSError:
- if i == retries-1:
- raise
- time.sleep(0.1 * (2**i))
-
-passing_tests = 0
-failing_tests = 0
-skipped_tests = 0
-failing_logs = []
-print_debug = 'MESON_PRINT_TEST_OUTPUT' in os.environ
-
-meson_command = os.path.join(os.getcwd(), 'meson')
-if not os.path.exists(meson_command):
- meson_command += '.py'
- if not os.path.exists(meson_command):
- raise RuntimeError('Could not find main Meson script to run.')
-
-class StopException(Exception):
- def __init__(self):
- super().__init__('Stopped by user')
-
-stop = False
-def stop_handler(signal, frame):
- global stop
- stop = True
-signal.signal(signal.SIGINT, stop_handler)
-signal.signal(signal.SIGTERM, stop_handler)
-
-#unity_flags = ['--unity']
-unity_flags = []
-
-backend_flags = None
-compile_commands = None
-test_commands = None
-install_commands = None
-
-def setup_commands(backend):
- global backend_flags, compile_commands, test_commands, install_commands
- msbuild_exe = shutil.which('msbuild')
- if backend == 'vs2010' or (backend is None and msbuild_exe is not None):
- backend_flags = ['--backend=vs2010']
- compile_commands = ['msbuild']
- test_commands = ['msbuild', 'RUN_TESTS.vcxproj']
- install_commands = []
- elif backend == 'vs2015':
- backend_flags = ['--backend=vs2015']
- compile_commands = ['msbuild']
- test_commands = ['msbuild', 'RUN_TESTS.vcxproj']
- install_commands = []
- elif backend == 'xcode' or (backend is None and mesonlib.is_osx()):
- backend_flags = ['--backend=xcode']
- compile_commands = ['xcodebuild']
- test_commands = ['xcodebuild', '-target', 'RUN_TESTS']
- install_commands = []
- else:
- backend_flags = []
- ninja_command = environment.detect_ninja()
- if ninja_command is None:
- raise RuntimeError('Could not find Ninja v1.6 or newer')
- if print_debug:
- compile_commands = [ninja_command, '-v']
- else:
- compile_commands = [ninja_command]
- compile_commands += ['-w', 'dupbuild=err']
- test_commands = [ninja_command, 'test', 'benchmark']
- install_commands = [ninja_command, 'install']
-
-def get_relative_files_list_from_dir(fromdir):
- paths = []
- for (root, _, files) in os.walk(fromdir):
- reldir = os.path.relpath(root, start=fromdir)
- for f in files:
- path = os.path.join(reldir, f).replace('\\', '/')
- if path.startswith('./'):
- path = path[2:]
- paths.append(path)
- return paths
-
-def platform_fix_exe_name(fname):
- if not fname.endswith('?exe'):
- return fname
- fname = fname[:-4]
- if mesonlib.is_windows():
- return fname + '.exe'
- return fname
-
-def validate_install(srcdir, installdir):
- # List of installed files
- info_file = os.path.join(srcdir, 'installed_files.txt')
- # If this exists, the test does not install any other files
- noinst_file = 'usr/no-installed-files'
- expected = {}
- found = {}
- ret_msg = ''
- # Generate list of expected files
- if os.path.exists(os.path.join(installdir, noinst_file)):
- expected[noinst_file] = False
- elif os.path.exists(info_file):
- with open(info_file) as f:
- for line in f:
- expected[platform_fix_exe_name(line.strip())] = False
- # Check if expected files were found
- for fname in expected:
- if os.path.exists(os.path.join(installdir, fname)):
- expected[fname] = True
- for (fname, found) in expected.items():
- if not found:
- ret_msg += 'Expected file {0} missing.\n'.format(fname)
- # Check if there are any unexpected files
- found = get_relative_files_list_from_dir(installdir)
- for fname in found:
- if fname not in expected and not fname.endswith('.pdb'):
- ret_msg += 'Extra file {0} found.\n'.format(fname)
- return ret_msg
-
-def log_text_file(logfile, testdir, stdo, stde):
- global stop, executor, futures
- logfile.write('%s\nstdout\n\n---\n' % testdir)
- logfile.write(stdo)
- logfile.write('\n\n---\n\nstderr\n\n---\n')
- logfile.write(stde)
- logfile.write('\n\n---\n\n')
- if print_debug:
- 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):
- old_stdout = sys.stdout
- sys.stdout = mystdout = StringIO()
- old_stderr = sys.stderr
- sys.stderr = mystderr = StringIO()
- try:
- returncode = mesonmain.run(commandlist[0], commandlist[1:])
- finally:
- sys.stdout = old_stdout
- sys.stderr = old_stderr
- return (returncode, mystdout.getvalue(), mystderr.getvalue())
-
-def run_test_inprocess(testdir):
- old_stdout = sys.stdout
- sys.stdout = mystdout = StringIO()
- old_stderr = sys.stderr
- sys.stderr = mystderr = StringIO()
- old_cwd = os.getcwd()
- os.chdir(testdir)
- try:
- returncode_test = meson_test.run(['meson-private/meson_test_setup.dat'])
- returncode_benchmark = meson_benchmark.run(['meson-private/meson_benchmark_setup.dat'])
- finally:
- sys.stdout = old_stdout
- sys.stderr = old_stderr
- os.chdir(old_cwd)
- return (max(returncode_test, returncode_benchmark), mystdout.getvalue(), mystderr.getvalue())
-
-def parse_test_args(testdir):
- args = []
- try:
- with open(os.path.join(testdir, 'test_args.txt'), 'r') as f:
- content = f.read()
- try:
- args = literal_eval(content)
- except Exception:
- raise Exception('Malformed test_args file.')
- args = stringlistify(args)
- except FileNotFoundError:
- pass
- return args
-
-def run_test(skipped, testdir, extra_args, flags, compile_commands, install_commands, should_succeed):
- if skipped:
- return None
- with AutoDeletedDir(tempfile.mkdtemp(prefix='b ', dir='.')) as build_dir:
- with AutoDeletedDir(tempfile.mkdtemp(prefix='i ', dir=os.getcwd())) as install_dir:
- try:
- return _run_test(testdir, build_dir, install_dir, extra_args, flags, compile_commands, install_commands, should_succeed)
- finally:
- mlog.shutdown() # Close the log file because otherwise Windows wets itself.
-
-def _run_test(testdir, test_build_dir, install_dir, extra_args, flags, compile_commands, install_commands, should_succeed):
- test_args = parse_test_args(testdir)
- gen_start = time.time()
- gen_command = [meson_command, '--prefix', '/usr', '--libdir', 'lib', testdir, test_build_dir]\
- + flags + test_args + extra_args
- (returncode, stdo, stde) = run_configure_inprocess(gen_command)
- try:
- logfile = os.path.join(test_build_dir, 'meson-logs/meson-log.txt')
- with open(logfile, errors='ignore') as f:
- mesonlog = f.read()
- except Exception:
- mesonlog = 'No meson-log.txt found.'
- gen_time = time.time() - gen_start
- if not should_succeed:
- if returncode != 0:
- return TestResult('', stdo, stde, mesonlog, gen_time)
- return TestResult('Test that should have failed succeeded', stdo, stde, mesonlog, gen_time)
- if returncode != 0:
- return TestResult('Generating the build system failed.', stdo, stde, mesonlog, gen_time)
- if 'msbuild' in compile_commands[0]:
- sln_name = glob(os.path.join(test_build_dir, '*.sln'))[0]
- comp = compile_commands + [os.path.split(sln_name)[-1]]
- else:
- comp = compile_commands
- build_start = time.time()
- pc = subprocess.Popen(comp, cwd=test_build_dir,
- stdout=subprocess.PIPE, stderr=subprocess.PIPE)
- (o, e) = pc.communicate()
- build_time = time.time() - build_start
- stdo += o.decode(sys.stdout.encoding)
- stde += e.decode(sys.stdout.encoding)
- if pc.returncode != 0:
- return TestResult('Compiling source code failed.', stdo, stde, mesonlog, gen_time, build_time)
- test_start = time.time()
- # Note that we don't test that running e.g. 'ninja test' actually
- # works. One hopes that this is a common enough happening that
- # it is picked up immediately on development.
- (returncode, tstdo, tstde) = run_test_inprocess(test_build_dir)
- test_time = time.time() - test_start
- stdo += tstdo
- stde += tstde
- if returncode != 0:
- return TestResult('Running unit tests failed.', stdo, stde, mesonlog, gen_time, build_time, test_time)
- if len(install_commands) == 0:
- return TestResult('', '', '', gen_time, build_time, test_time)
- else:
- env = os.environ.copy()
- env['DESTDIR'] = install_dir
- pi = subprocess.Popen(install_commands, cwd=test_build_dir, env=env,
- stdout=subprocess.PIPE, stderr=subprocess.PIPE)
- (o, e) = pi.communicate()
- stdo += o.decode(sys.stdout.encoding)
- stde += e.decode(sys.stdout.encoding)
- if pi.returncode != 0:
- return TestResult('Running install failed.', stdo, stde, mesonlog, gen_time, build_time, test_time)
- return TestResult(validate_install(testdir, install_dir), stdo, stde, mesonlog, gen_time, build_time, test_time)
-
-def gather_tests(testdir):
- tests = [t.replace('\\', '/').split('/', 2)[2] for t in glob(os.path.join(testdir, '*'))]
- testlist = [(int(t.split()[0]), t) for t in tests]
- testlist.sort()
- tests = [os.path.join(testdir, t[1]) for t in testlist]
- return tests
-
-def have_d_compiler():
- if shutil.which("ldc2"):
- return True
- elif shutil.which("ldc"):
- return True
- elif shutil.which("gdc"):
- return True
- elif shutil.which("dmd"):
- return True
- return False
-
-def detect_tests_to_run():
- all_tests = []
- all_tests.append(('common', gather_tests('test cases/common'), False))
- all_tests.append(('failing', gather_tests('test cases/failing'), False))
- all_tests.append(('prebuilt', gather_tests('test cases/prebuilt'), False))
-
- all_tests.append(('platform-osx', gather_tests('test cases/osx'), False if mesonlib.is_osx() else True))
- all_tests.append(('platform-windows', gather_tests('test cases/windows'), False if mesonlib.is_windows() else True))
- all_tests.append(('platform-linux', gather_tests('test cases/linuxlike'), False if not (mesonlib.is_osx() or mesonlib.is_windows()) else True))
- all_tests.append(('framework', gather_tests('test cases/frameworks'), False if not mesonlib.is_osx() and not mesonlib.is_windows() else True))
- all_tests.append(('java', gather_tests('test cases/java'), False if not mesonlib.is_osx() and shutil.which('javac') else True))
- all_tests.append(('C#', gather_tests('test cases/csharp'), False if shutil.which('mcs') else True))
- all_tests.append(('vala', gather_tests('test cases/vala'), False if shutil.which('valac') else True))
- all_tests.append(('rust', gather_tests('test cases/rust'), False if shutil.which('rustc') else True))
- all_tests.append(('d', gather_tests('test cases/d'), False if have_d_compiler() else True))
- all_tests.append(('objective c', gather_tests('test cases/objc'), False if not mesonlib.is_windows() else True))
- all_tests.append(('fortran', gather_tests('test cases/fortran'), False if shutil.which('gfortran') else True))
- all_tests.append(('swift', gather_tests('test cases/swift'), False if shutil.which('swiftc') else True))
- all_tests.append(('python3', gather_tests('test cases/python3'), False if shutil.which('python3') else True))
- return all_tests
-
-def run_tests(extra_args):
- 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')
- conf_time = 0
- build_time = 0
- test_time = 0
-
- executor = conc.ProcessPoolExecutor(max_workers=multiprocessing.cpu_count())
-
- for name, test_cases, skipped in all_tests:
- current_suite = ET.SubElement(junit_root, 'testsuite', {'name' : name, 'tests' : str(len(test_cases))})
- if skipped:
- print('\nNot running %s tests.\n' % name)
- else:
- print('\nRunning %s tests.\n' % name)
- futures = []
- for t in test_cases:
- # Jenkins screws us over by automatically sorting test cases by name
- # and getting it wrong by not doing logical number sorting.
- (testnum, testbase) = os.path.split(t)[-1].split(' ', 1)
- testname = '%.3d %s' % (int(testnum), testbase)
- result = executor.submit(run_test, skipped, t, extra_args, unity_flags + backend_flags, compile_commands, install_commands, name != 'failing')
- futures.append((testname, t, result))
- for (testname, t, result) in futures:
- result = result.result()
- if result is None:
- print('Skipping:', t)
- current_test = ET.SubElement(current_suite, 'testcase', {'name' : testname,
- 'classname' : name})
- ET.SubElement(current_test, 'skipped', {})
- global skipped_tests
- skipped_tests += 1
- else:
- without_install = "" if len(install_commands) > 0 else " (without install)"
- if result.msg != '':
- print('Failed test%s: %s' % (without_install, t))
- print('Reason:', result.msg)
- failing_tests += 1
- failing_logs.append(result.mlog)
- else:
- print('Succeeded test%s: %s' % (without_install, t))
- passing_tests += 1
- conf_time += result.conftime
- build_time += result.buildtime
- test_time += result.testtime
- total_time = conf_time + build_time + test_time
- log_text_file(logfile, t, result.stdo, result.stde)
- current_test = ET.SubElement(current_suite, 'testcase', {'name' : testname,
- 'classname' : name,
- 'time' : '%.3f' % total_time})
- if result.msg != '':
- ET.SubElement(current_test, 'failure', {'message' : result.msg})
- stdoel = ET.SubElement(current_test, 'system-out')
- stdoel.text = result.stdo
- stdeel = ET.SubElement(current_test, 'system-err')
- stdeel.text = result.stde
- print("\nTotal configuration time: %.2fs" % conf_time)
- print("Total build time: %.2fs" % build_time)
- print("Total test time: %.2fs" % test_time)
- ET.ElementTree(element=junit_root).write('meson-test-run.xml', xml_declaration=True, encoding='UTF-8')
-
-def check_file(fname):
- linenum = 1
- with open(fname, 'rb') as f:
- lines = f.readlines()
- for line in lines:
- if b'\t' in line:
- print("File %s contains a literal tab on line %d. Only spaces are permitted." % (fname, linenum))
- sys.exit(1)
- if b'\r' in line:
- print("File %s contains DOS line ending on line %d. Only unix-style line endings are permitted." % (fname, linenum))
- sys.exit(1)
- linenum += 1
-
-def check_format():
- for (root, _, files) in os.walk('.'):
- for file in files:
- if file.endswith('.py') or file.endswith('.build') or file == 'meson_options.txt':
- fullname = os.path.join(root, file)
- check_file(fullname)
-
-def pbcompile(compiler, source, objectfile):
- if compiler == 'cl':
- cmd = [compiler, '/nologo', '/Fo'+objectfile, '/c', source]
- else:
- cmd = [compiler, '-c', source, '-o', objectfile]
- subprocess.check_call(cmd, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
-
-def generate_pb_object(compiler, object_suffix):
- source = 'test cases/prebuilt/1 object/source.c'
- objectfile = 'test cases/prebuilt/1 object/prebuilt.' + object_suffix
- pbcompile(compiler, source, objectfile)
- return objectfile
-
-def generate_pb_static(compiler, object_suffix, static_suffix):
- source = 'test cases/prebuilt/2 static/libdir/best.c'
- objectfile = 'test cases/prebuilt/2 static/libdir/best.' + object_suffix
- stlibfile = 'test cases/prebuilt/2 static/libdir/libbest.' + static_suffix
- pbcompile(compiler, source, objectfile)
- if compiler == 'cl':
- linker = ['lib', '/NOLOGO', '/OUT:' + stlibfile, objectfile]
- else:
- linker = ['ar', 'csr', stlibfile, objectfile]
- subprocess.check_call(linker)
- os.unlink(objectfile)
- return stlibfile
-
-def generate_prebuilt():
- static_suffix = 'a'
- if shutil.which('cl'):
- compiler = 'cl'
- static_suffix = 'lib'
- elif shutil.which('cc'):
- compiler = 'cc'
- elif shutil.which('gcc'):
- compiler = 'gcc'
- else:
- raise RuntimeError("Could not find C compiler.")
- if mesonlib.is_windows():
- object_suffix = 'obj'
- else:
- object_suffix = 'o'
- objectfile = generate_pb_object(compiler, object_suffix)
- stlibfile = generate_pb_static(compiler, object_suffix, static_suffix)
- return (objectfile, stlibfile)
if __name__ == '__main__':
- parser = argparse.ArgumentParser(description="Run the test suite of Meson.")
- parser.add_argument('extra_args', nargs='*',
- help='arguments that are passed directly to Meson (remember to have -- before these).')
- parser.add_argument('--backend', default=None, dest='backend',
- choices = backendlist)
- options = parser.parse_args()
- setup_commands(options.backend)
-
- script_dir = os.path.split(__file__)[0]
- if script_dir != '':
- os.chdir(script_dir)
- check_format()
- pbfiles = generate_prebuilt()
- try:
- run_tests(options.extra_args)
- except StopException:
- pass
- for f in pbfiles:
- os.unlink(f)
- print('\nTotal passed tests:', passing_tests)
- print('Total failed tests:', failing_tests)
- print('Total skipped tests:', skipped_tests)
- if failing_tests > 0 and ('TRAVIS' in os.environ or 'APPVEYOR' in os.environ):
- print('\nMesonlogs of failing tests\n')
- for l in failing_logs:
- print(l, '\n')
- sys.exit(failing_tests)
-
+ returncode = 0
+ if mesonlib.is_linux():
+ myenv = os.environ.copy()
+ myenv['CC'] = 'gcc'
+ myenv['CXX'] = 'g++'
+ print('Running unittests with GCC.\n')
+ returncode += subprocess.call([sys.executable, 'run_unittests.py', '-v'], env=myenv)
+ if shutil.which('clang'):
+ myenv['CC'] = 'clang'
+ myenv['CXX'] = 'clang++'
+ print('\nRunning unittests with clang.\n')
+ returncode += subprocess.call([sys.executable, 'run_unittests.py', '-v'], env=myenv)
+ returncode += subprocess.call([sys.executable, 'run_project_tests.py'] + sys.argv[1:])
+ sys.exit(returncode)
diff --git a/run_unittests.py b/run_unittests.py
new file mode 100755
index 0000000..9ea9e23
--- /dev/null
+++ b/run_unittests.py
@@ -0,0 +1,91 @@
+#!/usr/bin/env python3
+# Copyright 2016 The Meson development team
+
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+
+# http://www.apache.org/licenses/LICENSE-2.0
+
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import unittest, os, sys, shutil, time
+import subprocess
+import re, json
+import tempfile
+from mesonbuild.environment import detect_ninja
+
+def get_soname(fname):
+ # HACK, fix to not use shell.
+ raw_out = subprocess.check_output(['readelf', '-a', fname])
+ pattern = re.compile(b'soname: \[(.*?)\]')
+ for line in raw_out.split(b'\n'):
+ m = pattern.search(line)
+ if m is not None:
+ return m.group(1)
+
+class LinuxlikeTests(unittest.TestCase):
+ def setUp(self):
+ super().setUp()
+ src_root = os.path.dirname(__file__)
+ self.builddir = tempfile.mkdtemp()
+ self.meson_command = [sys.executable, os.path.join(src_root, 'meson.py')]
+ self.mconf_command = [sys.executable, os.path.join(src_root, 'mesonconf.py')]
+ self.ninja_command = [detect_ninja(), '-C', self.builddir]
+ self.common_test_dir = os.path.join(src_root, 'test cases/common')
+ self.output = b''
+
+ def tearDown(self):
+ shutil.rmtree(self.builddir)
+ super().tearDown()
+
+ def init(self, srcdir):
+ self.output += subprocess.check_output(self.meson_command + [srcdir, self.builddir])
+
+ def build(self):
+ self.output += subprocess.check_output(self.ninja_command)
+
+ def setconf(self, arg):
+ self.output += subprocess.check_output(self.mconf_command + [arg, self.builddir])
+
+ def get_compdb(self):
+ with open(os.path.join(self.builddir, 'compile_commands.json')) as ifile:
+ return json.load(ifile)
+
+ def test_basic_soname(self):
+ testdir = os.path.join(self.common_test_dir, '4 shared')
+ self.init(testdir)
+ self.build()
+ lib1 = os.path.join(self.builddir, 'libmylib.so')
+ soname = get_soname(lib1)
+ self.assertEqual(soname, b'libmylib.so')
+
+ def test_custom_soname(self):
+ testdir = os.path.join(self.common_test_dir, '27 library versions')
+ self.init(testdir)
+ self.build()
+ lib1 = os.path.join(self.builddir, 'prefixsomelib.suffix')
+ soname = get_soname(lib1)
+ self.assertEqual(soname, b'prefixsomelib.suffix')
+
+ def test_pic(self):
+ testdir = os.path.join(self.common_test_dir, '3 static')
+ self.init(testdir)
+ compdb = self.get_compdb()
+ self.assertTrue('-fPIC' in compdb[0]['command'])
+ # This is needed to increase the difference between build.ninja's
+ # timestamp and coredata.dat's timestamp due to a Ninja bug.
+ # https://github.com/ninja-build/ninja/issues/371
+ time.sleep(1)
+ self.setconf('-Db_staticpic=false')
+ # Regenerate build
+ self.build()
+ compdb = self.get_compdb()
+ self.assertTrue('-fPIC' not in compdb[0]['command'])
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/setup.py b/setup.py
index d5b79ae..42f8d49 100644
--- a/setup.py
+++ b/setup.py
@@ -14,7 +14,9 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+import os
import sys
+from os import path
if sys.version_info[0] < 3:
print('Tried to install with Python 2, Meson only supports Python 3.')
@@ -25,8 +27,32 @@ if sys.version_info[0] < 3:
# plain distutils when setuptools is not available.
try:
from setuptools import setup
+ from setuptools.command.install_scripts import install_scripts as orig
except ImportError:
from distutils.core import setup
+ from distutils.command.install_scripts import install_scripts as orig
+
+from distutils.file_util import copy_file
+from distutils.dir_util import mkpath
+from stat import ST_MODE
+
+class install_scripts(orig):
+ def run(self):
+ if sys.platform == 'win32':
+ super().run()
+ return
+
+ self.outfiles = []
+ if not self.dry_run:
+ mkpath(self.install_dir)
+
+ # We want the files to be installed without a suffix on Unix
+ for infile in self.get_inputs():
+ in_stripped = infile[:-3] if infile.endswith('.py') else infile
+ outfile = path.join(self.install_dir, in_stripped)
+ # NOTE: Mode is preserved by default
+ copy_file(infile, outfile, dry_run=self.dry_run)
+ self.outfiles.append(outfile)
from mesonbuild.coredata import version
@@ -46,6 +72,7 @@ setup(name='meson',
'mesonconf.py',
'mesonintrospect.py',
'wraptool.py'],
+ cmdclass={'install_scripts': install_scripts},
data_files=[('share/man/man1', ['man/meson.1',
'man/mesonconf.1',
'man/mesonintrospect.1',
diff --git a/test cases/common/1 trivial/meson.build b/test cases/common/1 trivial/meson.build
index 3f14539..1f7b375 100644
--- a/test cases/common/1 trivial/meson.build
+++ b/test cases/common/1 trivial/meson.build
@@ -1,5 +1,8 @@
# Comment on the first line
-project('trivial test', 'c', meson_version : '>=0.27.0')
+project('trivial test',
+ # Comment inside a function call + array for language list
+ ['c'],
+ meson_version : '>=0.27.0')
#this is a comment
sources = 'trivial.c'
diff --git a/test cases/common/117 custom target capture/meson.build b/test cases/common/117 custom target capture/meson.build
index 6c19752..fa59d51 100644
--- a/test cases/common/117 custom target capture/meson.build
+++ b/test cases/common/117 custom target capture/meson.build
@@ -7,10 +7,10 @@ python = find_program('python3')
comp = '@0@/@1@'.format(meson.current_source_dir(), 'my_compiler.py')
mytarget = custom_target('bindat',
-output : 'data.dat',
-input : 'data_source.txt',
-capture : true,
-command : [python, comp, '@INPUT@'],
-install : true,
-install_dir : 'subdir'
+ output : 'data.dat',
+ input : 'data_source.txt',
+ capture : true,
+ command : [python, comp, '@INPUT@'],
+ install : true,
+ install_dir : 'subdir'
)
diff --git a/test cases/common/119 pathjoin/meson.build b/test cases/common/119 pathjoin/meson.build
new file mode 100644
index 0000000..dd1cf9c
--- /dev/null
+++ b/test cases/common/119 pathjoin/meson.build
@@ -0,0 +1,9 @@
+project('pathjoin', 'c')
+
+assert(path_join('foo') == 'foo', 'Single argument join is broken')
+assert(path_join('foo', 'bar') == 'foo/bar', 'Path joining is broken')
+assert(path_join('foo', 'bar', 'baz') == 'foo/bar/baz', 'Path joining is broken')
+assert(path_join('/foo', 'bar') == '/foo/bar', 'Path joining is broken')
+assert(path_join('foo', '/bar') == '/bar', 'Absolute path joining is broken')
+assert(path_join('/foo', '/bar') == '/bar', 'Absolute path joining is broken')
+
diff --git a/test cases/common/62 exe static shared/meson.build b/test cases/common/62 exe static shared/meson.build
index 3c75391..2888882 100644
--- a/test cases/common/62 exe static shared/meson.build
+++ b/test cases/common/62 exe static shared/meson.build
@@ -1,6 +1,11 @@
project('statchain', 'c')
subdir('subdir')
-statlib = static_library('stat', 'stat.c', link_with : shlib)
-exe = executable('prog', 'prog.c', link_with : statlib)
+# Test that -fPIC in c_args is also accepted
+statlib2 = static_library('stat2', 'stat2.c', c_args : '-fPIC', pic : false)
+# Test that pic is needed for both direct and indirect static library
+# dependencies of shared libraries (on Linux and BSD)
+statlib = static_library('stat', 'stat.c', link_with : [shlib, statlib2], pic : true)
+shlib2 = shared_library('shr2', 'shlib2.c', link_with : statlib)
+exe = executable('prog', 'prog.c', link_with : shlib2)
test('runtest', exe)
diff --git a/test cases/common/62 exe static shared/prog.c b/test cases/common/62 exe static shared/prog.c
index 4f82a6b..26603b6 100644
--- a/test cases/common/62 exe static shared/prog.c
+++ b/test cases/common/62 exe static shared/prog.c
@@ -1,5 +1,10 @@
+int shlibfunc2();
int statlibfunc();
int main(int argc, char **argv) {
- return statlibfunc() == 42 ? 0 : 1;
+ if (statlibfunc() != 42)
+ return 1;
+ if (shlibfunc2() != 24)
+ return 1;
+ return 0;
}
diff --git a/test cases/common/62 exe static shared/shlib2.c b/test cases/common/62 exe static shared/shlib2.c
new file mode 100644
index 0000000..12bc913
--- /dev/null
+++ b/test cases/common/62 exe static shared/shlib2.c
@@ -0,0 +1,8 @@
+#include "subdir/exports.h"
+
+int statlibfunc(void);
+int statlibfunc2(void);
+
+int DLL_PUBLIC shlibfunc2(void) {
+ return statlibfunc() - statlibfunc2();
+}
diff --git a/test cases/common/62 exe static shared/stat2.c b/test cases/common/62 exe static shared/stat2.c
new file mode 100644
index 0000000..4ae3775
--- /dev/null
+++ b/test cases/common/62 exe static shared/stat2.c
@@ -0,0 +1,3 @@
+int statlibfunc2() {
+ return 18;
+}
diff --git a/test cases/common/62 exe static shared/subdir/exports.h b/test cases/common/62 exe static shared/subdir/exports.h
new file mode 100644
index 0000000..c89ccb2
--- /dev/null
+++ b/test cases/common/62 exe static shared/subdir/exports.h
@@ -0,0 +1,12 @@
+#pragma once
+
+#if defined _WIN32 || defined __CYGWIN__
+ #define DLL_PUBLIC __declspec(dllexport)
+#else
+ #if defined __GNUC__
+ #define DLL_PUBLIC __attribute__ ((visibility("default")))
+ #else
+ #pragma message ("Compiler does not support symbol visibility.")
+ #define DLL_PUBLIC
+ #endif
+#endif
diff --git a/test cases/common/62 exe static shared/subdir/shlib.c b/test cases/common/62 exe static shared/subdir/shlib.c
index d649c7d..002c83f 100644
--- a/test cases/common/62 exe static shared/subdir/shlib.c
+++ b/test cases/common/62 exe static shared/subdir/shlib.c
@@ -1,13 +1,4 @@
-#if defined _WIN32 || defined __CYGWIN__
- #define DLL_PUBLIC __declspec(dllexport)
-#else
- #if defined __GNUC__
- #define DLL_PUBLIC __attribute__ ((visibility("default")))
- #else
- #pragma message ("Compiler does not support symbol visibility.")
- #define DLL_PUBLIC
- #endif
-#endif
+#include "exports.h"
int DLL_PUBLIC shlibfunc() {
return 42;
diff --git a/test cases/common/95 dep fallback/gensrc.py b/test cases/common/95 dep fallback/gensrc.py
new file mode 100644
index 0000000..da503e2
--- /dev/null
+++ b/test cases/common/95 dep fallback/gensrc.py
@@ -0,0 +1,6 @@
+#!/usr/bin/env python
+
+import sys
+import shutil
+
+shutil.copyfile(sys.argv[1], sys.argv[2])
diff --git a/test cases/common/95 dep fallback/meson.build b/test cases/common/95 dep fallback/meson.build
index 4cf0577..13541f2 100644
--- a/test cases/common/95 dep fallback/meson.build
+++ b/test cases/common/95 dep fallback/meson.build
@@ -6,5 +6,14 @@ if not bob.found()
endif
jimmy = dependency('jimmylib', fallback : ['jimmylib', 'jimmy_dep'], required: false)
-exe = executable('bobtester', 'tester.c', dependencies : bob)
+gensrc_py = find_program('gensrc.py')
+gensrc = custom_target('gensrc.c',
+ input : 'tester.c',
+ output : 'gensrc.c',
+ command : [gensrc_py, '@INPUT@', '@OUTPUT@'])
+
+exe = executable('bobtester',
+ [gensrc],
+ dependencies : bob)
+
test('bobtester', exe)
diff --git a/test cases/common/95 dep fallback/subprojects/boblib/bob.c b/test cases/common/95 dep fallback/subprojects/boblib/bob.c
index b483a55..ae0f394 100644
--- a/test cases/common/95 dep fallback/subprojects/boblib/bob.c
+++ b/test cases/common/95 dep fallback/subprojects/boblib/bob.c
@@ -1,5 +1,8 @@
#include"bob.h"
+#ifdef _MSC_VER
+__declspec(dllexport)
+#endif
const char* get_bob() {
return "bob";
}
diff --git a/test cases/common/95 dep fallback/subprojects/boblib/bob.h b/test cases/common/95 dep fallback/subprojects/boblib/bob.h
index bc170ef..f874ae7 100644
--- a/test cases/common/95 dep fallback/subprojects/boblib/bob.h
+++ b/test cases/common/95 dep fallback/subprojects/boblib/bob.h
@@ -1,3 +1,6 @@
#pragma once
+#ifdef _MSC_VER
+__declspec(dllimport)
+#endif
const char* get_bob();
diff --git a/test cases/common/95 dep fallback/subprojects/boblib/genbob.py b/test cases/common/95 dep fallback/subprojects/boblib/genbob.py
new file mode 100644
index 0000000..824194b
--- /dev/null
+++ b/test cases/common/95 dep fallback/subprojects/boblib/genbob.py
@@ -0,0 +1,7 @@
+#!/usr/bin/env python
+
+import os
+import sys
+
+with open(sys.argv[1], 'w') as f:
+ f.write('')
diff --git a/test cases/common/95 dep fallback/subprojects/boblib/meson.build b/test cases/common/95 dep fallback/subprojects/boblib/meson.build
index 8dc1f3a..bb250e4 100644
--- a/test cases/common/95 dep fallback/subprojects/boblib/meson.build
+++ b/test cases/common/95 dep fallback/subprojects/boblib/meson.build
@@ -1,7 +1,16 @@
project('bob', 'c')
-boblib = static_library('bob', 'bob.c')
+gensrc_py = find_program('genbob.py')
+genbob_h = custom_target('genbob.h',
+ output : 'genbob.h',
+ command : [gensrc_py, '@OUTPUT@'])
+genbob_c = custom_target('genbob.c',
+ output : 'genbob.c',
+ command : [gensrc_py, '@OUTPUT@'])
+
+boblib = library('bob', ['bob.c', genbob_c])
bobinc = include_directories('.')
bob_dep = declare_dependency(link_with : boblib,
+ sources : [genbob_h],
include_directories : bobinc)
diff --git a/test cases/common/95 dep fallback/tester.c b/test cases/common/95 dep fallback/tester.c
index 59e1635..e6651d9 100644
--- a/test cases/common/95 dep fallback/tester.c
+++ b/test cases/common/95 dep fallback/tester.c
@@ -1,4 +1,5 @@
#include"bob.h"
+#include"genbob.h"
#include<string.h>
#include<stdio.h>
diff --git a/test cases/failing/33 exe static shared/meson.build b/test cases/failing/33 exe static shared/meson.build
new file mode 100644
index 0000000..b102764
--- /dev/null
+++ b/test cases/failing/33 exe static shared/meson.build
@@ -0,0 +1,11 @@
+project('statchain', 'c')
+
+host_system = host_machine.system()
+if host_system == 'windows' or host_system == 'darwin'
+ error('Test only fails on Linux and BSD')
+endif
+
+statlib = static_library('stat', 'stat.c', pic : false)
+shlib2 = shared_library('shr2', 'shlib2.c', link_with : statlib)
+exe = executable('prog', 'prog.c', link_with : shlib2)
+test('runtest', exe)
diff --git a/test cases/failing/33 exe static shared/prog.c b/test cases/failing/33 exe static shared/prog.c
new file mode 100644
index 0000000..26603b6
--- /dev/null
+++ b/test cases/failing/33 exe static shared/prog.c
@@ -0,0 +1,10 @@
+int shlibfunc2();
+int statlibfunc();
+
+int main(int argc, char **argv) {
+ if (statlibfunc() != 42)
+ return 1;
+ if (shlibfunc2() != 24)
+ return 1;
+ return 0;
+}
diff --git a/test cases/failing/33 exe static shared/shlib2.c b/test cases/failing/33 exe static shared/shlib2.c
new file mode 100644
index 0000000..5b68843
--- /dev/null
+++ b/test cases/failing/33 exe static shared/shlib2.c
@@ -0,0 +1,16 @@
+#if defined _WIN32 || defined __CYGWIN__
+ #define DLL_PUBLIC __declspec(dllexport)
+#else
+ #if defined __GNUC__
+ #define DLL_PUBLIC __attribute__ ((visibility("default")))
+ #else
+ #pragma message ("Compiler does not support symbol visibility.")
+ #define DLL_PUBLIC
+ #endif
+#endif
+
+int statlibfunc(void);
+
+int DLL_PUBLIC shlibfunc2(void) {
+ return 24;
+}
diff --git a/test cases/failing/33 exe static shared/stat.c b/test cases/failing/33 exe static shared/stat.c
new file mode 100644
index 0000000..56ec66c
--- /dev/null
+++ b/test cases/failing/33 exe static shared/stat.c
@@ -0,0 +1,3 @@
+int statlibfunc() {
+ return 42;
+}
diff --git a/test cases/frameworks/7 gnome/genmarshal/main.c b/test cases/frameworks/7 gnome/genmarshal/main.c
new file mode 100644
index 0000000..83b08af
--- /dev/null
+++ b/test cases/frameworks/7 gnome/genmarshal/main.c
@@ -0,0 +1,102 @@
+#include<stdio.h>
+#include<stdlib.h>
+#include<glib-object.h>
+#include"marshaller.h"
+
+static int singleton = 42;
+
+void foo(gpointer user_data, gpointer data) {
+ if (user_data != &singleton) {
+ fprintf(stderr, "Invoked foo function was passed incorrect user data.\n");
+ exit(1);
+ }
+}
+
+void bar(gpointer user_data, gint param1, gpointer data) {
+ if (param1 != singleton) {
+ fprintf(stderr, "Invoked bar function was passed incorrect param1, but %d.\n", param1);
+ exit(2);
+ }
+ if (user_data != &singleton) {
+ fprintf(stderr, "Invoked bar function was passed incorrect user data.\n");
+ exit(3);
+ }
+}
+
+gfloat baz(gpointer user_data, gboolean param1, guchar param2, gpointer data) {
+ if (param1 != TRUE) {
+ fprintf(stderr, "Invoked baz function was passed incorrect param1.\n");
+ exit(4);
+ }
+ if (param2 != singleton) {
+ fprintf(stderr, "Invoked baz function was passed incorrect param2.\n");
+ exit(5);
+ }
+ if (user_data != &singleton) {
+ fprintf(stderr, "Invoked baz function was passed incorrect user data.\n");
+ exit(6);
+ }
+ return (gfloat)param2;
+}
+
+int main(int argc, char **argv) {
+ GClosure *cc_foo, *cc_bar, *cc_baz;
+ GValue return_value = G_VALUE_INIT;
+ GValue param_values[3] = {G_VALUE_INIT, G_VALUE_INIT, G_VALUE_INIT};
+
+ fprintf(stderr, "Invoking foo function.\n");
+ cc_foo = g_cclosure_new(G_CALLBACK(foo), NULL, NULL);
+ g_closure_set_marshal(cc_foo, g_cclosure_user_marshal_VOID__VOID);
+ g_value_init(&param_values[0], G_TYPE_POINTER);
+ g_value_set_pointer(&param_values[0], &singleton);
+ g_closure_invoke(cc_foo, &return_value, 1, param_values, NULL);
+ if (G_VALUE_TYPE(&return_value) != G_TYPE_INVALID) {
+ fprintf(stderr, "Invoked foo function did not return empty value, but %s.\n",
+ G_VALUE_TYPE_NAME(&return_value));
+ return 7;
+ }
+ g_value_unset(&param_values[0]);
+ g_value_unset(&return_value);
+ g_closure_unref(cc_foo);
+
+ fprintf(stderr, "Invoking bar function.\n");
+ cc_bar = g_cclosure_new(G_CALLBACK(bar), NULL, NULL);
+ g_closure_set_marshal(cc_bar, g_cclosure_user_marshal_VOID__INT);
+ g_value_init(&param_values[0], G_TYPE_POINTER);
+ g_value_set_pointer(&param_values[0], &singleton);
+ g_value_init(&param_values[1], G_TYPE_INT);
+ g_value_set_int(&param_values[1], 42);
+ g_closure_invoke(cc_bar, &return_value, 2, param_values, NULL);
+ if (G_VALUE_TYPE(&return_value) != G_TYPE_INVALID) {
+ fprintf(stderr, "Invoked bar function did not return empty value.\n");
+ return 8;
+ }
+ g_value_unset(&param_values[0]);
+ g_value_unset(&param_values[1]);
+ g_value_unset(&return_value);
+ g_closure_unref(cc_bar);
+
+ fprintf(stderr, "Invoking baz function.\n");
+ cc_baz = g_cclosure_new(G_CALLBACK(baz), NULL, NULL);
+ g_closure_set_marshal(cc_baz, g_cclosure_user_marshal_FLOAT__BOOLEAN_UCHAR);
+ g_value_init(&param_values[0], G_TYPE_POINTER);
+ g_value_set_pointer(&param_values[0], &singleton);
+ g_value_init(&param_values[1], G_TYPE_BOOLEAN);
+ g_value_set_boolean(&param_values[1], TRUE);
+ g_value_init(&param_values[2], G_TYPE_UCHAR);
+ g_value_set_uchar(&param_values[2], 42);
+ g_value_init(&return_value, G_TYPE_FLOAT);
+ g_closure_invoke(cc_baz, &return_value, 3, param_values, NULL);
+ if (g_value_get_float(&return_value) != 42.0f) {
+ fprintf(stderr, "Invoked baz function did not return expected value.\n");
+ return 9;
+ }
+ g_value_unset(&param_values[0]);
+ g_value_unset(&param_values[1]);
+ g_value_unset(&param_values[2]);
+ g_value_unset(&return_value);
+ g_closure_unref(cc_baz);
+
+ fprintf(stderr, "All ok.\n");
+ return 0;
+}
diff --git a/test cases/frameworks/7 gnome/genmarshal/marshaller.list b/test cases/frameworks/7 gnome/genmarshal/marshaller.list
new file mode 100644
index 0000000..a29f6c9
--- /dev/null
+++ b/test cases/frameworks/7 gnome/genmarshal/marshaller.list
@@ -0,0 +1,3 @@
+VOID:VOID
+VOID:INT
+FLOAT:BOOLEAN,UCHAR
diff --git a/test cases/frameworks/7 gnome/genmarshal/meson.build b/test cases/frameworks/7 gnome/genmarshal/meson.build
new file mode 100644
index 0000000..4a1a7f9
--- /dev/null
+++ b/test cases/frameworks/7 gnome/genmarshal/meson.build
@@ -0,0 +1,11 @@
+marshallers = gnome.genmarshal('marshaller',
+sources : 'marshaller.list',
+install_header : true,
+install_dir : get_option('includedir'))
+
+marshaller_c = marshallers[0]
+marshaller_h = marshallers[1]
+
+genmarshalexe = executable('genmarshalprog', 'main.c', marshaller_c, marshaller_h,
+dependencies : gobj)
+test('genmarshal test', genmarshalexe)
diff --git a/test cases/frameworks/7 gnome/gir/meson.build b/test cases/frameworks/7 gnome/gir/meson.build
index 287c0d7..a513062 100644
--- a/test cases/frameworks/7 gnome/gir/meson.build
+++ b/test cases/frameworks/7 gnome/gir/meson.build
@@ -14,6 +14,8 @@ girexe = executable(
link_with : girlib
)
+fake_dep = dependency('no-way-this-exists', required: false)
+
gnome.generate_gir(
girlib,
sources : libsources,
@@ -22,6 +24,7 @@ gnome.generate_gir(
symbol_prefix : 'meson_',
identifier_prefix : 'Meson',
includes : ['GObject-2.0'],
+ dependencies : [fake_dep],
install : true
)
diff --git a/test cases/frameworks/7 gnome/installed_files.txt b/test cases/frameworks/7 gnome/installed_files.txt
index 741d9b8..c922f8b 100644
--- a/test cases/frameworks/7 gnome/installed_files.txt
+++ b/test cases/frameworks/7 gnome/installed_files.txt
@@ -1,3 +1,7 @@
+usr/include/enums.h
+usr/include/enums2.h
+usr/include/enums3.h
+usr/include/marshaller.h
usr/lib/girepository-1.0/Meson-1.0.typelib
usr/lib/libgirlib.so
usr/share/gir-1.0/Meson-1.0.gir
diff --git a/test cases/frameworks/7 gnome/meson.build b/test cases/frameworks/7 gnome/meson.build
index 6afe508..2c2e953 100644
--- a/test cases/frameworks/7 gnome/meson.build
+++ b/test cases/frameworks/7 gnome/meson.build
@@ -13,4 +13,5 @@ subdir('resources')
subdir('gir')
subdir('schemas')
subdir('gdbus')
-
+subdir('mkenums')
+subdir('genmarshal')
diff --git a/test cases/frameworks/7 gnome/mkenums/enums.c.in b/test cases/frameworks/7 gnome/mkenums/enums.c.in
new file mode 100644
index 0000000..62e1adc
--- /dev/null
+++ b/test cases/frameworks/7 gnome/mkenums/enums.c.in
@@ -0,0 +1,41 @@
+/*** BEGIN file-header ***/
+
+#include "enums.h"
+
+/*** END file-header ***/
+/*** BEGIN file-production ***/
+
+/* enumerations from "@basename@" */
+#include "@basename@"
+
+/*** END file-production ***/
+
+/*** BEGIN value-header ***/
+GType
+@enum_name@_get_type(void) {
+ static volatile gsize g_define_type_id__volatile = 0;
+
+ if(g_once_init_enter(&g_define_type_id__volatile)) {
+ static const G@Type@Value values [] = {
+/*** END value-header ***/
+
+/*** BEGIN value-production ***/
+ { @VALUENAME@, "@VALUENAME@", "@valuenick@" },
+/*** END value-production ***/
+
+/*** BEGIN value-tail ***/
+ { 0, NULL, NULL }
+ };
+
+ GType g_define_type_id =
+ g_@type@_register_static(g_intern_static_string("@EnumName@"), values);
+ g_once_init_leave(&g_define_type_id__volatile, g_define_type_id);
+ }
+
+ return g_define_type_id__volatile;
+}
+
+/*** END value-tail ***/
+
+/*** BEGIN file-tail ***/
+/*** END file-tail ***/
diff --git a/test cases/frameworks/7 gnome/mkenums/enums.h.in b/test cases/frameworks/7 gnome/mkenums/enums.h.in
new file mode 100644
index 0000000..479867f
--- /dev/null
+++ b/test cases/frameworks/7 gnome/mkenums/enums.h.in
@@ -0,0 +1,24 @@
+/*** BEGIN file-header ***/
+#ifndef MESON_ENUMS_H
+#define MESON_ENUMS_H
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+/*** END file-header ***/
+
+/*** BEGIN file-production ***/
+
+/* enumerations from "@basename@" */
+/*** END file-production ***/
+/*** BEGIN value-header ***/
+GType @enum_name@_get_type(void) G_GNUC_CONST;
+#define @ENUMPREFIX@_TYPE_@ENUMSHORT@ (@enum_name@_get_type())
+/*** END value-header ***/
+
+/*** BEGIN file-tail ***/
+
+G_END_DECLS
+
+#endif /* MESON_ENUMS_H */
+/*** END file-tail ***/
diff --git a/test cases/frameworks/7 gnome/mkenums/enums2.c.in b/test cases/frameworks/7 gnome/mkenums/enums2.c.in
new file mode 100644
index 0000000..62e1adc
--- /dev/null
+++ b/test cases/frameworks/7 gnome/mkenums/enums2.c.in
@@ -0,0 +1,41 @@
+/*** BEGIN file-header ***/
+
+#include "enums.h"
+
+/*** END file-header ***/
+/*** BEGIN file-production ***/
+
+/* enumerations from "@basename@" */
+#include "@basename@"
+
+/*** END file-production ***/
+
+/*** BEGIN value-header ***/
+GType
+@enum_name@_get_type(void) {
+ static volatile gsize g_define_type_id__volatile = 0;
+
+ if(g_once_init_enter(&g_define_type_id__volatile)) {
+ static const G@Type@Value values [] = {
+/*** END value-header ***/
+
+/*** BEGIN value-production ***/
+ { @VALUENAME@, "@VALUENAME@", "@valuenick@" },
+/*** END value-production ***/
+
+/*** BEGIN value-tail ***/
+ { 0, NULL, NULL }
+ };
+
+ GType g_define_type_id =
+ g_@type@_register_static(g_intern_static_string("@EnumName@"), values);
+ g_once_init_leave(&g_define_type_id__volatile, g_define_type_id);
+ }
+
+ return g_define_type_id__volatile;
+}
+
+/*** END value-tail ***/
+
+/*** BEGIN file-tail ***/
+/*** END file-tail ***/
diff --git a/test cases/frameworks/7 gnome/mkenums/enums2.h.in b/test cases/frameworks/7 gnome/mkenums/enums2.h.in
new file mode 100644
index 0000000..479867f
--- /dev/null
+++ b/test cases/frameworks/7 gnome/mkenums/enums2.h.in
@@ -0,0 +1,24 @@
+/*** BEGIN file-header ***/
+#ifndef MESON_ENUMS_H
+#define MESON_ENUMS_H
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+/*** END file-header ***/
+
+/*** BEGIN file-production ***/
+
+/* enumerations from "@basename@" */
+/*** END file-production ***/
+/*** BEGIN value-header ***/
+GType @enum_name@_get_type(void) G_GNUC_CONST;
+#define @ENUMPREFIX@_TYPE_@ENUMSHORT@ (@enum_name@_get_type())
+/*** END value-header ***/
+
+/*** BEGIN file-tail ***/
+
+G_END_DECLS
+
+#endif /* MESON_ENUMS_H */
+/*** END file-tail ***/
diff --git a/test cases/frameworks/7 gnome/mkenums/main.c b/test cases/frameworks/7 gnome/mkenums/main.c
new file mode 100644
index 0000000..d257185
--- /dev/null
+++ b/test cases/frameworks/7 gnome/mkenums/main.c
@@ -0,0 +1,30 @@
+#include<stdio.h>
+#include<string.h>
+#include<glib-object.h>
+#include"meson-sample.h"
+#include"@ENUM_FILE@"
+
+int main(int argc, char **argv) {
+ GEnumClass *xenum = g_type_class_ref(MESON_TYPE_THE_XENUM);
+ GFlagsClass *flags_enum = g_type_class_ref(MESON_TYPE_THE_FLAGS_ENUM);
+ if (g_enum_get_value_by_name(xenum, "MESON_THE_XVALUE")->value != MESON_THE_XVALUE) {
+ fprintf(stderr, "Get MESON_THE_XVALUE by name failed.\n");
+ return 1;
+ }
+ if (g_enum_get_value_by_nick(xenum, "the-xvalue")->value != MESON_THE_XVALUE) {
+ fprintf(stderr, "Get MESON_THE_XVALUE by nick failed.\n");
+ return 2;
+ }
+ if (g_flags_get_value_by_name(flags_enum, "MESON_THE_FIRST_VALUE")->value != MESON_THE_FIRST_VALUE) {
+ fprintf(stderr, "Get MESON_THE_FIRST_VALUE by name failed.\n");
+ return 3;
+ }
+ if (g_flags_get_value_by_nick(flags_enum, "the-first-value")->value != MESON_THE_FIRST_VALUE) {
+ fprintf(stderr, "Get MESON_THE_FIRST_VALUE by nick failed.\n");
+ return 4;
+ }
+ g_type_class_unref(xenum);
+ g_type_class_unref(flags_enum);
+ fprintf(stderr, "All ok.\n");
+ return 0;
+}
diff --git a/test cases/frameworks/7 gnome/mkenums/meson-sample.h b/test cases/frameworks/7 gnome/mkenums/meson-sample.h
new file mode 100644
index 0000000..51e5421
--- /dev/null
+++ b/test cases/frameworks/7 gnome/mkenums/meson-sample.h
@@ -0,0 +1,18 @@
+typedef enum
+{
+ MESON_THE_XVALUE,
+ MESON_ANOTHER_VALUE
+} MesonTheXEnum;
+
+typedef enum /*< skip >*/
+{
+ MESON_FOO
+} MesonThisEnumWillBeSkipped;
+
+typedef enum /*< flags,prefix=MESON >*/
+{
+ MESON_THE_ZEROTH_VALUE, /*< skip >*/
+ MESON_THE_FIRST_VALUE,
+ MESON_THE_SECOND_VALUE,
+ MESON_THE_THIRD_VALUE, /*< nick=the-last-value >*/
+} MesonTheFlagsEnum;
diff --git a/test cases/frameworks/7 gnome/mkenums/meson.build b/test cases/frameworks/7 gnome/mkenums/meson.build
new file mode 100644
index 0000000..e01e9eb
--- /dev/null
+++ b/test cases/frameworks/7 gnome/mkenums/meson.build
@@ -0,0 +1,119 @@
+# Generate both header and source via template together.
+
+myenums = gnome.mkenums('abc1',
+ sources : 'meson-sample.h',
+ h_template : 'enums.h.in',
+ c_template : 'enums.c.in',
+ install_header : true,
+ install_dir : get_option('includedir'))
+
+enums_c1 = myenums[0]
+enums_h1 = myenums[1]
+
+conf = configuration_data()
+conf.set('ENUM_FILE', 'enums.h')
+main = configure_file(
+ input : 'main.c',
+ output : 'main1.c',
+ configuration : conf)
+
+enumexe1 = executable('enumprog1', main, enums_c1, enums_h1,
+dependencies : gobj)
+test('enum test 1', enumexe1)
+
+# Generate both header and source via template individually and overriding.
+
+enums_h2 = gnome.mkenums('abc2',
+ sources : 'meson-sample.h',
+ h_template : 'enums2.h.in',
+ ftail : '/* trailing header file info */',
+ install_header : true,
+ install_dir : get_option('includedir'))
+
+enums_c2 = gnome.mkenums('abc2',
+ sources : 'meson-sample.h',
+ depends : [enums_h1, enums_h2],
+ c_template : 'enums2.c.in',
+ ftail : '/* trailing source file info */',
+ install_header : true,
+ install_dir : get_option('includedir'))
+
+conf = configuration_data()
+conf.set('ENUM_FILE', 'enums2.h')
+main = configure_file(
+ input : 'main.c',
+ output : 'main2.c',
+ configuration : conf)
+
+enumexe2 = executable('enumprog2', main, enums_c2, enums_h2,
+dependencies : gobj)
+test('enum test 2', enumexe2)
+
+# Generate both header and source by options only.
+# These are specified in a way that should produce the same result as above
+# (modulo any filename changes.)
+
+enums_h3 = gnome.mkenums('enums3.h',
+ sources : 'meson-sample.h',
+ fhead : '''#ifndef MESON_ENUMS_H
+#define MESON_ENUMS_H
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+''',
+ fprod : '''
+/* enumerations from "@basename@" */
+''',
+ vhead : '''GType @enum_name@_get_type(void) G_GNUC_CONST;
+#define @ENUMPREFIX@_TYPE_@ENUMSHORT@ (@enum_name@_get_type())
+''',
+ ftail : '''
+G_END_DECLS
+
+#endif /* MESON_ENUMS_H */
+''',
+ install_header : true,
+ install_dir : get_option('includedir'))
+
+enums_c3 = gnome.mkenums('enums3.c',
+ sources : 'meson-sample.h',
+ depends : enums_h3,
+ fhead : '''#include "enums3.h"
+''',
+ fprod : '''
+
+/* enumerations from "@basename@" */
+#include "@basename@"
+''',
+ vhead : '''
+GType
+@enum_name@_get_type(void) {
+ static volatile gsize g_define_type_id__volatile = 0;
+
+ if(g_once_init_enter(&g_define_type_id__volatile)) {
+ static const G@Type@Value values [] = {
+''',
+ vprod : ''' { @VALUENAME@, "@VALUENAME@", "@valuenick@" },''',
+ vtail : ''' { 0, NULL, NULL }
+ };
+
+ GType g_define_type_id =
+ g_@type@_register_static(g_intern_static_string("@EnumName@"), values);
+ g_once_init_leave(&g_define_type_id__volatile, g_define_type_id);
+ }
+
+ return g_define_type_id__volatile;
+}
+''')
+
+conf = configuration_data()
+conf.set('ENUM_FILE', 'enums3.h')
+main = configure_file(
+ input : 'main.c',
+ output : 'main3.c',
+ configuration : conf)
+
+enumexe3 = executable('enumprog3', main, enums_c3, enums_h3,
+dependencies : gobj)
+test('enum test 3', enumexe3)
diff --git a/test cases/frameworks/7 gnome/schemas/meson.build b/test cases/frameworks/7 gnome/schemas/meson.build
index b4765b6..1947604 100644
--- a/test cases/frameworks/7 gnome/schemas/meson.build
+++ b/test cases/frameworks/7 gnome/schemas/meson.build
@@ -1,8 +1,8 @@
-gnome.compile_schemas()
+compiled = gnome.compile_schemas()
install_data('com.github.meson.gschema.xml',
install_dir : 'share/glib-2.0/schemas')
-schemaexe = executable('schemaprog', 'schemaprog.c',
+schemaexe = executable('schemaprog', 'schemaprog.c', compiled,
dependencies : gio)
test('schema test', schemaexe)
diff --git a/test cases/swift/2 multifile/main.swift b/test cases/swift/2 multifile/main.swift
index 61d67e2..9867e85 100644
--- a/test cases/swift/2 multifile/main.swift
+++ b/test cases/swift/2 multifile/main.swift
@@ -1 +1,5 @@
+#if swift(>=3.0)
+printSomething(text:"String from main")
+#else
printSomething("String from main")
+#endif
diff --git a/test cases/swift/4 generate/gen/main.swift b/test cases/swift/4 generate/gen/main.swift
index 27398fd..03acdbb 100644
--- a/test cases/swift/4 generate/gen/main.swift
+++ b/test cases/swift/4 generate/gen/main.swift
@@ -4,7 +4,11 @@
import Glibc
#endif
+#if swift(>=3.0)
+let fname = CommandLine.arguments[1]
+#else
let fname = Process.arguments[1]
+#endif
let code = "public func getGenerated() -> Int {\n return 42\n}\n"
let f = fopen(fname, "w")
diff --git a/test cases/vala/11 mixed sources/bar.vala b/test cases/vala/11 mixed sources/bar.vala
new file mode 100644
index 0000000..10dce1e
--- /dev/null
+++ b/test cases/vala/11 mixed sources/bar.vala
@@ -0,0 +1,5 @@
+extern int test ();
+
+public int main (string[] args) {
+ return test ();
+}
diff --git a/test cases/vala/11 mixed sources/foo.c b/test cases/vala/11 mixed sources/foo.c
new file mode 100644
index 0000000..05910a6
--- /dev/null
+++ b/test cases/vala/11 mixed sources/foo.c
@@ -0,0 +1,3 @@
+int test () {
+ return 0;
+}
diff --git a/test cases/vala/11 mixed sources/meson.build b/test cases/vala/11 mixed sources/meson.build
new file mode 100644
index 0000000..c84c8cd
--- /dev/null
+++ b/test cases/vala/11 mixed sources/meson.build
@@ -0,0 +1,5 @@
+project('foo', 'c', 'vala')
+
+glib = dependency('glib-2.0')
+
+executable('foo', 'foo.c', 'bar.vala', dependencies: [glib])
diff --git a/test cases/vala/8 generated source/installed_files.txt b/test cases/vala/8 generated source/installed_files.txt
new file mode 100644
index 0000000..a4c37f6
--- /dev/null
+++ b/test cases/vala/8 generated source/installed_files.txt
@@ -0,0 +1 @@
+usr/bin/generatedtest
diff --git a/test cases/vala/8 generated source/meson.build b/test cases/vala/8 generated source/meson.build
new file mode 100644
index 0000000..7271821
--- /dev/null
+++ b/test cases/vala/8 generated source/meson.build
@@ -0,0 +1,7 @@
+project('mytest', 'vala', 'c')
+
+cd = configuration_data()
+cd.set('x', 'y')
+
+subdir('src')
+subdir('tools')
diff --git a/test cases/vala/8 generated source/src/config.vala.in b/test cases/vala/8 generated source/src/config.vala.in
new file mode 100644
index 0000000..a5196fd
--- /dev/null
+++ b/test cases/vala/8 generated source/src/config.vala.in
@@ -0,0 +1,3 @@
+namespace Config {
+ public static const string x = "@x@";
+}
diff --git a/test cases/vala/8 generated source/src/meson.build b/test cases/vala/8 generated source/src/meson.build
new file mode 100644
index 0000000..9096c67
--- /dev/null
+++ b/test cases/vala/8 generated source/src/meson.build
@@ -0,0 +1,5 @@
+config = configure_file(input: 'config.vala.in',
+ output: 'config.vala',
+ configuration: cd)
+
+src = files('test.vala')
diff --git a/test cases/vala/8 generated source/src/test.vala b/test cases/vala/8 generated source/src/test.vala
new file mode 100644
index 0000000..98d6821
--- /dev/null
+++ b/test cases/vala/8 generated source/src/test.vala
@@ -0,0 +1,3 @@
+void main() {
+ print (Config.x);
+}
diff --git a/test cases/vala/8 generated source/tools/meson.build b/test cases/vala/8 generated source/tools/meson.build
new file mode 100644
index 0000000..834ec1a
--- /dev/null
+++ b/test cases/vala/8 generated source/tools/meson.build
@@ -0,0 +1,3 @@
+executable('generatedtest', [src, config],
+ install : true,
+ dependencies: [dependency('glib-2.0'), dependency('gobject-2.0')])
diff --git a/tools/ac_converter.py b/tools/ac_converter.py
index c7c9f44..4f284af 100755
--- a/tools/ac_converter.py
+++ b/tools/ac_converter.py
@@ -94,7 +94,7 @@ function_data = \
'HAVE_READLINK': ('readlink', 'unistd.h'),
'HAVE_RES_INIT': ('res_init', 'resolv.h'),
'HAVE_SENDMMSG': ('sendmmsg', 'sys/socket.h'),
- 'HAVE_SOCKET' : ('socket',' sys/socket.h'),
+ 'HAVE_SOCKET' : ('socket', 'sys/socket.h'),
'HAVE_GETENV': ('getenv', 'stdlib.h'),
'HAVE_SETENV': ('setenv', 'stdlib.h'),
'HAVE_PUTENV': ('putenv', 'stdlib.h'),
@@ -115,7 +115,6 @@ function_data = \
'HAVE_SYMLINK': ('symlink', 'unistd.h'),
'HAVE_SYSCTLBYNAME': ('sysctlbyname', 'sys/sysctl.h'),
'HAVE_TIMEGM': ('timegm', 'time.h'),
- 'HAVE_UNSETENV': ('unsetenv', 'stdlib.h'),
'HAVE_USELOCALE': ('uselocale', 'xlocale.h'),
'HAVE_UTIMES': ('utimes', 'sys/time.h'),
'HAVE_VALLOC': ('valloc', 'stdlib.h'),
@@ -280,7 +279,7 @@ endforeach
print('check_functions = [')
for token in functions:
- if len(func) == 3:
+ if len(token) == 3:
token, fdata0, fdata1 = token
print(" ['%s', '%s', '#include<%s>']," % (token, fdata0, fdata1))
else: