構文

Mesonの記述言語の構文は、できる限りシンプルに保たれています。これは強く型付けされているため、オブジェクトが内部で別のオブジェクトに変換されることはありません。変数には表示される型がないため、Mesonは動的型付けダック型とも呼ばれる)になります。

この言語の主な構成要素は、変数数値ブール値文字列配列関数呼び出しメソッド呼び出しif文、およびincludeです。

通常、1つのMesonステートメントは1行のみを使用します。例えばCのように、1行に複数のステートメントを含めることはできません。関数およびメソッド呼び出しの引数リストは、複数行に分割できます。Mesonはこの場合を自動的に検出し、適切な処理を行います。

他のケースでは、(0.50で追加) 行末に\を付けることで複数行のステートメントを作成できます。行末を除いて、空白には構文上の意味はありません。

変数

Mesonの変数は、他の高水準プログラミング言語と同様に機能します。変数には、整数や文字列など、任意の型の値を格納できます。変数を事前宣言する必要はありません。値を代入するだけで変数が出現します。以下は、2つの異なる変数に値を代入する方法です。

var1 = 'hello'
var2 = 102

Mesonでの変数の動作に関する重要な違いの1つは、すべてのオブジェクトが不変であることです。ミューテーションのように見える操作を行うと、実際には新しいオブジェクトが作成され、その名前が割り当てられます。これは、たとえばPythonがオブジェクトに対してどのように動作するかとは異なりますが、たとえばPythonの文字列と同様です。

var1 = [1, 2, 3]
var2 = var1
var2 += [4]
# var2 is now [1, 2, 3, 4]
# var1 is still [1, 2, 3]

数値

Mesonは整数のみをサポートしています。それらは単純に書き出すことによって宣言されます。基本的な算術演算がサポートされています。

x = 1 + 2
y = 3 * 4
d = 5 % 3 # Yields 2.

16進数リテラルはバージョン0.45.0からサポートされています

int_255 = 0xFF

8進数および2進数リテラルはバージョン0.47.0からサポートされています

int_493 = 0o755
int_1365 = 0b10101010101

文字列は次のように数値に変換できます

string_var = '42'
num = string_var.to_int()

数値は文字列に変換できます

int_var = 42
string_var = int_var.to_string()

ブール値

ブール値はtrueまたはfalseのいずれかです。

truth = true

ブール値は文字列または数値に変換できます

bool_var = true
string_var = bool_var.to_string()
int_var = bool_var.to_int()

文字列

Mesonの文字列は、単一引用符で宣言します。リテラルの単一引用符を入力するには、次のようにします

single_quote = 'contains a \' character'

エスケープシーケンスの完全なリストは次のとおりです

  • \\ バックスラッシュ
  • \' 単一引用符
  • \a ベル
  • \b バックスペース
  • \f 改ページ
  • \n 改行
  • \r キャリッジリターン
  • \t 水平タブ
  • \v 垂直タブ
  • \ooo 8進数値oooを持つ文字
  • \xhh 16進数値hhを持つ文字
  • \uxxxx 16ビット16進数値xxxxを持つ文字
  • \Uxxxxxxxx 32ビット16進数値xxxxxxxxを持つ文字
  • \N{name} Unicodeデータベースでnameという名前の文字

PythonやCと同様に、\oooでは最大3桁の8進数が許可されます。

認識されないエスケープシーケンスは文字列内で変更されずに残ります。つまり、バックスラッシュは文字列に残ります。

文字列連結

文字列は+記号を使用して連結して新しい文字列を形成できます。

str1 = 'abc'
str2 = 'xyz'
combined = str1 + '_' + str2 # combined is now abc_xyz

文字列パス構築

(0.49で追加)

/を演算子として使用して、2つの文字列を連結し、パスを構築できます。これは常にすべてのプラットフォームでパス区切り文字として/を使用します。

joined = '/usr/share' / 'projectname'    # => /usr/share/projectname
joined = '/usr/local' / '/etc/name'      # => /etc/name

joined = 'C:\\foo\\bar' / 'builddir'     # => C:/foo/bar/builddir
joined = 'C:\\foo\\bar' / 'D:\\builddir' # => D:/builddir

これは、この演算子によって廃止されたjoin_paths()を使用するのと同じであることに注意してください。

複数行にわたる文字列

複数行にわたる文字列は、次のように3つの単一引用符で宣言できます

multiline_string = '''#include <foo.h>
int main (int argc, char ** argv) {
  return FOO_SUCCESS;
}'''

これらは、上記のエスケープシーケンスをサポートしないraw文字列です。これらの文字列は、以下で説明する.format()を介して文字列フォーマット機能と組み合わせることもできます。

複数行のf文字列のサポートは、バージョン0.63で追加されたことに注意してください。

文字列インデックス

文字列はインデックス([<num>])演算子をサポートしています。この演算子を使用すると、特定の文字に(読み取り専用で)アクセスできます。返される値は、長さが1の文字列であることが保証されています。

foo = 'abcd'
message(foo[1])  # Will print 'b'
foo[2] = 'C'     # ERROR: Meson objects are immutable!

文字列フォーマット

.format()

文字列は文字列フォーマット機能を使用して構築できます。

template = 'string: @0@, number: @1@, bool: @2@'
res = template.format('text', 1, true)
# res now has value 'string: text, number: 1, bool: true'

わかるように、フォーマットは@number@型のプレースホルダーを対応する引数で置き換えることによって機能します。

フォーマット文字列

(0.58で追加)

フォーマット文字列は、上記で説明した文字列フォーマット機能の非位置指定の代替として使用できます。複数行のf文字列のサポートは、バージョン0.63で追加されたことに注意してください。

n = 10
m = 'hi'

s = f'int: @n@, string: @m@'
# s now has the value 'int: 10, string: hi'

現在、フォーマット文字列内でサポートされているのはアイデンティティ式のみです。つまり、その中で任意のMeson式を使用することはできません。

n = 10
m = 5

# The following is not a valid format string
s = f'result: @n + m@'

文字列メソッド

文字列は、変換されたコピーを返す他の多くのメソッドもサポートしています。

.replace()

0.58.0以降、文字列から部分文字列を置き換えることができます。

# Replaces all instances of one substring with another
s = 'semicolons;as;separators'
s = s.replace('as', 'are')
# 's' now has the value of 'semicolons;are;separators'

.strip()

# Similar to the Python str.strip(). Removes leading/ending spaces and newlines.
define = ' -Dsomedefine '
stripped_define = define.strip()
# 'stripped_define' now has the value '-Dsomedefine'

# You may also pass a string to strip, which specifies the set of characters to
# be removed instead of the default whitespace.
string = 'xyxHelloxyx'.strip('xy')
# 'string' now has the value 'Hello'

0.43.0以降、1つの位置指定の文字列引数を指定でき、その文字列内のすべての文字が削除されます。

.to_upper(), .to_lower()

target = 'x86_FreeBSD'
upper = target.to_upper() # t now has the value 'X86_FREEBSD'
lower = target.to_lower() # t now has the value 'x86_freebsd'

.to_int()

version = '1'
# Converts the string to an int and throws an error if it can't be
ver_int = version.to_int()

.contains(), .startswith(), .endswith()

target = 'x86_FreeBSD'
is_fbsd = target.to_lower().contains('freebsd')
# is_fbsd now has the boolean value 'true'
is_x86 = target.startswith('x86') # boolean value 'true'
is_bsd = target.to_lower().endswith('bsd') # boolean value 'true'

.substring()

0.56.0以降、文字列から部分文字列を抽出できます。

# Similar to the Python str[start:end] syntax
target = 'x86_FreeBSD'
platform = target.substring(0, 3) # prefix string value 'x86'
system = target.substring(4) # suffix string value 'FreeBSD'

このメソッドは、負のstartが文字列の末尾len(string) - startを基準としている負の値と、負のendを受け入れます。

string = 'foobar'
string.substring(-5, -3) # => 'oo'
string.substring(1, -1) # => 'ooba'

.split(), .join()

# Similar to the Python str.split()
components = 'a b   c d '.split()
# components now has the value ['a', 'b', 'c', 'd']
components = 'a b   c d '.split(' ')
# components now has the value ['a', 'b', '', '', 'c', 'd', '']

# Similar to the Python str.join()
output = ' '.join(['foo', 'bar'])
# Output value is 'foo bar'
pathsep = ':'
path = pathsep.join(['/usr/bin', '/bin', '/usr/local/bin'])
# path now has the value '/usr/bin:/bin:/usr/local/bin'

# For joining path elements, you should use path1 / path2
# This has the advantage of being cross-platform
path = '/usr' / 'local' / 'bin'
# path now has the value '/usr/local/bin'

# For sources files, use files():
my_sources = files('foo.c')
...
my_sources += files('bar.c')
# This has the advantage of always calculating the correct relative path, even
# if you add files in another directory or use them in a different directory
# than they're defined in

# Example to set an API version for use in library(), install_header(), etc
project('project', 'c', version: '0.2.3')
version_array = meson.project_version().split('.')
# version_array now has the value ['0', '2', '3']
api_version = '.'.join([version_array[0], version_array[1]])
# api_version now has the value '0.2'

# We can do the same with .format() too:
api_version = '@0@.@1@'.format(version_array[0], version_array[1])
# api_version now (again) has the value '0.2'

.underscorify()

name = 'Meson Docs.txt#Reference-manual'
# Replaces all characters other than `a-zA-Z0-9` with `_` (underscore)
# Useful for substituting into #defines, filenames, etc.
underscored = name.underscorify()
# underscored now has the value 'Meson_Docs_txt_Reference_manual'

.version_compare()

version = '1.2.3'
# Compare version numbers semantically
is_new = version.version_compare('>=2.0')
# is_new now has the boolean value false
# Supports the following operators: '>', '<', '>=', '<=', '!=', '==', '='

Mesonのバージョン比較規則には、以下が含まれます

'3.6'.version_compare('>=3.6.0') == false

比較するには、完全なリビジョンレベルを指定するのが最善です。

配列

配列は角かっこで区切られます。配列には、任意の型の任意の数のオブジェクトを含めることができます。

my_array = [1, 2, 'string', some_obj]

配列の要素へのアクセスは、配列インデックスを介して行うことができます

my_array = [1, 2, 'string', some_obj]
second_element = my_array[1]
last_element = my_array[-1]

次のように配列に項目を追加できます

my_array += ['foo', 3, 4, another_obj]

単一の項目を追加する場合、それを配列で囲む必要はありません

my_array += ['something']
# This also works
my_array += 'else'

Mesonのすべてのオブジェクトは不変であるため、配列に追加すると、元のオブジェクトを変更する代わりに、常に新しい配列オブジェクトが作成され、my_arrayに割り当てられることに注意してください。

0.49.0以降、配列に要素が含まれているかどうかを次のように確認できます

my_array = [1, 2]
if 1 in my_array
# This condition is true
endif
if 1 not in my_array
# This condition is false
endif

配列メソッド

次のメソッドは、すべての配列に対して定義されています

  • length、配列のサイズ
  • contains、配列に引数として指定されたオブジェクトが含まれている場合はtrueを返し、それ以外の場合はfalseを返します
  • get、指定されたインデックスにあるオブジェクトを返します。負のインデックスは配列の後ろからカウントします。範囲外のインデックスは致命的なエラーです。下位互換性を提供するために、配列インデックスと同じです。

辞書

辞書は中かっこで区切られます。辞書には、任意の数のキーと値のペアを含めることができます。キーは文字列である必要がありますが、値は任意の型のオブジェクトにすることができます。0.53.0より前は、キーはリテラル文字列である必要がありました。つまり、文字列値を含む変数をキーとして使用することはできませんでした。

my_dict = {'foo': 42, 'bar': 'baz'}

キーは一意である必要があります

# This will fail
my_dict = {'foo': 42, 'foo': 43}

辞書の要素へのアクセスは、配列インデックスと同様に機能します

my_dict = {'foo': 42, 'bar': 'baz'}
forty_two = my_dict['foo']
# This will fail
my_dict['does_not_exist']

辞書は不変であり、順序は保証されていません。

辞書は0.47.0以降で使用できます。

辞書によって公開されるメソッドについては、リファレンスマニュアルのdictオブジェクトのページをご覧ください。

0.49.0以降、辞書にキーが含まれているかどうかを次のように確認できます

my_dict = {'foo': 42, 'bar': 43}
if 'foo' in my_dict
# This condition is true
endif
if 42 in my_dict
# This condition is false
endif
if 'foo' not in my_dict
# This condition is false
endif

0.53.0以降、キーは文字列値に評価される任意の式にすることができ、もはや文字列リテラルに限定されません。

d = {'a' + 'b' : 42}
k = 'cd'
d += {k : 43}

関数呼び出し

Mesonは使用可能な一連の関数を提供します。最も一般的なユースケースは、ビルドオブジェクトの作成です。

executable('progname', 'prog.c')

ほとんどの関数は、いくつかの位置引数のみを取り、次のように指定されたいくつかのキーワード引数を取り

executable('progname',
  sources: 'prog.c',
  c_args: '-DFOO=1')

バージョン0.49.0以降、キーワード引数を動的に指定できます。これは、kwargsキーワードに設定するキーワードを表す辞書を渡すことによって行われます。前の例は次のように指定されます

d = {'sources': 'prog.c',
  'c_args': '-DFOO=1'}

executable('progname',
  kwargs: d)

単一の関数は、関数呼び出しで直接、およびkwargsキーワード引数を介して間接的にキーワード引数を受け取ることができます。唯一の制限は、特定 のキーを直接引数と間接引数の両方として渡すと、ハードエラーになることです。

d = {'c_args': '-DFOO'}
executable('progname', 'prog.c',
  c_args: '-DBAZ=1',
  kwargs: d) # This is an error!

これを試みると、Mesonはエラーで直ちに終了します。

引数の平坦化

引数の平坦化は、メソッドと関数の使用を簡素化することを目的としたMesonの機能です。この機能がアクティブになっている関数では、Mesonは引数のリストを取得し、ネストされたすべてのリストを1つの大きなリストに平坦化します。

たとえば、executable()への次の関数呼び出しは、Mesonでは同じです

# A normal example:
executable('exe1', ['foo.c', 'bar.c', 'foobar.c'])

# A more contrived example that also works but certainly
# isn't good Meson code:
l1 = ['bar.c']
executable('exe1', [[['foo.c', l1]], ['foobar.c']])

# How meson will treat all the previous calls internally:
executable('exe1', 'foo.c', 'bar.c', 'foobar.c')

内部実装の詳細により、executable()の最初の引数はlistではなく単一のstrであるにもかかわらず、次の構文も現在サポートされています

# WARNING: This example is only valid because of an internal
#          implementation detail and not because it is intended
#
#          PLEASE DO NOT DO SOMETHING LIKE THIS!
#
executable(['exe1', 'foo.c'], 'bar.c', 'foobar.c')

このコードは、引数の平坦化がパラメーターが評価される前に行われるため、現在受け入れられています。このような構成の「サポート」は、将来のMesonリリースで削除される可能性が高くなります!

引数の平坦化は、ほとんどのMeson関数とメソッドでサポートされていますが、すべてではありません。一般的なルールとして、関数のリスト構造が関数に関係ない場合、関数またはメソッドが引数の平坦化をサポートしていると想定できます。

関数が引数の平坦化をサポートしているかどうかは、リファレンスマニュアルに記載されています。

メソッド呼び出し

オブジェクトには、ドット演算子で呼び出されるメソッドを含めることができます。提供される正確なメソッドは、オブジェクトによって異なります。

myobj = some_function()
myobj.do_something('now')

if文

if文は、他の言語と同様に機能します。

var1 = 1
var2 = 2
if var1 == var2 # Evaluates to false
  something_broke()
elif var3 == var2
  something_else_broke()
else
  everything_ok()
endif

opt = get_option('someoption')
if opt != 'foo'
  do_something()
endif

論理演算

Mesonには、ifステートメントで使用できる標準的な論理演算の範囲があります。

if a and b
  # do something
endif
if c or d
  # do something
endif
if not e
  # do something
endif
if not (f or g)
  # do something
endif

論理演算はブール値でのみ機能します。

foreachステートメント

反復可能オブジェクトのすべての要素に対して操作を実行するには、foreachコマンドを使用します。

Meson変数は不変であることに注意してください。foreachループ内で反復されたオブジェクトに新しい値を割り当てようとしても、foreachの制御フローには影響しません。

配列を使用したForeach

配列とforeachを使用して、対応するテストを含む2つの実行可能ファイルを定義する方法の例を次に示します。

progs = [['prog1', ['prog1.c', 'foo.c']],
         ['prog2', ['prog2.c', 'bar.c']]]

foreach p : progs
  exe = executable(p[0], p[1])
  test(p[0], exe)
endforeach

辞書を使用したForeach

構成に従ってコンパイルする必要がある一連のコンポーネントを反復処理する方法の例を次に示します。これは、0.47.0以降で使用可能な辞書を使用します。

components = {
  'foo': ['foo.c'],
  'bar': ['bar.c'],
  'baz': ['baz.c'],
}

# compute a configuration based on system dependencies, custom logic
conf = configuration_data()
conf.set('USE_FOO', 1)

# Determine the sources to compile
sources_to_compile = []
foreach name, sources : components
  if conf.get('USE_@0@'.format(name.to_upper()), 0) == 1
    sources_to_compile += sources
  endif
endforeach

Foreach breakcontinue

0.49.0以降、breakcontinueキーワードをforeachループ内で使用できるようになりました。

items = ['a', 'continue', 'b', 'break', 'c']
result = []
foreach i : items
  if i == 'continue'
    continue
  elif i == 'break'
    break
  endif
  result += i
endforeach
# result is ['a', 'b']

コメント

コメントは#文字で始まり、行末まで続きます。

some_function() # This is a comment
some_other_function()

三項演算子

三項演算子は他の言語と同様に機能します。

x = condition ? true_value : false_value

唯一の例外は、可読性を向上させるために、ネストされた三項演算子が禁止されていることです。分岐処理がこれよりも複雑な場合は、if/else構文を記述する必要があります。

インクルード

ほとんどのソースツリーには、処理対象となる複数のサブディレクトリがあります。これらは、Mesonのsubdirコマンドで処理できます。このコマンドは、指定されたサブディレクトリに移動し、そのサブディレクトリのmeson.buildの内容を実行します。すべての状態(変数など)は、サブディレクトリとの間で渡されます。効果は、サブディレクトリのMesonファイルの内容がincludeコマンドの場所に記述された場合とほぼ同じです。

test_data_dir = 'data'
subdir('tests')

ユーザー定義の関数とメソッド

Mesonは現在、ユーザー定義の関数やメソッドをサポートしていません。ユーザー定義の関数を追加すると、Mesonがチューリング完全となり、推論が難しくなり、IDEなどのツールとの統合が困難になります。これに関する詳細はFAQに記載されています。この制限のために、コードのコピーアンドペーストを頻繁に行う必要がある場合は、代わりにforeachループを使用できる場合があります

安定性の保証

Mesonは非常に活発に開発されており、継続的に改善されています。Mesonビルドシステムの将来の機能強化には、構文の変更が必要になる可能性があります。このような変更には、新しい予約語の追加、既存のキーワードの意味の変更、またはステートメントや基本型などの基本構成要素に関する追加などが考えられます。構文は1.0リリースで安定化する予定です。

文法

これは、Mesonビルド定義ファイルの解析に使用されるMesonの完全な文法です。

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_statement: expression assignment_operator expression
assignment_operator: "=" | "+="
binary_literal: "0b" BINARY_NUMBER
BINARY_NUMBER: /[01]+/
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: conditional_expression | logical_or_expression
expression_list: expression ("," expression)*
expression_statement: 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 | assignment_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" | "-"

検索結果は次のとおりです