diff options
28 files changed, 270 insertions, 30 deletions
@@ -248,14 +248,17 @@ class BuildTarget(): if 'link_with' in self.kwargs: self.kwargs['link_with'] = self.unpack_holder(self.kwargs['link_with']) - def extract_objects(self, srclist): + def extract_objects(self, srcargs): obj_src = [] - for src in srclist: - if not isinstance(src, str): - raise coredata.MesonException('Extraction arguments must be strings.') - if src not in self.sources: - raise coredata.MesonException('Tried to extract unknown source %s.' % src) - obj_src.append(src) + for srclist in srcargs: + if not isinstance(srclist, list): + srclist = [srclist] + for src in srclist: + if not isinstance(src, str): + raise coredata.MesonException('Extraction arguments must be strings.') + if src not in self.sources: + raise coredata.MesonException('Tried to extract unknown source %s.' % src) + obj_src.append(src) return ExtractedObjects(self, obj_src) def get_rpaths(self): @@ -552,6 +555,7 @@ class GeneratedList(): self.infilelist = [] self.outfilelist = [] self.outmap = {} + self.extra_depends = [] def add_file(self, newfile): self.infilelist.append(newfile) @@ -665,11 +669,14 @@ class CustomTarget: 'command' : True, 'install' : True, 'install_dir' : True, - 'build_always' : True} + 'build_always' : True, + 'depends' : True} + def __init__(self, name, subdir, kwargs): self.name = name self.subdir = subdir self.dependencies = [] + self.extra_depends = [] self.process_kwargs(kwargs) self.extra_files = [] self.install_rpath = '' @@ -741,6 +748,15 @@ class CustomTarget: self.build_always = kwargs.get('build_always', False) if not isinstance(self.build_always, bool): raise InvalidArguments('Argument build_always must be a boolean.') + extra_deps = kwargs.get('depends', []) + if not isinstance(extra_deps, list): + extra_deps = [extra_deps] + for ed in extra_deps: + while hasattr(ed, 'held_object'): + ed = ed.held_object + if not isinstance(ed, CustomTarget) and not isinstance(ed, BuildTarget): + raise InvalidArguments('Can only depend on toplevel targets.') + self.extra_depends.append(ed) def get_basename(self): return self.name diff --git a/compilers.py b/compilers.py index 9b9c2c8..61a2372 100644 --- a/compilers.py +++ b/compilers.py @@ -1003,12 +1003,18 @@ def get_gcc_soname_args(gcc_type, shlib_name, path, soversion): raise RuntimeError('Not impelented yet.') class GnuCCompiler(CCompiler): - std_warn_args = ['-Wall', '-Wpedantic', '-Winvalid-pch'] + std_warn_args = [] + old_warn = ['-Wall', '-pedantic', '-Winvalid-pch'] + new_warn = ['-Wall', '-Wpedantic', '-Winvalid-pch'] def __init__(self, exelist, version, gcc_type, is_cross, exe_wrapper=None): CCompiler.__init__(self, exelist, version, is_cross, exe_wrapper) self.id = 'gcc' self.gcc_type = gcc_type + if mesonlib.version_compare(version, ">=4.9.0"): + GnuCCompiler.std_warn_args= GnuCCompiler.new_warn + else: + GnuCCompiler.std_warn_args = GnuCCompiler.old_warn def get_always_args(self): return ['-pipe'] @@ -1119,7 +1125,9 @@ class ClangCCompiler(CCompiler): class GnuCPPCompiler(CPPCompiler): - std_warn_args = ['-Wall', '-Wpedantic', '-Winvalid-pch', '-Wnon-virtual-dtor'] + std_warn_args = [] + new_warn = ['-Wall', '-Wpedantic', '-Winvalid-pch', '-Wnon-virtual-dtor'] + old_warn = ['-Wall', '-pedantic', '-Winvalid-pch', '-Wnon-virtual-dtor'] # may need to separate the latter to extra_debug_args or something std_debug_args = ['-g'] @@ -1127,6 +1135,10 @@ class GnuCPPCompiler(CPPCompiler): CPPCompiler.__init__(self, exelist, version, is_cross, exe_wrap) self.id = 'gcc' self.gcc_type = gcc_type + if mesonlib.version_compare(version, ">=4.9.0"): + GnuCPPCompiler.std_warn_args= GnuCPPCompiler.new_warn + else: + GnuCPPCompiler.std_warn_args = GnuCPPCompiler.old_warn def get_always_args(self): return ['-pipe'] diff --git a/contributing.txt b/contributing.txt index 50446e4..0e7a7ff 100644 --- a/contributing.txt +++ b/contributing.txt @@ -6,7 +6,7 @@ mailing list. Remember to add your name to the list of contributors in authors.txt. -Coding style +Python Coding style Meson follows the basic Python coding style. Additional rules are the following: @@ -20,6 +20,15 @@ following: a big feature) +C/C++ coding style + +Meson has a bunch of test code in several languages. The rules for +those are simple. + +- indent 4 spaces, no tabs ever +- brace always on the same line as if/for/else/function definition + + External dependencies The goal of Meson is to be as easily usable as possible. The user diff --git a/dependencies.py b/dependencies.py index c276458..50c53d9 100644 --- a/dependencies.py +++ b/dependencies.py @@ -39,6 +39,7 @@ class CustomRule: class Dependency(): def __init__(self): self.name = "null" + self.is_found = False def get_compile_args(self): return [] @@ -47,7 +48,7 @@ class Dependency(): return [] def found(self): - return False + return self.is_found def get_sources(self): """Source files that need to be added to the target. @@ -593,7 +594,6 @@ class GnuStepDependency(Dependency): try: gp = subprocess.Popen([confprog, '--help'], stdout=subprocess.PIPE, stderr=subprocess.PIPE) - gp.communicate() except FileNotFoundError: self.args = None @@ -675,6 +675,31 @@ class AppleFrameworks(Dependency): def found(self): return mesonlib.is_osx() +class GLDependency(Dependency): + def __init__(self, kwargs): + Dependency.__init__(self) + self.is_found = False + self.cargs = [] + self.linkargs = [] + try: + pcdep = PkgConfigDependency('gl', kwargs) + if pcdep.found(): + self.is_found = True + self.cargs = pcdep.get_compile_args() + self.linkargs = pcdep.get_link_args() + except Exception: + pass + if mesonlib.is_osx(): + self.is_found = True + self.linkargs = ['-framework', 'OpenGL'] + return + if mesonlib.is_windows(): + self.is_found = True + return + + def get_link_args(self): + return self.linkargs + # There are three different ways of depending on SDL2: # sdl2-config, pkg-config and OSX framework class SDL2Dependency(Dependency): @@ -746,10 +771,14 @@ class ExtraFrameworkDependency(Dependency): return def get_compile_args(self): - return ['-I' + os.path.join(self.path, self.name, 'Headers')] + if self.found(): + return ['-I' + os.path.join(self.path, self.name, 'Headers')] + return [] def get_link_args(self): - return ['-F' + self.path, '-framework', self.name.split('.')[0]] + if self.found(): + return ['-F' + self.path, '-framework', self.name.split('.')[0]] + return [] def found(self): return self.name is not None @@ -782,9 +811,13 @@ def find_external_dependency(name, kwargs): except Exception as e: pkg_exc = e if mesonlib.is_osx(): - return ExtraFrameworkDependency(name, required) + fwdep = ExtraFrameworkDependency(name, required) + if required and not fwdep.found(): + raise DependencyException('Dependency "%s" not found' % name) + return fwdep if pkg_exc is not None: raise pkg_exc + mlog.log('Dependency', mlog.bold(name), 'found:', mlog.red('NO')) return pkgdep # This has to be at the end so the classes it references @@ -797,4 +830,5 @@ packages = {'boost': BoostDependency, 'appleframeworks': AppleFrameworks, 'wxwidgets' : WxDependency, 'sdl2' : SDL2Dependency, + 'gl' : GLDependency, } diff --git a/interpreter.py b/interpreter.py index f14e981..75df340 100644 --- a/interpreter.py +++ b/interpreter.py @@ -1020,7 +1020,7 @@ class Interpreter(): fullstack = self.subproject_stack + [dirname] incpath = ' => '.join(fullstack) raise InterpreterException('Recursive include of subprojects: %s.' % incpath) - if dirname == self.subprojects: + if dirname in self.subprojects: return self.subprojects[dirname] subdir = os.path.join('subprojects', dirname) r = wrap.Resolver(os.path.join(self.build.environment.get_source_dir(), 'subprojects')) @@ -1032,11 +1032,13 @@ class Interpreter(): self.global_args_frozen = True mlog.log('\nExecuting subproject ', mlog.bold(dirname), '.\n', sep='') subi = Interpreter(self.build, dirname, subdir) + subi.subprojects = self.subprojects subi.subproject_stack = self.subproject_stack + [dirname] subi.run() mlog.log('\nSubproject', mlog.bold(dirname), 'finished.') self.build.subprojects[dirname] = True + self.subprojects.update(subi.subprojects) self.subprojects[dirname] = SubprojectHolder(subi) self.build_def_files += subi.build_def_files return self.subprojects[dirname] diff --git a/manual tests/4 standalone binaries/osx_bundler.sh b/manual tests/4 standalone binaries/osx_bundler.sh index f61187f..7b83573 100755 --- a/manual tests/4 standalone binaries/osx_bundler.sh +++ b/manual tests/4 standalone binaries/osx_bundler.sh @@ -1,6 +1,6 @@ #!/bin/sh mkdir -p ${MESON_INSTALL_PREFIX}/Contents/Frameworks -cp -r /Library/Frameworks/SDL2.framework ${MESON_INSTALL_PREFIX}/Contents/Frameworks +cp -R /Library/Frameworks/SDL2.framework ${MESON_INSTALL_PREFIX}/Contents/Frameworks install_name_tool -change @rpath/SDL2.framework/Versions/A/SDL2 @executable_path/../Frameworks/SDL2.framework/Versions/A/SDL2 ${MESON_INSTALL_PREFIX}/Contents/MacOS/myapp diff --git a/mesonlib.py b/mesonlib.py index 180e21e..af29421 100644 --- a/mesonlib.py +++ b/mesonlib.py @@ -64,6 +64,8 @@ def detect_vcs(source_dir): return None def version_compare(vstr1, vstr2): + if '-' in vstr1: + vstr1 = vstr1.split('-')[0] if vstr2.startswith('>='): cmpop = operator.ge vstr2 = vstr2[2:] diff --git a/modules/qt5.py b/modules/qt5.py index 2b9e7d8..5312416 100644 --- a/modules/qt5.py +++ b/modules/qt5.py @@ -16,6 +16,7 @@ import dependencies, mlog import os, subprocess import build from coredata import MesonException +import xml.etree.ElementTree as ET class Qt5Module(): @@ -87,6 +88,22 @@ class Qt5Module(): else: mlog.log(' rcc:', mlog.red('NO')) + def parse_qrc(self, state, fname): + abspath = os.path.join(state.environment.source_dir, state.subdir, fname) + 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: + result.append(os.path.join(state.subdir, child.text)) + return result + except Exception: + return [] + def preprocess(self, state, args, kwargs): rcc_files = kwargs.pop('qresources', []) if not isinstance(rcc_files, list): @@ -109,6 +126,10 @@ class Qt5Module(): 'arguments' : ['@INPUT@', '-o', '@OUTPUT@']} rcc_gen = build.Generator([self.rcc], rcc_kwargs) rcc_output = build.GeneratedList(rcc_gen) + qrc_deps = [] + for i in rcc_files: + qrc_deps += self.parse_qrc(state, i) + rcc_output.extra_depends = qrc_deps [rcc_output.add_file(os.path.join(state.subdir, a)) for a in rcc_files] sources.append(rcc_output) if len(ui_files) > 0: @@ -135,4 +156,6 @@ class Qt5Module(): return sources def initialize(): + mlog.log('Warning, rcc dependencies will not work properly until this upstream issue is fixed:', + mlog.bold('https://bugreports.qt.io/browse/QTBUG-45460')) return Qt5Module() diff --git a/ninjabackend.py b/ninjabackend.py index d467c07..adfc59f 100644 --- a/ninjabackend.py +++ b/ninjabackend.py @@ -283,6 +283,12 @@ class NinjaBackend(backends.Backend): if target.build_always: deps.append('PHONY') elem = NinjaBuildElement(ofilenames, 'CUSTOM_COMMAND', deps) + for d in target.extra_depends: + tmp = d.get_filename() + if not isinstance(tmp, list): + tmp = [tmp] + for fname in tmp: + elem.add_dep(os.path.join(d.get_subdir(), fname)) cmd = [] for i in target.command: for (j, src) in enumerate(srcs): @@ -992,6 +998,7 @@ rule FORTRAN_DEP_HACK else: exe_arr = exe.get_command() base_args = generator.get_arglist() + extra_dependencies = [os.path.join(self.build_to_src, i) for i in genlist.extra_depends] for i in range(len(infilelist)): if len(generator.outputs) == 1: sole_output = os.path.join(self.get_target_private_dir(target), outfilelist[i]) @@ -1008,6 +1015,8 @@ rule FORTRAN_DEP_HACK for x in args] cmdlist = exe_arr + args elem = NinjaBuildElement(outfiles, 'CUSTOM_COMMAND', infilename) + if len(extra_dependencies) > 0: + elem.add_dep(extra_dependencies) elem.add_item('DESC', 'Generating $out') if isinstance(exe, build.BuildTarget): elem.add_dep(self.get_target_filename(exe)) diff --git a/test cases/common/25 object extraction/meson.build b/test cases/common/25 object extraction/meson.build index f936609..0a17c60 100644 --- a/test cases/common/25 object extraction/meson.build +++ b/test cases/common/25 object extraction/meson.build @@ -4,8 +4,13 @@ if meson.is_unity() message('Skipping extraction test because this is a Unity build.') else lib = shared_library('somelib', 'lib.c') - obj = lib.extract_objects('lib.c') - e = executable('main', 'main.c', objects : obj) - test('extraction test', e) + obj1 = lib.extract_objects('lib.c') + obj2 = lib.extract_objects(['lib.c']) + + e1 = executable('main 1', 'main.c', objects : obj1) + e2 = executable('main 2', 'main.c', objects : obj2) + + test('extraction test 1', e1) + test('extraction test 2', e2) endif diff --git a/test cases/common/78 ctarget dependency/gen1.py b/test cases/common/78 ctarget dependency/gen1.py new file mode 100755 index 0000000..64b8e6d --- /dev/null +++ b/test cases/common/78 ctarget dependency/gen1.py @@ -0,0 +1,10 @@ +#!/usr/bin/env python3 + +import time, sys + +# Make sure other script runs first if dependency +# is missing. +time.sleep(0.5) + +contents = open(sys.argv[1], 'r').read() +open(sys.argv[2], 'w').write(contents) diff --git a/test cases/common/78 ctarget dependency/gen2.py b/test cases/common/78 ctarget dependency/gen2.py new file mode 100755 index 0000000..3f3595b --- /dev/null +++ b/test cases/common/78 ctarget dependency/gen2.py @@ -0,0 +1,9 @@ +#!/usr/bin/env python3 + +import sys +from glob import glob + +files = glob('*.tmp') +assert(len(files) == 1) + +open(sys.argv[1], 'w').write(open(files[0], 'r').read()) diff --git a/test cases/common/78 ctarget dependency/input.dat b/test cases/common/78 ctarget dependency/input.dat new file mode 100644 index 0000000..7af91e2 --- /dev/null +++ b/test cases/common/78 ctarget dependency/input.dat @@ -0,0 +1 @@ +This is a piece of text. diff --git a/test cases/common/78 ctarget dependency/meson.build b/test cases/common/78 ctarget dependency/meson.build new file mode 100644 index 0000000..baed2da --- /dev/null +++ b/test cases/common/78 ctarget dependency/meson.build @@ -0,0 +1,20 @@ +project('custom target dependency', 'c') + +# Sometimes custom targets do not take input files +# but instead do globbing or some similar wackiness. +# In this case we need to be able to specify a +# manual dependency between two custom targets, +# if one needs to be run before the other. + +g1 = find_program('gen1.py') +g2 = find_program('gen2.py') + +c1 = custom_target('medput', +input : 'input.dat', +output : 'medput.tmp', +command : [g1, '@INPUT@', '@OUTPUT@']) + +custom_target('output', +output : 'output.dat', +command : [g2, '@OUTPUT@'], +depends : c1) diff --git a/test cases/common/79 shared subproject/a.c b/test cases/common/79 shared subproject/a.c new file mode 100644 index 0000000..6ed96fa --- /dev/null +++ b/test cases/common/79 shared subproject/a.c @@ -0,0 +1,13 @@ +#include<assert.h> +char func_b(); +char func_c(); + +int main(int argc, char **argv) { + if(func_b() != 'b') { + return 1; + } + if(func_c() != 'c') { + return 2; + } + return 0; +} diff --git a/test cases/common/79 shared subproject/meson.build b/test cases/common/79 shared subproject/meson.build new file mode 100644 index 0000000..6803d51 --- /dev/null +++ b/test cases/common/79 shared subproject/meson.build @@ -0,0 +1,10 @@ +project('A', 'c') + +B = subproject('B') +b = B.get_variable('b') + +C = subproject('C') +c = C.get_variable('c') + +a = executable('a', 'a.c', link_with : [b, c]) +test('a test', a) diff --git a/test cases/common/79 shared subproject/subprojects/B/b.c b/test cases/common/79 shared subproject/subprojects/B/b.c new file mode 100644 index 0000000..03b0cc7 --- /dev/null +++ b/test cases/common/79 shared subproject/subprojects/B/b.c @@ -0,0 +1,9 @@ +#include<stdlib.h> +char func_c(); + +char func_b() { + if(func_c() != 'c') { + exit(3); + } + return 'b'; +} diff --git a/test cases/common/79 shared subproject/subprojects/B/meson.build b/test cases/common/79 shared subproject/subprojects/B/meson.build new file mode 100644 index 0000000..280c60c --- /dev/null +++ b/test cases/common/79 shared subproject/subprojects/B/meson.build @@ -0,0 +1,4 @@ +project('B', 'c') +C = subproject('C') +c = C.get_variable('c') +b = shared_library('b', 'b.c', link_with : c) diff --git a/test cases/common/79 shared subproject/subprojects/C/c.c b/test cases/common/79 shared subproject/subprojects/C/c.c new file mode 100644 index 0000000..3bbac08 --- /dev/null +++ b/test cases/common/79 shared subproject/subprojects/C/c.c @@ -0,0 +1,3 @@ +char func_c() { + return 'c'; +} diff --git a/test cases/common/79 shared subproject/subprojects/C/meson.build b/test cases/common/79 shared subproject/subprojects/C/meson.build new file mode 100644 index 0000000..abf0b1e --- /dev/null +++ b/test cases/common/79 shared subproject/subprojects/C/meson.build @@ -0,0 +1,2 @@ +project('C', 'c') +c = shared_library('c', 'c.c') diff --git a/test cases/common/80 shared subproject 2/a.c b/test cases/common/80 shared subproject 2/a.c new file mode 100644 index 0000000..6ed96fa --- /dev/null +++ b/test cases/common/80 shared subproject 2/a.c @@ -0,0 +1,13 @@ +#include<assert.h> +char func_b(); +char func_c(); + +int main(int argc, char **argv) { + if(func_b() != 'b') { + return 1; + } + if(func_c() != 'c') { + return 2; + } + return 0; +} diff --git a/test cases/common/80 shared subproject 2/meson.build b/test cases/common/80 shared subproject 2/meson.build new file mode 100644 index 0000000..0647325 --- /dev/null +++ b/test cases/common/80 shared subproject 2/meson.build @@ -0,0 +1,13 @@ +project('A', 'c') + +# Same as the previous test but use C and B in +# the opposite order. + +C = subproject('C') +c = C.get_variable('c') + +B = subproject('B') +b = B.get_variable('b') + +a = executable('a', 'a.c', link_with : [b, c]) +test('a test', a) diff --git a/test cases/common/80 shared subproject 2/subprojects/B/b.c b/test cases/common/80 shared subproject 2/subprojects/B/b.c new file mode 100644 index 0000000..03b0cc7 --- /dev/null +++ b/test cases/common/80 shared subproject 2/subprojects/B/b.c @@ -0,0 +1,9 @@ +#include<stdlib.h> +char func_c(); + +char func_b() { + if(func_c() != 'c') { + exit(3); + } + return 'b'; +} diff --git a/test cases/common/80 shared subproject 2/subprojects/B/meson.build b/test cases/common/80 shared subproject 2/subprojects/B/meson.build new file mode 100644 index 0000000..280c60c --- /dev/null +++ b/test cases/common/80 shared subproject 2/subprojects/B/meson.build @@ -0,0 +1,4 @@ +project('B', 'c') +C = subproject('C') +c = C.get_variable('c') +b = shared_library('b', 'b.c', link_with : c) diff --git a/test cases/common/80 shared subproject 2/subprojects/C/c.c b/test cases/common/80 shared subproject 2/subprojects/C/c.c new file mode 100644 index 0000000..3bbac08 --- /dev/null +++ b/test cases/common/80 shared subproject 2/subprojects/C/c.c @@ -0,0 +1,3 @@ +char func_c() { + return 'c'; +} diff --git a/test cases/common/80 shared subproject 2/subprojects/C/meson.build b/test cases/common/80 shared subproject 2/subprojects/C/meson.build new file mode 100644 index 0000000..abf0b1e --- /dev/null +++ b/test cases/common/80 shared subproject 2/subprojects/C/meson.build @@ -0,0 +1,2 @@ +project('C', 'c') +c = shared_library('c', 'c.c') diff --git a/test cases/frameworks/4 qt5/meson.build b/test cases/frameworks/4 qt5/meson.build index 9542331..ae85d1d 100644 --- a/test cases/frameworks/4 qt5/meson.build +++ b/test cases/frameworks/4 qt5/meson.build @@ -7,12 +7,14 @@ if meson.get_compiler('cpp').get_id() != 'msvc' add_global_arguments('-std=c++11', language : 'cpp') endif +prep = qt5.preprocess(moc_headers : ['mainWindow.h'], # These need to be fed through the moc tool before use. + ui_files : 'mainWindow.ui', # XML files that need to be compiled with the uic tol. + qresources : 'stuff.qrc', # Resource file for rcc compiler. +) + q5exe = executable('qt5app', sources : ['main.cpp', 'mainWindow.cpp', # Sources that don't need preprocessing. -qt5.preprocess(moc_headers : ['mainWindow.h'], # These need to be fed through the moc tool before use. - ui_files : 'mainWindow.ui', # XML files that need to be compiled with the uic tol. - qresources : 'stuff.qrc', # Resource file for rcc compiler. -)], +prep], dependencies : qt5dep) # We need a console test application because some test environments diff --git a/test cases/frameworks/4 qt5/stuff.qrc b/test cases/frameworks/4 qt5/stuff.qrc index 48f8fda..9152500 100644 --- a/test cases/frameworks/4 qt5/stuff.qrc +++ b/test cases/frameworks/4 qt5/stuff.qrc @@ -1,6 +1,7 @@ -<!DOCTYPE RCC><RCC version="1.0"> -<qresource> - <file>thing.png</file> - <file>thing2.png</file> -</qresource> +<!DOCTYPE RCC> +<RCC version="1.0"> + <qresource> + <file>thing.png</file> + <file>thing2.png</file> + </qresource> </RCC> |