aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md4
-rw-r--r--mesonbuild/backend/backends.py35
-rw-r--r--mesonbuild/backend/ninjabackend.py33
-rw-r--r--mesonbuild/backend/vs2010backend.py84
-rw-r--r--mesonbuild/build.py2
-rw-r--r--mesonbuild/compilers.py26
-rw-r--r--mesonbuild/environment.py36
-rw-r--r--mesonbuild/modules/pkgconfig.py15
-rw-r--r--mesonbuild/scripts/depfixer.py23
-rw-r--r--mesonbuild/scripts/meson_install.py18
-rwxr-xr-xrun_tests.py25
-rw-r--r--setup.py6
-rw-r--r--test cases/common/110 extract same name/lib.c3
-rw-r--r--test cases/common/110 extract same name/main.c6
-rw-r--r--test cases/common/110 extract same name/meson.build6
-rw-r--r--test cases/common/110 extract same name/src/lib.c3
-rw-r--r--test cases/common/51 pkgconfig-gen/meson.build5
-rw-r--r--test cases/failing/28 noprog use/meson.build9
18 files changed, 213 insertions, 126 deletions
diff --git a/README.md b/README.md
index bd166eb..82ee3f7 100644
--- a/README.md
+++ b/README.md
@@ -31,6 +31,10 @@ called 'meson.build'. To generate the build system run this command:
`meson <source directory> <build directory>`
+Depending on how you obtained Meson the command might also be called
+`meson.py` instead of plain `meson`. In the rest of this document we
+are going to use the latter form.
+
You can omit either of the two directories, and Meson will substitute
the current directory and autodetect what you mean. This allows you to
do things like this:
diff --git a/mesonbuild/backend/backends.py b/mesonbuild/backend/backends.py
index 8d0b0f6..313580b 100644
--- a/mesonbuild/backend/backends.py
+++ b/mesonbuild/backend/backends.py
@@ -21,12 +21,11 @@ import subprocess
from ..coredata import MesonException
class InstallData():
- def __init__(self, source_dir, build_dir, prefix, depfixer):
+ def __init__(self, source_dir, build_dir, prefix):
self.source_dir = source_dir
self.build_dir= build_dir
self.prefix = prefix
self.targets = []
- self.depfixer = depfixer
self.headers = []
self.man = []
self.data = []
@@ -142,7 +141,7 @@ class Backend():
return os.path.relpath(os.path.join('dummyprefixdir', todir),\
os.path.join('dummyprefixdir', fromdir))
- def flatten_object_list(self, target, proj_dir_to_build_root='', include_dir_names=True):
+ def flatten_object_list(self, target, proj_dir_to_build_root=''):
obj_list = []
for obj in target.get_objects():
if isinstance(obj, str):
@@ -150,7 +149,7 @@ class Backend():
self.build_to_src, target.get_subdir(), obj)
obj_list.append(o)
elif isinstance(obj, build.ExtractedObjects):
- obj_list += self.determine_ext_objs(obj, proj_dir_to_build_root, include_dir_names)
+ obj_list += self.determine_ext_objs(obj, proj_dir_to_build_root)
else:
raise MesonException('Unknown data type in object list.')
return obj_list
@@ -210,28 +209,21 @@ class Backend():
return c
raise RuntimeError('Unreachable code')
- def determine_ext_objs(self, extobj, proj_dir_to_build_root='', include_dir_names=True):
+ def object_filename_from_source(self, target, source):
+ return source.fname.replace('/', '_').replace('\\', '_') + '.' + self.environment.get_object_suffix()
+
+ def determine_ext_objs(self, extobj, proj_dir_to_build_root=''):
result = []
targetdir = self.get_target_private_dir(extobj.target)
- suffix = '.' + self.environment.get_object_suffix()
for osrc in extobj.srclist:
- osrc_base = osrc.fname
- if not self.source_suffix_in_objs:
- osrc_base = '.'.join(osrc.split('.')[:-1])
# If extracting in a subproject, the subproject
# name gets duplicated in the file name.
pathsegs = osrc.subdir.split(os.sep)
if pathsegs[0] == 'subprojects':
pathsegs = pathsegs[2:]
fixedpath = os.sep.join(pathsegs)
- if include_dir_names:
- objbase = osrc_base.replace('/', '_').replace('\\', '_')
- else:
- # vs2010 backend puts all obj files without directory prefixes into build dir, so just
- # use the file name without a directory (will be stripped by os.path.basename() below).
- objbase = osrc_base
- objname = os.path.join(proj_dir_to_build_root,
- targetdir, os.path.basename(objbase) + suffix)
+ objname = os.path.join(proj_dir_to_build_root, targetdir,
+ self.object_filename_from_source(extobj.target, osrc))
result.append(objname)
return result
@@ -388,6 +380,15 @@ class Backend():
exe_arr = exe.get_command()
return exe_arr
+ def replace_extra_args(self, args, genlist):
+ final_args = []
+ for a in args:
+ if a == '@EXTRA_ARGS@':
+ final_args += genlist.get_extra_args()
+ else:
+ final_args.append(a)
+ return final_args
+
def eval_custom_target_command(self, target, absolute_paths=False):
if not absolute_paths:
ofilenames = [os.path.join(self.get_target_dir(target), i) for i in target.output]
diff --git a/mesonbuild/backend/ninjabackend.py b/mesonbuild/backend/ninjabackend.py
index 29ce8cd..4757bd3 100644
--- a/mesonbuild/backend/ninjabackend.py
+++ b/mesonbuild/backend/ninjabackend.py
@@ -129,7 +129,6 @@ class NinjaBackend(backends.Backend):
def __init__(self, build):
super().__init__(build)
- self.source_suffix_in_objs = True
self.ninja_filename = 'build.ninja'
self.fortran_deps = {}
self.all_outputs = {}
@@ -137,7 +136,10 @@ class NinjaBackend(backends.Backend):
def detect_vs_dep_prefix(self, outfile, tempfilename):
'''VS writes its dependency in a locale dependent format.
Detect the search prefix to use.'''
- if shutil.which('cl') is None:
+ # Of course there is another program called 'cl' on
+ # some platforms. Let's just require that on Windows
+ # cl points to msvc.
+ if not mesonlib.is_windows() or shutil.which('cl') is None:
return outfile
outfile.close()
open(os.path.join(self.environment.get_scratch_dir(), 'incdetect.c'),
@@ -182,7 +184,8 @@ int dummy;
self.generate_tests(outfile)
outfile.write('# Install rules\n\n')
self.generate_install(outfile)
- if self.environment.coredata.base_options.get('b_coverage', False):
+ if 'b_coverage' in self.environment.coredata.base_options and \
+ self.environment.coredata.base_options['b_coverage'].value:
outfile.write('# Coverage rules\n\n')
self.generate_coverage_rules(outfile)
outfile.write('# Suffix\n\n')
@@ -234,7 +237,8 @@ int dummy;
self.generate_cs_target(target, outfile)
return
if 'vala' in self.environment.coredata.compilers.keys() and self.has_vala(target):
- vala_output_files = self.generate_vala_compile(target, outfile)
+ 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):
self.generate_swift_target(target, outfile)
@@ -443,10 +447,11 @@ int dummy;
phony_elem.write(outfile)
elem = NinjaBuildElement(self.all_outputs, 'coveragereport/index.html', 'CUSTOM_COMMAND', '')
+ htmloutdir = os.path.join(self.environment.get_log_dir(), 'coveragereport')
command = [lcov_exe, '--directory', self.environment.get_build_dir(),\
'--capture', '--output-file', 'coverage.info', '--no-checksum',\
'&&', genhtml_exe, '--prefix', self.environment.get_build_dir(),\
- '--output-directory', self.environment.get_log_dir(), '--title', 'Code coverage',\
+ '--output-directory', htmloutdir, '--title', 'Code coverage',\
'--legend', '--show-details', 'coverage.info']
elem.add_item('COMMAND', command)
elem.add_item('DESC', 'Generating HTML coverage report.')
@@ -458,10 +463,9 @@ int dummy;
script_root = self.environment.get_script_dir()
install_script = os.path.join(script_root, 'meson_install.py')
install_data_file = os.path.join(self.environment.get_scratch_dir(), 'install.dat')
- depfixer = [sys.executable, self.environment.get_build_command(), '--internal', 'depfixer']
d = InstallData(self.environment.get_source_dir(),
self.environment.get_build_dir(),
- self.environment.get_prefix(), depfixer)
+ self.environment.get_prefix())
elem = NinjaBuildElement(self.all_outputs, 'install', 'CUSTOM_COMMAND', 'PHONY')
elem.add_dep('all')
elem.add_item('DESC', 'Installing files.')
@@ -789,7 +793,7 @@ int dummy;
break
return result
- def generate_vala_compile(self, target, outfile):
+ def generate_vala_compile(self, compiler, 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())
@@ -809,7 +813,10 @@ int dummy;
generated_c_files = []
outputs = [vapiname]
- args = ['-d', self.get_target_private_dir(target)]
+ args = []
+ args += self.build.get_global_args(compiler)
+ args += compiler.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):
outputs.append(hname)
@@ -1349,13 +1356,7 @@ rule FORTRAN_DEP_HACK
relout = self.get_target_private_dir(target)
args = [x.replace("@SOURCE_DIR@", self.build_to_src).replace("@BUILD_DIR@", relout)
for x in args]
- final_args = []
- for a in args:
- if a == '@EXTRA_ARGS@':
- final_args += genlist.get_extra_args()
- else:
- final_args.append(a)
- cmdlist = exe_arr + final_args
+ cmdlist = exe_arr + self.replace_extra_args(args, genlist)
elem = NinjaBuildElement(self.all_outputs, outfiles, 'CUSTOM_COMMAND', infilename)
if len(extra_dependencies) > 0:
elem.add_dep(extra_dependencies)
diff --git a/mesonbuild/backend/vs2010backend.py b/mesonbuild/backend/vs2010backend.py
index 84ef8c3..ae4cd33 100644
--- a/mesonbuild/backend/vs2010backend.py
+++ b/mesonbuild/backend/vs2010backend.py
@@ -16,6 +16,8 @@ import os, sys
import pickle
from mesonbuild import compilers
+from mesonbuild.build import BuildTarget
+from mesonbuild.mesonlib import File
from . import backends
from .. import build
from .. import dependencies
@@ -35,8 +37,35 @@ class Vs2010Backend(backends.Backend):
def __init__(self, build):
super().__init__(build)
self.project_file_version = '10.0.30319.1'
- # foo.c compiles to foo.obj, not foo.c.obj
- self.source_suffix_in_objs = False
+ self.sources_conflicts = {}
+
+ def object_filename_from_source(self, target, source):
+ basename = os.path.basename(source.fname)
+ filename_without_extension = '.'.join(basename.split('.')[:-1])
+ if basename in self.sources_conflicts[target.get_id()]:
+ # If there are multiple source files with the same basename, we must resolve the conflict
+ # by giving each a unique object output file.
+ filename_without_extension = '.'.join(source.fname.split('.')[:-1]).replace('/', '_').replace('\\', '_')
+ return filename_without_extension + '.' + self.environment.get_object_suffix()
+
+ def resolve_source_conflicts(self):
+ for name, target in self.build.targets.items():
+ if not isinstance(target, BuildTarget):
+ continue
+ conflicts = {}
+ for s in target.get_sources():
+ if hasattr(s, 'held_object'):
+ s = s.held_object
+ if not isinstance(s, File):
+ continue
+ basename = os.path.basename(s.fname)
+ conflicting_sources = conflicts.get(basename, None)
+ if conflicting_sources is None:
+ conflicting_sources = []
+ conflicts[basename] = conflicting_sources
+ conflicting_sources.append(s)
+ self.sources_conflicts[target.get_id()] = {name: src_conflicts for name, src_conflicts in conflicts.items()
+ if len(src_conflicts) > 1}
def generate_custom_generator_commands(self, target, parent_node):
all_output_files = []
@@ -51,26 +80,24 @@ class Vs2010Backend(backends.Backend):
exe = generator.get_exe()
infilelist = genlist.get_infilelist()
outfilelist = genlist.get_outfilelist()
- 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()[0]
+ exe_arr = self.exe_object_to_cmd_array(exe)
base_args = generator.get_arglist()
+ target_private_dir = self.relpath(self.get_target_private_dir(target), self.get_target_dir(target))
for i in range(len(infilelist)):
if len(infilelist) == len(outfilelist):
- sole_output = os.path.join(self.get_target_private_dir(target), outfilelist[i])
+ sole_output = os.path.join(target_private_dir, outfilelist[i])
else:
sole_output = ''
curfile = infilelist[i]
infilename = os.path.join(self.environment.get_source_dir(), curfile)
outfiles = genlist.get_outputs_for(curfile)
- outfiles = [os.path.join(self.get_target_private_dir(target), of) for of in outfiles]
+ outfiles = [os.path.join(target_private_dir, of) for of in outfiles]
all_output_files += outfiles
args = [x.replace("@INPUT@", infilename).replace('@OUTPUT@', sole_output)\
for x in base_args]
- args = [x.replace("@SOURCE_DIR@", self.environment.get_source_dir()).replace("@BUILD_DIR@", self.get_target_private_dir(target))
+ args = [x.replace("@SOURCE_DIR@", self.environment.get_source_dir()).replace("@BUILD_DIR@", target_private_dir)
for x in args]
- fullcmd = [exe_file] + args
+ fullcmd = exe_arr + self.replace_extra_args(args, genlist)
commands.append(' '.join(self.special_quote(fullcmd)))
inputs.append(infilename)
outputs.extend(outfiles)
@@ -86,6 +113,7 @@ class Vs2010Backend(backends.Backend):
return all_output_files
def generate(self, interp):
+ self.resolve_source_conflicts()
self.interpreter = interp
self.platform = 'Win32'
self.buildtype = self.environment.coredata.get_builtin_option('buildtype')
@@ -421,11 +449,8 @@ class Vs2010Backend(backends.Backend):
clconf = ET.SubElement(compiles, 'ClCompile')
opt = ET.SubElement(clconf, 'Optimization')
opt.text = 'disabled'
- inc_dirs = [proj_to_src_dir, self.get_target_private_dir(target)]
- cur_dir = target.subdir
- if cur_dir == '':
- cur_dir= '.'
- inc_dirs.append(cur_dir)
+ inc_dirs = ['.', self.relpath(self.get_target_private_dir(target), self.get_target_dir(target)),
+ proj_to_src_dir]
extra_args = {'c': [], 'cpp': []}
for l, args in self.environment.coredata.external_args.items():
@@ -437,7 +462,7 @@ class Vs2010Backend(backends.Backend):
for l, args in target.extra_args.items():
if l in extra_args:
extra_args[l] += args
- general_args = compiler.get_buildtype_args(self.buildtype)
+ general_args = compiler.get_buildtype_args(self.buildtype).copy()
# FIXME all the internal flags of VS (optimization etc) are represented
# by their own XML elements. In theory we should split all flags to those
# that have an XML element and those that don't and serialise them
@@ -469,6 +494,10 @@ class Vs2010Backend(backends.Backend):
curdir = os.path.join(d.curdir, i)
inc_dirs.append(self.relpath(curdir, target.subdir)) # build dir
inc_dirs.append(os.path.join(proj_to_src_root, curdir)) # src dir
+ for i in d.get_extra_build_dirs():
+ curdir = os.path.join(d.curdir, i)
+ inc_dirs.append(self.relpath(curdir, target.subdir)) # build dir
+
inc_dirs.append('%(AdditionalIncludeDirectories)')
ET.SubElement(clconf, 'AdditionalIncludeDirectories').text = ';'.join(inc_dirs)
preproc = ET.SubElement(clconf, 'PreprocessorDefinitions')
@@ -519,13 +548,13 @@ class Vs2010Backend(backends.Backend):
ET.SubElement(link, "AdditionalOptions").text = ' '.join(extra_link_args)
additional_links = []
- for t in target.link_targets:
+ for t in target.get_dependencies():
lobj = self.build.targets[t.get_id()]
rel_path = self.relpath(lobj.subdir, target.subdir)
linkname = os.path.join(rel_path, lobj.get_import_filename())
additional_links.append(linkname)
additional_objects = []
- for o in self.flatten_object_list(target, down, include_dir_names=False):
+ for o in self.flatten_object_list(target, down):
assert(isinstance(o, str))
additional_objects.append(o)
if len(additional_links) > 0:
@@ -548,17 +577,18 @@ class Vs2010Backend(backends.Backend):
targetmachine = ET.SubElement(link, 'TargetMachine')
targetmachine.text = 'MachineX86'
- if len(headers) + len(gen_hdrs) > 0:
+ extra_files = target.extra_files
+ if len(headers) + len(gen_hdrs) + len(extra_files) > 0:
inc_hdrs = ET.SubElement(root, 'ItemGroup')
for h in headers:
relpath = h.rel_to_builddir(proj_to_src_root)
ET.SubElement(inc_hdrs, 'CLInclude', Include=relpath)
for h in gen_hdrs:
- if isinstance(h, str):
- relpath = h
- else:
- relpath = h.rel_to_builddir(proj_to_src_root)
- ET.SubElement(inc_hdrs, 'CLInclude', Include = relpath)
+ ET.SubElement(inc_hdrs, 'CLInclude', Include=h)
+ for h in target.extra_files:
+ relpath = os.path.join(proj_to_src_dir, h)
+ ET.SubElement(inc_hdrs, 'CLInclude', Include=relpath)
+
if len(sources) + len(gen_src) + len(pch_sources) > 0:
inc_src = ET.SubElement(root, 'ItemGroup')
for s in sources:
@@ -566,9 +596,11 @@ class Vs2010Backend(backends.Backend):
inc_cl = ET.SubElement(inc_src, 'CLCompile', Include=relpath)
self.add_pch(inc_cl, proj_to_src_dir, pch_sources, s)
self.add_additional_options(s, inc_cl, extra_args, additional_options_set)
+ basename = os.path.basename(s.fname)
+ if basename in self.sources_conflicts[target.get_id()]:
+ ET.SubElement(inc_cl, 'ObjectFileName').text = "$(IntDir)" + self.object_filename_from_source(target, s)
for s in gen_src:
- relpath = self.relpath(s, target.subdir)
- inc_cl = ET.SubElement(inc_src, 'CLCompile', Include=relpath)
+ inc_cl = ET.SubElement(inc_src, 'CLCompile', Include=s)
self.add_pch(inc_cl, proj_to_src_dir, pch_sources, s)
self.add_additional_options(s, inc_cl, extra_args, additional_options_set)
for lang in pch_sources:
diff --git a/mesonbuild/build.py b/mesonbuild/build.py
index 8732987..2a91aa3 100644
--- a/mesonbuild/build.py
+++ b/mesonbuild/build.py
@@ -849,6 +849,8 @@ class CustomTarget:
if isinstance(c, str):
final_cmd.append(c)
elif isinstance(c, dependencies.ExternalProgram):
+ if not c.found():
+ raise InvalidArguments('Tried to use not found external program in a build rule.')
final_cmd += c.get_command()
elif isinstance(c, BuildTarget) or isinstance(c, CustomTarget):
self.dependencies.append(c)
diff --git a/mesonbuild/compilers.py b/mesonbuild/compilers.py
index ff2df56..7bc59d8 100644
--- a/mesonbuild/compilers.py
+++ b/mesonbuild/compilers.py
@@ -126,7 +126,7 @@ base_options = {
'off'),
'b_coverage': coredata.UserBooleanOption('b_coverage',
'Enable coverage tracking.',
- True),
+ False),
}
def sanitizer_compile_args(value):
@@ -484,7 +484,6 @@ int someSymbolHereJustForFun;
return p.returncode == 0
def links(self, code, extra_args = []):
- suflen = len(self.default_suffix)
(fd, srcname) = tempfile.mkstemp(suffix='.'+self.default_suffix)
os.close(fd)
(fd, dstname) = tempfile.mkstemp()
@@ -574,7 +573,7 @@ int main(int argc, char **argv) {
'''
res = self.run(templ % (prefix, element), extra_args)
if not res.compiled:
- raise EnvironmentException('Could not compile sizeof test.')
+ return -1
if res.returncode != 0:
raise EnvironmentException('Could not run sizeof test binary.')
return int(res.stdout)
@@ -1044,6 +1043,11 @@ class ValaCompiler(Compiler):
suffix = filename.split('.')[-1]
return suffix in ('vala', 'vapi')
+ def get_buildtype_args(self, buildtype):
+ if buildtype == 'debug' or buildtype == 'debugoptimized':
+ return ['--debug']
+ return []
+
class RustCompiler(Compiler):
def __init__(self, exelist, version):
super().__init__(exelist, version)
@@ -1427,7 +1431,7 @@ class GnuCCompiler(CCompiler):
self.warn_args = {'1': ['-Wall', '-Winvalid-pch'],
'2': ['-Wall', '-Wextra', '-Winvalid-pch'],
'3' : ['-Wall', '-Wpedantic', '-Wextra', '-Winvalid-pch']}
- self.base_options = ['b_pch', 'b_lto', 'b_pgo', 'b_sanitize']
+ self.base_options = ['b_pch', 'b_lto', 'b_pgo', 'b_sanitize', 'b_coverage']
if self.gcc_type != GCC_OSX:
self.base_options.append('b_lundef')
@@ -1492,7 +1496,7 @@ class GnuObjCCompiler(ObjCCompiler):
self.warn_args = {'1': ['-Wall', '-Winvalid-pch'],
'2': ['-Wall', '-Wextra', '-Winvalid-pch'],
'3' : ['-Wall', '-Wpedantic', '-Wextra', '-Winvalid-pch']}
- self.base_options = ['b_pch', 'b_lto', 'b_pgo', 'b_sanitize']
+ self.base_options = ['b_pch', 'b_lto', 'b_pgo', 'b_sanitize', 'b_coverage']
if self.gcc_type != GCC_OSX:
self.base_options.append('b_lundef')
@@ -1520,7 +1524,7 @@ class GnuObjCPPCompiler(ObjCPPCompiler):
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']}
- self.base_options = ['b_pch', 'b_lto', 'b_pgo', 'b_sanitize']
+ self.base_options = ['b_pch', 'b_lto', 'b_pgo', 'b_sanitize', 'b_coverage']
if self.gcc_type != GCC_OSX:
self.base_options.append('b_lundef')
@@ -1540,7 +1544,7 @@ class ClangObjCCompiler(GnuObjCCompiler):
def __init__(self, exelist, version, cltype, is_cross, exe_wrapper=None):
super().__init__(exelist, version, is_cross, exe_wrapper)
self.id = 'clang'
- self.base_options = ['b_pch', 'b_lto', 'b_pgo', 'b_sanitize']
+ self.base_options = ['b_pch', 'b_lto', 'b_pgo', 'b_sanitize', 'b_coverage']
self.clang_type = cltype
if self.clang_type != CLANG_OSX:
self.base_options.append('b_lundef')
@@ -1550,7 +1554,7 @@ class ClangObjCPPCompiler(GnuObjCPPCompiler):
super().__init__(exelist, version, is_cross, exe_wrapper)
self.id = 'clang'
self.clang_type = cltype
- self.base_options = ['b_pch', 'b_lto', 'b_pgo', 'b_sanitize']
+ self.base_options = ['b_pch', 'b_lto', 'b_pgo', 'b_sanitize', 'b_coverage']
if self.clang_type != CLANG_OSX:
self.base_options.append('b_lundef')
@@ -1562,7 +1566,7 @@ class ClangCCompiler(CCompiler):
self.warn_args = {'1': ['-Wall', '-Winvalid-pch'],
'2': ['-Wall', '-Wextra', '-Winvalid-pch'],
'3' : ['-Wall', '-Wpedantic', '-Wextra', '-Winvalid-pch']}
- self.base_options = ['b_pch', 'b_lto', 'b_pgo', 'b_sanitize']
+ self.base_options = ['b_pch', 'b_lto', 'b_pgo', 'b_sanitize', 'b_coverage']
if self.clang_type != CLANG_OSX:
self.base_options.append('b_lundef')
@@ -1610,7 +1614,7 @@ class GnuCPPCompiler(CPPCompiler):
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']}
- self.base_options = ['b_pch', 'b_lto', 'b_pgo', 'b_sanitize']
+ self.base_options = ['b_pch', 'b_lto', 'b_pgo', 'b_sanitize', 'b_coverage']
if self.gcc_type != GCC_OSX:
self.base_options.append('b_lundef')
@@ -1660,7 +1664,7 @@ class ClangCPPCompiler(CPPCompiler):
'2': ['-Wall', '-Wextra', '-Winvalid-pch', '-Wnon-virtual-dtor'],
'3': ['-Wall', '-Wpedantic', '-Wextra', '-Winvalid-pch', '-Wnon-virtual-dtor']}
self.clang_type = cltype
- self.base_options = ['b_pch', 'b_lto', 'b_pgo', 'b_sanitize']
+ self.base_options = ['b_pch', 'b_lto', 'b_pgo', 'b_sanitize', 'b_coverage']
if self.clang_type != CLANG_OSX:
self.base_options.append('b_lundef')
diff --git a/mesonbuild/environment.py b/mesonbuild/environment.py
index c381ab5..df848f8 100644
--- a/mesonbuild/environment.py
+++ b/mesonbuild/environment.py
@@ -251,11 +251,11 @@ class Environment():
for compiler in compilers:
for arg in ['--version', '-V']:
try:
- p = subprocess.Popen([compiler] + [arg],
- stdout=subprocess.PIPE,
- stderr=subprocess.PIPE)
+ p = subprocess.Popen([compiler] + [arg],
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE)
except OSError:
- continue
+ continue
(out, err) = p.communicate()
out = out.decode(errors='ignore')
err = err.decode(errors='ignore')
@@ -266,32 +266,32 @@ class Environment():
version = vmatch.group(0)
if 'GNU Fortran' in out:
- return GnuFortranCompiler([compiler], version, GCC_STANDARD, is_cross, exe_wrap)
+ return GnuFortranCompiler([compiler], version, GCC_STANDARD, is_cross, exe_wrap)
if 'G95' in out:
- return G95FortranCompiler([compiler], version, is_cross, exe_wrap)
+ return G95FortranCompiler([compiler], version, is_cross, exe_wrap)
if 'Sun Fortran' in err:
- version = 'unknown version'
- vmatch = re.search(Environment.version_regex, err)
- if vmatch:
- version = vmatch.group(0)
- return SunFortranCompiler([compiler], version, is_cross, exe_wrap)
+ version = 'unknown version'
+ vmatch = re.search(Environment.version_regex, err)
+ if vmatch:
+ version = vmatch.group(0)
+ return SunFortranCompiler([compiler], version, is_cross, exe_wrap)
if 'ifort (IFORT)' in out:
- return IntelFortranCompiler([compiler], version, is_cross, exe_wrap)
-
+ return IntelFortranCompiler([compiler], version, is_cross, exe_wrap)
+
if 'PathScale EKOPath(tm)' in err:
- return PathScaleFortranCompiler([compiler], version, is_cross, exe_wrap)
+ return PathScaleFortranCompiler([compiler], version, is_cross, exe_wrap)
if 'pgf90' in out:
- return PGIFortranCompiler([compiler], version, is_cross, exe_wrap)
+ return PGIFortranCompiler([compiler], version, is_cross, exe_wrap)
if 'Open64 Compiler Suite' in err:
- return Open64FortranCompiler([compiler], version, is_cross, exe_wrap)
+ return Open64FortranCompiler([compiler], version, is_cross, exe_wrap)
if 'NAG Fortran' in err:
- return NAGFortranCompiler([compiler], version, is_cross, exe_wrap)
+ return NAGFortranCompiler([compiler], version, is_cross, exe_wrap)
raise EnvironmentException('Unknown compiler(s): "' + ', '.join(compilers) + '"')
@@ -514,7 +514,7 @@ class Environment():
evar = 'AR'
if evar in os.environ:
linker = os.environ[evar].strip()
- if isinstance(compiler, VisualStudioCCompiler):
+ elif isinstance(compiler, VisualStudioCCompiler):
linker= self.vs_static_linker
else:
linker = self.default_static_linker
diff --git a/mesonbuild/modules/pkgconfig.py b/mesonbuild/modules/pkgconfig.py
index f18decf..ffe03e2 100644
--- a/mesonbuild/modules/pkgconfig.py
+++ b/mesonbuild/modules/pkgconfig.py
@@ -21,7 +21,8 @@ class PkgConfigModule:
def print_hello(self, state, args, kwargs):
print('Hello from a Meson module')
- def generate_pkgconfig_file(self, state, libraries, subdirs, name, description, version, filebase):
+ def generate_pkgconfig_file(self, state, libraries, subdirs, name, description, version, filebase,
+ pub_reqs, priv_reqs, priv_libs):
outdir = state.environment.scratch_dir
fname = os.path.join(outdir, filebase + '.pc')
ofile = open(fname, 'w')
@@ -34,6 +35,12 @@ class PkgConfigModule:
ofile.write('Description: %s\n' % description)
if len(version) > 0:
ofile.write('Version: %s\n' % version)
+ if len(pub_reqs) > 0:
+ ofile.write('Requires: {}\n'.format(' '.join(pub_reqs)))
+ if len(priv_reqs) > 0:
+ ofile.write('Requires.private: {}\n'.format(' '.join(priv_reqs)))
+ if len(priv_libs) > 0:
+ ofile.write('Libraries.private: {}\n'.format(' '.join(priv_libs)))
ofile.write('Libs: -L${libdir} ')
for l in libraries:
ofile.write('-l%s ' % l.name)
@@ -73,9 +80,13 @@ class PkgConfigModule:
description = kwargs.get('description', None)
if not isinstance(description, str):
raise coredata.MesonException('Description is not a string.')
+ pub_reqs = mesonlib.stringlistify(kwargs.get('requires', []))
+ priv_reqs = mesonlib.stringlistify(kwargs.get('requires_private', []))
+ priv_libs = mesonlib.stringlistify(kwargs.get('libraries_private', []))
pcfile = filebase + '.pc'
pkgroot = os.path.join(state.environment.coredata.get_builtin_option('libdir'), 'pkgconfig')
- self.generate_pkgconfig_file(state, libs, subdirs, name, description, version, filebase)
+ self.generate_pkgconfig_file(state, libs, subdirs, name, description, version, filebase,
+ pub_reqs, priv_reqs, priv_libs)
return build.Data(False, state.environment.get_scratch_dir(), [pcfile], pkgroot)
def initialize():
diff --git a/mesonbuild/scripts/depfixer.py b/mesonbuild/scripts/depfixer.py
index 1ab83b6..8ff0dd1 100644
--- a/mesonbuild/scripts/depfixer.py
+++ b/mesonbuild/scripts/depfixer.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
-# Copyright 2013-2014 The Meson development team
+# Copyright 2013-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.
@@ -110,8 +110,9 @@ class SectionHeader(DataSizes):
self.sh_entsize = struct.unpack(self.Word, ifile.read(self.WordSize))[0]
class Elf(DataSizes):
- def __init__(self, bfile):
+ def __init__(self, bfile, verbose=True):
self.bfile = bfile
+ self.verbose = verbose
self.bf = open(bfile, 'r+b')
(self.ptrsize, self.is_le) = self.detect_elf_type()
super().__init__(self.ptrsize, self.is_le)
@@ -124,22 +125,21 @@ class Elf(DataSizes):
if data[1:4] != b'ELF':
# This script gets called to non-elf targets too
# so just ignore them.
- print('File "%s" is not an ELF file.' % self.bfile)
+ if self.verbose:
+ print('File "%s" is not an ELF file.' % self.bfile)
sys.exit(0)
if data[4] == 1:
ptrsize = 32
elif data[4] == 2:
ptrsize = 64
else:
- print('File "%s" has unknown ELF class.' % self.bfile)
- sys.exit(1)
+ sys.exit('File "%s" has unknown ELF class.' % self.bfile)
if data[5] == 1:
is_le = True
elif data[5] == 2:
is_le = False
else:
- print('File "%s" has unknown ELF endianness.' % self.bfile)
- sys.exit(1)
+ sys.exit('File "%s" has unknown ELF endianness.' % self.bfile)
return (ptrsize, is_le)
def parse_header(self):
@@ -257,14 +257,17 @@ class Elf(DataSizes):
self.bf.write(newname)
def fix_rpath(self, new_rpath):
+ if isinstance(new_rpath, str):
+ new_rpath = new_rpath.encode('utf8')
rp_off = self.get_rpath_offset()
if rp_off is None:
- print('File does not have rpath. It should be a fully static executable.')
+ if self.verbose:
+ print('File does not have rpath. It should be a fully static executable.')
return
self.bf.seek(rp_off)
old_rpath = self.read_str()
if len(old_rpath) < len(new_rpath):
- print("New rpath must not be longer than the old one.")
+ sys.exit("New rpath must not be longer than the old one.")
self.bf.seek(rp_off)
self.bf.write(new_rpath)
self.bf.write(b'\0'*(len(old_rpath) - len(new_rpath) + 1))
@@ -295,7 +298,7 @@ def run(args):
e.print_rpath()
else:
new_rpath = args[1]
- e.fix_rpath(new_rpath.encode('utf8'))
+ e.fix_rpath(new_rpath)
return 0
if __name__ == '__main__':
diff --git a/mesonbuild/scripts/meson_install.py b/mesonbuild/scripts/meson_install.py
index 8e3d0ca..cc86b62 100644
--- a/mesonbuild/scripts/meson_install.py
+++ b/mesonbuild/scripts/meson_install.py
@@ -16,6 +16,7 @@
import sys, pickle, os, shutil, subprocess, gzip, platform
from glob import glob
+from mesonbuild.scripts import depfixer
def do_install(datafilename):
ifile = open(datafilename, 'rb')
@@ -203,15 +204,14 @@ def install_targets(d):
print("Symlink creation does not work on this platform.")
printed_symlink_error = True
if is_elf_platform():
- p = subprocess.Popen(d.depfixer + [outname, install_rpath],
- stdout=subprocess.PIPE,
- stderr=subprocess.PIPE)
- (stdo, stde) = p.communicate()
- if p.returncode != 0:
- print('Could not fix dependency info.\n')
- print('Stdout:\n%s\n' % stdo.decode())
- print('Stderr:\n%s\n' % stde.decode())
- sys.exit(1)
+ try:
+ e = depfixer.Elf(outname, False)
+ e.fix_rpath(install_rpath)
+ except SystemExit as e:
+ if isinstance(e.code, int) and e.code == 0:
+ pass
+ else:
+ raise
def run(args):
if len(args) != 1:
diff --git a/run_tests.py b/run_tests.py
index c4f14ec..a3ec0dc 100755
--- a/run_tests.py
+++ b/run_tests.py
@@ -18,7 +18,7 @@ from glob import glob
import os, subprocess, shutil, sys, signal
from io import StringIO
from ast import literal_eval
-import sys
+import sys, tempfile
from mesonbuild import environment
from mesonbuild import mesonlib
from mesonbuild import mlog
@@ -45,8 +45,6 @@ failing_tests = 0
skipped_tests = 0
print_debug = 'MESON_PRINT_TEST_OUTPUT' in os.environ
-test_build_dir = 'work area'
-install_dir = os.path.join(os.path.split(os.path.abspath(__file__))[0], 'install dir')
meson_command = os.path.join(os.getcwd(), 'meson')
if not os.path.exists(meson_command):
meson_command += '.py'
@@ -198,12 +196,15 @@ def parse_test_args(testdir):
return args
def run_test(testdir, extra_args, should_succeed):
+ with tempfile.TemporaryDirectory(prefix='b ', dir='.') as build_dir:
+ with tempfile.TemporaryDirectory(prefix='i ', dir=os.getcwd()) as install_dir:
+ try:
+ return _run_test(testdir, build_dir, install_dir, extra_args, 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, should_succeed):
global compile_commands
- mlog.shutdown() # Close the log file because otherwise Windows wets itself.
- shutil.rmtree(test_build_dir)
- shutil.rmtree(install_dir)
- os.mkdir(test_build_dir)
- os.mkdir(install_dir)
print('Running test: ' + testdir)
test_args = parse_test_args(testdir)
gen_start = time.time()
@@ -290,14 +291,6 @@ def run_tests(extra_args):
conf_time = 0
build_time = 0
test_time = 0
- try:
- os.mkdir(test_build_dir)
- except OSError:
- pass
- try:
- os.mkdir(install_dir)
- except OSError:
- pass
for name, test_cases, skipped in all_tests:
current_suite = ET.SubElement(junit_root, 'testsuite', {'name' : name, 'tests' : str(len(test_cases))})
diff --git a/setup.py b/setup.py
index 0acce4d..1c96435 100644
--- a/setup.py
+++ b/setup.py
@@ -14,6 +14,12 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+import sys
+
+if sys.version_info[0] < 3:
+ print('Tried to install with Python 2, Meson only supports Python 3.')
+ sys.exit(1)
+
# We need to support Python installations that have nothing but the basic
# Python installation. Use setuptools when possible and fall back to
# plain distutils when setuptools is not available.
diff --git a/test cases/common/110 extract same name/lib.c b/test cases/common/110 extract same name/lib.c
new file mode 100644
index 0000000..6bdeda7
--- /dev/null
+++ b/test cases/common/110 extract same name/lib.c
@@ -0,0 +1,3 @@
+int func1() {
+ return 23;
+}
diff --git a/test cases/common/110 extract same name/main.c b/test cases/common/110 extract same name/main.c
new file mode 100644
index 0000000..dc57dd5
--- /dev/null
+++ b/test cases/common/110 extract same name/main.c
@@ -0,0 +1,6 @@
+int func1();
+int func2();
+
+int main(int argc, char **argv) {
+ return !(func1() == 23 && func2() == 42);
+}
diff --git a/test cases/common/110 extract same name/meson.build b/test cases/common/110 extract same name/meson.build
new file mode 100644
index 0000000..9384c47
--- /dev/null
+++ b/test cases/common/110 extract same name/meson.build
@@ -0,0 +1,6 @@
+project('object extraction', 'c')
+
+lib = shared_library('somelib', ['lib.c', 'src/lib.c'])
+obj = lib.extract_objects(['lib.c', 'src/lib.c'])
+exe = executable('main', 'main.c', objects: obj)
+test('extraction', exe)
diff --git a/test cases/common/110 extract same name/src/lib.c b/test cases/common/110 extract same name/src/lib.c
new file mode 100644
index 0000000..68e6ab9
--- /dev/null
+++ b/test cases/common/110 extract same name/src/lib.c
@@ -0,0 +1,3 @@
+int func2() {
+ return 42;
+}
diff --git a/test cases/common/51 pkgconfig-gen/meson.build b/test cases/common/51 pkgconfig-gen/meson.build
index a54fd66..4044b3d 100644
--- a/test cases/common/51 pkgconfig-gen/meson.build
+++ b/test cases/common/51 pkgconfig-gen/meson.build
@@ -12,5 +12,8 @@ pkgg.generate(
version : libver,
name : 'libsimple',
filebase : 'simple',
- description : 'A simple demo library.'
+ description : 'A simple demo library.',
+ requires : 'glib-2.0', # Not really, but only here to test that this works.
+ requires_private : ['gio-2.0', 'gobject-2.0'],
+ libraries_private : '-lz',
)
diff --git a/test cases/failing/28 noprog use/meson.build b/test cases/failing/28 noprog use/meson.build
new file mode 100644
index 0000000..e4de42f
--- /dev/null
+++ b/test cases/failing/28 noprog use/meson.build
@@ -0,0 +1,9 @@
+project('using not found exe', 'c')
+
+nope = find_program('nonexisting', required : false)
+
+custom_target( 'aa',
+ input: 'meson.build',
+ output: 'foobar',
+ command: [nope, '@INPUT@', '@OUTPUT@']
+)