Files created with generator can have path segments.

This is OK, because they are written in the private directory
of each target and its layout can be anything.
pull/2764/head
Jussi Pakkanen 7 years ago
parent 19cd60205d
commit 4af4145d09
  1. 37
      mesonbuild/build.py
  2. 2
      mesonbuild/interpreter.py
  3. 4
      test cases/frameworks/5 protocol buffers/asubdir/defs.proto
  4. 4
      test cases/frameworks/5 protocol buffers/defs.proto
  5. 1
      test cases/frameworks/5 protocol buffers/meson.build
  6. 7
      test cases/frameworks/5 protocol buffers/withpath/com/mesonbuild/simple.proto
  7. 10
      test cases/frameworks/5 protocol buffers/withpath/com/mesonbuild/subsite/complex.proto
  8. 14
      test cases/frameworks/5 protocol buffers/withpath/meson.build
  9. 16
      test cases/frameworks/5 protocol buffers/withpath/pathprog.cpp

@ -1072,11 +1072,22 @@ class Generator:
if not isinstance(capture, bool):
raise InvalidArguments('Capture must be boolean.')
self.capture = capture
if 'preserve_path_from' in kwargs:
self.preserve_path_from = kwargs['preserve_path_from']
if not isinstance(self.preserve_path_from, str):
raise InvalidArguments('Preserve_path_from must be a string.')
self.preserve_path_from = os.path.normpath(self.preserve_path_from)
if not os.path.isabs(self.preserve_path_from):
# This is a bit of a hack. Fix properly before merging.
raise InvalidArguments('Preserve_path_from must be an absolute path for now. Sorry.')
else:
self.preserve_path_from = None
def get_base_outnames(self, inname):
plainname = os.path.split(inname)[1]
basename = os.path.splitext(plainname)[0]
return [x.replace('@BASENAME@', basename).replace('@PLAINNAME@', plainname) for x in self.outputs]
bases = [x.replace('@BASENAME@', basename).replace('@PLAINNAME@', plainname) for x in self.outputs]
return bases
def get_dep_outname(self, inname):
if self.depfile is None:
@ -1090,6 +1101,10 @@ class Generator:
basename = os.path.splitext(plainname)[0]
return [x.replace('@BASENAME@', basename).replace('@PLAINNAME@', plainname) for x in self.arglist]
def is_parent_path(self, parent, trial):
relpath = os.path.relpath(os.path.normpath(trial), os.path.normpath(parent))
return not relpath.startswith('..') # For subdirs we can only go "down".
def process_files(self, name, files, state, extra_args=[]):
output = GeneratedList(self, extra_args=extra_args)
for f in files:
@ -1097,7 +1112,11 @@ class Generator:
f = File.from_source_file(state.environment.source_dir, state.subdir, f)
elif not isinstance(f, File):
raise InvalidArguments('{} arguments must be strings or files not {!r}.'.format(name, f))
output.add_file(f)
if self.preserve_path_from:
abs_f = f.absolute_path(state.environment.source_dir, state.environment.build_dir)
if not self.is_parent_path(self.preserve_path_from, abs_f):
raise InvalidArguments('When using preserve_path_from, all input files must be in a subdirectory of the given dir.')
output.add_file(f, state)
return output
@ -1113,9 +1132,21 @@ class GeneratedList:
self.extra_depends = []
self.extra_args = extra_args
def add_file(self, newfile):
def add_preserved_path_segment(self, infile, outfiles, state):
result = []
in_abs = infile.absolute_path(state.environment.source_dir, state.environment.build_dir)
assert(os.path.isabs(self.generator.preserve_path_from))
rel = os.path.relpath(in_abs, self.generator.preserve_path_from)
path_segment = os.path.split(rel)[0]
for of in outfiles:
result.append(os.path.join(path_segment, of))
return result
def add_file(self, newfile, state):
self.infilelist.append(newfile)
outfiles = self.generator.get_base_outnames(newfile.fname)
if self.generator.preserve_path_from:
outfiles = self.add_preserved_path_segment(newfile, outfiles, state)
self.outfilelist += outfiles
self.outmap[newfile] = outfiles

@ -1372,7 +1372,7 @@ permitted_kwargs = {'add_global_arguments': {'language'},
'declare_dependency': {'include_directories', 'link_with', 'sources', 'dependencies', 'compile_args', 'link_args', 'version'},
'executable': exe_kwargs,
'find_program': {'required', 'native'},
'generator': {'arguments', 'output', 'depfile', 'capture'},
'generator': {'arguments', 'output', 'depfile', 'capture', 'preserve_path_from'},
'include_directories': {'is_system'},
'install_data': {'install_dir', 'install_mode', 'sources'},
'install_headers': {'install_dir', 'subdir'},

@ -1,3 +1,5 @@
syntax = "proto3";
message Dummy {
required string text = 1;
string text = 1;
}

@ -1,3 +1,5 @@
syntax = "proto3";
message Dummy {
required string text = 1;
string text = 1;
}

@ -18,3 +18,4 @@ e = executable('prog', 'main.cpp', generated,
test('prototest', e)
subdir('asubdir')
subdir('withpath')

@ -0,0 +1,7 @@
syntax = "proto3";
package subdirectorial;
message SimpleMessage {
int32 the_integer = 1;
}

@ -0,0 +1,10 @@
syntax = "proto3";
package subdirectorial;
import "com/mesonbuild/simple.proto";
message ComplexMessage {
string a_message = 1;
SimpleMessage sm = 2;
}

@ -0,0 +1,14 @@
# Testing protobuf files that are deeply hierarchical
# and must preserve their path segments in output files
# because protoc will always put it in there.
gen = generator(protoc, \
output : ['@BASENAME@.pb.cc', '@BASENAME@.pb.h'],
preserve_path_from : meson.current_source_dir(),
arguments : ['--proto_path=@CURRENT_SOURCE_DIR@', '--cpp_out=@BUILD_DIR@', '@INPUT@'])
generated = gen.process('com/mesonbuild/simple.proto',
'com/mesonbuild/subsite/complex.proto')
e = executable('pathprog', 'pathprog.cpp', generated,
dependencies : dep)
test('pathprog', e)

@ -0,0 +1,16 @@
#include"com/mesonbuild/simple.pb.h"
#include"com/mesonbuild/subsite/complex.pb.h"
#include<memory>
int main(int argc, char **argv) {
GOOGLE_PROTOBUF_VERIFY_VERSION;
{
subdirectorial::SimpleMessage *s = new subdirectorial::SimpleMessage();
s->set_the_integer(3);
subdirectorial::ComplexMessage c;
c.set_allocated_sm(s);
}
google::protobuf::ShutdownProtobufLibrary();
return 0;
}
Loading…
Cancel
Save