Merge pull request #2764 from mesonbuild/generatorpath
Generator outputs can have path segmentspull/2915/head
commit
d6bed2a77d
20 changed files with 231 additions and 20 deletions
@ -0,0 +1,21 @@ |
||||
## Generator outputs can preserve directory structure |
||||
|
||||
Normally when generating files with a generator, Meson flattens the |
||||
input files so they all go in the same directory. Some code |
||||
generators, such as Protocol Buffers, require that the generated files |
||||
have the same directory layout as the input files used to generate |
||||
them. This can now be achieved like this: |
||||
|
||||
```meson |
||||
g = generator(...) # Compiles protobuf sources |
||||
generated = gen.process('com/mesonbuild/one.proto', |
||||
'com/mesonbuild/two.proto', |
||||
preserve_path_from : meson.current_source_dir()) |
||||
|
||||
This would cause the following files to be generated inside the target |
||||
private directory: |
||||
|
||||
com/mesonbuild/one.pb.h |
||||
com/mesonbuild/one.pb.cc |
||||
com/mesonbuild/two.pb.h |
||||
com/mesonbuild/two.pb.cc |
@ -0,0 +1 @@ |
||||
base |
@ -0,0 +1 @@ |
||||
subbie |
@ -0,0 +1,47 @@ |
||||
#!/usr/bin/env python3 |
||||
|
||||
import os, sys, argparse |
||||
import pathlib |
||||
|
||||
h_templ = '''#pragma once |
||||
|
||||
int %s(); |
||||
''' |
||||
|
||||
c_templ = '''#include"%s.h" |
||||
|
||||
int %s() { |
||||
return 0; |
||||
} |
||||
''' |
||||
|
||||
parser = argparse.ArgumentParser() |
||||
parser.add_argument('--searchdir', required=True) |
||||
parser.add_argument('--outdir', required=True) |
||||
parser.add_argument('ifiles', nargs='+') |
||||
|
||||
options = parser.parse_args() |
||||
|
||||
searchdir = options.searchdir |
||||
outdir = options.outdir |
||||
ifiles = options.ifiles |
||||
|
||||
rel_ofiles = [] |
||||
|
||||
for ifile in ifiles: |
||||
if not ifile.startswith(options.searchdir): |
||||
sys.exit('Input file %s does not start with search dir %s.' % (ifile, searchdir)) |
||||
rel_ofile = ifile[len(searchdir):] |
||||
if rel_ofile[0] == '/' or rel_ofile[0] == '\\': |
||||
rel_ofile = rel_ofile[1:] |
||||
rel_ofiles.append(os.path.splitext(rel_ofile)[0]) |
||||
|
||||
ofile_bases = [os.path.join(outdir, i) for i in rel_ofiles] |
||||
|
||||
for i, ifile_name in enumerate(ifiles): |
||||
proto_name = open(ifile_name).readline().strip() |
||||
h_out = ofile_bases[i] + '.h' |
||||
c_out = ofile_bases[i] + '.c' |
||||
os.makedirs(os.path.split(ofile_bases[i])[0], exist_ok=True) |
||||
open(h_out, 'w').write(h_templ % (proto_name)) |
||||
open(c_out, 'w').write(c_templ % (proto_name, proto_name)) |
@ -0,0 +1,13 @@ |
||||
project('preserve subdir', 'c') |
||||
|
||||
gprog = find_program('genprog.py') |
||||
|
||||
gen = generator(gprog, \ |
||||
output : ['@BASENAME@.c', '@BASENAME@.h'], |
||||
arguments : ['--searchdir=@CURRENT_SOURCE_DIR@', '--outdir=@BUILD_DIR@', '@INPUT@']) |
||||
|
||||
generated = gen.process('base.inp', 'com/mesonbuild/subbie.inp', |
||||
preserve_path_from : meson.current_source_dir()) |
||||
|
||||
e = executable('testprog', 'testprog.c', generated) |
||||
test('testprog', e) |
@ -0,0 +1,6 @@ |
||||
#include"base.h" |
||||
#include"com/mesonbuild/subbie.h" |
||||
|
||||
int main(int argc, char **argv) { |
||||
return base() + subbie(); |
||||
} |
@ -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; |
||||
} |
||||
|
@ -0,0 +1,7 @@ |
||||
# Generated source defined in one directory but |
||||
# used in another. |
||||
|
||||
e = executable('sideprog', 'sideprog.cpp', generated, |
||||
override_options : ['unity=off'], |
||||
dependencies : dep) |
||||
test('sideprog', 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; |
||||
} |
@ -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,13 @@ |
||||
# Testing protobuf files that are deeply hierarchical |
||||
# and must preserve their path segments in output files |
||||
# because protoc will always put it in there. |
||||
|
||||
generated = gen.process('com/mesonbuild/simple.proto', |
||||
'com/mesonbuild/subsite/complex.proto', |
||||
preserve_path_from : meson.current_source_dir(), |
||||
) |
||||
|
||||
e = executable('pathprog', 'pathprog.cpp', generated, |
||||
override_options : ['unity=off'], |
||||
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…
Reference in new issue