aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Fort <contact@hardening-consulting.com>2018-02-21 10:43:56 +0100
committerJussi Pakkanen <jpakkane@gmail.com>2018-04-08 22:00:45 +0300
commit6dea1777743fe26173d9c674b0870790a7caae92 (patch)
tree115139f40952d714faed6cf8248b771137f289ea
parentaed11affd3a68ec22a0527d82457c8ff365639ec (diff)
downloadmeson-6dea1777743fe26173d9c674b0870790a7caae92.zip
meson-6dea1777743fe26173d9c674b0870790a7caae92.tar.gz
meson-6dea1777743fe26173d9c674b0870790a7caae92.tar.bz2
add support for cmakedefine in configure_file()
The added format argument for configure_file allows to specify the kind of file that is treated. It defaults to 'meson', but can also have the 'cmake' or 'cmake@' value to treat config.h.in files in the cmake format with #cmakedefine statements.
-rw-r--r--docs/markdown/Reference-manual.md7
-rw-r--r--mesonbuild/interpreter.py14
-rw-r--r--mesonbuild/mesonlib.py29
-rw-r--r--test cases/common/16 configure file/config7.h.in16
-rw-r--r--test cases/common/16 configure file/meson.build12
-rw-r--r--test cases/common/16 configure file/prog7.c10
6 files changed, 78 insertions, 10 deletions
diff --git a/docs/markdown/Reference-manual.md b/docs/markdown/Reference-manual.md
index d98fc19..0d3d1aa 100644
--- a/docs/markdown/Reference-manual.md
+++ b/docs/markdown/Reference-manual.md
@@ -186,7 +186,12 @@ These are all the supported keyword arguments:
`output`. Available since v0.41.0.
- `command` as explained above, if specified, Meson does not create
the file itself but rather runs the specified command, which allows
- you to do fully custom file generation
+ you to do fully custom file generation.
+- `format` *(added 0.46.0)* the format of defines. It defaults to `meson`, and so substitutes
+`#mesondefine` statements and variables surrounded by `@` characters, you can also use `cmake`
+to replace `#cmakedefine` statements and variables with the `${variable}` syntax. Finally you can use
+`cmake@` in which case substitutions will apply on `#cmakedefine` statements and variables with
+the `@variable@` syntax.
- `input` the input file name. If it's not specified in configuration
mode, all the variables in the `configuration:` object (see above)
are written to the `output:` file.
diff --git a/mesonbuild/interpreter.py b/mesonbuild/interpreter.py
index 6e3b864..6ecd285 100644
--- a/mesonbuild/interpreter.py
+++ b/mesonbuild/interpreter.py
@@ -1463,7 +1463,7 @@ permitted_kwargs = {'add_global_arguments': {'language'},
'add_test_setup': {'exe_wrapper', 'gdb', 'timeout_multiplier', 'env'},
'benchmark': {'args', 'env', 'should_fail', 'timeout', 'workdir', 'suite'},
'build_target': known_build_target_kwargs,
- 'configure_file': {'input', 'output', 'configuration', 'command', 'install_dir', 'capture', 'install'},
+ 'configure_file': {'input', 'output', 'configuration', 'command', 'install_dir', 'capture', 'install', 'format'},
'custom_target': {'input', 'output', 'command', 'install', 'install_dir', 'build_always', 'capture', 'depends', 'depend_files', 'depfile', 'build_by_default'},
'dependency': {'default_options', 'fallback', 'language', 'main', 'method', 'modules', 'optional_modules', 'native', 'required', 'static', 'version'},
'declare_dependency': {'include_directories', 'link_with', 'sources', 'dependencies', 'compile_args', 'link_args', 'link_whole', 'version'},
@@ -2885,6 +2885,16 @@ root and issuing %s.
if 'command' not in kwargs:
raise InterpreterException('"capture" keyword requires "command" keyword.')
+ if 'format' in kwargs:
+ format = kwargs['format']
+ if not isinstance(format, str):
+ raise InterpreterException('"format" keyword must be a string.')
+ else:
+ format = 'meson'
+
+ if format not in ('meson', 'cmake', 'cmake@'):
+ raise InterpreterException('"format" possible values are "meson", "cmake" or "cmake@".')
+
# Validate input
inputfile = None
ifile_abs = None
@@ -2924,7 +2934,7 @@ root and issuing %s.
if inputfile is not None:
os.makedirs(os.path.join(self.environment.build_dir, self.subdir), exist_ok=True)
missing_variables = mesonlib.do_conf_file(ifile_abs, ofile_abs,
- conf.held_object)
+ conf.held_object, format)
if missing_variables:
var_list = ", ".join(map(repr, sorted(missing_variables)))
mlog.warning(
diff --git a/mesonbuild/mesonlib.py b/mesonbuild/mesonlib.py
index a076e3e..9b00c28 100644
--- a/mesonbuild/mesonlib.py
+++ b/mesonbuild/mesonlib.py
@@ -541,8 +541,13 @@ def has_path_sep(name, sep='/\\'):
return True
return False
-def do_replacement(regex, line, confdata):
+def do_replacement(regex, line, format, confdata):
missing_variables = set()
+ start_tag = '@'
+ backslash_tag = '\\@'
+ if format == 'cmake':
+ start_tag = '${'
+ backslash_tag = '\\${'
def variable_replace(match):
# Pairs of escape characters before '@' or '\@'
@@ -550,8 +555,8 @@ def do_replacement(regex, line, confdata):
num_escapes = match.end(0) - match.start(0)
return '\\' * (num_escapes // 2)
# Single escape character and '@'
- elif match.group(0) == '\\@':
- return '@'
+ elif match.group(0) == backslash_tag:
+ return start_tag
# Template variable to be replaced
else:
varname = match.group(1)
@@ -591,7 +596,7 @@ def do_mesondefine(line, confdata):
raise MesonException('#mesondefine argument "%s" is of unknown type.' % varname)
-def do_conf_file(src, dst, confdata):
+def do_conf_file(src, dst, confdata, format):
try:
with open(src, encoding='utf-8') as f:
data = f.readlines()
@@ -599,14 +604,24 @@ def do_conf_file(src, dst, confdata):
raise MesonException('Could not read input file %s: %s' % (src, str(e)))
# Only allow (a-z, A-Z, 0-9, _, -) as valid characters for a define
# Also allow escaping '@' with '\@'
- regex = re.compile(r'(?:\\\\)+(?=\\?@)|\\@|@([-a-zA-Z0-9_]+)@')
+ if format in ['meson', 'cmake@']:
+ regex = re.compile(r'(?:\\\\)+(?=\\?@)|\\@|@([-a-zA-Z0-9_]+)@')
+ elif format == 'cmake':
+ regex = re.compile(r'(?:\\\\)+(?=\\?\$)|\\\${|\${([-a-zA-Z0-9_]+)}')
+ else:
+ raise MesonException('Format "{}" not handled'.format(format))
+
+ search_token = '#mesondefine'
+ if format != 'meson':
+ search_token = '#cmakedefine'
+
result = []
missing_variables = set()
for line in data:
- if line.startswith('#mesondefine'):
+ if line.startswith(search_token):
line = do_mesondefine(line, confdata)
else:
- line, missing = do_replacement(regex, line, confdata)
+ line, missing = do_replacement(regex, line, format, confdata)
missing_variables.update(missing)
result.append(line)
dst_tmp = dst + '~'
diff --git a/test cases/common/16 configure file/config7.h.in b/test cases/common/16 configure file/config7.h.in
new file mode 100644
index 0000000..edd0bb3
--- /dev/null
+++ b/test cases/common/16 configure file/config7.h.in
@@ -0,0 +1,16 @@
+/* No escape */
+#define MESSAGE1 "${var1}"
+
+/* Single escape means no replace */
+#define MESSAGE2 "\${var1}"
+
+/* Replace pairs of escapes before '@' or '\@' with escape characters
+ * (note we have to double number of pairs due to C string escaping)
+ */
+#define MESSAGE3 "\\\\${var1}"
+
+/* Pairs of escapes and then single escape to avoid replace */
+#define MESSAGE4 "\\\\\${var1}"
+
+/* Check escape character outside variables */
+#define MESSAGE5 "\\ ${ \${ \\\\${ \\\\\${"
diff --git a/test cases/common/16 configure file/meson.build b/test cases/common/16 configure file/meson.build
index 71a2563..5c3a1a5 100644
--- a/test cases/common/16 configure file/meson.build
+++ b/test cases/common/16 configure file/meson.build
@@ -137,3 +137,15 @@ cfile = configure_file(input : 'config.h.in',
output : 'do_not_get_installed.h',
install_dir : '',
configuration : conf)
+
+# Test escaping with cmake format
+conf7 = configuration_data()
+conf7.set('var1', 'foo')
+conf7.set('var2', 'bar')
+configure_file(
+ input : 'config7.h.in',
+ output : '@BASENAME@',
+ format : 'cmake',
+ configuration : conf7
+)
+test('test7', executable('prog7', 'prog7.c'))
diff --git a/test cases/common/16 configure file/prog7.c b/test cases/common/16 configure file/prog7.c
new file mode 100644
index 0000000..0bb7d13
--- /dev/null
+++ b/test cases/common/16 configure file/prog7.c
@@ -0,0 +1,10 @@
+#include <string.h>
+#include <config7.h>
+
+int main(int argc, char **argv) {
+ return strcmp(MESSAGE1, "foo")
+ || strcmp(MESSAGE2, "${var1}")
+ || strcmp(MESSAGE3, "\\foo")
+ || strcmp(MESSAGE4, "\\${var1}")
+ || strcmp(MESSAGE5, "\\ ${ ${ \\${ \\${");
+}