diff options
-rw-r--r-- | docs/markdown/Project-templates.md | 30 | ||||
-rw-r--r-- | docs/markdown/Reference-manual.md | 5 | ||||
-rw-r--r-- | docs/markdown/index.md | 6 | ||||
-rw-r--r-- | docs/markdown/snippets/templates.md | 8 | ||||
-rw-r--r-- | docs/sitemap.txt | 1 | ||||
-rw-r--r-- | mesonbuild/interpreter.py | 2 | ||||
-rw-r--r-- | mesonbuild/mesonmain.py | 4 | ||||
-rw-r--r-- | mesonbuild/minit.py | 373 | ||||
-rw-r--r-- | mesonbuild/mparser.py | 4 | ||||
-rwxr-xr-x | run_unittests.py | 24 | ||||
-rw-r--r-- | test cases/unit/20 warning location/a.c | 0 | ||||
-rw-r--r-- | test cases/unit/20 warning location/b.c | 0 | ||||
-rw-r--r-- | test cases/unit/20 warning location/main.c | 0 | ||||
-rw-r--r-- | test cases/unit/20 warning location/meson.build | 6 | ||||
-rw-r--r-- | test cases/unit/20 warning location/sub/c.c | 0 | ||||
-rw-r--r-- | test cases/unit/20 warning location/sub/d.c | 0 | ||||
-rw-r--r-- | test cases/unit/20 warning location/sub/meson.build | 4 | ||||
-rw-r--r-- | test cases/unit/20 warning location/sub/sub.c | 0 |
18 files changed, 459 insertions, 8 deletions
diff --git a/docs/markdown/Project-templates.md b/docs/markdown/Project-templates.md new file mode 100644 index 0000000..d8459c6 --- /dev/null +++ b/docs/markdown/Project-templates.md @@ -0,0 +1,30 @@ +--- +short-description: Project templates +... + +# Project templates + +To make it easier for new developers to start working, Meson ships a +tool to generate the basic setup of different kinds of projects. This +functionality can be accessed with the `meson init` command. A typical +project setup would go like this: + +```console +$ mkdir project_name +$ cd project_name +$ meson init --language=c --name=myproject --version=0.1 +``` + +This would create the build definitions for a helloworld type +project. The result can be compiled as usual. For example compiling it +with Ninja could be done like this: + +``` +$ meson builddir +$ ninja -C builddir +``` + +The generator has many different projects and settings. They can all +be listed by invoking the command `meson test --help`. + +This feature is available since Meson version 0.45.0. diff --git a/docs/markdown/Reference-manual.md b/docs/markdown/Reference-manual.md index 14c931d..e30b79c 100644 --- a/docs/markdown/Reference-manual.md +++ b/docs/markdown/Reference-manual.md @@ -606,6 +606,11 @@ installed, and so on, use a [`custom_target`](#custom_target) instead. Obtains the value of the [project build option](Build-options.md) specified in the positional argument. +Note that the value returned for built-in options that end in `dir` such as +`bindir` and `libdir` is always a path relative to (and inside) the `prefix`. +The only exceptions are: `sysconfdir`, `localstatedir`, and `sharedstatedir` +which will return the value passed during configuration as-is. + ### get_variable() ``` meson diff --git a/docs/markdown/index.md b/docs/markdown/index.md index 5f42cc7..6893564 100644 --- a/docs/markdown/index.md +++ b/docs/markdown/index.md @@ -16,7 +16,7 @@ code. ## Features -* multiplatform support for Linux, OSX, Windows, GCC, Clang, Visual Studio and others +* multiplatform support for Linux, macOS, Windows, GCC, Clang, Visual Studio and others * supported languages include C, C++, D, Fortran, Java, Rust * build definitions in a very readable and user friendly non-Turing complete DSL * cross compilation for many operating systems as well as bare metal @@ -35,8 +35,8 @@ The second way is via IRC. The channel to use is `#mesonbuild` at ## Development -All development on Meson is done on [GitHub -project](https://github.com/mesonbuild/meson). Instruction on +All development on Meson is done on the [GitHub +project](https://github.com/mesonbuild/meson). Instructions for contributing can be found on the [contribution page](Contributing.md). diff --git a/docs/markdown/snippets/templates.md b/docs/markdown/snippets/templates.md new file mode 100644 index 0000000..6f0474d --- /dev/null +++ b/docs/markdown/snippets/templates.md @@ -0,0 +1,8 @@ +## Project templates + +Meson ships with predefined project templates. To start a new project from +scratch, simply go to an empty directory and type: + +```meson +meson init --name=myproject --type=executable --language=c +``` diff --git a/docs/sitemap.txt b/docs/sitemap.txt index b7ee136..87a5eb5 100644 --- a/docs/sitemap.txt +++ b/docs/sitemap.txt @@ -48,6 +48,7 @@ index.md Creating-releases.md Creating-OSX-packages.md Creating-Linux-binaries.md + Project-templates.md Reference-manual.md Reference-tables.md FAQ.md diff --git a/mesonbuild/interpreter.py b/mesonbuild/interpreter.py index b30ba36..1abc134 100644 --- a/mesonbuild/interpreter.py +++ b/mesonbuild/interpreter.py @@ -1935,7 +1935,7 @@ to directly access options of other subprojects.''') @noKwargs def func_warning(self, node, args, kwargs): argstr = self.get_message_string_arg(node) - mlog.warning(argstr) + mlog.warning('%s in file %s, line %d' % (argstr, os.path.join(node.subdir, 'meson.build'), node.lineno)) @noKwargs def func_error(self, node, args, kwargs): diff --git a/mesonbuild/mesonmain.py b/mesonbuild/mesonmain.py index 20ec304..12bbd69 100644 --- a/mesonbuild/mesonmain.py +++ b/mesonbuild/mesonmain.py @@ -17,7 +17,7 @@ import time, datetime import os.path from . import environment, interpreter, mesonlib from . import build -from . import mconf, mintro, mtest, rewriter +from . import mconf, mintro, mtest, rewriter, minit import platform from . import mlog, coredata from .mesonlib import MesonException @@ -308,6 +308,8 @@ def run(original_args, mainfile=None): sys.exit(1) elif cmd_name == 'wrap': return wraptool.run(remaining_args) + elif cmd_name == 'init': + return minit.run(remaining_args) elif cmd_name == 'runpython': import runpy script_file = remaining_args[0] diff --git a/mesonbuild/minit.py b/mesonbuild/minit.py new file mode 100644 index 0000000..98817cb --- /dev/null +++ b/mesonbuild/minit.py @@ -0,0 +1,373 @@ +# Copyright 2017 The Meson development team +from pyclbr import Function + +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at + +# http://www.apache.org/licenses/LICENSE-2.0 + +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Code that creates simple startup projects.""" + +import os, sys, argparse, re +from glob import glob + +lib_h_template = '''#pragma once +#if defined _WIN32 || defined __CYGWIN__ + #ifdef BUILDING_{utoken} + #define {utoken}_PUBLIC __declspec(dllexport) + #else + #define {utoken}_PUBLIC __declspec(dllimport) + #endif +#else + #ifdef BUILDING_{utoken} + #define {utoken}_PUBLIC __attribute__ ((visibility ("default"))) + #else + #define {utoken}_PUBLIC + #endif +#endif + +int {utoken}_PUBLIC {function_name}(); + +''' + +lib_c_template = '''#include <{header_file}> + +/* This function will not be exported and is not + * directly callable by users of this library. + */ +int internal_function() {{ + return 0; +}} + +int {function_name}() {{ + return internal_function(); +}} +''' + +lib_c_test_template = '''#include <{header_file}> +#include <stdio.h> + +int main(int argc, char **argv) {{ + if(argc != 1) {{ + printf("%s takes no arguments.\\n", argv[0]); + return 1; + }} + return {function_name}(); +}} +''' + +lib_c_meson_template = '''project('{project_name}', 'c', + version : '{version}', + default_options : ['warning_level=3']) + +# These arguments are only used to build the shared library +# not the executables that use the library. +lib_args = ['-DBUILDING_{utoken}'] + +# Hiding symbols that are not explicitly marked as exported +# requires a compiler flag on all compilers except VS. +cc = meson.get_compiler('c') +if cc.get_id() != 'msvc' + lib_args += ['-fvisibility=hidden'] +endif + +shlib = shared_library('{lib_name}', '{source_file}', + install : true, + c_args : lib_args, +) + +test_exe = executable('{test_exe_name}', '{test_source_file}', + link_with : shlib) +test('{test_name}', test_exe) + +# Make this library usable as a Meson subproject. +{ltoken}_dep = declare_dependency( + include_directories: include_directories('.'), + link_with : shlib) + +# Make this library usable from the system's +# package manager. +install_headers('{header_file}', subdir : '{header_dir}') + +pkg_mod = import('pkgconfig') +pkg_mod.generate( + name : '{project_name}', + filebase : '{ltoken}', + description : 'Meson sample project.', + subdirs : '{header_dir}', + libraries : shlib, + version : '{version}', +) +''' + +hello_c_template = '''#include <stdio.h> + +#define PROJECT_NAME "{project_name}" + +int main(int argc, char **argv) {{ + if(argc != 1) {{ + printf("%s takes no arguments.\\n", argv[0]); + return 1; + }} + printf("This is project %s.\\n", PROJECT_NAME); + return 0; +}} +''' + +hello_c_meson_template = '''project('{project_name}', 'c', + version : '{version}', + default_options : ['warning_level=3', + 'cpp_std=c++14']) + +exe = executable('{exe_name}', '{source_name}', + install : true) + +test('basic', exe) +''' + +hello_cpp_template = '''#include <iostream> + +#define PROJECT_NAME "{project_name}" + +int main(int argc, char **argv) {{ + if(argc != 1) {{ + std::cout << argv[0] << "takes no arguments.\\n"; + return 1; + }} + std::cout << "This is project " << PROJECT_NAME << ".\\n"; + return 0; +}} +''' + +hello_cpp_meson_template = '''project('{project_name}', 'cpp', + version : '{version}', + default_options : ['warning_level=3']) + +exe = executable('{exe_name}', '{source_name}', + install : true) + +test('basic', exe) +''' + +lib_hpp_template = '''#pragma once +#if defined _WIN32 || defined __CYGWIN__ + #ifdef BUILDING_{utoken} + #define {utoken}_PUBLIC __declspec(dllexport) + #else + #define {utoken}_PUBLIC __declspec(dllimport) + #endif +#else + #ifdef BUILDING_{utoken} + #define {utoken}_PUBLIC __attribute__ ((visibility ("default"))) + #else + #define {utoken}_PUBLIC + #endif +#endif + +namespace {namespace} {{ + +class {utoken}_PUBLIC {class_name} {{ + +public: + {class_name}(); + int get_number() const; + +private: + + int number; + +}}; + +}} + +''' + +lib_cpp_template = '''#include <{header_file}> + +namespace {namespace} {{ + +{class_name}::{class_name}() {{ + number = 6; +}} + +int {class_name}::get_number() const {{ + return number; +}} + +}} +''' + +lib_cpp_test_template = '''#include <{header_file}> +#include <iostream> + +int main(int argc, char **argv) {{ + if(argc != 1) {{ + std::cout << argv[0] << " takes no arguments.\\n"; + return 1; + }} + {namespace}::{class_name} c; + return c.get_number() != 6; +}} +''' + +lib_cpp_meson_template = '''project('{project_name}', 'cpp', + version : '{version}', + default_options : ['warning_level=3', 'cpp_std=c++14']) + +# These arguments are only used to build the shared library +# not the executables that use the library. +lib_args = ['-DBUILDING_{utoken}'] + +# Hiding symbols that are not explicitly marked as exported +# requires a compiler flag on all compilers except VS. +cpp = meson.get_compiler('cpp') +if cpp.get_id() != 'msvc' + lib_args += ['-fvisibility=hidden'] +endif + +shlib = shared_library('{lib_name}', '{source_file}', + install : true, + cpp_args : lib_args, +) + +test_exe = executable('{test_exe_name}', '{test_source_file}', + link_with : shlib) +test('{test_name}', test_exe) + +# Make this library usable as a Meson subproject. +{ltoken}_dep = declare_dependency( + include_directories: include_directories('.'), + link_with : shlib) + +# Make this library usable from the system's +# package manager. +install_headers('{header_file}', subdir : '{header_dir}') + +pkg_mod = import('pkgconfig') +pkg_mod.generate( + name : '{project_name}', + filebase : '{ltoken}', + description : 'Meson sample project.', + subdirs : '{header_dir}', + libraries : shlib, + version : '{version}', +) +''' + +info_message = '''Sample project created. To build it run the +following commands: + +meson builddir +ninja -C builddir +''' + +def create_exe_c_sample(project_name, project_version): + lowercase_token = re.sub(r'[^a-z0-9]', '_', project_name.lower()) + uppercase_token = lowercase_token.upper() + source_name = lowercase_token + '.c' + open(source_name, 'w').write(hello_c_template.format(project_name=project_name)) + open('meson.build', 'w').write(hello_c_meson_template.format(project_name=project_name, + exe_name=lowercase_token, + source_name=source_name, + version=project_version)) + +def create_lib_c_sample(project_name, version): + lowercase_token = re.sub(r'[^a-z0-9]', '_', project_name.lower()) + uppercase_token = lowercase_token.upper() + function_name = lowercase_token[0:3] + '_func' + lib_h_name = lowercase_token + '.h' + lib_c_name = lowercase_token + '.c' + test_c_name = lowercase_token + '_test.c' + kwargs = {'utoken': uppercase_token, + 'ltoken': lowercase_token, + 'header_dir': lowercase_token, + 'function_name': function_name, + 'header_file': lib_h_name, + 'source_file': lib_c_name, + 'test_source_file': test_c_name, + 'test_exe_name': lowercase_token, + 'project_name': project_name, + 'lib_name': lowercase_token, + 'test_name': lowercase_token, + 'version': version, + } + open(lib_h_name, 'w').write(lib_h_template.format(**kwargs)) + open(lib_c_name, 'w').write(lib_c_template.format(**kwargs)) + open(test_c_name, 'w').write(lib_c_test_template.format(**kwargs)) + open('meson.build', 'w').write(lib_c_meson_template.format(**kwargs)) + +def create_exe_cpp_sample(project_name, project_version): + lowercase_token = re.sub(r'[^a-z0-9]', '_', project_name.lower()) + uppercase_token = lowercase_token.upper() + source_name = lowercase_token + '.cpp' + open(source_name, 'w').write(hello_cpp_template.format(project_name=project_name)) + open('meson.build', 'w').write(hello_cpp_meson_template.format(project_name=project_name, + exe_name=lowercase_token, + source_name=source_name, + version=project_version)) + +def create_lib_cpp_sample(project_name, version): + lowercase_token = re.sub(r'[^a-z0-9]', '_', project_name.lower()) + uppercase_token = lowercase_token.upper() + class_name = uppercase_token[0] + lowercase_token[1:] + namespace = lowercase_token + lib_h_name = lowercase_token + '.hpp' + lib_c_name = lowercase_token + '.cpp' + test_c_name = lowercase_token + '_test.cpp' + kwargs = {'utoken': uppercase_token, + 'ltoken': lowercase_token, + 'header_dir': lowercase_token, + 'class_name': class_name, + 'namespace': namespace, + 'header_file': lib_h_name, + 'source_file': lib_c_name, + 'test_source_file': test_c_name, + 'test_exe_name': lowercase_token, + 'project_name': project_name, + 'lib_name': lowercase_token, + 'test_name': lowercase_token, + 'version': version, + } + open(lib_h_name, 'w').write(lib_hpp_template.format(**kwargs)) + open(lib_c_name, 'w').write(lib_cpp_template.format(**kwargs)) + open(test_c_name, 'w').write(lib_cpp_test_template.format(**kwargs)) + open('meson.build', 'w').write(lib_cpp_meson_template.format(**kwargs)) + +def create_sample(options): + if options.language == 'c': + if options.type == 'executable': + create_exe_c_sample(options.name, options.version) + elif options.type == 'library': + create_lib_c_sample(options.name, options.version) + else: + raise RuntimeError('Unreachable code') + elif options.language == 'cpp': + if options.type == 'executable': + create_exe_cpp_sample(options.name, options.version) + elif options.type == 'library': + create_lib_cpp_sample(options.name, options.version) + else: + raise RuntimeError('Unreachable code') + else: + raise RuntimeError('Unreachable code') + print(info_message) + +def run(args): + parser = argparse.ArgumentParser(prog='meson') + parser.add_argument('--name', default = 'mesonsample') + parser.add_argument('--type', default='executable', + choices=['executable', 'library']) + parser.add_argument('--language', default='c', choices=['c', 'cpp']) + parser.add_argument('--version', default='1.0') + options = parser.parse_args(args) + if len(glob('*')) != 0: + sys.exit('This command must be run in an empty directory.') + create_sample(options) + return 0 diff --git a/mesonbuild/mparser.py b/mesonbuild/mparser.py index 0465d24..782b7a7 100644 --- a/mesonbuild/mparser.py +++ b/mesonbuild/mparser.py @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -import re +import os, re from .mesonlib import MesonException from . import mlog @@ -368,7 +368,7 @@ class ArgumentNode: def set_kwarg(self, name, value): if name in self.kwargs: - mlog.warning('Keyword argument "%s" defined multiple times. This will be a an error in future Meson releases.' % name) + mlog.warning('Keyword argument "%s" defined multiple times in file %s, line %d. This will be an error in future Meson releases.' % (name, os.path.join(self.subdir, 'meson.build'), self.lineno)) self.kwargs[name] = value def num_args(self): diff --git a/run_unittests.py b/run_unittests.py index 107306b..e5011c3 100755 --- a/run_unittests.py +++ b/run_unittests.py @@ -36,7 +36,7 @@ import mesonbuild.coredata from mesonbuild.interpreter import ObjectHolder from mesonbuild.mesonlib import is_linux, is_windows, is_osx, is_cygwin, windows_proof_rmtree from mesonbuild.mesonlib import python_command, meson_command, version_compare -from mesonbuild.environment import Environment +from mesonbuild.environment import Environment, detect_ninja from mesonbuild.mesonlib import MesonException, EnvironmentException from mesonbuild.dependencies import PkgConfigDependency, ExternalProgram @@ -1707,6 +1707,28 @@ int main(int argc, char **argv) { self.init(workdir) self.build() + def test_warning_location(self): + tdir = os.path.join(self.unit_test_dir, '20 warning location') + out = self.init(tdir) + self.assertRegex(out, r'WARNING: Keyword argument "link_with" defined multiple times in file meson.build, line 4') + self.assertRegex(out, r'WARNING: Keyword argument "link_with" defined multiple times in file sub' + re.escape(os.path.sep) + r'meson.build, line 3') + self.assertRegex(out, r'WARNING: a warning of some sort in file meson.build, line 6') + self.assertRegex(out, r'WARNING: subdir warning in file sub' + re.escape(os.path.sep) + r'meson.build, line 4') + + def test_templates(self): + ninja = detect_ninja() + if ninja is None: + raise unittest.SkipTest('This test currently requires ninja. Fix this once "meson build" works.') + for lang in ('c', 'cpp'): + for type in ('executable', 'library'): + with tempfile.TemporaryDirectory() as tmpdir: + self._run(meson_command + ['init', '--language', lang, '--type', type], + workdir=tmpdir) + self._run(self.meson_command + ['--backend=ninja', 'builddir'], + workdir=tmpdir) + self._run(ninja, + workdir=os.path.join(tmpdir, 'builddir')) + class FailureTests(BasePlatformTests): ''' diff --git a/test cases/unit/20 warning location/a.c b/test cases/unit/20 warning location/a.c new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/test cases/unit/20 warning location/a.c diff --git a/test cases/unit/20 warning location/b.c b/test cases/unit/20 warning location/b.c new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/test cases/unit/20 warning location/b.c diff --git a/test cases/unit/20 warning location/main.c b/test cases/unit/20 warning location/main.c new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/test cases/unit/20 warning location/main.c diff --git a/test cases/unit/20 warning location/meson.build b/test cases/unit/20 warning location/meson.build new file mode 100644 index 0000000..e26c6c9 --- /dev/null +++ b/test cases/unit/20 warning location/meson.build @@ -0,0 +1,6 @@ +project('duplicate kwarg', 'c') +a = library('liba', 'a.c') +b = library('libb', 'b.c') +executable('main', 'main.c', link_with: a, link_with: b) +subdir('sub') +warning('a warning of some sort') diff --git a/test cases/unit/20 warning location/sub/c.c b/test cases/unit/20 warning location/sub/c.c new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/test cases/unit/20 warning location/sub/c.c diff --git a/test cases/unit/20 warning location/sub/d.c b/test cases/unit/20 warning location/sub/d.c new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/test cases/unit/20 warning location/sub/d.c diff --git a/test cases/unit/20 warning location/sub/meson.build b/test cases/unit/20 warning location/sub/meson.build new file mode 100644 index 0000000..27f6778 --- /dev/null +++ b/test cases/unit/20 warning location/sub/meson.build @@ -0,0 +1,4 @@ +c = library('libc', 'c.c') +d = library('libd', 'd.c') +executable('sub', 'sub.c', link_with: c, link_with: d) +warning('subdir warning') diff --git a/test cases/unit/20 warning location/sub/sub.c b/test cases/unit/20 warning location/sub/sub.c new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/test cases/unit/20 warning location/sub/sub.c |