aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--MANIFEST.in4
-rw-r--r--authors.txt3
-rw-r--r--cross/ubuntu-mingw.txt1
-rw-r--r--man/meson.12
-rw-r--r--man/mesonconf.12
-rw-r--r--man/mesongui.12
-rw-r--r--man/mesonintrospect.12
-rw-r--r--man/wraptool.12
-rw-r--r--mesonbuild/backend/__init__.py0
-rw-r--r--mesonbuild/backend/backends.py (renamed from mesonbuild/backends.py)38
-rw-r--r--mesonbuild/backend/ninjabackend.py (renamed from mesonbuild/ninjabackend.py)210
-rw-r--r--mesonbuild/backend/vs2010backend.py (renamed from mesonbuild/vs2010backend.py)73
-rw-r--r--mesonbuild/backend/xcodebackend.py (renamed from mesonbuild/xcodebackend.py)9
-rw-r--r--mesonbuild/build.py2
-rw-r--r--mesonbuild/compilers.py54
-rw-r--r--mesonbuild/coredata.py9
-rw-r--r--mesonbuild/dependencies.py10
-rw-r--r--mesonbuild/environment.py24
-rw-r--r--mesonbuild/interpreter.py176
-rw-r--r--mesonbuild/mconf.py3
-rw-r--r--mesonbuild/mesonlib.py10
-rw-r--r--mesonbuild/mesonmain.py22
-rw-r--r--mesonbuild/modules/gnome.py83
-rw-r--r--mesonbuild/modules/qt5.py2
-rw-r--r--mesonbuild/mparser.py21
-rw-r--r--mesonbuild/scripts/meson_install.py10
-rw-r--r--mesonbuild/scripts/meson_test.py22
-rw-r--r--mesonbuild/scripts/regen_checker.py11
-rw-r--r--mesonbuild/wrap/wrap.py2
-rwxr-xr-xrun_tests.py8
-rw-r--r--setup.py1
-rw-r--r--test cases/common/105 find program path/meson.build9
-rw-r--r--test cases/common/105 find program path/program.py3
-rw-r--r--test cases/common/42 string formatting/meson.build2
-rwxr-xr-xtest cases/common/59 object generator/obj_generator.py2
-rwxr-xr-xtest cases/common/60 install script/myinstall.sh2
-rw-r--r--test cases/common/68 number arithmetic/meson.build12
-rw-r--r--test cases/common/89 add language/meson.build3
-rw-r--r--test cases/failing/25 int conversion/meson.build3
-rw-r--r--test cases/failing/26 badlang/meson.build3
-rw-r--r--test cases/failing/27 output subdir/foo.in1
-rw-r--r--test cases/failing/27 output subdir/meson.build5
-rw-r--r--test cases/failing/27 output subdir/subdir/dummy.txt2
-rw-r--r--test cases/vala/7 shared library/lib/meson.build1
-rw-r--r--test cases/vala/7 shared library/lib/mylib.vala5
-rw-r--r--test cases/vala/7 shared library/meson.build10
-rw-r--r--test cases/vala/7 shared library/prog/meson.build4
-rw-r--r--test cases/vala/7 shared library/prog/prog.vala7
48 files changed, 558 insertions, 334 deletions
diff --git a/MANIFEST.in b/MANIFEST.in
index 8d8f136..2381203 100644
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -5,11 +5,9 @@ graft data
graft graphics
graft man
graft tools
-include run_tests.py
-include run_cross_test.py
-include readme.txt
include authors.txt
include contributing.txt
include COPYING
+include readme.txt
include run_cross_test.py
include run_tests.py
diff --git a/authors.txt b/authors.txt
index 0d043eb..4552b23 100644
--- a/authors.txt
+++ b/authors.txt
@@ -27,3 +27,6 @@ Wink Saville
Yoav Alon
Martin Ejdestig
Rémi Nicole
+Damián Nohales
+Nirbheek Chauhan
+Nicolas Schneider
diff --git a/cross/ubuntu-mingw.txt b/cross/ubuntu-mingw.txt
index 2373565..4c8fcac 100644
--- a/cross/ubuntu-mingw.txt
+++ b/cross/ubuntu-mingw.txt
@@ -7,6 +7,7 @@ c = '/usr/bin/i686-w64-mingw32-gcc'
cpp = '/usr/bin/i686-w64-mingw32-g++'
ar = '/usr/bin/i686-w64-mingw32-ar'
strip = '/usr/bin/i686-w64-mingw32-strip'
+pkgconfig = '/usr/bin/mingw32-pkg-config'
[properties]
root = '/usr/i686-w64-mingw32'
diff --git a/man/meson.1 b/man/meson.1
index 15b17e4..19721c1 100644
--- a/man/meson.1
+++ b/man/meson.1
@@ -1,4 +1,4 @@
-.TH MESON "1" "December 2015" "meson 0.28.0" "User Commands"
+.TH MESON "1" "January 2016" "meson 0.29.0" "User Commands"
.SH NAME
meson - a high productivity build system
.SH DESCRIPTION
diff --git a/man/mesonconf.1 b/man/mesonconf.1
index d8137a9..be690ae 100644
--- a/man/mesonconf.1
+++ b/man/mesonconf.1
@@ -1,4 +1,4 @@
-.TH MESONCONF "1" "December 2015" "mesonconf 0.28.0" "User Commands"
+.TH MESONCONF "1" "January 2016" "mesonconf 0.29.0" "User Commands"
.SH NAME
mesonconf - a tool to configure Meson builds
.SH DESCRIPTION
diff --git a/man/mesongui.1 b/man/mesongui.1
index 4d41015..d1eff90 100644
--- a/man/mesongui.1
+++ b/man/mesongui.1
@@ -1,4 +1,4 @@
-.TH MESONGUI "1" "December 2015" "mesongui 0.28.0" "User Commands"
+.TH MESONGUI "1" "January 2016" "mesongui 0.29.0" "User Commands"
.SH NAME
mesongui - a gui for the Meson build system
.SH DESCRIPTION
diff --git a/man/mesonintrospect.1 b/man/mesonintrospect.1
index de0b766..9fa629c 100644
--- a/man/mesonintrospect.1
+++ b/man/mesonintrospect.1
@@ -1,4 +1,4 @@
-.TH MESONCONF "1" "December 2015" "mesonintrospect 0.28.0" "User Commands"
+.TH MESONCONF "1" "January 2016" "mesonintrospect 0.29.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 8a6f03c..b37c129 100644
--- a/man/wraptool.1
+++ b/man/wraptool.1
@@ -1,4 +1,4 @@
-.TH WRAPTOOL "1" "December 2015" "meson 0.28.0" "User Commands"
+.TH WRAPTOOL "1" "January 2016" "meson 0.29.0" "User Commands"
.SH NAME
wraptool - source dependency downloader
.SH DESCRIPTION
diff --git a/mesonbuild/backend/__init__.py b/mesonbuild/backend/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/mesonbuild/backend/__init__.py
diff --git a/mesonbuild/backends.py b/mesonbuild/backend/backends.py
index c583a7b..d2176c7 100644
--- a/mesonbuild/backends.py
+++ b/mesonbuild/backend/backends.py
@@ -1,4 +1,4 @@
-# Copyright 2012-2014 The Meson development team
+# 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.
@@ -13,11 +13,11 @@
# limitations under the License.
import os, pickle, re
-from . import build
-from . import dependencies
-from . import mesonlib
+from .. import build
+from .. import dependencies
+from .. import mesonlib
import json
-from .coredata import MesonException
+from ..coredata import MesonException
class InstallData():
def __init__(self, source_dir, build_dir, prefix, depfixer):
@@ -83,10 +83,20 @@ class Backend():
targetdir = self.get_target_dir(target)
fname = target.get_filename()
if isinstance(fname, list):
- fname = fname[0] # HORROR, HORROR! Fix this.
+ # FIXME FIXME FIXME: build.CustomTarget has multiple output files
+ # and get_filename() returns them all
+ fname = fname[0]
filename = os.path.join(targetdir, fname)
return filename
+ def get_target_filename_for_linking(self, target):
+ # On some platforms (msvc for instance), the file that is used for
+ # dynamic linking is not the same as the dynamic library itself. This
+ # file is called an import library, and we want to link against that.
+ # On platforms where this distinction is not important, the import
+ # library is the same as the dynamic library itself.
+ return os.path.join(self.get_target_dir(target), target.get_import_filename())
+
def get_target_dir(self, target):
if self.environment.coredata.get_builtin_option('layout') == 'mirror':
dirname = target.get_subdir()
@@ -115,6 +125,9 @@ class Backend():
outfileabs = os.path.join(self.environment.get_build_dir(), outfilename)
outfileabs_tmp = outfileabs + '.tmp'
abs_files.append(outfileabs)
+ outfileabs_tmp_dir = os.path.dirname(outfileabs_tmp)
+ if not os.path.exists(outfileabs_tmp_dir):
+ os.makedirs(outfileabs_tmp_dir)
outfile = open(outfileabs_tmp, 'w')
langlist[language] = outfile
result.append(outfilename)
@@ -231,8 +244,7 @@ class Backend():
def generate_basic_compiler_args(self, target, compiler):
commands = []
commands += compiler.get_always_args()
- if self.environment.coredata.get_builtin_option('buildtype') != 'plain':
- commands += compiler.get_warn_args(self.environment.coredata.get_builtin_option('warning_level'))
+ commands += compiler.get_warn_args(self.environment.coredata.get_builtin_option('warning_level'))
commands += compiler.get_option_compile_args(self.environment.coredata.compiler_options)
commands += self.build.get_global_args(compiler)
commands += self.environment.coredata.external_args[compiler.get_language()]
@@ -245,7 +257,9 @@ class Backend():
if isinstance(target, build.SharedLibrary):
commands += compiler.get_pic_args()
for dep in target.get_external_deps():
- commands += dep.get_compile_args()
+ # Cflags required by external deps might have UNIX-specific flags,
+ # so filter them out if needed
+ commands += compiler.unix_compile_flags_to_native(dep.get_compile_args())
if isinstance(target, build.Executable):
commands += dep.get_exe_args()
@@ -263,11 +277,7 @@ class Backend():
if not isinstance(d, build.StaticLibrary) and\
not isinstance(d, build.SharedLibrary):
raise RuntimeError('Tried to link with a non-library target "%s".' % d.get_basename())
- fname = self.get_target_filename(d)
- if compiler.id == 'msvc':
- if fname.endswith('dll'):
- fname = fname[:-3] + 'lib'
- args.append(fname)
+ args.append(self.get_target_filename_for_linking(d))
# If you have executable e that links to shared lib s1 that links to shared library s2
# you have to specify s2 as well as s1 when linking e even if e does not directly use
# s2. Gcc handles this case fine but Clang does not for some reason. Thus we need to
diff --git a/mesonbuild/ninjabackend.py b/mesonbuild/backend/ninjabackend.py
index 840957c..f5c06dc 100644
--- a/mesonbuild/ninjabackend.py
+++ b/mesonbuild/backend/ninjabackend.py
@@ -13,14 +13,14 @@
# limitations under the License.
from . import backends
-from . import environment, mesonlib
-from . import build
-from . import mlog
-from . import dependencies
-from .mesonlib import File
+from .. import environment, mesonlib
+from .. import build
+from .. import mlog
+from .. import dependencies
+from ..mesonlib import File
from .backends import InstallData
-from .build import InvalidArguments
-from .coredata import MesonException
+from ..build import InvalidArguments
+from ..coredata import MesonException
import os, sys, pickle, re
import subprocess, shutil
@@ -45,7 +45,7 @@ class RawFilename():
return self.fname.startswith(s)
class NinjaBuildElement():
- def __init__(self, outfilenames, rule, infilenames):
+ def __init__(self, all_outputs, outfilenames, rule, infilenames):
if isinstance(outfilenames, str):
self.outfilenames = [outfilenames]
else:
@@ -59,6 +59,7 @@ class NinjaBuildElement():
self.deps = []
self.orderdeps = []
self.elems = []
+ self.all_outputs = all_outputs
def add_dep(self, dep):
if isinstance(dep, list):
@@ -78,6 +79,7 @@ class NinjaBuildElement():
self.elems.append((name, elems))
def write(self, outfile):
+ self.check_outputs()
line = 'build %s: %s %s' % (' '.join([ninja_quote(i) for i in self.outfilenames]),\
self.rule,
' '.join([ninja_quote(i) for i in self.infilenames]))
@@ -116,6 +118,12 @@ class NinjaBuildElement():
outfile.write(line)
outfile.write('\n')
+ def check_outputs(self):
+ for n in self.outfilenames:
+ if n in self.all_outputs:
+ raise MesonException('Multiple producers for Ninja target "%s". Please rename your targets.' % n)
+ self.all_outputs[n] = True
+
class NinjaBackend(backends.Backend):
def __init__(self, build):
@@ -125,12 +133,6 @@ class NinjaBackend(backends.Backend):
self.fortran_deps = {}
self.all_outputs = {}
- def check_outputs(self, elem):
- for n in elem.outfilenames:
- if n in self.all_outputs:
- raise MesonException('Multiple producers for Ninja target "%s". Please rename your targets.' % n)
- self.all_outputs[n] = True
-
def detect_vs_dep_prefix(self, outfile, tempfilename):
'''VS writes its dependency in a locale dependent format.
Detect the search prefix to use.'''
@@ -231,7 +233,8 @@ int dummy;
self.generate_cs_target(target, outfile)
return
if 'vala' in self.environment.coredata.compilers.keys() and self.has_vala(target):
- gen_src_deps += self.generate_vala_compile(target, outfile)
+ vala_output_files = self.generate_vala_compile(target, outfile)
+ gen_src_deps += vala_output_files
if 'swift' in self.environment.coredata.compilers.keys() and self.has_swift(target):
self.generate_swift_target(target, outfile)
return
@@ -344,7 +347,7 @@ int dummy;
deps.append(os.path.join(self.get_target_dir(i), fname))
if target.build_always:
deps.append('PHONY')
- elem = NinjaBuildElement(ofilenames, 'CUSTOM_COMMAND', srcs)
+ elem = NinjaBuildElement(self.all_outputs, ofilenames, 'CUSTOM_COMMAND', srcs)
for i in target.depend_files:
if isinstance(i, mesonlib.File):
deps.append(i.rel_to_builddir(self.build_to_src))
@@ -361,7 +364,6 @@ int dummy;
elem.add_item('COMMAND', cmd)
elem.add_item('description', 'Generating %s with a custom command.' % target.name)
elem.write(outfile)
- self.check_outputs(elem)
self.processed_targets[target.name + target.type_suffix()] = True
def generate_run_target(self, target, outfile):
@@ -378,7 +380,7 @@ int dummy;
else:
mlog.debug(str(i))
raise MesonException('Unreachable code in generate_run_target.')
- elem = NinjaBuildElement(target.name, 'CUSTOM_COMMAND', deps)
+ elem = NinjaBuildElement(self.all_outputs, target.name, 'CUSTOM_COMMAND', deps)
cmd = runnerscript + [self.environment.get_source_dir(), self.environment.get_build_dir(), target.subdir]
texe = target.command
try:
@@ -399,51 +401,47 @@ int dummy;
elem.add_item('description', 'Running external command %s.' % target.name)
elem.add_item('pool', 'console')
elem.write(outfile)
- self.check_outputs(elem)
self.processed_targets[target.name + target.type_suffix()] = True
def generate_po(self, outfile):
for p in self.build.pot:
(packagename, languages, subdir) = p
input_file = os.path.join(subdir, 'POTFILES')
- elem = NinjaBuildElement('pot', 'GEN_POT', [])
+ elem = NinjaBuildElement(self.all_outputs, 'pot', 'GEN_POT', [])
elem.add_item('PACKAGENAME', packagename)
elem.add_item('OUTFILE', packagename + '.pot')
elem.add_item('FILELIST', os.path.join(self.environment.get_source_dir(), input_file))
elem.add_item('OUTDIR', os.path.join(self.environment.get_source_dir(), subdir))
elem.write(outfile)
- self.check_outputs(elem)
for l in languages:
infile = os.path.join(self.environment.get_source_dir(), subdir, l + '.po')
outfilename = os.path.join(subdir, l + '.gmo')
- lelem = NinjaBuildElement(outfilename, 'GEN_GMO', infile)
+ lelem = NinjaBuildElement(self.all_outputs, outfilename, 'GEN_GMO', infile)
lelem.add_item('INFILE', infile)
lelem.add_item('OUTFILE', outfilename)
lelem.write(outfile)
- self.check_outputs(lelem)
def generate_coverage_rules(self, outfile):
(gcovr_exe, lcov_exe, genhtml_exe) = environment.find_coverage_tools()
added_rule = False
if gcovr_exe:
added_rule = True
- elem = NinjaBuildElement('coverage-xml', 'CUSTOM_COMMAND', '')
+ elem = NinjaBuildElement(self.all_outputs, 'coverage-xml', 'CUSTOM_COMMAND', '')
elem.add_item('COMMAND', [gcovr_exe, '-x', '-r', self.environment.get_build_dir(),\
'-o', os.path.join(self.environment.get_log_dir(), 'coverage.xml')])
elem.add_item('DESC', 'Generating XML coverage report.')
elem.write(outfile)
- elem = NinjaBuildElement('coverage-text', 'CUSTOM_COMMAND', '')
+ elem = NinjaBuildElement(self.all_outputs, 'coverage-text', 'CUSTOM_COMMAND', '')
elem.add_item('COMMAND', [gcovr_exe, '-r', self.environment.get_build_dir(),\
'-o', os.path.join(self.environment.get_log_dir(), 'coverage.txt')])
elem.add_item('DESC', 'Generating text coverage report.')
elem.write(outfile)
- self.check_outputs(elem)
if lcov_exe and genhtml_exe:
added_rule = True
- phony_elem = NinjaBuildElement('coverage-html', 'phony', 'coveragereport/index.html')
+ phony_elem = NinjaBuildElement(self.all_outputs, 'coverage-html', 'phony', 'coveragereport/index.html')
phony_elem.write(outfile)
- elem = NinjaBuildElement('coveragereport/index.html', 'CUSTOM_COMMAND', '')
+ elem = NinjaBuildElement(self.all_outputs, 'coveragereport/index.html', 'CUSTOM_COMMAND', '')
command = [lcov_exe, '--directory', self.environment.get_build_dir(),\
'--capture', '--output-file', 'coverage.info', '--no-checksum',\
'&&', genhtml_exe, '--prefix', self.environment.get_build_dir(),\
@@ -451,7 +449,6 @@ int dummy;
'--legend', '--show-details', 'coverage.info']
elem.add_item('COMMAND', command)
elem.add_item('DESC', 'Generating HTML coverage report.')
- self.check_outputs(elem)
elem.write(outfile)
if not added_rule:
mlog.log(mlog.red('Warning:'), 'coverage requested but neither gcovr nor lcov/genhtml found.')
@@ -464,7 +461,7 @@ int dummy;
d = InstallData(self.environment.get_source_dir(),
self.environment.get_build_dir(),
self.environment.get_prefix(), depfixer)
- elem = NinjaBuildElement('install', 'CUSTOM_COMMAND', 'PHONY')
+ elem = NinjaBuildElement(self.all_outputs, 'install', 'CUSTOM_COMMAND', 'PHONY')
elem.add_dep('all')
elem.add_item('DESC', 'Installing files.')
elem.add_item('COMMAND', [sys.executable, self.environment.get_build_command(), '--internal', 'install', install_data_file])
@@ -478,7 +475,6 @@ int dummy;
self.generate_custom_install_script(d)
self.generate_subdir_install(d)
elem.write(outfile)
- self.check_outputs(elem)
ofile = open(install_data_file, 'wb')
pickle.dump(d, ofile)
@@ -574,12 +570,11 @@ int dummy;
visible_name = 'for top level tests'
else:
visible_name = s
- elem = NinjaBuildElement('test-' + s, 'CUSTOM_COMMAND', ['all', 'PHONY'])
+ elem = NinjaBuildElement(self.all_outputs, 'test-' + s, 'CUSTOM_COMMAND', ['all', 'PHONY'])
elem.add_item('COMMAND', cmd + ['--suite=' + s])
elem.add_item('DESC', 'Running test suite %s.' % visible_name)
elem.add_item('pool', 'console')
elem.write(outfile)
- self.check_outputs(elem)
def generate_tests(self, outfile):
self.serialise_tests()
@@ -587,32 +582,29 @@ int dummy;
script_root = self.environment.get_script_dir()
test_data = os.path.join(self.environment.get_scratch_dir(), 'meson_test_setup.dat')
cmd = [sys.executable, self.environment.get_build_command(), '--internal', 'test', test_data]
- elem = NinjaBuildElement('test', 'CUSTOM_COMMAND', ['all', 'PHONY'])
+ elem = NinjaBuildElement(self.all_outputs, 'test', 'CUSTOM_COMMAND', ['all', 'PHONY'])
elem.add_item('COMMAND', cmd)
elem.add_item('DESC', 'Running all tests.')
elem.add_item('pool', 'console')
elem.write(outfile)
- self.check_outputs(elem)
self.write_test_suite_targets(cmd, outfile)
if valgrind:
- velem = NinjaBuildElement('test-valgrind', 'CUSTOM_COMMAND', ['all', 'PHONY'])
+ velem = NinjaBuildElement(self.all_outputs, 'test-valgrind', 'CUSTOM_COMMAND', ['all', 'PHONY'])
velem.add_item('COMMAND', cmd + ['--wrapper=' + valgrind])
velem.add_item('DESC', 'Running test suite under Valgrind.')
velem.add_item('pool', 'console')
velem.write(outfile)
- self.check_outputs(velem)
# And then benchmarks.
benchmark_script = os.path.join(script_root, 'meson_benchmark.py')
benchmark_data = os.path.join(self.environment.get_scratch_dir(), 'meson_benchmark_setup.dat')
cmd = [sys.executable, self.environment.get_build_command(), '--internal', 'benchmark', benchmark_data]
- elem = NinjaBuildElement('benchmark', 'CUSTOM_COMMAND', ['all', 'PHONY'])
+ elem = NinjaBuildElement(self.all_outputs, 'benchmark', 'CUSTOM_COMMAND', ['all', 'PHONY'])
elem.add_item('COMMAND', cmd)
elem.add_item('DESC', 'Running benchmark suite.')
elem.add_item('pool', 'console')
elem.write(outfile)
- self.check_outputs(elem)
def generate_rules(self, outfile):
outfile.write('# Rules for compiling.\n\n')
@@ -689,11 +681,10 @@ int dummy;
commands.append(self.get_target_filename(target))
for cls in class_list:
commands += ['-C', self.get_target_private_dir(target), cls]
- elem = NinjaBuildElement(outname_rel, jar_rule, [])
+ elem = NinjaBuildElement(self.all_outputs, outname_rel, jar_rule, [])
elem.add_dep(class_dep_list)
elem.add_item('ARGS', commands)
elem.write(outfile)
- self.check_outputs(elem)
def generate_cs_resource_tasks(self, target, outfile):
args = []
@@ -705,11 +696,10 @@ int dummy;
elif r.endswith('.txt') or r.endswith('.resx'):
ofilebase = os.path.splitext(os.path.basename(r))[0] + '.resources'
ofilename = os.path.join(self.get_target_private_dir(target), ofilebase)
- elem = NinjaBuildElement(ofilename, "CUSTOM_COMMAND", rel_sourcefile)
+ elem = NinjaBuildElement(self.all_outputs, ofilename, "CUSTOM_COMMAND", rel_sourcefile)
elem.add_item('COMMAND', ['resgen', rel_sourcefile, ofilename])
elem.add_item('DESC', 'Compiling resource %s.' % rel_sourcefile)
elem.write(outfile)
- self.check_outputs(elem)
deps.append(ofilename)
a = '-resource:' + ofilename
else:
@@ -746,10 +736,9 @@ int dummy;
outputs = [outname_rel, outname_rel + '.mdb']
else:
outputs = [outname_rel]
- elem = NinjaBuildElement(outputs, 'cs_COMPILER', rel_srcs)
+ elem = NinjaBuildElement(self.all_outputs, outputs, 'cs_COMPILER', rel_srcs)
elem.add_dep(deps)
elem.add_item('ARGS', commands)
- self.check_outputs(elem)
elem.write(outfile)
def generate_single_java_compile(self, src, target, compiler, outfile):
@@ -762,10 +751,9 @@ int dummy;
rel_src = src.rel_to_builddir(self.build_to_src)
plain_class_path = src.fname[:-4] + 'class'
rel_obj = os.path.join(self.get_target_private_dir(target), plain_class_path)
- element = NinjaBuildElement(rel_obj, compiler.get_language() + '_COMPILER', rel_src)
+ element = NinjaBuildElement(self.all_outputs, rel_obj, compiler.get_language() + '_COMPILER', rel_src)
element.add_item('ARGS', args)
element.write(outfile)
- self.check_outputs(element)
return plain_class_path
def generate_java_link(self, outfile):
@@ -795,7 +783,7 @@ int dummy;
i = i.fname
if i.endswith('vala'):
vapiname = os.path.splitext(os.path.split(i)[1])[0] + '.vapi'
- fullname = os.path.join(self.get_target_private_dir(dep), vapiname)
+ fullname = os.path.join(self.get_target_dir(dep), vapiname)
result.append(fullname)
break
return result
@@ -810,20 +798,28 @@ int dummy;
for s in src:
if s.endswith('.vala'):
vala_input_files.append(s.rel_to_builddir(self.build_to_src))
- namebase = os.path.splitext(os.path.split(vala_input_files[0])[1])[0]
- hname = namebase + '.h'
- vapiname = namebase + '.vapi'
+ if len(src) == 0:
+ raise InvalidArguments('Vala library has no Vala source files.')
+ namebase = os.path.splitext(os.path.split(src[0].fname)[1])[0]
+ base_h = namebase + '.h'
+ base_vapi = namebase + '.vapi'
+ hname = os.path.normpath(os.path.join(self.get_target_dir(target), base_h))
+ vapiname = os.path.normpath(os.path.join(self.get_target_dir(target), base_vapi))
+
+ generated_c_files = []
outputs = [vapiname]
-
args = ['-d', self.get_target_private_dir(target)]
args += ['-C']#, '-o', cname]
if not isinstance(target, build.Executable):
outputs.append(hname)
args += ['-H', hname]
- args += ['--vapi=' + vapiname]
+ 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'
- outputs.append(namebase)
+ full_c = os.path.join(self.get_target_private_dir(target), namebase)
+ generated_c_files.append(full_c)
+ outputs.append(full_c)
if self.environment.coredata.get_builtin_option('werror'):
args += valac.get_werror_args()
for d in target.external_deps:
@@ -845,15 +841,13 @@ int dummy;
extra_dep_files += dependency_vapis
args += extra_args
args += dependency_vapis
- outputs = [os.path.join(self.get_target_private_dir(target), x) for x in outputs]
- element = NinjaBuildElement(outputs,
+ element = NinjaBuildElement(self.all_outputs, outputs,
valac.get_language() + '_COMPILER',
vala_input_files + vapi_src)
element.add_item('ARGS', args)
element.add_dep(extra_dep_files)
element.write(outfile)
- self.check_outputs(element)
- return outputs
+ return generated_c_files
def generate_rust_target(self, target, outfile):
rustc = self.environment.coredata.compilers['rust']
@@ -885,14 +879,13 @@ int dummy;
if d == '':
d = '.'
args += ['-L', d]
- element = NinjaBuildElement(target_name, 'rust_COMPILER', relsrc)
+ element = NinjaBuildElement(self.all_outputs, target_name, 'rust_COMPILER', relsrc)
if len(orderdeps) > 0:
element.add_orderdep(orderdeps)
element.add_item('ARGS', args)
element.add_item('targetdep', depfile)
element.add_item('cratetype', cratetype)
element.write(outfile)
- self.check_outputs(element)
def swift_module_file_name(self, target):
return os.path.join(self.get_target_private_dir(target),
@@ -990,7 +983,7 @@ int dummy;
rel_objects.append(os.path.join(self.get_target_private_dir(target), oname))
# Swiftc does not seem to be able to emit objects and module files in one go.
- elem = NinjaBuildElement(rel_objects,
+ elem = NinjaBuildElement(self.all_outputs, rel_objects,
'swift_COMPILER',
abssrc)
elem.add_dep(in_module_files + rel_generated)
@@ -998,27 +991,24 @@ int dummy;
elem.add_item('ARGS', compile_args + header_imports + abs_generated + module_includes)
elem.add_item('RUNDIR', rundir)
elem.write(outfile)
- self.check_outputs(elem)
- elem = NinjaBuildElement(out_module_name,
+ elem = NinjaBuildElement(self.all_outputs, out_module_name,
'swift_COMPILER',
abssrc)
elem.add_dep(in_module_files + rel_generated)
elem.add_item('ARGS', compile_args + abs_generated + module_includes + swiftc.get_mod_gen_args())
elem.add_item('RUNDIR', rundir)
elem.write(outfile)
- self.check_outputs(elem)
if isinstance(target, build.StaticLibrary):
elem = self.generate_link(target, outfile, self.get_target_filename(target),
rel_objects, self.build.static_linker)
elem.write(outfile)
elif isinstance(target, build.Executable):
- elem = NinjaBuildElement(self.get_target_filename(target), 'swift_COMPILER', [])
+ elem = NinjaBuildElement(self.all_outputs, self.get_target_filename(target), 'swift_COMPILER', [])
elem.add_dep(rel_objects)
elem.add_dep(link_deps)
elem.add_item('ARGS', link_args + swiftc.get_std_exe_link_args() + objects + abs_link_deps)
elem.add_item('RUNDIR', rundir)
elem.write(outfile)
- self.check_outputs(elem)
else:
raise MesonException('Swift supports only executable and static library targets.')
@@ -1365,7 +1355,7 @@ rule FORTRAN_DEP_HACK
else:
final_args.append(a)
cmdlist = exe_arr + final_args
- elem = NinjaBuildElement(outfiles, 'CUSTOM_COMMAND', infilename)
+ elem = NinjaBuildElement(self.all_outputs, outfiles, 'CUSTOM_COMMAND', infilename)
if len(extra_dependencies) > 0:
elem.add_dep(extra_dependencies)
elem.add_item('DESC', 'Generating $out')
@@ -1373,7 +1363,6 @@ rule FORTRAN_DEP_HACK
elem.add_dep(self.get_target_filename(exe))
elem.add_item('COMMAND', cmdlist)
elem.write(outfile)
- self.check_outputs(elem)
def scan_fortran_module_outputs(self, target):
compiler = None
@@ -1446,6 +1435,23 @@ rule FORTRAN_DEP_HACK
if curdir == '':
curdir = '.'
commands += compiler.get_include_args(curdir, False)
+ # -I args work differently than other ones. In them the
+ # first found directory is used whereas for other flags
+ # (such as -ffoo -fno-foo) the latest one is used.
+ # Therefore put the internal include directories here
+ # at the beginning so they override args coming from
+ # e.g. pkg-config.
+ for i in target.get_include_dirs():
+ basedir = i.get_curdir()
+ for d in i.get_incdirs():
+ expdir = os.path.join(basedir, d)
+ srctreedir = os.path.join(self.build_to_src, expdir)
+ bargs = compiler.get_include_args(expdir, i.is_system)
+ sargs = compiler.get_include_args(srctreedir, i.is_system)
+ commands += bargs
+ commands += sargs
+ for d in i.get_extra_build_dirs():
+ commands += compiler.get_include_args(d, i.is_system)
for d in target.external_deps:
if d.need_threads():
commands += compiler.thread_flags()
@@ -1487,17 +1493,6 @@ rule FORTRAN_DEP_HACK
i = os.path.join(self.get_target_private_dir(target), compiler.get_pch_name(pchlist[0]))
arr.append(i)
pch_dep = arr
- for i in target.get_include_dirs():
- basedir = i.get_curdir()
- for d in i.get_incdirs():
- expdir = os.path.join(basedir, d)
- srctreedir = os.path.join(self.build_to_src, expdir)
- bargs = compiler.get_include_args(expdir, i.is_system)
- sargs = compiler.get_include_args(srctreedir, i.is_system)
- commands += bargs
- commands += sargs
- for d in i.get_extra_build_dirs():
- commands += compiler.get_include_args(d, i.is_system)
custom_target_include_dirs = []
for i in target.generated:
if isinstance(i, build.CustomTarget):
@@ -1521,12 +1516,11 @@ rule FORTRAN_DEP_HACK
modfile = os.path.join(self.get_target_private_dir(target),
compiler.module_name_to_filename(modname))
if srcfile == src:
- depelem = NinjaBuildElement(modfile, 'FORTRAN_DEP_HACK', rel_obj)
+ depelem = NinjaBuildElement(self.all_outputs, modfile, 'FORTRAN_DEP_HACK', rel_obj)
depelem.write(outfile)
- self.check_outputs(depelem)
commands += compiler.get_module_outdir_args(self.get_target_private_dir(target))
- element = NinjaBuildElement(rel_obj, compiler_name, rel_src)
+ element = NinjaBuildElement(self.all_outputs, rel_obj, compiler_name, rel_src)
for d in header_deps:
if isinstance(d, RawFilename):
d = d.fname
@@ -1548,7 +1542,6 @@ rule FORTRAN_DEP_HACK
element.add_item('DEPFILE', dep_file)
element.add_item('ARGS', commands)
element.write(outfile)
- self.check_outputs(element)
return rel_obj
def has_dir_part(self, fname):
@@ -1611,24 +1604,22 @@ rule FORTRAN_DEP_HACK
extradep = None
pch_objects += objs
rulename = compiler.get_language() + cstr + '_PCH'
- elem = NinjaBuildElement(dst, rulename, src)
+ elem = NinjaBuildElement(self.all_outputs, dst, rulename, src)
if extradep is not None:
elem.add_dep(extradep)
elem.add_item('ARGS', commands)
elem.add_item('DEPFILE', dep)
elem.write(outfile)
- self.check_outputs(elem)
return pch_objects
def generate_shsym(self, outfile, target):
target_name = self.get_target_filename(target)
targetdir = self.get_target_private_dir(target)
symname = os.path.join(targetdir, target_name + '.symbols')
- elem = NinjaBuildElement(symname, 'SHSYM', target_name)
+ elem = NinjaBuildElement(self.all_outputs, symname, 'SHSYM', target_name)
if self.environment.is_cross_build() and self.environment.cross_info.need_cross_compiler():
elem.add_item('CROSS', '--cross-host=' + self.environment.cross_info.config['host_machine']['system'])
elem.write(outfile)
- self.check_outputs(elem)
def generate_link(self, target, outfile, outname, obj_list, linker, extra_args=[]):
if isinstance(target, build.StaticLibrary):
@@ -1690,14 +1681,13 @@ rule FORTRAN_DEP_HACK
custom_target_libraries = self.get_custom_target_provided_libraries(target)
commands += extra_args
commands += custom_target_libraries
- commands = linker.unixtype_flags_to_native(commands)
+ commands = linker.unix_link_flags_to_native(commands)
dep_targets = [self.get_dependency_filename(t) for t in dependencies]
dep_targets += [os.path.join(self.environment.source_dir,
target.subdir, t) for t in target.link_depends]
- elem = NinjaBuildElement(outname, linker_rule, obj_list)
+ elem = NinjaBuildElement(self.all_outputs, outname, linker_rule, obj_list)
elem.add_dep(dep_targets + custom_target_libraries)
elem.add_item('LINK_ARGS', commands)
- self.check_outputs(elem)
return elem
def get_custom_target_provided_libraries(self, target):
@@ -1727,33 +1717,33 @@ rule FORTRAN_DEP_HACK
def generate_shlib_aliases(self, target, outdir):
basename = target.get_filename()
aliases = target.get_aliaslist()
- if not mesonlib.is_windows():
- for alias in aliases:
- aliasfile = os.path.join(self.environment.get_build_dir(), outdir, alias)
- try:
- os.remove(aliasfile)
- except Exception:
- pass
+ for alias in aliases:
+ aliasfile = os.path.join(self.environment.get_build_dir(), outdir, alias)
+ try:
+ os.remove(aliasfile)
+ except Exception:
+ pass
+ try:
os.symlink(basename, aliasfile)
- else:
- mlog.debug("Library versioning disabled because host does not support symlinks.")
+ except NotImplementedError:
+ mlog.debug("Library versioning disabled because symlinks are not supported.")
+ except OSError:
+ mlog.debug("Library versioning disabled because we do not have symlink creation privileges.")
def generate_gcov_clean(self, outfile):
- gcno_elem = NinjaBuildElement('clean-gcno', 'CUSTOM_COMMAND', 'PHONY')
+ gcno_elem = NinjaBuildElement(self.all_outputs, 'clean-gcno', 'CUSTOM_COMMAND', 'PHONY')
script_root = self.environment.get_script_dir()
clean_script = os.path.join(script_root, 'delwithsuffix.py')
gcno_elem.add_item('COMMAND', [sys.executable, clean_script, '.', 'gcno'])
gcno_elem.add_item('description', 'Deleting gcno files')
gcno_elem.write(outfile)
- self.check_outputs(gcno_elem)
- gcda_elem = NinjaBuildElement('clean-gcda', 'CUSTOM_COMMAND', 'PHONY')
+ gcda_elem = NinjaBuildElement(self.all_outputs, 'clean-gcda', 'CUSTOM_COMMAND', 'PHONY')
script_root = self.environment.get_script_dir()
clean_script = os.path.join(script_root, 'delwithsuffix.py')
gcda_elem.add_item('COMMAND', [sys.executable, clean_script, '.', 'gcda'])
gcda_elem.add_item('description', 'Deleting gcda files')
gcda_elem.write(outfile)
- self.check_outputs(gcda_elem)
def is_compilable_file(self, filename):
if filename.endswith('.cpp') or\
@@ -1777,9 +1767,8 @@ rule FORTRAN_DEP_HACK
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(outfilename, rule.name, infilename)
+ elem = NinjaBuildElement(self.all_outputs, outfilename, rule.name, infilename)
elem.write(outfile)
- self.check_outputs(elem)
if self.is_compilable_file(outfilename):
src_deps.append(outfilename)
else:
@@ -1790,9 +1779,8 @@ rule FORTRAN_DEP_HACK
targetlist = [self.get_target_filename(t) for t in self.build.get_targets().values()\
if not isinstance(t, build.RunTarget)]
- elem = NinjaBuildElement('all', 'phony', targetlist)
+ elem = NinjaBuildElement(self.all_outputs, 'all', 'phony', targetlist)
elem.write(outfile)
- self.check_outputs(elem)
default = 'default all\n\n'
outfile.write(default)
@@ -1800,7 +1788,7 @@ rule FORTRAN_DEP_HACK
ninja_command = environment.detect_ninja()
if ninja_command is None:
raise MesonException('Could not detect ninja command')
- elem = NinjaBuildElement('clean', 'CUSTOM_COMMAND', 'PHONY')
+ elem = NinjaBuildElement(self.all_outputs, 'clean', 'CUSTOM_COMMAND', 'PHONY')
elem.add_item('COMMAND', [ninja_command, '-t', 'clean'])
elem.add_item('description', 'Cleaning')
if self.environment.coredata.get_builtin_option('coverage'):
@@ -1808,13 +1796,11 @@ rule FORTRAN_DEP_HACK
elem.add_dep('clean-gcda')
elem.add_dep('clean-gcno')
elem.write(outfile)
- self.check_outputs(elem)
deps = self.get_regen_filelist()
- elem = NinjaBuildElement('build.ninja', 'REGENERATE_BUILD', deps)
+ elem = NinjaBuildElement(self.all_outputs, 'build.ninja', 'REGENERATE_BUILD', deps)
elem.add_item('pool', 'console')
elem.write(outfile)
- elem = NinjaBuildElement(deps, 'phony', '')
+ elem = NinjaBuildElement(self.all_outputs, deps, 'phony', '')
elem.write(outfile)
- self.check_outputs(elem)
diff --git a/mesonbuild/vs2010backend.py b/mesonbuild/backend/vs2010backend.py
index 33e9646..fc241e3 100644
--- a/mesonbuild/vs2010backend.py
+++ b/mesonbuild/backend/vs2010backend.py
@@ -1,4 +1,4 @@
-# Copyright 2014-2015 The Meson development team
+# Copyright 2014-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.
@@ -14,12 +14,13 @@
import os, sys
import pickle
-from . import backends, build
-from . import dependencies
-from . import mlog
+from . import backends
+from .. import build
+from .. import dependencies
+from .. import mlog
import xml.etree.ElementTree as ET
import xml.dom.minidom
-from .coredata import MesonException
+from ..coredata import MesonException
class RegenInfo():
def __init__(self, source_dir, build_dir, depfiles, solutionfile):
@@ -36,8 +37,10 @@ class Vs2010Backend(backends.Backend):
self.source_suffix_in_obj = False
def generate_custom_generator_commands(self, target, parent_node):
- idgroup = ET.SubElement(parent_node, 'ItemDefinitionGroup')
all_output_files = []
+ commands = []
+ inputs = []
+ outputs = []
for genlist in target.get_generated_sources():
if isinstance(genlist, build.CustomTarget):
all_output_files += [os.path.join(self.get_target_dir(genlist), i) for i in genlist.output]
@@ -49,7 +52,7 @@ class Vs2010Backend(backends.Backend):
if isinstance(exe, build.BuildTarget):
exe_file = os.path.join(self.environment.get_build_dir(), self.get_target_filename(exe))
else:
- exe_file = exe.get_command()
+ exe_file = exe.get_command()[0]
base_args = generator.get_arglist()
for i in range(len(infilelist)):
if len(infilelist) == len(outfilelist):
@@ -66,13 +69,18 @@ class Vs2010Backend(backends.Backend):
args = [x.replace("@SOURCE_DIR@", self.environment.get_source_dir()).replace("@BUILD_DIR@", self.get_target_private_dir(target))
for x in args]
fullcmd = [exe_file] + args
- cbs = ET.SubElement(idgroup, 'CustomBuildStep')
- ET.SubElement(cbs, 'Command').text = ' '.join(self.special_quote(fullcmd))
- ET.SubElement(cbs, 'Inputs').text = infilename
- ET.SubElement(cbs, 'Outputs').text = ';'.join(outfiles)
- ET.SubElement(cbs, 'Message').text = 'Generating sources from %s.' % infilename
- pg = ET.SubElement(parent_node, 'PropertyGroup')
- ET.SubElement(pg, 'CustomBuildBeforeTargets').text = 'ClCompile'
+ commands.append(' '.join(self.special_quote(fullcmd)))
+ inputs.append(infilename)
+ outputs.extend(outfiles)
+ if len(commands) > 0:
+ idgroup = ET.SubElement(parent_node, 'ItemDefinitionGroup')
+ cbs = ET.SubElement(idgroup, 'CustomBuildStep')
+ ET.SubElement(cbs, 'Command').text = '\r\n'.join(commands)
+ ET.SubElement(cbs, 'Inputs').text = ";".join(inputs)
+ ET.SubElement(cbs, 'Outputs').text = ';'.join(outputs)
+ ET.SubElement(cbs, 'Message').text = 'Generating custom sources.'
+ pg = ET.SubElement(parent_node, 'PropertyGroup')
+ ET.SubElement(pg, 'CustomBuildBeforeTargets').text = 'ClCompile'
return all_output_files
def generate(self, interp):
@@ -205,12 +213,15 @@ class Vs2010Backend(backends.Backend):
def split_sources(self, srclist):
sources = []
headers = []
+ objects = []
for i in srclist:
if self.environment.is_header(i):
headers.append(i)
+ elif self.environment.is_object(i):
+ objects.append(i)
else:
sources.append(i)
- return (sources, headers)
+ return (sources, headers, objects)
def target_to_build_root(self, target):
if target.subdir == '':
@@ -322,7 +333,7 @@ class Vs2010Backend(backends.Backend):
down = self.target_to_build_root(target)
proj_to_src_root = os.path.join(down, self.build_to_src)
proj_to_src_dir = os.path.join(proj_to_src_root, target.subdir)
- (sources, headers) = self.split_sources(target.sources)
+ (sources, headers, objects) = self.split_sources(target.sources)
buildtype = self.buildtype
project_name = target.name
target_name = target.name
@@ -355,7 +366,7 @@ class Vs2010Backend(backends.Backend):
ET.SubElement(type_config, 'UseDebugLibraries').text = 'true'
ET.SubElement(root, 'Import', Project='$(VCTargetsPath)\Microsoft.Cpp.props')
generated_files = self.generate_custom_generator_commands(target, root)
- (gen_src, gen_hdrs) = self.split_sources(generated_files)
+ (gen_src, gen_hdrs, gen_objs) = self.split_sources(generated_files)
direlem = ET.SubElement(root, 'PropertyGroup')
fver = ET.SubElement(direlem, '_ProjectFileVersion')
fver.text = self.project_file_version
@@ -482,6 +493,13 @@ class Vs2010Backend(backends.Backend):
for s in gen_src:
relpath = self.relpath(s, target.subdir)
ET.SubElement(inc_src, 'CLCompile', Include=relpath)
+ if len(objects) > 0:
+ # Do not add gen_objs to project file. Those are automatically used by MSBuild, because they are part of
+ # the CustomBuildStep Outputs.
+ inc_objs = ET.SubElement(root, 'ItemGroup')
+ for s in objects:
+ relpath = s.rel_to_builddir(proj_to_src_root)
+ ET.SubElement(inc_objs, 'Object', Include=relpath)
ET.SubElement(root, 'Import', Project='$(VCTargetsPath)\Microsoft.Cpp.targets')
# Reference the regen target.
ig = ET.SubElement(root, 'ItemGroup')
@@ -542,11 +560,13 @@ class Vs2010Backend(backends.Backend):
ET.SubElement(midl, 'TypeLibraryName').text = '%(Filename).tlb'
ET.SubElement(midl, 'InterfaceIdentifierFilename').text = '%(Filename)_i.c'
ET.SubElement(midl, 'ProxyFileName').text = '%(Filename)_p.c'
- script_root = self.environment.get_script_dir()
- regen_script = os.path.join(script_root, 'regen_checker.py')
+ regen_command = [sys.executable,
+ self.environment.get_build_command(),
+ '--internal',
+ 'regencheck']
private_dir = self.environment.get_scratch_dir()
cmd_templ = '''setlocal
-"%s" "%s" "%s"
+"%s" "%s"
if %%errorlevel%% neq 0 goto :cmEnd
:cmEnd
endlocal & call :cmErrorLevel %%errorlevel%% & goto :cmDone
@@ -559,7 +579,7 @@ if %%errorlevel%% neq 0 goto :VCEnd'''
message = ET.SubElement(custombuild, 'Message')
message.text = 'Checking whether solution needs to be regenerated.'
ET.SubElement(custombuild, 'Command').text = cmd_templ % \
- (sys.executable, regen_script, private_dir)
+ ('" "'.join(regen_command), private_dir)
ET.SubElement(custombuild, 'Outputs').text = os.path.join(self.environment.get_scratch_dir(), 'regen.stamp')
deps = self.get_regen_filelist()
depstr = ';'.join([os.path.join(self.environment.get_source_dir(), d) for d in deps])
@@ -616,11 +636,13 @@ if %%errorlevel%% neq 0 goto :VCEnd'''
ET.SubElement(midl, 'ProxyFileName').text = '%(Filename)_p.c'
postbuild = ET.SubElement(action, 'PostBuildEvent')
ET.SubElement(postbuild, 'Message')
- script_root = self.environment.get_script_dir()
- test_script = os.path.join(script_root, 'meson_test.py')
test_data = os.path.join(self.environment.get_scratch_dir(), 'meson_test_setup.dat')
+ test_command = [sys.executable,
+ self.environment.get_build_command(),
+ '--internal',
+ 'test']
cmd_templ = '''setlocal
-"%s" "%s" "%s"
+"%s" "%s"
if %%errorlevel%% neq 0 goto :cmEnd
:cmEnd
endlocal & call :cmErrorLevel %%errorlevel%% & goto :cmDone
@@ -628,7 +650,8 @@ endlocal & call :cmErrorLevel %%errorlevel%% & goto :cmDone
exit /b %%1
:cmDone
if %%errorlevel%% neq 0 goto :VCEnd'''
- ET.SubElement(postbuild, 'Command').text = cmd_templ % (sys.executable, test_script, test_data)
+ ET.SubElement(postbuild, 'Command').text =\
+ cmd_templ % ('" "'.join(test_command), test_data)
ET.SubElement(root, 'Import', Project='$(VCTargetsPath)\Microsoft.Cpp.targets')
tree = ET.ElementTree(root)
tree.write(ofname, encoding='utf-8', xml_declaration=True)
diff --git a/mesonbuild/xcodebackend.py b/mesonbuild/backend/xcodebackend.py
index 8ac3f67..d874be9 100644
--- a/mesonbuild/xcodebackend.py
+++ b/mesonbuild/backend/xcodebackend.py
@@ -1,4 +1,4 @@
-# Copyright 2014 The Meson development team
+# Copyright 2014-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.
@@ -12,11 +12,12 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-from . import backends, build
-from . import mesonlib
+from . import backends
+from .. import build
+from .. import mesonlib
import uuid, os, sys
-from .coredata import MesonException
+from ..coredata import MesonException
class XCodeBackend(backends.Backend):
def __init__(self, build):
diff --git a/mesonbuild/build.py b/mesonbuild/build.py
index c0ba895..f9e628d 100644
--- a/mesonbuild/build.py
+++ b/mesonbuild/build.py
@@ -808,6 +808,8 @@ class CustomTarget:
if not isinstance(s, str):
raise InvalidArguments('Array as argument %d contains a non-string.' % i)
final_cmd.append(s)
+ elif isinstance(c, File):
+ final_cmd.append(os.path.join(c.subdir, c.fname))
else:
raise InvalidArguments('Argument %s in "command" is invalid.' % i)
self.command = final_cmd
diff --git a/mesonbuild/compilers.py b/mesonbuild/compilers.py
index ec0181e..3d2f2b3 100644
--- a/mesonbuild/compilers.py
+++ b/mesonbuild/compilers.py
@@ -61,7 +61,7 @@ gnulike_buildtype_args = {'plain' : [],
msvc_buildtype_args = {'plain' : [],
'debug' : ["/MDd", "/ZI", "/Ob0", "/Od", "/RTC1"],
- 'debugoptimized' : ["/MD", "/Zi", "/O2", "/Ob1", "/D"],
+ 'debugoptimized' : ["/MD", "/Zi", "/O2", "/Ob1"],
'release' : ["/MD", "/O2", "/Ob2"]}
gnulike_buildtype_linker_args = {}
@@ -184,7 +184,10 @@ class Compiler():
def has_function(self, *args, **kwargs):
raise EnvironmentException('Language %s does not support function checks.' % self.language)
- def unixtype_flags_to_native(self, args):
+ def unix_link_flags_to_native(self, args):
+ return args
+
+ def unix_compile_flags_to_native(self, args):
return args
class CCompiler(Compiler):
@@ -437,7 +440,13 @@ int someSymbolHereJustForFun;
se = se.decode()
mlog.debug('Program stdout:\n', so)
mlog.debug('Program stderr:\n', se)
- os.remove(exename)
+ try:
+ os.remove(exename)
+ except PermissionError:
+ # On Windows antivirus programs and the like hold
+ # on to files so they can't be deleted. There's not
+ # much to do in this case.
+ pass
return RunResult(True, pe.returncode, so, se)
def cross_sizeof(self, element, prefix, env, extra_args=[]):
@@ -890,6 +899,7 @@ class ValaCompiler(Compiler):
self.version = version
self.id = 'unknown'
self.language = 'vala'
+ self.is_cross = False
def name_string(self):
return ' '.join(self.exelist)
@@ -1122,7 +1132,7 @@ class VisualStudioCCompiler(CCompiler):
return ['/OUT:' + outputname]
def get_pic_args(self):
- return ['/LD']
+ return [] # PIC is handled by the loader on Windows
def get_std_shared_lib_link_args(self):
return ['/DLL']
@@ -1168,11 +1178,23 @@ class VisualStudioCCompiler(CCompiler):
def get_option_link_args(self, options):
return options['c_winlibs'].value
- def unixtype_flags_to_native(self, args):
+ def unix_link_flags_to_native(self, args):
result = []
for i in args:
if i.startswith('-L'):
i = '/LIBPATH:' + i[2:]
+ # Translate GNU-style -lfoo library name to the import library
+ if i.startswith('-l'):
+ i = i[2:] + '.lib'
+ result.append(i)
+ return result
+
+ def unix_compile_flags_to_native(self, args):
+ result = []
+ for i in args:
+ # -mms-bitfields is specific to MinGW-GCC
+ if i == '-mms-bitfields':
+ continue
result.append(i)
return result
@@ -1374,7 +1396,7 @@ class ClangCCompiler(CCompiler):
self.id = 'clang'
self.warn_args = {'1': ['-Wall', '-Winvalid-pch'],
'2': ['-Wall', '-Wextra', '-Winvalid-pch'],
- '3' : ['-Weverything']}
+ '3' : ['-Wall', '-Wpedantic', '-Wextra', '-Winvalid-pch']}
def get_buildtype_args(self, buildtype):
return gnulike_buildtype_args[buildtype]
@@ -1465,7 +1487,7 @@ class ClangCPPCompiler(CPPCompiler):
self.id = 'clang'
self.warn_args = {'1': ['-Wall', '-Winvalid-pch', '-Wnon-virtual-dtor'],
'2': ['-Wall', '-Wextra', '-Winvalid-pch', '-Wnon-virtual-dtor'],
- '3': ['-Weverything']}
+ '3': ['-Wall', '-Wpedantic', '-Wextra', '-Winvalid-pch', '-Wnon-virtual-dtor']}
def get_buildtype_args(self, buildtype):
return gnulike_buildtype_args[buildtype]
@@ -1793,15 +1815,24 @@ class VisualStudioLinker():
def get_option_link_args(self, options):
return []
- def unixtype_flags_to_native(self, args):
+ def unix_link_flags_to_native(self, args):
+ return args
+
+ def unix_compile_flags_to_native(self, args):
return args
class ArLinker():
- std_args = ['csr']
def __init__(self, exelist):
self.exelist = exelist
self.id = 'ar'
+ pc = subprocess.Popen(self.exelist + ['-h'], stdout=subprocess.PIPE, stderr=subprocess.DEVNULL)
+ (stdo, _) = pc.communicate()
+ # Enable deterministic builds if they are available.
+ if b'[D]' in stdo:
+ self.std_args = ['csrD']
+ else:
+ self.std_args = ['csr']
def build_rpath_args(self, build_dir, rpath_paths, install_rpath):
return []
@@ -1833,5 +1864,8 @@ class ArLinker():
def get_option_link_args(self, options):
return []
- def unixtype_flags_to_native(self, args):
+ def unix_link_flags_to_native(self, args):
+ return args
+
+ def unix_compile_flags_to_native(self, args):
return args
diff --git a/mesonbuild/coredata.py b/mesonbuild/coredata.py
index 7f2254b..0cfa279 100644
--- a/mesonbuild/coredata.py
+++ b/mesonbuild/coredata.py
@@ -1,4 +1,4 @@
-# Copyright 2012-2015 The Meson development team
+# 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.
@@ -14,7 +14,7 @@
import pickle, os, uuid
-version = '0.29.0.dev2'
+version = '0.30.0.dev1'
build_types = ['plain', 'debug', 'debugoptimized', 'release']
layouts = ['mirror', 'flat']
@@ -60,9 +60,9 @@ 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(newvalue), self.name))
+ 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 must be an absolute path.')
+ 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)
@@ -154,7 +154,6 @@ class CoreData():
self.compilers = {}
self.cross_compilers = {}
self.deps = {}
- self.ext_progs = {}
self.modules = {}
def init_builtins(self, options):
diff --git a/mesonbuild/dependencies.py b/mesonbuild/dependencies.py
index 974559f..b89bc11 100644
--- a/mesonbuild/dependencies.py
+++ b/mesonbuild/dependencies.py
@@ -72,6 +72,9 @@ class PkgConfigDependency(Dependency):
Dependency.__init__(self)
self.is_libtool = False
self.required = kwargs.get('required', True)
+ self.static = kwargs.get('static', False)
+ if not isinstance(self.static, bool):
+ raise DependencyException('Static keyword must be boolean')
if 'native' in kwargs and environment.is_cross_build():
want_cross = not kwargs['native']
else:
@@ -133,7 +136,10 @@ class PkgConfigDependency(Dependency):
(name, out.decode(errors='ignore')))
self.cargs = out.decode().split()
- p = subprocess.Popen([pkgbin, '--libs', name], stdout=subprocess.PIPE,
+ libcmd = [pkgbin, '--libs']
+ if self.static:
+ libcmd.append('--static')
+ p = subprocess.Popen(libcmd + [name], stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
out = p.communicate()[0]
if p.returncode != 0:
@@ -1074,7 +1080,7 @@ def get_dep_identifier(name, kwargs):
modlist = [modlist]
for module in modlist:
elements.append(module)
- return '/'.join(elements) + '/main' + str(kwargs.get('main', False))
+ return '/'.join(elements) + '/main' + str(kwargs.get('main', False)) + '/static' + str(kwargs.get('static', False))
def find_external_dependency(name, environment, kwargs):
required = kwargs.get('required', True)
diff --git a/mesonbuild/environment.py b/mesonbuild/environment.py
index 8df856c..369ca20 100644
--- a/mesonbuild/environment.py
+++ b/mesonbuild/environment.py
@@ -58,7 +58,7 @@ class Environment():
log_dir = 'meson-logs'
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):
+ 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))
self.source_dir = source_dir
@@ -80,6 +80,7 @@ class Environment():
else:
self.cross_info = None
self.cmd_line_options = options
+ self.original_cmd_line_args = original_cmd_line_args
# List of potential compilers.
if mesonlib.is_windows():
@@ -98,7 +99,12 @@ class Environment():
if (not cross and mesonlib.is_windows()) \
or (cross and self.cross_info.has_host() and self.cross_info.config['host_machine']['system'] == 'windows'):
self.exe_suffix = 'exe'
- self.import_lib_suffix = 'lib'
+ if self.detect_c_compiler(cross).get_id() == 'msvc':
+ self.import_lib_suffix = 'lib'
+ else:
+ # MinGW-GCC doesn't generate and can't link with a .lib
+ # It uses the DLL file as the import library
+ self.import_lib_suffix = 'dll'
self.shared_lib_suffix = 'dll'
self.shared_lib_prefix = ''
self.static_lib_suffix = 'lib'
@@ -148,6 +154,18 @@ class Environment():
def is_library(self, fname):
return is_library(fname)
+ def had_argument_for(self, option):
+ trial1 = '--' + option
+ trial2 = '-D' + option
+ previous_is_plaind = False
+ for i in self.original_cmd_line_args:
+ if i.startswith(trial1) or i.startswith(trial2):
+ return True
+ if previous_is_plaind and i.startswith(option):
+ return True
+ previous_is_plaind = i == '-D'
+ return False
+
def merge_options(self, options):
for (name, value) in options.items():
if name not in self.coredata.user_options:
@@ -546,7 +564,7 @@ class Environment():
def get_exe_suffix(self):
return self.exe_suffix
- # On Windows the library has suffix dll
+ # On Windows (MSVC) the library has suffix dll
# but you link against a file that has suffix lib.
def get_import_lib_suffix(self):
return self.import_lib_suffix
diff --git a/mesonbuild/interpreter.py b/mesonbuild/interpreter.py
index 4894ac7..b64eb7f 100644
--- a/mesonbuild/interpreter.py
+++ b/mesonbuild/interpreter.py
@@ -1,4 +1,4 @@
-# Copyright 2012-2015 The Meson development team
+# 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.
@@ -242,11 +242,15 @@ class ExternalProgramHolder(InterpreterObject):
def __init__(self, ep):
InterpreterObject.__init__(self)
self.held_object = ep
- self.methods.update({'found': self.found_method})
+ self.methods.update({'found': self.found_method,
+ 'path': self.path_method})
def found_method(self, args, kwargs):
return self.found()
+ def path_method(self, args, kwargs):
+ return self.get_command()
+
def found(self):
return self.held_object.found()
@@ -1327,7 +1331,7 @@ class Interpreter():
key, value = option.split('=', 1)
builtin_options = self.coredata.builtin_options
if key in builtin_options:
- if not hasattr(self.environment.cmd_line_options, value):
+ if not self.environment.had_argument_for(key):
self.coredata.set_builtin_option(key, value)
# If this was set on the command line, do not override.
else:
@@ -1360,16 +1364,15 @@ 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:])
+ self.add_languages(node, args[1:], True)
langs = self.coredata.compilers.keys()
if 'vala' in langs:
if not 'c' in langs:
raise InterpreterException('Compiling Vala requires C. Add C to your project languages and rerun Meson.')
- @noKwargs
@stringArgs
def func_add_languages(self, node, args, kwargs):
- self.add_languages(node, args)
+ return self.add_languages(node, args, kwargs.get('required', True))
@noKwargs
def func_message(self, node, args, kwargs):
@@ -1397,7 +1400,72 @@ class Interpreter():
self.validate_arguments(args, 1, [str])
raise InterpreterException('Error encountered: ' + args[0])
- def add_languages(self, node, args):
+ def detect_compilers(self, lang, need_cross_compiler):
+ cross_comp = None
+ if lang == 'c':
+ comp = self.environment.detect_c_compiler(False)
+ if need_cross_compiler:
+ cross_comp = self.environment.detect_c_compiler(True)
+ elif lang == 'cpp':
+ comp = self.environment.detect_cpp_compiler(False)
+ if need_cross_compiler:
+ cross_comp = self.environment.detect_cpp_compiler(True)
+ elif lang == 'objc':
+ comp = self.environment.detect_objc_compiler(False)
+ if need_cross_compiler:
+ cross_comp = self.environment.detect_objc_compiler(True)
+ elif lang == 'objcpp':
+ comp = self.environment.detect_objcpp_compiler(False)
+ if need_cross_compiler:
+ cross_comp = self.environment.detect_objcpp_compiler(True)
+ elif lang == 'java':
+ comp = self.environment.detect_java_compiler()
+ if need_cross_compiler:
+ cross_comp = comp # Java is platform independent.
+ elif lang == 'cs':
+ comp = self.environment.detect_cs_compiler()
+ if need_cross_compiler:
+ cross_comp = comp # C# is platform independent.
+ elif lang == 'vala':
+ comp = self.environment.detect_vala_compiler()
+ if need_cross_compiler:
+ cross_comp = comp # Vala is too (I think).
+ elif lang == 'rust':
+ comp = self.environment.detect_rust_compiler()
+ if need_cross_compiler:
+ cross_comp = comp # FIXME, probably not correct.
+ elif lang == 'fortran':
+ comp = self.environment.detect_fortran_compiler(False)
+ if need_cross_compiler:
+ cross_comp = self.environment.detect_fortran_compiler(True)
+ elif lang == 'swift':
+ comp = self.environment.detect_swift_compiler()
+ if need_cross_compiler:
+ raise InterpreterException('Cross compilation with Swift is not working yet.')
+ # cross_comp = self.environment.detect_fortran_compiler(True)
+ else:
+ raise InvalidCode('Tried to use unknown language "%s".' % lang)
+ comp.sanity_check(self.environment.get_scratch_dir())
+ self.coredata.compilers[lang] = comp
+ if cross_comp is not None:
+ cross_comp.sanity_check(self.environment.get_scratch_dir())
+ self.coredata.cross_compilers[lang] = cross_comp
+ new_options = comp.get_options()
+ optprefix = lang + '_'
+ for i in new_options:
+ if not i.startswith(optprefix):
+ raise InterpreterException('Internal error, %s has incorrect prefix.' % i)
+ cmd_prefix = i + '='
+ for cmd_arg in self.environment.cmd_line_options.projectoptions:
+ if cmd_arg.startswith(cmd_prefix):
+ value = cmd_arg.split('=', 1)[1]
+ new_options[i].set_value(value)
+ new_options.update(self.coredata.compiler_options)
+ self.coredata.compiler_options = new_options
+ return (comp, cross_comp)
+
+ def add_languages(self, node, args, required):
+ success = True
need_cross_compiler = self.environment.is_cross_build() and self.environment.cross_info.need_cross_compiler()
for lang in args:
lang = lang.lower()
@@ -1405,67 +1473,15 @@ class Interpreter():
comp = self.coredata.compilers[lang]
cross_comp = self.coredata.cross_compilers.get(lang, None)
else:
- cross_comp = None
- if lang == 'c':
- comp = self.environment.detect_c_compiler(False)
- if need_cross_compiler:
- cross_comp = self.environment.detect_c_compiler(True)
- elif lang == 'cpp':
- comp = self.environment.detect_cpp_compiler(False)
- if need_cross_compiler:
- cross_comp = self.environment.detect_cpp_compiler(True)
- elif lang == 'objc':
- comp = self.environment.detect_objc_compiler(False)
- if need_cross_compiler:
- cross_comp = self.environment.detect_objc_compiler(True)
- elif lang == 'objcpp':
- comp = self.environment.detect_objcpp_compiler(False)
- if need_cross_compiler:
- cross_comp = self.environment.detect_objcpp_compiler(True)
- elif lang == 'java':
- comp = self.environment.detect_java_compiler()
- if need_cross_compiler:
- cross_comp = comp # Java is platform independent.
- elif lang == 'cs':
- comp = self.environment.detect_cs_compiler()
- if need_cross_compiler:
- cross_comp = comp # C# is platform independent.
- elif lang == 'vala':
- comp = self.environment.detect_vala_compiler()
- if need_cross_compiler:
- cross_comp = comp # Vala is too (I think).
- elif lang == 'rust':
- comp = self.environment.detect_rust_compiler()
- if need_cross_compiler:
- cross_comp = comp # FIXME, probably not correct.
- elif lang == 'fortran':
- comp = self.environment.detect_fortran_compiler(False)
- if need_cross_compiler:
- cross_comp = self.environment.detect_fortran_compiler(True)
- elif lang == 'swift':
- comp = self.environment.detect_swift_compiler()
- if need_cross_compiler:
- raise InterpreterException('Cross compilation with Swift is not working yet.')
- #cross_comp = self.environment.detect_fortran_compiler(True)
- else:
- raise InvalidCode('Tried to use unknown language "%s".' % lang)
- comp.sanity_check(self.environment.get_scratch_dir())
- self.coredata.compilers[lang] = comp
- if cross_comp is not None:
- cross_comp.sanity_check(self.environment.get_scratch_dir())
- self.coredata.cross_compilers[lang] = cross_comp
- new_options = comp.get_options()
- optprefix = lang + '_'
- for i in new_options:
- if not i.startswith(optprefix):
- raise InterpreterException('Internal error, %s has incorrect prefix.' % i)
- cmd_prefix = i + '='
- for cmd_arg in self.environment.cmd_line_options.projectoptions:
- if cmd_arg.startswith(cmd_prefix):
- value = cmd_arg.split('=', 1)[1]
- new_options[i].set_value(value)
- new_options.update(self.coredata.compiler_options)
- self.coredata.compiler_options = new_options
+ try:
+ (comp, cross_comp) = self.detect_compilers(lang, need_cross_compiler)
+ except Exception:
+ if not required:
+ mlog.log('Compiler for language', mlog.bold(lang), 'not found.')
+ success = False
+ continue
+ else:
+ raise
mlog.log('Native %s compiler: ' % lang, mlog.bold(' '.join(comp.get_exelist())), ' (%s %s)' % (comp.id, comp.version), sep='')
if not comp.get_language() in self.coredata.external_args:
(ext_compile_args, ext_link_args) = environment.get_args_from_envvars(comp.get_language())
@@ -1477,6 +1493,7 @@ class Interpreter():
self.build.add_cross_compiler(cross_comp)
if self.environment.is_cross_build() and not need_cross_compiler:
self.build.add_cross_compiler(comp)
+ return success
def func_find_program(self, node, args, kwargs):
self.validate_arguments(args, 1, [str])
@@ -1484,14 +1501,12 @@ class Interpreter():
if not isinstance(required, bool):
raise InvalidArguments('"required" argument must be a boolean.')
exename = args[0]
- if exename in self.coredata.ext_progs and\
- self.coredata.ext_progs[exename].found():
- return ExternalProgramHolder(self.coredata.ext_progs[exename])
# Search for scripts relative to current subdir.
+ # Do not cache found programs because find_program('foobar')
+ # might give different results when run from different source dirs.
search_dir = os.path.join(self.environment.get_source_dir(), self.subdir)
extprog = dependencies.ExternalProgram(exename, search_dir=search_dir)
progobj = ExternalProgramHolder(extprog)
- self.coredata.ext_progs[exename] = extprog
if required and not progobj.found():
raise InvalidArguments('Program "%s" not found.' % exename)
return progobj
@@ -1805,6 +1820,8 @@ class Interpreter():
raise InterpreterException('Input must be a string.')
if not isinstance(output, str):
raise InterpreterException('Output must be a string.')
+ if os.path.split(output)[0] != '':
+ raise InterpreterException('Output file name must not contain a subdirectory.')
if 'configuration' in kwargs:
conf = kwargs['configuration']
if not isinstance(conf, ConfigurationDataHolder):
@@ -2019,6 +2036,11 @@ class Interpreter():
if method_name == 'startswith':
return obj.startswith(s)
return obj.endswith(s)
+ elif method_name == 'to_int':
+ try:
+ return int(obj)
+ except Exception:
+ raise InterpreterException('String can not be converted to int: ' + obj)
raise InterpreterException('Unknown method "%s" for a string.' % method_name)
def to_native(self, arg):
@@ -2176,8 +2198,16 @@ class Interpreter():
return val1 == val2
elif node.ctype == '!=':
return val1 != val2
+ elif node.ctype == '<':
+ return val1 < val2
+ elif node.ctype == '<=':
+ return val1 <= val2
+ elif node.ctype == '>':
+ return val1 > val2
+ elif node.ctype == '>=':
+ return val1 >= val2
else:
- raise InvalidCode('You broke me.')
+ raise InvalidCode('You broke my compare eval.')
def evaluate_andstatement(self, cur):
l = self.evaluate_statement(cur.left)
diff --git a/mesonbuild/mconf.py b/mesonbuild/mconf.py
index f174425..03cbe55 100644
--- a/mesonbuild/mconf.py
+++ b/mesonbuild/mconf.py
@@ -123,6 +123,7 @@ class Conf:
booleans = '[true, false]'
carr.append(['buildtype', 'Build type', self.coredata.get_builtin_option('buildtype'), build_types])
carr.append(['warning_level', 'Warning level', self.coredata.get_builtin_option('warning_level'), warning_levels])
+ carr.append(['werror', 'Treat warnings as errors', self.coredata.get_builtin_option('werror'), booleans])
carr.append(['strip', 'Strip on install', self.coredata.get_builtin_option('strip'), booleans])
carr.append(['coverage', 'Coverage report', self.coredata.get_builtin_option('coverage'), booleans])
carr.append(['use_pch', 'Precompiled headers', self.coredata.get_builtin_option('use_pch'), booleans])
@@ -182,7 +183,7 @@ class Conf:
def run(args):
args = mesonlib.expand_arguments(args)
if not args:
- sys.exit(1)
+ args = [os.getcwd()]
options = parser.parse_args(args)
if len(options.directory) > 1:
print('%s <build directory>' % args[0])
diff --git a/mesonbuild/mesonlib.py b/mesonbuild/mesonlib.py
index a814567..a20ddf0 100644
--- a/mesonbuild/mesonlib.py
+++ b/mesonbuild/mesonlib.py
@@ -161,9 +161,13 @@ def version_compare(vstr1, vstr2):
def default_libdir():
try:
- archpath = subprocess.check_output(['dpkg-architecture', '-qDEB_HOST_MULTIARCH']).decode().strip()
- return 'lib/' + archpath
- except:
+ pc = subprocess.Popen(['dpkg-architecture', '-qDEB_HOST_MULTIARCH'],
+ stdout=subprocess.PIPE, stderr=subprocess.DEVNULL)
+ (stdo, _) = pc.communicate()
+ if pc.returncode == 0:
+ archpath = stdo.decode().strip()
+ return 'lib/' + archpath
+ except Exception:
pass
if os.path.isdir('/usr/lib64'):
return 'lib64'
diff --git a/mesonbuild/mesonmain.py b/mesonbuild/mesonmain.py
index dfeb06e..1a7b084 100644
--- a/mesonbuild/mesonmain.py
+++ b/mesonbuild/mesonmain.py
@@ -79,12 +79,20 @@ parser.add_argument('directories', nargs='*')
class MesonApp():
- def __init__(self, dir1, dir2, script_file, handshake, options):
+ def __init__(self, dir1, dir2, script_file, 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 must be an absolute path.')
+ raise RuntimeError('--prefix value \'{0}\' must be an absolute path: '.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.
+ if len(options.prefix) == 3 and options.prefix[1] == ':':
+ pass
+ else:
+ options.prefix = options.prefix[:-1]
self.meson_script_file = script_file
self.options = options
+ self.original_cmd_line_args = original_cmd_line_args
def has_build_file(self, dirname):
fname = os.path.join(dirname, environment.build_filename)
@@ -123,7 +131,7 @@ itself as required.'''
return (src_dir, build_dir)
def generate(self):
- env = environment.Environment(self.source_dir, self.build_dir, self.meson_script_file, self.options)
+ env = environment.Environment(self.source_dir, self.build_dir, self.meson_script_file, 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)
@@ -138,13 +146,13 @@ itself as required.'''
mlog.log('Build type:', mlog.bold('native build'))
b = build.Build(env)
if self.options.backend == 'ninja':
- from . import ninjabackend
+ from .backend import ninjabackend
g = ninjabackend.NinjaBackend(b)
elif self.options.backend == 'vs2010':
- from . import vs2010backend
+ from .backend import vs2010backend
g = vs2010backend.Vs2010Backend(b)
elif self.options.backend == 'xcode':
- from . import xcodebackend
+ from .backend import xcodebackend
g = xcodebackend.XCodeBackend(b)
else:
raise RuntimeError('Unknown backend "%s".' % self.options.backend)
@@ -246,7 +254,7 @@ def run(mainfile, args):
else:
mainfile = resolved
try:
- app = MesonApp(dir1, dir2, mainfile, handshake, options)
+ app = MesonApp(dir1, dir2, mainfile, handshake, options, sys.argv)
except Exception as e:
# Log directory does not exist, so just print
# to stdout.
diff --git a/mesonbuild/modules/gnome.py b/mesonbuild/modules/gnome.py
index a351694..1e55b55 100644
--- a/mesonbuild/modules/gnome.py
+++ b/mesonbuild/modules/gnome.py
@@ -20,63 +20,52 @@ import os, sys
import subprocess
from ..coredata import MesonException
from .. import mlog
-import xml.etree.ElementTree as ET
-from ..mesonlib import File
girwarning_printed = False
class GnomeModule:
def compile_resources(self, state, args, kwargs):
- cmd = ['glib-compile-resources', '@INPUT@', '--generate']
- if 'source_dir' in kwargs:
- resource_loc = os.path.join(state.subdir, kwargs.pop('source_dir'))
- d = os.path.join(state.build_to_src, resource_loc)
- cmd += ['--sourcedir', d]
- else:
- resource_loc = state.subdir
+ cmd = ['glib-compile-resources', '@INPUT@']
+
+ source_dirs = kwargs.pop('source_dir', [])
+ if not isinstance(source_dirs, list):
+ source_dirs = [source_dirs]
+
+ kwargs['depend_files'] = self.get_gresource_dependencies(state, args[1], source_dirs)
+
+ for source_dir in source_dirs:
+ sourcedir = os.path.join(state.build_to_src, state.subdir, source_dir)
+ cmd += ['--sourcedir', sourcedir]
+
if 'c_name' in kwargs:
cmd += ['--c-name', kwargs.pop('c_name')]
- cmd += ['--target', '@OUTPUT@']
+ cmd += ['--generate', '--target', '@OUTPUT@']
+
kwargs['command'] = cmd
- output_c = args[0] + '.c'
- output_h = args[0] + '.h'
- resfile = args[1]
- kwargs['depend_files'] = self.parse_gresource_xml(state, resfile, resource_loc)
- kwargs['input'] = resfile
- kwargs['output'] = output_c
- target_c = build.CustomTarget(args[0]+'_c', state.subdir, kwargs)
- kwargs['output'] = output_h
+ kwargs['input'] = args[1]
+ kwargs['output'] = args[0] + '.c'
+ target_c = build.CustomTarget(args[0] + '_c', state.subdir, kwargs)
+ kwargs['output'] = args[0] + '.h'
target_h = build.CustomTarget(args[0] + '_h', state.subdir, kwargs)
return [target_c, target_h]
- def parse_gresource_xml(self, state, fobj, resource_loc):
- if isinstance(fobj, File):
- fname = fobj.fname
- subdir = fobj.subdir
- else:
- fname = fobj
- subdir = state.subdir
- abspath = os.path.join(state.environment.source_dir, state.subdir, fname)
- relative_part = os.path.split(fname)[0]
- try:
- tree = ET.parse(abspath)
- root = tree.getroot()
- result = []
- for child in root[0]:
- if child.tag != 'file':
- mlog.log("Warning, malformed rcc file: ", os.path.join(state.subdir, fname))
- break
- else:
- relfname = os.path.join(resource_loc, child.text)
- absfname = os.path.join(state.environment.source_dir, relfname)
- if os.path.isfile(absfname):
- result.append(relfname)
- else:
- mlog.log('Warning, resource file points to nonexisting file %s.' % relfname)
- return result
- except Exception:
- return []
+ def get_gresource_dependencies(self, state, input_file, source_dirs):
+ cmd = ['glib-compile-resources',
+ os.path.join(state.subdir, input_file),
+ '--generate-dependencies']
+
+ for source_dir in source_dirs:
+ cmd += ['--sourcedir', os.path.join(state.subdir, source_dir)]
+
+ pc = subprocess.Popen(cmd, stdout=subprocess.PIPE, universal_newlines=True,
+ cwd=state.environment.get_source_dir())
+ (stdout, _) = pc.communicate()
+ if pc.returncode != 0:
+ mlog.log(mlog.bold('Warning:'), 'glib-compile-resources has failed to get the dependencies for {}'.format(cmd[1]))
+ raise subprocess.CalledProcessError(pc.returncode, cmd)
+
+ return stdout.split('\n')[:-1]
def generate_gir(self, state, args, kwargs):
if len(args) != 1:
@@ -203,7 +192,7 @@ class GnomeModule:
scankwargs['install'] = kwargs['install']
scankwargs['install_dir'] = os.path.join(state.environment.get_datadir(), 'gir-1.0')
scan_target = GirTarget(girfile, state.subdir, scankwargs)
-
+
typelib_output = '%s-%s.typelib' % (ns, nsversion)
typelib_cmd = ['g-ir-compiler', scan_target, '--output', '@OUTPUT@']
if inc_dirs:
@@ -317,7 +306,7 @@ class GnomeModule:
return build.CustomTarget(namebase + '-gdbus', state.subdir, custom_kwargs)
def initialize():
- mlog.log('Warning, glib compiled dependencies will not work until this upstream issue is fixed:',
+ mlog.log('Warning, glib compiled dependencies will not work reliably until this upstream issue is fixed:',
mlog.bold('https://bugzilla.gnome.org/show_bug.cgi?id=745754'))
return GnomeModule()
diff --git a/mesonbuild/modules/qt5.py b/mesonbuild/modules/qt5.py
index 81edc76..cb743a6 100644
--- a/mesonbuild/modules/qt5.py
+++ b/mesonbuild/modules/qt5.py
@@ -157,6 +157,6 @@ class Qt5Module():
return sources
def initialize():
- mlog.log('Warning, rcc dependencies will not work properly until this upstream issue is fixed:',
+ mlog.log('Warning, rcc dependencies will not work reliably until this upstream issue is fixed:',
mlog.bold('https://bugreports.qt.io/browse/QTBUG-45460'))
return Qt5Module()
diff --git a/mesonbuild/mparser.py b/mesonbuild/mparser.py
index 1d569d5..090684c 100644
--- a/mesonbuild/mparser.py
+++ b/mesonbuild/mparser.py
@@ -1,4 +1,4 @@
-# Copyright 2014-2015 The Meson development team
+# Copyright 2014-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.
@@ -63,6 +63,10 @@ class Lexer:
('equal', re.compile(r'==')),
('nequal', re.compile(r'\!=')),
('assign', re.compile(r'=')),
+ ('le', re.compile(r'<=')),
+ ('lt', re.compile(r'<')),
+ ('ge', re.compile(r'>=')),
+ ('gt', re.compile(r'>')),
]
def lex(self, code):
@@ -313,6 +317,14 @@ class ArgumentNode():
def __len__(self):
return self.num_args() # Fixme
+comparison_map = {'equal': '==',
+ 'nequal': '!=',
+ 'lt': '<',
+ 'le': '<=',
+ 'gt': '>',
+ 'ge': '>='
+ }
+
# Recursive descent parser for Meson's definition language.
# Very basic apart from the fact that we have many precedence
# levels so there are not enough words to describe them all.
@@ -387,10 +399,9 @@ class Parser:
def e4(self):
left = self.e5()
- if self.accept('equal'):
- return ComparisonNode(left.lineno, left.colno, '==', left, self.e5())
- if self.accept('nequal'):
- return ComparisonNode(left.lineno, left.colno, '!=', left, self.e5())
+ for nodename, operator_type in comparison_map.items():
+ if self.accept(nodename):
+ return ComparisonNode(left.lineno, left.colno, operator_type, left, self.e5())
return left
def e5(self):
diff --git a/mesonbuild/scripts/meson_install.py b/mesonbuild/scripts/meson_install.py
index 1ede757..792af6c 100644
--- a/mesonbuild/scripts/meson_install.py
+++ b/mesonbuild/scripts/meson_install.py
@@ -125,7 +125,13 @@ def run_install_script(d):
final_command = commands + [script] + i.cmd_arr[1:]
else:
final_command = i.cmd_arr
- subprocess.check_call(final_command, env=child_env)
+ try:
+ rc = subprocess.call(final_command, env=child_env)
+ if rc != 0:
+ sys.exit(rc)
+ except Exception:
+ print('Failed to run install script:', i.cmd_arr[0])
+ sys.exit(1)
def is_elf_platform():
platname = platform.system().lower()
@@ -188,7 +194,7 @@ def install_targets(d):
except FileNotFoundError:
pass
os.symlink(os.path.split(fname)[-1], symlinkfilename)
- except NotImplementedError:
+ except (NotImplementedError, OSError):
if not printed_symlink_error:
print("Symlink creation does not work on this platform.")
printed_symlink_error = True
diff --git a/mesonbuild/scripts/meson_test.py b/mesonbuild/scripts/meson_test.py
index 03fd073..453ea61 100644
--- a/mesonbuild/scripts/meson_test.py
+++ b/mesonbuild/scripts/meson_test.py
@@ -19,6 +19,7 @@ import sys, os, subprocess, time, datetime, pickle, multiprocessing, json
import concurrent.futures as conc
import argparse
import platform
+import signal
def is_windows():
platname = platform.system().lower()
@@ -110,14 +111,28 @@ def run_single_test(wrap, test):
child_env.update(test.env)
if len(test.extra_paths) > 0:
child_env['PATH'] = child_env['PATH'] + ';'.join([''] + test.extra_paths)
- p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
- env=child_env, cwd=test.workdir)
+ if is_windows():
+ setsid = None
+ else:
+ setsid = os.setsid
+ p = subprocess.Popen(cmd,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE,
+ env=child_env,
+ cwd=test.workdir,
+ preexec_fn=setsid)
timed_out = False
try:
(stdo, stde) = p.communicate(timeout=test.timeout)
except subprocess.TimeoutExpired:
timed_out = True
- p.kill()
+ # Python does not provide multiplatform support for
+ # killing a process and all its children so we need
+ # to roll our own.
+ if is_windows():
+ subprocess.call(['taskkill', '/F', '/T', '/PID', str(p.pid)])
+ else:
+ os.killpg(os.getpgid(p.pid), signal.SIGKILL)
(stdo, stde) = p.communicate()
endtime = time.time()
duration = endtime - starttime
@@ -208,6 +223,7 @@ def run_tests(options, datafilename):
def run(args):
global tests_failed
+ tests_failed = [] # To avoid state leaks when invoked multiple times (running tests in-process)
options = parser.parse_args(args)
if len(options.args) != 1:
print('Test runner for Meson. Do not run on your own, mmm\'kay?')
diff --git a/mesonbuild/scripts/regen_checker.py b/mesonbuild/scripts/regen_checker.py
index f360a7c..a5e5fab 100644
--- a/mesonbuild/scripts/regen_checker.py
+++ b/mesonbuild/scripts/regen_checker.py
@@ -30,9 +30,14 @@ def need_regen(regeninfo):
def regen(regeninfo):
scriptdir = os.path.split(__file__)[0]
- mesonscript = os.path.join(scriptdir, 'meson.py')
- cmd = [sys.executable, mesonscript, regeninfo.build_dir, regeninfo.source_dir,
- '--backend=vs2010', 'secret-handshake']
+ mesonscript = os.path.join(scriptdir, '../../', 'meson')
+ cmd = [sys.executable,
+ mesonscript,
+ '--internal',
+ 'regenerate',
+ regeninfo.build_dir,
+ regeninfo.source_dir,
+ '--backend=vs2010']
subprocess.check_call(cmd)
def run(args):
diff --git a/mesonbuild/wrap/wrap.py b/mesonbuild/wrap/wrap.py
index 2818fa0..ad8f106 100644
--- a/mesonbuild/wrap/wrap.py
+++ b/mesonbuild/wrap/wrap.py
@@ -25,6 +25,8 @@ except ImportError:
has_ssl = False
API_ROOT = 'http://wrapdb.mesonbuild.com/v1/'
+ssl_warning_printed = False
+
def build_ssl_context():
ctx = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
ctx.options |= ssl.OP_NO_SSLv2
diff --git a/run_tests.py b/run_tests.py
index 2211949..d4c6ff2 100755
--- a/run_tests.py
+++ b/run_tests.py
@@ -207,8 +207,8 @@ def run_test(testdir, extra_args, should_succeed):
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
(o, e) = pc.communicate()
build_time = time.time() - build_start
- stdo += o.decode('utf-8')
- stde += e.decode('utf-8')
+ stdo += o.decode(sys.stdout.encoding)
+ stde += e.decode(sys.stdout.encoding)
if pc.returncode != 0:
return TestResult('Compiling source code failed.', stdo, stde, gen_time, build_time)
test_start = time.time()
@@ -230,8 +230,8 @@ def run_test(testdir, extra_args, should_succeed):
pi = subprocess.Popen(install_commands, cwd=test_build_dir, env=env,
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
(o, e) = pi.communicate()
- stdo += o.decode('utf-8')
- stde += e.decode('utf-8')
+ stdo += o.decode(sys.stdout.encoding)
+ stde += e.decode(sys.stdout.encoding)
if pi.returncode != 0:
return TestResult('Running install failed.', stdo, stde, gen_time, build_time, test_time)
return TestResult(validate_install(testdir, install_dir), stdo, stde, gen_time, build_time, test_time)
diff --git a/setup.py b/setup.py
index 49607ee..0ccd81f 100644
--- a/setup.py
+++ b/setup.py
@@ -34,6 +34,7 @@ setup(name='meson',
packages=['mesonbuild',
'mesonbuild.modules',
'mesonbuild.scripts',
+ 'mesonbuild.backend',
'mesonbuild.wrap'],
package_data={'mesonbuild': ['*.ui']},
scripts=['meson', 'mesonconf', 'mesongui', 'mesonintrospect', 'wraptool'],
diff --git a/test cases/common/105 find program path/meson.build b/test cases/common/105 find program path/meson.build
new file mode 100644
index 0000000..2ece2bc
--- /dev/null
+++ b/test cases/common/105 find program path/meson.build
@@ -0,0 +1,9 @@
+project('find program', 'c')
+
+prog = find_program('program.py')
+
+# Python 3 is guaranteed to be available because Meson
+# is implemented in it.
+python = find_program('python3')
+
+run_command(python, prog.path())
diff --git a/test cases/common/105 find program path/program.py b/test cases/common/105 find program path/program.py
new file mode 100644
index 0000000..2ebc564
--- /dev/null
+++ b/test cases/common/105 find program path/program.py
@@ -0,0 +1,3 @@
+#!/usr/bin/env python3
+
+print("Found")
diff --git a/test cases/common/42 string formatting/meson.build b/test cases/common/42 string formatting/meson.build
index 81f5268..39737f7 100644
--- a/test cases/common/42 string formatting/meson.build
+++ b/test cases/common/42 string formatting/meson.build
@@ -40,3 +40,5 @@ endif
if long.endswith(prefix)
error('Not suffix.')
endif
+
+assert('3'.to_int() == 3, 'String int conversion does not work.')
diff --git a/test cases/common/59 object generator/obj_generator.py b/test cases/common/59 object generator/obj_generator.py
index 6960059..204f1eb 100755
--- a/test cases/common/59 object generator/obj_generator.py
+++ b/test cases/common/59 object generator/obj_generator.py
@@ -12,7 +12,7 @@ if __name__ == '__main__':
ifile = sys.argv[2]
ofile = sys.argv[3]
if compiler.endswith('cl'):
- cmd = [compiler, '/nologo', '/Fo'+ofile, '/c', ifile]
+ cmd = [compiler, '/nologo', '/MDd', '/Fo'+ofile, '/c', ifile]
else:
cmd = [compiler, '-c', ifile, '-o', ofile]
sys.exit(subprocess.call(cmd))
diff --git a/test cases/common/60 install script/myinstall.sh b/test cases/common/60 install script/myinstall.sh
index 4739dee..42a415e 100755
--- a/test cases/common/60 install script/myinstall.sh
+++ b/test cases/common/60 install script/myinstall.sh
@@ -1,5 +1,7 @@
#!/bin/sh
+set -eu
+
echo Starting custom installation step
# These commands fail on Windows, but we don't really care.
diff --git a/test cases/common/68 number arithmetic/meson.build b/test cases/common/68 number arithmetic/meson.build
index 894c065..3872a11 100644
--- a/test cases/common/68 number arithmetic/meson.build
+++ b/test cases/common/68 number arithmetic/meson.build
@@ -20,3 +20,15 @@ endif
if (5 / 3) * 3 != 3
error('Integer division is broken')
endif
+
+assert(3 < 4, 'Lt broken')
+assert(not(4 < 3), 'Lt broken')
+assert(3 <= 4, 'Lte broken')
+assert(not(4 <= 3), 'Lte broken')
+assert(3 <= 3, 'Lte broken')
+
+assert(4 > 3, 'Gt broken')
+assert(not(3 > 4), 'Gt broken')
+assert(4 >= 3, 'Gte broken')
+assert(not(3 >= 4), 'Gte broken')
+assert(3 >= 3, 'Gte broken')
diff --git a/test cases/common/89 add language/meson.build b/test cases/common/89 add language/meson.build
index 339fe22..d9bc0fa 100644
--- a/test cases/common/89 add language/meson.build
+++ b/test cases/common/89 add language/meson.build
@@ -2,6 +2,7 @@ project('add language', 'c')
test('C', executable('cprog', 'prog.c'))
-add_languages('cpp')
+assert(add_languages('cpp'), 'Add_languages returned false on success')
+assert(not add_languages('klingon', required : false), 'Add_languages returned true on failure.')
test('C++', executable('cppprog', 'prog.cc'))
diff --git a/test cases/failing/25 int conversion/meson.build b/test cases/failing/25 int conversion/meson.build
new file mode 100644
index 0000000..51f6c7e
--- /dev/null
+++ b/test cases/failing/25 int conversion/meson.build
@@ -0,0 +1,3 @@
+project('int conversion', 'c')
+
+'notanumber'.to_int()
diff --git a/test cases/failing/26 badlang/meson.build b/test cases/failing/26 badlang/meson.build
new file mode 100644
index 0000000..f6bf0cc
--- /dev/null
+++ b/test cases/failing/26 badlang/meson.build
@@ -0,0 +1,3 @@
+project('badlang', 'c')
+
+add_languages('nonexisting')
diff --git a/test cases/failing/27 output subdir/foo.in b/test cases/failing/27 output subdir/foo.in
new file mode 100644
index 0000000..3d1bf19
--- /dev/null
+++ b/test cases/failing/27 output subdir/foo.in
@@ -0,0 +1 @@
+Nothing here.
diff --git a/test cases/failing/27 output subdir/meson.build b/test cases/failing/27 output subdir/meson.build
new file mode 100644
index 0000000..282d0b7
--- /dev/null
+++ b/test cases/failing/27 output subdir/meson.build
@@ -0,0 +1,5 @@
+project('outdir path', 'c')
+
+configure_file(input : 'foo.in',
+ output : 'subdir/foo',
+ configuration : configuration_data())
diff --git a/test cases/failing/27 output subdir/subdir/dummy.txt b/test cases/failing/27 output subdir/subdir/dummy.txt
new file mode 100644
index 0000000..f10acf3
--- /dev/null
+++ b/test cases/failing/27 output subdir/subdir/dummy.txt
@@ -0,0 +1,2 @@
+I'm only here because Git is stupid about empty dirs.
+
diff --git a/test cases/vala/7 shared library/lib/meson.build b/test cases/vala/7 shared library/lib/meson.build
new file mode 100644
index 0000000..8eca0d4
--- /dev/null
+++ b/test cases/vala/7 shared library/lib/meson.build
@@ -0,0 +1 @@
+l = shared_library('valalib', 'mylib.vala', dependencies : valadeps)
diff --git a/test cases/vala/7 shared library/lib/mylib.vala b/test cases/vala/7 shared library/lib/mylib.vala
new file mode 100644
index 0000000..5cc903b
--- /dev/null
+++ b/test cases/vala/7 shared library/lib/mylib.vala
@@ -0,0 +1,5 @@
+public class LibraryObject : Object {
+ public void func() {
+ stdout.printf("Method in library called.");
+ }
+}
diff --git a/test cases/vala/7 shared library/meson.build b/test cases/vala/7 shared library/meson.build
new file mode 100644
index 0000000..9c56f14
--- /dev/null
+++ b/test cases/vala/7 shared library/meson.build
@@ -0,0 +1,10 @@
+project('shared library', 'vala', 'c')
+
+valadeps = [dependency('glib-2.0'), dependency('gobject-2.0')]
+
+libinc = include_directories('lib')
+
+subdir('lib')
+subdir('prog')
+
+test('valasharedtest', e)
diff --git a/test cases/vala/7 shared library/prog/meson.build b/test cases/vala/7 shared library/prog/meson.build
new file mode 100644
index 0000000..2b842ea
--- /dev/null
+++ b/test cases/vala/7 shared library/prog/meson.build
@@ -0,0 +1,4 @@
+e = executable('valaprog', 'prog.vala',
+ link_with : l,
+ include_directories : libinc,
+ dependencies : valadeps)
diff --git a/test cases/vala/7 shared library/prog/prog.vala b/test cases/vala/7 shared library/prog/prog.vala
new file mode 100644
index 0000000..3c4a017
--- /dev/null
+++ b/test cases/vala/7 shared library/prog/prog.vala
@@ -0,0 +1,7 @@
+class MainApp : Object {
+ public static int main(string[] args) {
+ var l = new LibraryObject();
+ l.func();
+ return 0;
+ }
+}