aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/markdown/Reference-manual.md15
-rw-r--r--docs/markdown/Syntax.md70
-rw-r--r--docs/markdown/Users.md1
-rw-r--r--docs/markdown/snippets/add_foo_script_type_additions.md24
-rw-r--r--docs/markdown/snippets/link_language_all_targets.md8
-rw-r--r--mesonbuild/backend/backends.py12
-rw-r--r--mesonbuild/backend/ninjabackend.py61
-rw-r--r--mesonbuild/backend/vs2010backend.py3
-rw-r--r--mesonbuild/build.py15
-rw-r--r--mesonbuild/coredata.py8
-rw-r--r--mesonbuild/dependencies/base.py4
-rw-r--r--mesonbuild/dependencies/boost.py100
-rw-r--r--mesonbuild/interpreter.py80
-rw-r--r--mesonbuild/interpreterbase.py2
-rw-r--r--mesonbuild/modules/gnome.py8
-rwxr-xr-xrun_unittests.py29
-rw-r--r--test cases/common/104 postconf with args/meson.build7
-rw-r--r--test cases/common/163 disabler/meson.build28
-rw-r--r--test cases/common/232 link language/c_linkage.cpp5
-rw-r--r--test cases/common/232 link language/c_linkage.h10
-rw-r--r--test cases/common/232 link language/lib.cpp5
-rw-r--r--test cases/common/232 link language/main.c5
-rw-r--r--test cases/common/232 link language/meson.build18
-rwxr-xr-xtest cases/common/56 install script/customtarget.py19
-rw-r--r--test cases/common/56 install script/meson.build26
-rw-r--r--test cases/common/56 install script/myinstall.py29
-rw-r--r--test cases/common/56 install script/src/a file.txt0
-rw-r--r--test cases/common/56 install script/src/exe.c24
-rw-r--r--test cases/common/56 install script/src/meson.build4
-rw-r--r--test cases/common/56 install script/src/myinstall.py4
-rw-r--r--test cases/common/56 install script/test.json10
-rwxr-xr-xtest cases/common/56 install script/wrap.py6
-rw-r--r--test cases/frameworks/1 boost/meson.build2
-rw-r--r--test cases/unit/35 dist script/meson.build1
-rw-r--r--test cases/unit/75 subdir libdir/meson.build2
-rw-r--r--test cases/unit/75 subdir libdir/subprojects/flub/meson.build1
-rwxr-xr-xtools/boost_names.py56
37 files changed, 562 insertions, 140 deletions
diff --git a/docs/markdown/Reference-manual.md b/docs/markdown/Reference-manual.md
index 15a438b..97d3e83 100644
--- a/docs/markdown/Reference-manual.md
+++ b/docs/markdown/Reference-manual.md
@@ -600,8 +600,12 @@ be passed to [shared and static libraries](#library).
depends on such as a symbol visibility map. The purpose is to
automatically trigger a re-link (but not a re-compile) of the target
when this file changes.
-- `link_language` since 0.51.0 makes the linker for this target
- be for the specified language. This is helpful for multi-language targets.
+- `link_language` since 0.51.0 (broken until 0.55.0) makes the linker for this
+ target be for the specified language. It is generally unnecessary to set
+ this, as meson will detect the right linker to use in most cases. There are
+ only two cases where this is needed. One, your main function in an
+ executable is not in the language meson picked, or second you want to force
+ a library to use only one ABI.
- `link_whole` links all contents of the given static libraries
whether they are used by not, equivalent to the
`-Wl,--whole-archive` argument flag of GCC, available since 0.40.0.
@@ -1738,6 +1742,8 @@ the following methods.
0.49.0, the function only accepted a single argument. Since 0.54.0
the `MESON_SOURCE_ROOT` and `MESON_BUILD_ROOT` environment variables
are set when dist scripts are run.
+ *(Since 0.55.0)* The output of `configure_file`, `files`, and `find_program`
+ as well as strings.
- `add_install_script(script_name, arg1, arg2, ...)` causes the script
given as an argument to be run during the install step, this script
@@ -1745,6 +1751,9 @@ the following methods.
`MESON_BUILD_ROOT`, `MESON_INSTALL_PREFIX`,
`MESON_INSTALL_DESTDIR_PREFIX`, and `MESONINTROSPECT` set.
All positional arguments are passed as parameters.
+ *(Since 0.55.0)* The output of `configure_file`, `files`, `find_program`,
+ `custom_target`, indexes of `custom_target`, `executable`, `library`, and
+ other built targets as well as strings.
*(added 0.54)* If `meson install` is called with the `--quiet` option, the
environment variable `MESON_INSTALL_QUIET` will be set.
@@ -1775,6 +1784,8 @@ the following methods.
executable given as an argument after all project files have been
generated. This script will have the environment variables
`MESON_SOURCE_ROOT` and `MESON_BUILD_ROOT` set.
+ *(Since 0.55.0)* The output of `configure_file`, `files`, and `find_program`
+ as well as strings.
- `backend()` *(added 0.37.0)* returns a string representing the
current backend: `ninja`, `vs2010`, `vs2015`, `vs2017`, `vs2019`,
diff --git a/docs/markdown/Syntax.md b/docs/markdown/Syntax.md
index cf0516c..666d50e 100644
--- a/docs/markdown/Syntax.md
+++ b/docs/markdown/Syntax.md
@@ -588,3 +588,73 @@ FAQ](FAQ.md#why-is-meson-not-just-a-python-module-so-i-could-code-my-build-setup
because of this limitation you find yourself copying and pasting code
a lot you may be able to use a [`foreach` loop
instead](#foreach-statements).
+
+Stability Promises
+--
+
+Meson is very actively developed and continuously improved. There is a
+possibility that future enhancements to the Meson build system will require
+changes to the syntax. Such changes might be the addition of new reserved
+keywords, changing the meaning of existing keywords or additions around the
+basic building blocks like statements and fundamental types. It is planned
+to stabilize the syntax with the 1.0 release.
+
+Grammar
+--
+
+This is the full Meson grammar, as it is used to parse Meson build definition files:
+
+```
+additive_expression: multiplicative_expression | (additive_expression additive_operator multiplicative_expression)
+additive_operator: "+" | "-"
+argument_list: positional_arguments ["," keyword_arguments] | keyword_arguments
+array_literal: "[" [expression_list] "]"
+assignment_expression: conditional_expression | (logical_or_expression assignment_operator assignment_expression)
+assignment_operator: "=" | "*=" | "/=" | "%=" | "+=" | "-="
+boolean_literal: "true" | "false"
+build_definition: (NEWLINE | statement)*
+condition: expression
+conditional_expression: logical_or_expression | (logical_or_expression "?" expression ":" assignment_expression
+decimal_literal: DECIMAL_NUMBER
+DECIMAL_NUMBER: /[1-9][0-9]*/
+dictionary_literal: "{" [key_value_list] "}"
+equality_expression: relational_expression | (equality_expression equality_operator relational_expression)
+equality_operator: "==" | "!="
+expression: assignment_expression
+expression_list: expression ("," expression)*
+expression_statememt: expression
+function_expression: id_expression "(" [argument_list] ")"
+hex_literal: "0x" HEX_NUMBER
+HEX_NUMBER: /[a-fA-F0-9]+/
+id_expression: IDENTIFIER
+IDENTIFIER: /[a-zA-Z_][a-zA-Z_0-9]*/
+identifier_list: id_expression ("," id_expression)*
+integer_literal: decimal_literal | octal_literal | hex_literal
+iteration_statement: "foreach" identifier_list ":" id_expression NEWLINE (statement | jump_statement)* "endforeach"
+jump_statement: ("break" | "continue") NEWLINE
+key_value_item: expression ":" expression
+key_value_list: key_value_item ("," key_value_item)*
+keyword_item: id_expression ":" expression
+keyword_arguments: keyword_item ("," keyword_item)*
+literal: integer_literal | string_literal | boolean_literal | array_literal | dictionary_literal
+logical_and_expression: equality_expression | (logical_and_expression "and" equality_expression)
+logical_or_expression: logical_and_expression | (logical_or_expression "or" logical_and_expression)
+method_expression: postfix_expression "." function_expression
+multiplicative_expression: unary_expression | (multiplicative_expression multiplicative_operator unary_expression)
+multiplicative_operator: "*" | "/" | "%"
+octal_literal: "0o" OCTAL_NUMBER
+OCTAL_NUMBER: /[0-7]+/
+positional_arguments: expression ("," expression)*
+postfix_expression: primary_expression | subscript_expression | function_expression | method_expression
+primary_expression: literal | ("(" expression ")") | id_expression
+relational_expression: additive_expression | (relational_expression relational_operator additive_expression)
+relational_operator: ">" | "<" | ">=" | "<=" | "in" | ("not" "in")
+selection_statement: "if" condition NEWLINE (statement)* ("elif" condition NEWLINE (statement)*)* ["else" (statement)*] "endif"
+statement: (expression_statement | selection_statement | iteration_statement) NEWLINE
+string_literal: ("'" STRING_SIMPLE_VALUE "'") | ("'''" STRING_MULTILINE_VALUE "'''")
+STRING_MULTILINE_VALUE: \.*?(''')\
+STRING_SIMPLE_VALUE: \.*?(?<!\\)(\\\\)*?'\
+subscript_expression: postfix_expression "[" expression "]"
+unary_expression: postfix_expression | (unary_operator unary_expression)
+unary_operator: "not" | "+" | "-"
+```
diff --git a/docs/markdown/Users.md b/docs/markdown/Users.md
index bfc8a7a..41d8dfa 100644
--- a/docs/markdown/Users.md
+++ b/docs/markdown/Users.md
@@ -124,6 +124,7 @@ format files
- [Terminology](https://github.com/billiob/terminology), a terminal emulator based on the Enlightenment Foundation Libraries
- [Tilix](https://github.com/gnunn1/tilix), a tiling terminal emulator for Linux using GTK+ 3
- [Tizonia](https://github.com/tizonia/tizonia-openmax-il), a command-line cloud music player for Linux with support for Spotify, Google Play Music, YouTube, SoundCloud, TuneIn, Plex servers and Chromecast devices
+ - [Vala Language Server](https://github.com/benwaffle/vala-language-server), code intelligence engine for the Vala and Genie programming languages
- [Valum](https://github.com/valum-framework/valum), a micro web framework written in Vala
- [Venom](https://github.com/naxuroqa/Venom), a modern Tox client for the GNU/Linux desktop
- [VMAF](https://github.com/Netflix/vmaf) (by Netflix), a perceptual video quality assessment based on multi-method fusion
diff --git a/docs/markdown/snippets/add_foo_script_type_additions.md b/docs/markdown/snippets/add_foo_script_type_additions.md
new file mode 100644
index 0000000..88a88b2
--- /dev/null
+++ b/docs/markdown/snippets/add_foo_script_type_additions.md
@@ -0,0 +1,24 @@
+## meson.add_*_script methods accept new types
+
+All three (`add_install_script`, `add_dist_script`, and
+`add_postconf_script`) now accept ExternalPrograms (as returned by
+`find_program`), Files, and the output of `configure_file`. The dist and
+postconf methods cannot accept other types because of when they are run.
+While dist could, in theory, take other dependencies, it would require more
+extensive changes, particularly to the backend.
+
+```meson
+meson.add_install_script(find_program('foo'), files('bar'))
+meson.add_dist_script(find_program('foo'), files('bar'))
+meson.add_postconf_script(find_program('foo'), files('bar'))
+```
+
+The install script variant is also able to accept custom_targets,
+custom_target indexes, and build targets (executables, libraries), and can
+use built executables a the script to run
+
+```meson
+installer = executable('installer', ...)
+meson.add_install_script(installer, ...)
+meson.add_install_script('foo.py', installer)
+```
diff --git a/docs/markdown/snippets/link_language_all_targets.md b/docs/markdown/snippets/link_language_all_targets.md
new file mode 100644
index 0000000..9019d50
--- /dev/null
+++ b/docs/markdown/snippets/link_language_all_targets.md
@@ -0,0 +1,8 @@
+## link_language argument added to all targets
+
+Previously the `link_language` argument was only supposed to be allowed in
+executables, because the linker used needs to be the linker for the language
+that implements the main function. Unfortunately it didn't work in that case,
+and, even worse, if it had been implemented properly it would have worked for
+*all* targets. In 0.55.0 this restriction has been removed, and the bug fixed.
+It now is valid for `executable` and all derivative of `library`.
diff --git a/mesonbuild/backend/backends.py b/mesonbuild/backend/backends.py
index d41cef1..2727abe 100644
--- a/mesonbuild/backend/backends.py
+++ b/mesonbuild/backend/backends.py
@@ -227,7 +227,7 @@ class Backend:
return os.path.join(self.get_target_dir(target), target.get_filename())
elif isinstance(target, (build.CustomTarget, build.CustomTargetIndex)):
if not target.is_linkable_target():
- raise MesonException('Tried to link against custom target "%s", which is not linkable.' % target.name)
+ raise MesonException('Tried to link against custom target "{}", which is not linkable.'.format(target.name))
return os.path.join(self.get_target_dir(target), target.get_filename())
elif isinstance(target, build.Executable):
if target.import_filename:
@@ -313,7 +313,7 @@ class Backend:
ofile = init_language_file(comp.get_default_suffix(), unity_file_number)
unity_file_number += 1
files_in_current = 0
- ofile.write('#include<%s>\n' % src)
+ ofile.write('#include<{}>\n'.format(src))
files_in_current += 1
if ofile:
ofile.close()
@@ -568,14 +568,14 @@ class Backend:
def create_msvc_pch_implementation(self, target, lang, pch_header):
# We have to include the language in the file name, otherwise
# pch.c and pch.cpp will both end up as pch.obj in VS backends.
- impl_name = 'meson_pch-%s.%s' % (lang, lang)
+ impl_name = 'meson_pch-{}.{}'.format(lang, lang)
pch_rel_to_build = os.path.join(self.get_target_private_dir(target), impl_name)
# Make sure to prepend the build dir, since the working directory is
# not defined. Otherwise, we might create the file in the wrong path.
pch_file = os.path.join(self.build_dir, pch_rel_to_build)
os.makedirs(os.path.dirname(pch_file), exist_ok=True)
- content = '#include "%s"' % os.path.basename(pch_header)
+ content = '#include "{}"'.format(os.path.basename(pch_header))
pch_file_tmp = pch_file + '.tmp'
with open(pch_file_tmp, 'w') as f:
f.write(content)
@@ -695,7 +695,7 @@ class Backend:
args = []
for d in deps:
if not (d.is_linkable_target()):
- raise RuntimeError('Tried to link with a non-library target "%s".' % d.get_basename())
+ raise RuntimeError('Tried to link with a non-library target "{}".'.format(d.get_basename()))
arg = self.get_target_filename_for_linking(d)
if not arg:
continue
@@ -884,7 +884,7 @@ class Backend:
m = regex.search(arg)
while m is not None:
index = int(m.group(1))
- src = '@OUTPUT%d@' % index
+ src = '@OUTPUT{}@'.format(index)
arg = arg.replace(src, os.path.join(private_dir, output_list[index]))
m = regex.search(arg)
newargs.append(arg)
diff --git a/mesonbuild/backend/ninjabackend.py b/mesonbuild/backend/ninjabackend.py
index e765466..9b895c9 100644
--- a/mesonbuild/backend/ninjabackend.py
+++ b/mesonbuild/backend/ninjabackend.py
@@ -67,9 +67,9 @@ def ninja_quote(text, is_build_line=False):
if '\n' in text:
errmsg = '''Ninja does not support newlines in rules. The content was:
-%s
+{}
-Please report this error with a test case to the Meson bug tracker.''' % text
+Please report this error with a test case to the Meson bug tracker.'''.format(text)
raise MesonException(errmsg)
return text
@@ -101,18 +101,18 @@ class NinjaRule:
if not self.refcount:
return
- outfile.write('rule %s\n' % self.name)
+ outfile.write('rule {}\n'.format(self.name))
if self.rspable:
- outfile.write(' command = %s @$out.rsp\n' % ' '.join(self.command))
+ outfile.write(' command = {} @$out.rsp\n'.format(' '.join(self.command)))
outfile.write(' rspfile = $out.rsp\n')
- outfile.write(' rspfile_content = %s\n' % ' '.join(self.args))
+ outfile.write(' rspfile_content = {}\n'.format(' '.join(self.args)))
else:
- outfile.write(' command = %s\n' % ' '.join(self.command + self.args))
+ outfile.write(' command = {}\n'.format(' '.join(self.command + self.args)))
if self.deps:
- outfile.write(' deps = %s\n' % self.deps)
+ outfile.write(' deps = {}\n'.format(self.deps))
if self.depfile:
- outfile.write(' depfile = %s\n' % self.depfile)
- outfile.write(' description = %s\n' % self.description)
+ outfile.write(' depfile = {}\n'.format(self.depfile))
+ outfile.write(' description = {}\n'.format(self.description))
if self.extra:
for l in self.extra.split('\n'):
outfile.write(' ')
@@ -185,7 +185,7 @@ class NinjaBuildElement:
for e in self.elems:
(name, elems) = e
should_quote = name not in raw_names
- line = ' %s = ' % name
+ line = ' {} = '.format(name)
newelems = []
for i in elems:
if not should_quote or i == '&&': # Hackety hack hack
@@ -204,7 +204,7 @@ class NinjaBuildElement:
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)
+ raise MesonException('Multiple producers for Ninja target "{}". Please rename your targets.'.format(n))
self.all_outputs[n] = True
class NinjaBackend(backends.Backend):
@@ -299,8 +299,7 @@ int dummy;
outfilename = os.path.join(self.environment.get_build_dir(), self.ninja_filename)
tempfilename = outfilename + '~'
with open(tempfilename, 'w', encoding='utf-8') as outfile:
- outfile.write('# This is the build file for project "%s"\n' %
- self.build.get_project())
+ outfile.write('# This is the build file for project "{}"\n'.format(self.build.get_project()))
outfile.write('# It is autogenerated by the Meson build system.\n')
outfile.write('# Do not edit by hand.\n\n')
outfile.write('ninja_required_version = 1.7.1\n\n')
@@ -308,9 +307,9 @@ int dummy;
num_pools = self.environment.coredata.backend_options['backend_max_links'].value
if num_pools > 0:
outfile.write('''pool link_pool
- depth = %d
+ depth = {}
-''' % num_pools)
+'''.format(num_pools))
with self.detect_vs_dep_prefix(tempfilename) as outfile:
self.generate_rules()
@@ -765,7 +764,7 @@ int dummy;
target_name = 'meson-{}'.format(self.build_run_target_name(target))
elem = NinjaBuildElement(self.all_outputs, target_name, 'CUSTOM_COMMAND', [])
elem.add_item('COMMAND', cmd)
- elem.add_item('description', 'Running external command %s' % target.name)
+ elem.add_item('description', 'Running external command {}'.format(target.name))
elem.add_item('pool', 'console')
# Alias that runs the target defined above with the name the user specified
self.create_target_alias(target_name)
@@ -980,12 +979,12 @@ int dummy;
ofilename = os.path.join(self.get_target_private_dir(target), ofilebase)
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.add_item('DESC', 'Compiling resource {}'.format(rel_sourcefile))
self.add_build(elem)
deps.append(ofilename)
a = '-resource:' + ofilename
else:
- raise InvalidArguments('Unknown resource file %s.' % r)
+ raise InvalidArguments('Unknown resource file {}.'.format(r))
args.append(a)
return args, deps
@@ -1278,7 +1277,7 @@ int dummy;
main_rust_file = None
for i in target.get_sources():
if not rustc.can_compile(i):
- raise InvalidArguments('Rust target %s contains a non-rust source file.' % target.get_basename())
+ raise InvalidArguments('Rust target {} contains a non-rust source file.'.format(target.get_basename()))
if main_rust_file is None:
main_rust_file = i.rel_to_builddir(self.build_to_src)
if main_rust_file is None:
@@ -1377,11 +1376,11 @@ int dummy;
@classmethod
def get_compiler_rule_name(cls, lang: str, for_machine: MachineChoice) -> str:
- return '%s_COMPILER%s' % (lang, cls.get_rule_suffix(for_machine))
+ return '{}_COMPILER{}'.format(lang, cls.get_rule_suffix(for_machine))
@classmethod
def get_pch_rule_name(cls, lang: str, for_machine: MachineChoice) -> str:
- return '%s_PCH%s' % (lang, cls.get_rule_suffix(for_machine))
+ return '{}_PCH{}'.format(lang, cls.get_rule_suffix(for_machine))
@classmethod
def compiler_to_rule_name(cls, compiler: Compiler) -> str:
@@ -1453,7 +1452,7 @@ int dummy;
abs_headers.append(absh)
header_imports += swiftc.get_header_import_args(absh)
else:
- raise InvalidArguments('Swift target %s contains a non-swift source file.' % target.get_basename())
+ raise InvalidArguments('Swift target {} contains a non-swift source file.'.format(target.get_basename()))
os.makedirs(self.get_target_private_dir_abs(target), exist_ok=True)
compile_args = swiftc.get_compile_only_args()
compile_args += swiftc.get_optimization_args(self.get_option_for_target('optimization', target))
@@ -1540,7 +1539,7 @@ int dummy;
static_linker = self.build.static_linker[for_machine]
if static_linker is None:
return
- rule = 'STATIC_LINKER%s' % self.get_rule_suffix(for_machine)
+ rule = 'STATIC_LINKER{}'.format(self.get_rule_suffix(for_machine))
cmdlist = []
args = ['$in']
# FIXME: Must normalize file names with pathlib.Path before writing
@@ -1574,7 +1573,7 @@ int dummy;
or langname == 'rust' \
or langname == 'cs':
continue
- rule = '%s_LINKER%s' % (langname, self.get_rule_suffix(for_machine))
+ rule = '{}_LINKER{}'.format(langname, self.get_rule_suffix(for_machine))
command = compiler.get_linker_exelist()
args = ['$ARGS'] + compiler.get_linker_output_args('$out') + ['$in', '$LINK_ARGS']
description = 'Linking target $out'
@@ -1645,7 +1644,7 @@ int dummy;
self.add_rule(NinjaRule(rule, command, [], description))
def generate_fortran_dep_hack(self, crstr):
- rule = 'FORTRAN_DEP_HACK%s' % (crstr)
+ rule = 'FORTRAN_DEP_HACK{}'.format(crstr)
if mesonlib.is_windows():
cmd = ['cmd', '/C']
else:
@@ -1698,7 +1697,7 @@ https://gcc.gnu.org/bugzilla/show_bug.cgi?id=47485'''))
command = [ninja_quote(i) for i in compiler.get_exelist()]
args = ['$ARGS'] + quoted_depargs + compiler.get_output_args('$out') + compiler.get_compile_only_args() + ['$in']
- description = 'Compiling %s object $out' % compiler.get_display_language()
+ description = 'Compiling {} object $out'.format(compiler.get_display_language())
if isinstance(compiler, VisualStudioLikeCompiler):
deps = 'msvc'
depfile = None
@@ -1859,9 +1858,8 @@ https://gcc.gnu.org/bugzilla/show_bug.cgi?id=47485'''))
modname = modmatch.group(1).lower()
if modname in module_files:
raise InvalidArguments(
- 'Namespace collision: module %s defined in '
- 'two files %s and %s.' %
- (modname, module_files[modname], s))
+ 'Namespace collision: module {} defined in '
+ 'two files {} and {}.'.format(modname, module_files[modname], s))
module_files[modname] = s
else:
submodmatch = submodre.match(line)
@@ -1872,9 +1870,8 @@ https://gcc.gnu.org/bugzilla/show_bug.cgi?id=47485'''))
if submodname in submodule_files:
raise InvalidArguments(
- 'Namespace collision: submodule %s defined in '
- 'two files %s and %s.' %
- (submodname, submodule_files[submodname], s))
+ 'Namespace collision: submodule {} defined in '
+ 'two files {} and {}.'.format(submodname, submodule_files[submodname], s))
submodule_files[submodname] = s
self.fortran_deps[target.get_basename()] = {**module_files, **submodule_files}
diff --git a/mesonbuild/backend/vs2010backend.py b/mesonbuild/backend/vs2010backend.py
index 80ff910..b5803bf 100644
--- a/mesonbuild/backend/vs2010backend.py
+++ b/mesonbuild/backend/vs2010backend.py
@@ -1192,7 +1192,8 @@ class Vs2010Backend(backends.Backend):
# /nologo
ET.SubElement(link, 'SuppressStartupBanner').text = 'true'
# /release
- ET.SubElement(link, 'SetChecksum').text = 'true'
+ if not self.environment.coredata.get_builtin_option('debug'):
+ ET.SubElement(link, 'SetChecksum').text = 'true'
meson_file_group = ET.SubElement(root, 'ItemGroup')
ET.SubElement(meson_file_group, 'None', Include=os.path.join(proj_to_src_dir, build_filename))
diff --git a/mesonbuild/build.py b/mesonbuild/build.py
index b95988e..fbf2b17 100644
--- a/mesonbuild/build.py
+++ b/mesonbuild/build.py
@@ -84,6 +84,7 @@ buildtarget_kwargs = set([
'override_options',
'sources',
'gnu_symbol_visibility',
+ 'link_language',
])
known_build_target_kwargs = (
@@ -94,7 +95,7 @@ known_build_target_kwargs = (
rust_kwargs |
cs_kwargs)
-known_exe_kwargs = known_build_target_kwargs | {'implib', 'export_dynamic', 'link_language', 'pie'}
+known_exe_kwargs = known_build_target_kwargs | {'implib', 'export_dynamic', 'pie'}
known_shlib_kwargs = known_build_target_kwargs | {'version', 'soversion', 'vs_module_defs', 'darwin_versions'}
known_shmod_kwargs = known_build_target_kwargs | {'vs_module_defs'}
known_stlib_kwargs = known_build_target_kwargs | {'pic'}
@@ -1219,11 +1220,7 @@ You probably should put it in link_with instead.''')
See: https://github.com/mesonbuild/meson/issues/1653
'''
- langs = []
-
- # User specified link_language of target (for multi-language targets)
- if self.link_language:
- return [self.link_language]
+ langs = [] # type: T.List[str]
# Check if any of the external libraries were written in this language
for dep in self.external_deps:
@@ -1255,6 +1252,12 @@ You probably should put it in link_with instead.''')
# Populate list of all compilers, not just those being used to compile
# sources in this target
all_compilers = self.environment.coredata.compilers[self.for_machine]
+
+ # If the user set the link_language, just return that.
+ if self.link_language:
+ comp = all_compilers[self.link_language]
+ return comp, comp.language_stdlib_only_link_flags()
+
# Languages used by dependencies
dep_langs = self.get_langs_used_by_deps()
# Pick a compiler based on the language priority-order
diff --git a/mesonbuild/coredata.py b/mesonbuild/coredata.py
index 0b79084..fcb13f6 100644
--- a/mesonbuild/coredata.py
+++ b/mesonbuild/coredata.py
@@ -99,16 +99,16 @@ class UserBooleanOption(UserOption[bool]):
class UserIntegerOption(UserOption[int]):
def __init__(self, description, value, yielding=None):
min_value, max_value, default_value = value
- super().__init__(description, [True, False], yielding)
self.min_value = min_value
self.max_value = max_value
- self.set_value(default_value)
c = []
if min_value is not None:
c.append('>=' + str(min_value))
if max_value is not None:
c.append('<=' + str(max_value))
- self.choices = ', '.join(c)
+ choices = ', '.join(c)
+ super().__init__(description, choices, yielding)
+ self.set_value(default_value)
def validate_value(self, value) -> int:
if isinstance(value, str):
@@ -385,6 +385,7 @@ class CoreData:
# Only to print a warning if it changes between Meson invocations.
self.config_files = self.__load_config_files(options, scratch_dir, 'native')
self.init_builtins('')
+ self.libdir_cross_fixup()
@staticmethod
def __load_config_files(options: argparse.Namespace, scratch_dir: str, ftype: str) -> T.List[str]:
@@ -510,7 +511,6 @@ class CoreData:
for for_machine in iter(MachineChoice):
for key, opt in builtin_options_per_machine.items():
self.add_builtin_option(self.builtins_per_machine[for_machine], key, opt, subproject)
- self.libdir_cross_fixup()
def add_builtin_option(self, opts_map, key, opt, subproject):
if subproject:
diff --git a/mesonbuild/dependencies/base.py b/mesonbuild/dependencies/base.py
index c0ec089..95a3956 100644
--- a/mesonbuild/dependencies/base.py
+++ b/mesonbuild/dependencies/base.py
@@ -1800,6 +1800,10 @@ class ExternalProgram:
self.name = name
if command is not None:
self.command = listify(command)
+ if mesonlib.is_windows():
+ cmd = self.command[0]
+ args = self.command[1:]
+ self.command = self._search_windows_special_cases(name, cmd) + args
else:
all_search_dirs = [search_dir]
if extra_search_dirs:
diff --git a/mesonbuild/dependencies/boost.py b/mesonbuild/dependencies/boost.py
index 13054f5..fb9d573 100644
--- a/mesonbuild/dependencies/boost.py
+++ b/mesonbuild/dependencies/boost.py
@@ -637,11 +637,8 @@ class BoostDependency(ExternalDependency):
return BoostIncludeDir(hfile.parents[1], int(m.group(1)))
def _extra_compile_args(self) -> T.List[str]:
- args = [] # type: T.List[str]
- args += ['-DBOOST_ALL_NO_LIB'] # Disable automatic linking
- if not self.static:
- args += ['-DBOOST_ALL_DYN_LINK']
- return args
+ # BOOST_ALL_DYN_LINK should not be required with the known defines below
+ return ['-DBOOST_ALL_NO_LIB'] # Disable automatic linking
# See https://www.boost.org/doc/libs/1_72_0/more/getting_started/unix-variants.html#library-naming
@@ -665,9 +662,9 @@ boost_arch_map = {
#### ---- BEGIN GENERATED ---- ####
# #
# Generated with tools/boost_names.py:
-# - boost version: 1.72.0
-# - modules found: 158
-# - libraries found: 42
+# - boost version: 1.73.0
+# - modules found: 159
+# - libraries found: 43
#
class BoostLibrary():
@@ -690,16 +687,16 @@ class BoostModule():
boost_libraries = {
'boost_atomic': BoostLibrary(
name='boost_atomic',
- shared=[],
- static=[],
+ shared=['-DBOOST_ATOMIC_DYN_LINK=1'],
+ static=['-DBOOST_ATOMIC_STATIC_LINK=1'],
single=[],
multi=[],
),
'boost_chrono': BoostLibrary(
name='boost_chrono',
- shared=['-DBOOST_ALL_DYN_LINK=1'],
- static=['-DBOOST_All_STATIC_LINK=1'],
- single=[],
+ shared=['-DBOOST_CHRONO_DYN_LINK=1'],
+ static=['-DBOOST_CHRONO_STATIC_LINK=1'],
+ single=['-DBOOST_CHRONO_THREAD_DISABLED'],
multi=[],
),
'boost_container': BoostLibrary(
@@ -711,28 +708,28 @@ boost_libraries = {
),
'boost_context': BoostLibrary(
name='boost_context',
- shared=[],
+ shared=['-DBOOST_CONTEXT_DYN_LINK=1'],
static=[],
single=[],
multi=[],
),
'boost_contract': BoostLibrary(
name='boost_contract',
- shared=[],
- static=[],
- single=[],
+ shared=['-DBOOST_CONTRACT_DYN_LINK'],
+ static=['-DBOOST_CONTRACT_STATIC_LINK'],
+ single=['-DBOOST_CONTRACT_DISABLE_THREADS'],
multi=[],
),
'boost_coroutine': BoostLibrary(
name='boost_coroutine',
- shared=[],
+ shared=['-DBOOST_COROUTINES_DYN_LINK=1'],
static=[],
single=[],
multi=[],
),
'boost_date_time': BoostLibrary(
name='boost_date_time',
- shared=[],
+ shared=['-DBOOST_DATE_TIME_DYN_LINK=1'],
static=[],
single=[],
multi=[],
@@ -746,14 +743,14 @@ boost_libraries = {
),
'boost_fiber': BoostLibrary(
name='boost_fiber',
- shared=[],
+ shared=['-DBOOST_FIBERS_DYN_LINK=1'],
static=[],
single=[],
multi=[],
),
'boost_fiber_numa': BoostLibrary(
name='boost_fiber_numa',
- shared=[],
+ shared=['-DBOOST_FIBERS_DYN_LINK=1'],
static=[],
single=[],
multi=[],
@@ -767,84 +764,91 @@ boost_libraries = {
),
'boost_graph': BoostLibrary(
name='boost_graph',
- shared=['-DBOOST_GRAPH_DYN_LINK=1'],
+ shared=[],
static=[],
single=[],
multi=[],
),
'boost_iostreams': BoostLibrary(
name='boost_iostreams',
- shared=['-DBOOST_IOSTREAMS_DYN_LINK=1', '-DBOOST_IOSTREAMS_DYN_LINK=1'],
+ shared=['-DBOOST_IOSTREAMS_DYN_LINK=1'],
static=[],
single=[],
multi=[],
),
'boost_locale': BoostLibrary(
name='boost_locale',
- shared=['-DBOOST_LOCALE_DYN_LINK=1'],
+ shared=[],
static=[],
single=[],
multi=[],
),
'boost_log': BoostLibrary(
name='boost_log',
- shared=['-DBOOST_LOG_DLL', '-DBOOST_LOG_DYN_LINK=1'],
+ shared=['-DBOOST_LOG_DYN_LINK=1'],
static=[],
- single=['BOOST_LOG_NO_THREADS'],
+ single=['-DBOOST_LOG_NO_THREADS'],
multi=[],
),
'boost_log_setup': BoostLibrary(
name='boost_log_setup',
- shared=['-DBOOST_LOG_DYN_LINK=1', '-DBOOST_LOG_SETUP_DLL', '-DBOOST_LOG_SETUP_DYN_LINK=1'],
+ shared=['-DBOOST_LOG_SETUP_DYN_LINK=1'],
static=[],
- single=['BOOST_LOG_NO_THREADS'],
+ single=['-DBOOST_LOG_NO_THREADS'],
multi=[],
),
'boost_math_c99': BoostLibrary(
name='boost_math_c99',
- shared=['-DBOOST_MATH_TR1_DYN_LINK=1'],
+ shared=[],
static=[],
single=[],
multi=[],
),
'boost_math_c99f': BoostLibrary(
name='boost_math_c99f',
- shared=['-DBOOST_MATH_TR1_DYN_LINK=1'],
+ shared=[],
static=[],
single=[],
multi=[],
),
'boost_math_c99l': BoostLibrary(
name='boost_math_c99l',
- shared=['-DBOOST_MATH_TR1_DYN_LINK=1'],
+ shared=[],
static=[],
single=[],
multi=[],
),
'boost_math_tr1': BoostLibrary(
name='boost_math_tr1',
- shared=['-DBOOST_MATH_TR1_DYN_LINK=1'],
+ shared=[],
static=[],
single=[],
multi=[],
),
'boost_math_tr1f': BoostLibrary(
name='boost_math_tr1f',
- shared=['-DBOOST_MATH_TR1_DYN_LINK=1'],
+ shared=[],
static=[],
single=[],
multi=[],
),
'boost_math_tr1l': BoostLibrary(
name='boost_math_tr1l',
- shared=['-DBOOST_MATH_TR1_DYN_LINK=1'],
+ shared=[],
static=[],
single=[],
multi=[],
),
'boost_mpi': BoostLibrary(
name='boost_mpi',
- shared=['-DBOOST_MPI_DYN_LINK=1'],
+ shared=[],
+ static=[],
+ single=[],
+ multi=[],
+ ),
+ 'boost_nowide': BoostLibrary(
+ name='boost_nowide',
+ shared=['-DBOOST_NOWIDE_DYN_LINK=1'],
static=[],
single=[],
multi=[],
@@ -865,63 +869,63 @@ boost_libraries = {
),
'boost_random': BoostLibrary(
name='boost_random',
- shared=[],
+ shared=['-DBOOST_RANDOM_DYN_LINK'],
static=[],
single=[],
multi=[],
),
'boost_regex': BoostLibrary(
name='boost_regex',
- shared=['-DBOOST_REGEX_DYN_LINK=1'],
+ shared=[],
static=[],
single=[],
multi=[],
),
'boost_serialization': BoostLibrary(
name='boost_serialization',
- shared=['-DBOOST_SERIALIZATION_DYN_LINK=1'],
+ shared=[],
static=[],
single=[],
multi=[],
),
'boost_stacktrace_addr2line': BoostLibrary(
name='boost_stacktrace_addr2line',
- shared=['-DBOOST_STACKTRACE_DYN_LINK=1'],
+ shared=[],
static=[],
single=[],
multi=[],
),
'boost_stacktrace_backtrace': BoostLibrary(
name='boost_stacktrace_backtrace',
- shared=['-DBOOST_STACKTRACE_DYN_LINK=1'],
+ shared=[],
static=[],
single=[],
multi=[],
),
'boost_stacktrace_basic': BoostLibrary(
name='boost_stacktrace_basic',
- shared=['-DBOOST_STACKTRACE_DYN_LINK=1'],
+ shared=[],
static=[],
single=[],
multi=[],
),
'boost_stacktrace_noop': BoostLibrary(
name='boost_stacktrace_noop',
- shared=['-DBOOST_STACKTRACE_DYN_LINK=1'],
+ shared=[],
static=[],
single=[],
multi=[],
),
'boost_stacktrace_windbg': BoostLibrary(
name='boost_stacktrace_windbg',
- shared=['-DBOOST_STACKTRACE_DYN_LINK=1'],
+ shared=[],
static=[],
single=[],
multi=[],
),
'boost_stacktrace_windbg_cached': BoostLibrary(
name='boost_stacktrace_windbg_cached',
- shared=['-DBOOST_STACKTRACE_DYN_LINK=1'],
+ shared=[],
static=[],
single=[],
multi=[],
@@ -942,8 +946,8 @@ boost_libraries = {
),
'boost_thread': BoostLibrary(
name='boost_thread',
- shared=['-DBOOST_THREAD_USE_DLL=1'],
- static=['-DBOOST_THREAD_USE_LIB=1'],
+ shared=['-DBOOST_THREAD_BUILD_DLL=1', '-DBOOST_THREAD_USE_DLL=1'],
+ static=['-DBOOST_THREAD_BUILD_LIB=1', '-DBOOST_THREAD_USE_LIB=1'],
single=[],
multi=[],
),
@@ -956,7 +960,7 @@ boost_libraries = {
),
'boost_type_erasure': BoostLibrary(
name='boost_type_erasure',
- shared=[],
+ shared=['-DBOOST_TYPE_ERASURE_DYN_LINK'],
static=[],
single=[],
multi=[],
@@ -977,7 +981,7 @@ boost_libraries = {
),
'boost_wserialization': BoostLibrary(
name='boost_wserialization',
- shared=['-DBOOST_SERIALIZATION_DYN_LINK=1'],
+ shared=[],
static=[],
single=[],
multi=[],
diff --git a/mesonbuild/interpreter.py b/mesonbuild/interpreter.py
index c0be92a..a3e9dee 100644
--- a/mesonbuild/interpreter.py
+++ b/mesonbuild/interpreter.py
@@ -1894,48 +1894,98 @@ class MesonMain(InterpreterObject):
'backend': self.backend_method,
})
- def _find_source_script(self, name, args):
+ def _find_source_script(self, prog: T.Union[str, ExecutableHolder], args):
+ if isinstance(prog, ExecutableHolder):
+ prog_path = self.interpreter.backend.get_target_filename(prog.held_object)
+ return build.RunScript([prog_path], args)
+ elif isinstance(prog, ExternalProgramHolder):
+ return build.RunScript(prog.get_command(), args)
+
# Prefer scripts in the current source directory
search_dir = os.path.join(self.interpreter.environment.source_dir,
self.interpreter.subdir)
- key = (name, search_dir)
+ key = (prog, search_dir)
if key in self._found_source_scripts:
found = self._found_source_scripts[key]
else:
- found = dependencies.ExternalProgram(name, search_dir=search_dir)
+ found = dependencies.ExternalProgram(prog, search_dir=search_dir)
if found.found():
self._found_source_scripts[key] = found
else:
m = 'Script or command {!r} not found or not executable'
- raise InterpreterException(m.format(name))
+ raise InterpreterException(m.format(prog))
return build.RunScript(found.get_command(), args)
- @permittedKwargs({})
- def add_install_script_method(self, args, kwargs):
+ def _process_script_args(
+ self, name: str, args: T.List[T.Union[
+ str, mesonlib.File, CustomTargetHolder,
+ CustomTargetIndexHolder, ConfigureFileHolder,
+ ExternalProgramHolder, ExecutableHolder,
+ ]], allow_built: bool = False) -> T.List[str]:
+ script_args = [] # T.List[str]
+ new = False
+ for a in args:
+ a = unholder(a)
+ if isinstance(a, str):
+ script_args.append(a)
+ elif isinstance(a, mesonlib.File):
+ new = True
+ script_args.append(a.rel_to_builddir(self.interpreter.environment.source_dir))
+ elif isinstance(a, (build.BuildTarget, build.CustomTarget, build.CustomTargetIndex)):
+ if not allow_built:
+ raise InterpreterException('Arguments to {} cannot be built'.format(name))
+ new = True
+ script_args.extend([os.path.join(a.get_subdir(), o) for o in a.get_outputs()])
+
+ # This feels really hacky, but I'm not sure how else to fix
+ # this without completely rewriting install script handling.
+ # This is complicated by the fact that the install target
+ # depends on all.
+ if isinstance(a, build.CustomTargetIndex):
+ a.target.build_by_default = True
+ else:
+ a.build_by_default = True
+ elif isinstance(a, build.ConfigureFile):
+ new = True
+ script_args.append(os.path.join(a.subdir, a.targetname))
+ elif isinstance(a, dependencies.ExternalProgram):
+ script_args.extend(a.command)
+ new = True
+ else:
+ raise InterpreterException(
+ 'Arguments to {} must be strings, Files, CustomTargets, '
+ 'Indexes of CustomTargets, or ConfigureFiles'.format(name))
+ if new:
+ FeatureNew('Calling "{}" with File, CustomTaget, Index of CustomTarget, ConfigureFile, Executable, or ExternalProgram'.format(name), '0.55.0').use(
+ self.interpreter.subproject)
+ return script_args
+
+ @permittedKwargs(set())
+ def add_install_script_method(self, args: 'T.Tuple[T.Union[str, ExecutableHolder], T.Union[str, mesonlib.File, CustomTargetHolder, CustomTargetIndexHolder, ConfigureFileHolder], ...]', kwargs):
if len(args) < 1:
raise InterpreterException('add_install_script takes one or more arguments')
- check_stringlist(args, 'add_install_script args must be strings')
- script = self._find_source_script(args[0], args[1:])
+ script_args = self._process_script_args('add_install_script', args[1:], allow_built=True)
+ script = self._find_source_script(args[0], script_args)
self.build.install_scripts.append(script)
- @permittedKwargs({})
+ @permittedKwargs(set())
def add_postconf_script_method(self, args, kwargs):
if len(args) < 1:
raise InterpreterException('add_postconf_script takes one or more arguments')
- check_stringlist(args, 'add_postconf_script arguments must be strings')
- script = self._find_source_script(args[0], args[1:])
+ script_args = self._process_script_args('add_postconf_script', args[1:], allow_built=True)
+ script = self._find_source_script(args[0], script_args)
self.build.postconf_scripts.append(script)
- @permittedKwargs({})
+ @permittedKwargs(set())
def add_dist_script_method(self, args, kwargs):
if len(args) < 1:
raise InterpreterException('add_dist_script takes one or more arguments')
if len(args) > 1:
FeatureNew('Calling "add_dist_script" with multiple arguments', '0.49.0').use(self.interpreter.subproject)
- check_stringlist(args, 'add_dist_script argument must be a string')
if self.interpreter.subproject != '':
raise InterpreterException('add_dist_script may not be used in a subproject.')
- script = self._find_source_script(args[0], args[1:])
+ script_args = self._process_script_args('add_dist_script', args[1:], allow_built=True)
+ script = self._find_source_script(args[0], script_args)
self.build.dist_scripts.append(script)
@noPosargs
@@ -4664,6 +4714,8 @@ This will become a hard error in the future.''', location=self.current_node)
if len(args) < 1 or len(args) > 2:
raise InvalidCode('Get_variable takes one or two arguments.')
varname = args[0]
+ if isinstance(varname, Disabler):
+ return varname
if not isinstance(varname, str):
raise InterpreterException('First argument must be a string.')
try:
diff --git a/mesonbuild/interpreterbase.py b/mesonbuild/interpreterbase.py
index 1a7aa38..6246a06 100644
--- a/mesonbuild/interpreterbase.py
+++ b/mesonbuild/interpreterbase.py
@@ -819,7 +819,7 @@ The result of this is undefined and will become a hard error in a future Meson r
def function_call(self, node: mparser.FunctionNode) -> T.Optional[TYPE_var]:
func_name = node.func_name
(posargs, kwargs) = self.reduce_arguments(node.args)
- if is_disabled(posargs, kwargs) and func_name != 'set_variable' and func_name != 'is_disabler':
+ if is_disabled(posargs, kwargs) and func_name not in {'get_variable', 'set_variable', 'is_disabler'}:
return Disabler()
if func_name in self.funcs:
func = self.funcs[func_name]
diff --git a/mesonbuild/modules/gnome.py b/mesonbuild/modules/gnome.py
index 14cb4c4..7629f18 100644
--- a/mesonbuild/modules/gnome.py
+++ b/mesonbuild/modules/gnome.py
@@ -732,8 +732,12 @@ class GnomeModule(ExtensionModule):
gir_dep, giscanner, gicompiler = self._get_gir_dep(state)
- ns = kwargs.pop('namespace')
- nsversion = kwargs.pop('nsversion')
+ ns = kwargs.get('namespace')
+ if not ns:
+ raise MesonException('Missing "namespace" keyword argument')
+ nsversion = kwargs.get('nsversion')
+ if not nsversion:
+ raise MesonException('Missing "nsversion" keyword argument')
libsources = mesonlib.extract_as_list(kwargs, 'sources', pop=True)
girfile = '%s-%s.gir' % (ns, nsversion)
srcdir = os.path.join(state.environment.get_source_dir(), state.subdir)
diff --git a/run_unittests.py b/run_unittests.py
index 3826762..2939b20 100755
--- a/run_unittests.py
+++ b/run_unittests.py
@@ -4643,6 +4643,22 @@ recommended as it is not supported on some platforms''')
def test_junit_valid_gtest(self):
self._test_junit(os.path.join(self.framework_test_dir, '2 gtest'))
+ def test_link_language_linker(self):
+ # TODO: there should be some way to query how we're linking things
+ # without resorting to reading the ninja.build file
+ if self.backend is not Backend.ninja:
+ raise unittest.SkipTest('This test reads the ninja file')
+
+ testdir = os.path.join(self.common_test_dir, '232 link language')
+ self.init(testdir)
+
+ build_ninja = os.path.join(self.builddir, 'build.ninja')
+ with open(build_ninja, 'r', encoding='utf-8') as f:
+ contents = f.read()
+
+ self.assertRegex(contents, r'build main(\.exe)?.*: c_LINKER')
+ self.assertRegex(contents, r'build (lib|cyg)?mylib.*: c_LINKER')
+
class FailureTests(BasePlatformTests):
'''
@@ -5161,7 +5177,7 @@ class WindowsTests(BasePlatformTests):
raise
raise unittest.SkipTest('pefile module not found')
testdir = os.path.join(self.common_test_dir, '6 linkshared')
- self.init(testdir)
+ self.init(testdir, extra_args=['--buildtype=release'])
self.build()
# Test that binaries have a non-zero checksum
env = get_fake_env()
@@ -6669,6 +6685,17 @@ class LinuxCrossArmTests(BasePlatformTests):
return
self.assertTrue(False, 'Option libdir not in introspect data.')
+ def test_cross_libdir_subproject(self):
+ # Guard against a regression where calling "subproject"
+ # would reset the value of libdir to its default value.
+ testdir = os.path.join(self.unit_test_dir, '75 subdir libdir')
+ self.init(testdir, extra_args=['--libdir=fuf'])
+ for i in self.introspect('--buildoptions'):
+ if i['name'] == 'libdir':
+ self.assertEqual(i['value'], 'fuf')
+ return
+ self.assertTrue(False, 'Libdir specified on command line gets reset.')
+
def test_std_remains(self):
# C_std defined in project options must be in effect also when cross compiling.
testdir = os.path.join(self.unit_test_dir, '51 noncross options')
diff --git a/test cases/common/104 postconf with args/meson.build b/test cases/common/104 postconf with args/meson.build
index 8510c5b..a34502c 100644
--- a/test cases/common/104 postconf with args/meson.build
+++ b/test cases/common/104 postconf with args/meson.build
@@ -1,5 +1,10 @@
project('postconf script', 'c')
-meson.add_postconf_script('postconf.py', '5', '33')
+conf = configure_file(
+ configuration : configuration_data(),
+ output : 'out'
+)
+
+meson.add_postconf_script(find_program('postconf.py'), '5', '33', conf)
test('post', executable('prog', 'prog.c'))
diff --git a/test cases/common/163 disabler/meson.build b/test cases/common/163 disabler/meson.build
index 5554f14..d132e2b 100644
--- a/test cases/common/163 disabler/meson.build
+++ b/test cases/common/163 disabler/meson.build
@@ -9,6 +9,7 @@ d2 = dependency(d)
d3 = (d == d2)
d4 = d + 0
d5 = d2 or true
+set_variable('d6', disabler())
has_not_changed = false
if is_disabler(d)
@@ -23,12 +24,14 @@ assert(is_disabler(d2), 'Function laundered disabler was not identified correctl
assert(is_disabler(d3), 'Disabler comparison should yield disabler.')
assert(is_disabler(d4), 'Disabler addition should yield disabler.')
assert(is_disabler(d5), 'Disabler logic op should yield disabler.')
+assert(is_disabler(d6), 'set_variable with a disabler should set variable to disabler.')
assert(d, 'Disabler did not cause this to be skipped.')
assert(d2, 'Function laundered disabler did not cause this to be skipped.')
assert(d3, 'Disabler comparison should yield disabler and thus this would not be called.')
assert(d4, 'Disabler addition should yield disabler and thus this would not be called.')
assert(d5, 'Disabler logic op should yield disabler and thus this would not be called.')
+assert(d6, 'set_variable with a disabler did not cause this to be skipped.')
number = 0
@@ -80,6 +83,31 @@ else
endif
assert(has_not_changed, 'App has changed.')
+assert(not is_disabler(is_variable('d6')), 'is_variable should not return a disabler')
+assert(is_variable('d6'), 'is_variable for a disabler should return true')
+
+if_is_not_disabled = false
+if is_variable('d6')
+ if_is_not_disabled = true
+else
+ if_is_not_disabled = true
+endif
+assert(if_is_not_disabled, 'Disabler in is_variable should not skip blocks')
+
+get_d = get_variable('d6')
+assert(is_disabler(get_d), 'get_variable should yield a disabler')
+
+get_fallback_d = get_variable('nonexistant', disabler())
+assert(is_disabler(get_fallback_d), 'get_variable fallback should yield a disabler')
+
+var_true = true
+get_no_fallback_d = get_variable('var_true', disabler())
+assert(not is_disabler(get_no_fallback_d), 'get_variable should not fallback to disabler')
+assert(get_no_fallback_d, 'get_variable should yield true')
+
+assert(is_disabler(get_variable(disabler())), 'get_variable should yield a disabler')
+assert(is_disabler(get_variable(disabler(), var_true)), 'get_variable should yield a disabler')
+
if_is_disabled = true
if disabler()
if_is_disabled = false
diff --git a/test cases/common/232 link language/c_linkage.cpp b/test cases/common/232 link language/c_linkage.cpp
new file mode 100644
index 0000000..dc006b9
--- /dev/null
+++ b/test cases/common/232 link language/c_linkage.cpp
@@ -0,0 +1,5 @@
+extern "C" {
+ int makeInt(void) {
+ return 0;
+ }
+}
diff --git a/test cases/common/232 link language/c_linkage.h b/test cases/common/232 link language/c_linkage.h
new file mode 100644
index 0000000..1609f47
--- /dev/null
+++ b/test cases/common/232 link language/c_linkage.h
@@ -0,0 +1,10 @@
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int makeInt(void);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/test cases/common/232 link language/lib.cpp b/test cases/common/232 link language/lib.cpp
new file mode 100644
index 0000000..ab43828
--- /dev/null
+++ b/test cases/common/232 link language/lib.cpp
@@ -0,0 +1,5 @@
+extern "C" {
+ int makeInt(void) {
+ return 1;
+ }
+}
diff --git a/test cases/common/232 link language/main.c b/test cases/common/232 link language/main.c
new file mode 100644
index 0000000..5a167e7
--- /dev/null
+++ b/test cases/common/232 link language/main.c
@@ -0,0 +1,5 @@
+#include "c_linkage.h"
+
+int main(void) {
+ return makeInt();
+}
diff --git a/test cases/common/232 link language/meson.build b/test cases/common/232 link language/meson.build
new file mode 100644
index 0000000..f9af6cd
--- /dev/null
+++ b/test cases/common/232 link language/meson.build
@@ -0,0 +1,18 @@
+project(
+ 'link_language',
+ ['c', 'cpp'],
+)
+
+exe = executable(
+ 'main',
+ ['main.c', 'c_linkage.cpp'],
+ link_language : 'c',
+)
+
+lib = library(
+ 'mylib',
+ ['lib.cpp'],
+ link_language : 'c',
+)
+
+test('main', exe)
diff --git a/test cases/common/56 install script/customtarget.py b/test cases/common/56 install script/customtarget.py
new file mode 100755
index 0000000..e28373a
--- /dev/null
+++ b/test cases/common/56 install script/customtarget.py
@@ -0,0 +1,19 @@
+#!/usr/bin/env python3
+
+import argparse
+import os
+
+
+def main() -> None:
+ parser = argparse.ArgumentParser()
+ parser.add_argument('dirname')
+ args = parser.parse_args()
+
+ with open(os.path.join(args.dirname, '1.txt'), 'w') as f:
+ f.write('')
+ with open(os.path.join(args.dirname, '2.txt'), 'w') as f:
+ f.write('')
+
+
+if __name__ == "__main__":
+ main()
diff --git a/test cases/common/56 install script/meson.build b/test cases/common/56 install script/meson.build
index 6351518..e80e666 100644
--- a/test cases/common/56 install script/meson.build
+++ b/test cases/common/56 install script/meson.build
@@ -5,3 +5,29 @@ meson.add_install_script('myinstall.py', 'diiba/daaba', 'file.dat')
meson.add_install_script('myinstall.py', 'this/should', 'also-work.dat')
subdir('src')
+
+meson.add_install_script('myinstall.py', 'dir', afile, '--mode=copy')
+
+data = configuration_data()
+data.set10('foo', true)
+conf = configure_file(
+ configuration : data,
+ output : 'conf.txt'
+)
+
+meson.add_install_script('myinstall.py', 'dir', conf, '--mode=copy')
+
+t = custom_target(
+ 'ct',
+ command : [find_program('customtarget.py'), '@OUTDIR@'],
+ output : ['1.txt', '2.txt'],
+)
+
+meson.add_install_script('myinstall.py', 'customtarget', t, '--mode=copy')
+meson.add_install_script('myinstall.py', 'customtargetindex', t[0], '--mode=copy')
+
+meson.add_install_script(exe, 'generated.txt')
+wrap = find_program('wrap.py')
+# Yes, these are getting silly
+meson.add_install_script(wrap, exe, 'wrapped.txt')
+meson.add_install_script(wrap, wrap, exe, 'wrapped2.txt')
diff --git a/test cases/common/56 install script/myinstall.py b/test cases/common/56 install script/myinstall.py
index 812561e..a573342 100644
--- a/test cases/common/56 install script/myinstall.py
+++ b/test cases/common/56 install script/myinstall.py
@@ -1,12 +1,31 @@
#!/usr/bin/env python3
+import argparse
import os
-import sys
+import shutil
prefix = os.environ['MESON_INSTALL_DESTDIR_PREFIX']
-dirname = os.path.join(prefix, sys.argv[1])
-os.makedirs(dirname)
-with open(os.path.join(dirname, sys.argv[2]), 'w') as f:
- f.write('')
+def main() -> None:
+ parser = argparse.ArgumentParser()
+ parser.add_argument('dirname')
+ parser.add_argument('files', nargs='+')
+ parser.add_argument('--mode', action='store', default='create', choices=['create', 'copy'])
+ args = parser.parse_args()
+
+ dirname = os.path.join(prefix, args.dirname)
+ if not os.path.exists(dirname):
+ os.makedirs(dirname)
+
+ if args.mode == 'create':
+ for name in args.files:
+ with open(os.path.join(dirname, name), 'w') as f:
+ f.write('')
+ else:
+ for name in args.files:
+ shutil.copy(name, dirname)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/test cases/common/56 install script/src/a file.txt b/test cases/common/56 install script/src/a file.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test cases/common/56 install script/src/a file.txt
diff --git a/test cases/common/56 install script/src/exe.c b/test cases/common/56 install script/src/exe.c
new file mode 100644
index 0000000..b573b91
--- /dev/null
+++ b/test cases/common/56 install script/src/exe.c
@@ -0,0 +1,24 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+int main(int argc, char * argv[]) {
+ if (argc != 2) {
+ fprintf(stderr, "Takes exactly 2 arguments\n");
+ return 1;
+ }
+
+ char * dirname = getenv("MESON_INSTALL_DESTDIR_PREFIX");
+ char * fullname = malloc(strlen(dirname) + 1 + strlen(argv[1]) + 1);
+ strcpy(fullname, dirname);
+ strcat(fullname, "/");
+ strcat(fullname, argv[1]);
+
+ FILE * fp = fopen(fullname, "w");
+ fputs("Some text\n", fp);
+ fclose(fp);
+
+ free(fullname);
+
+ return 0;
+}
diff --git a/test cases/common/56 install script/src/meson.build b/test cases/common/56 install script/src/meson.build
index b23574a..1db424f 100644
--- a/test cases/common/56 install script/src/meson.build
+++ b/test cases/common/56 install script/src/meson.build
@@ -1 +1,5 @@
meson.add_install_script('myinstall.py', 'this/does', 'something-different.dat')
+
+afile = files('a file.txt')
+
+exe = executable('exe', 'exe.c', install : false, native : true)
diff --git a/test cases/common/56 install script/src/myinstall.py b/test cases/common/56 install script/src/myinstall.py
index 3b7ce37..3a9d89b 100644
--- a/test cases/common/56 install script/src/myinstall.py
+++ b/test cases/common/56 install script/src/myinstall.py
@@ -7,6 +7,8 @@ prefix = os.environ['MESON_INSTALL_DESTDIR_PREFIX']
dirname = os.path.join(prefix, sys.argv[1])
-os.makedirs(dirname)
+if not os.path.exists(dirname):
+ os.makedirs(dirname)
+
with open(os.path.join(dirname, sys.argv[2] + '.in'), 'w') as f:
f.write('')
diff --git a/test cases/common/56 install script/test.json b/test cases/common/56 install script/test.json
index d17625f..b2a5971 100644
--- a/test cases/common/56 install script/test.json
+++ b/test cases/common/56 install script/test.json
@@ -4,6 +4,14 @@
{"type": "pdb", "file": "usr/bin/prog"},
{"type": "file", "file": "usr/diiba/daaba/file.dat"},
{"type": "file", "file": "usr/this/should/also-work.dat"},
- {"type": "file", "file": "usr/this/does/something-different.dat.in"}
+ {"type": "file", "file": "usr/this/does/something-different.dat.in"},
+ {"type": "file", "file": "usr/dir/a file.txt"},
+ {"type": "file", "file": "usr/dir/conf.txt"},
+ {"type": "file", "file": "usr/customtarget/1.txt"},
+ {"type": "file", "file": "usr/customtarget/2.txt"},
+ {"type": "file", "file": "usr/customtargetindex/1.txt"},
+ {"type": "file", "file": "usr/generated.txt"},
+ {"type": "file", "file": "usr/wrapped.txt"},
+ {"type": "file", "file": "usr/wrapped2.txt"}
]
}
diff --git a/test cases/common/56 install script/wrap.py b/test cases/common/56 install script/wrap.py
new file mode 100755
index 0000000..87508e0
--- /dev/null
+++ b/test cases/common/56 install script/wrap.py
@@ -0,0 +1,6 @@
+#!/usr/bin/env python3
+
+import subprocess
+import sys
+
+subprocess.run(sys.argv[1:])
diff --git a/test cases/frameworks/1 boost/meson.build b/test cases/frameworks/1 boost/meson.build
index 501ed29..6c23360 100644
--- a/test cases/frameworks/1 boost/meson.build
+++ b/test cases/frameworks/1 boost/meson.build
@@ -13,7 +13,7 @@ endif
# within one project. The need to be independent of each other.
# Use one without a library dependency and one with it.
-linkdep = dependency('boost', static: s, modules : ['thread', 'system'])
+linkdep = dependency('boost', static: s, modules : ['thread', 'system', 'date_time'])
testdep = dependency('boost', static: s, modules : ['unit_test_framework'])
nomoddep = dependency('boost', static: s)
extralibdep = dependency('boost', static: s, modules : ['thread', 'system', 'date_time', 'log_setup', 'log', 'filesystem', 'regex'])
diff --git a/test cases/unit/35 dist script/meson.build b/test cases/unit/35 dist script/meson.build
index fd672a9..2ae9438 100644
--- a/test cases/unit/35 dist script/meson.build
+++ b/test cases/unit/35 dist script/meson.build
@@ -5,3 +5,4 @@ exe = executable('comparer', 'prog.c')
test('compare', exe)
meson.add_dist_script('replacer.py', '"incorrect"', '"correct"')
+meson.add_dist_script(find_program('replacer.py'), '"incorrect"', '"correct"')
diff --git a/test cases/unit/75 subdir libdir/meson.build b/test cases/unit/75 subdir libdir/meson.build
new file mode 100644
index 0000000..5099c91
--- /dev/null
+++ b/test cases/unit/75 subdir libdir/meson.build
@@ -0,0 +1,2 @@
+project('toplevel', 'c')
+subproject('flub')
diff --git a/test cases/unit/75 subdir libdir/subprojects/flub/meson.build b/test cases/unit/75 subdir libdir/subprojects/flub/meson.build
new file mode 100644
index 0000000..7bfd2c5
--- /dev/null
+++ b/test cases/unit/75 subdir libdir/subprojects/flub/meson.build
@@ -0,0 +1 @@
+project('subflub', 'c')
diff --git a/tools/boost_names.py b/tools/boost_names.py
index d26d34b..b66c6cc 100755
--- a/tools/boost_names.py
+++ b/tools/boost_names.py
@@ -43,10 +43,10 @@ export_modules = False
class BoostLibrary():
def __init__(self, name: str, shared: T.List[str], static: T.List[str], single: T.List[str], multi: T.List[str]):
self.name = name
- self.shared = shared
- self.static = static
- self.single = single
- self.multi = multi
+ self.shared = sorted(set(shared))
+ self.static = sorted(set(static))
+ self.single = sorted(set(single))
+ self.multi = sorted(set(multi))
def __lt__(self, other: T.Any) -> T.Union[bool, 'NotImplemented']:
if isinstance(other, BoostLibrary):
@@ -99,15 +99,35 @@ def get_libraries(jamfile: Path) -> T.List[BoostLibrary]:
cmds = raw.split(';') # Commands always terminate with a ; (I hope)
cmds = [x.strip() for x in cmds] # Some cleanup
+ project_usage_requirements: T.List[str] = []
+
# "Parse" the relevant sections
for i in cmds:
parts = i.split(' ')
- parts = [x for x in parts if x not in ['', ':']]
+ parts = [x for x in parts if x not in ['']]
if not parts:
continue
- # Parese libraries
- if parts[0] in ['lib', 'boost-lib']:
+ # Parse project
+ if parts[0] in ['project']:
+ attributes: T.Dict[str, T.List[str]] = {}
+ curr: T.Optional[str] = None
+
+ for j in parts:
+ if j == ':':
+ curr = None
+ elif curr is None:
+ curr = j
+ else:
+ if curr not in attributes:
+ attributes[curr] = []
+ attributes[curr] += [j]
+
+ if 'usage-requirements' in attributes:
+ project_usage_requirements = attributes['usage-requirements']
+
+ # Parse libraries
+ elif parts[0] in ['lib', 'boost-lib']:
assert len(parts) >= 2
# Get and check the library name
@@ -117,28 +137,36 @@ def get_libraries(jamfile: Path) -> T.List[BoostLibrary]:
if not lname.startswith('boost_'):
continue
+ # Count `:` to only select the 'usage-requirements'
+ # See https://boostorg.github.io/build/manual/master/index.html#bbv2.main-target-rule-syntax
+ colon_counter = 0
+ usage_requirements: T.List[str] = []
+ for j in parts:
+ if j == ':':
+ colon_counter += 1
+ elif colon_counter >= 4:
+ usage_requirements += [j]
+
# Get shared / static defines
shared: T.List[str] = []
static: T.List[str] = []
single: T.List[str] = []
multi: T.List[str] = []
- for j in parts:
+ for j in usage_requirements + project_usage_requirements:
m1 = re.match(r'<link>shared:<define>(.*)', j)
m2 = re.match(r'<link>static:<define>(.*)', j)
m3 = re.match(r'<threading>single:<define>(.*)', j)
m4 = re.match(r'<threading>multi:<define>(.*)', j)
if m1:
- shared += [m1.group(1)]
+ shared += [f'-D{m1.group(1)}']
if m2:
- static += [m2.group(1)]
+ static += [f'-D{m2.group(1)}']
if m3:
- single += [m3.group(1)]
+ single +=[f'-D{m3.group(1)}']
if m4:
- multi += [m4.group(1)]
+ multi += [f'-D{m4.group(1)}']
- shared = [f'-D{x}' for x in shared]
- static = [f'-D{x}' for x in static]
libs += [BoostLibrary(lname, shared, static, single, multi)]
return libs