@Test public void createLexYaccBuildRules() throws IOException { BuildRuleResolver resolver = new BuildRuleResolver(); // Setup our C++ buck config with the paths to the lex/yacc binaries. FakeProjectFilesystem filesystem = new FakeProjectFilesystem(); Path lexPath = Paths.get("lex"); filesystem.touch(lexPath); Path yaccPath = Paths.get("yacc"); filesystem.touch(yaccPath); BuckConfig buckConfig = FakeBuckConfig.builder() .setSections( ImmutableMap.of( "cxx", ImmutableMap.of( "lex", lexPath.toString(), "yacc", yaccPath.toString()))) .setFilesystem(filesystem) .build(); CxxPlatform cxxBuckConfig = DefaultCxxPlatforms.build(new CxxBuckConfig(buckConfig)); // Setup the target name and build params. UnflavoredBuildTarget target = BuildTargetFactory.newInstance("//:test").getUnflavoredBuildTarget(); BuildRuleParams params = new FakeBuildRuleParamsBuilder(BuildTarget.of(target)).build(); // Setup a genrule that generates our lex source. String lexSourceName = "test.ll"; BuildTarget genruleTarget = BuildTargetFactory.newInstance("//:genrule_lex"); Genrule genrule = (Genrule) GenruleBuilder.newGenruleBuilder(genruleTarget).setOut(lexSourceName).build(resolver); SourcePath lexSource = new BuildTargetSourcePath(genrule.getBuildTarget()); // Use a regular path for our yacc source. String yaccSourceName = "test.yy"; SourcePath yaccSource = new TestSourcePath(yaccSourceName); // Build the rules. CxxHeaderSourceSpec actual = CxxDescriptionEnhancer.createLexYaccBuildRules( params, resolver, cxxBuckConfig, ImmutableList.<String>of(), ImmutableMap.of(lexSourceName, lexSource), ImmutableList.<String>of(), ImmutableMap.of(yaccSourceName, yaccSource)); // Grab the generated lex rule and verify it has the genrule as a dep. Lex lex = (Lex) resolver.getRule(CxxDescriptionEnhancer.createLexBuildTarget(target, lexSourceName)); assertNotNull(lex); assertEquals(ImmutableSortedSet.<BuildRule>of(genrule), lex.getDeps()); // Grab the generated yacc rule and verify it has no deps. Yacc yacc = (Yacc) resolver.getRule(CxxDescriptionEnhancer.createYaccBuildTarget(target, yaccSourceName)); assertNotNull(yacc); assertEquals(ImmutableSortedSet.<BuildRule>of(), yacc.getDeps()); // Check the header/source spec is correct. Path lexOutputSource = CxxDescriptionEnhancer.getLexSourceOutputPath(target, lexSourceName); Path lexOutputHeader = CxxDescriptionEnhancer.getLexHeaderOutputPath(target, lexSourceName); Path yaccOutputPrefix = CxxDescriptionEnhancer.getYaccOutputPrefix( target, Files.getNameWithoutExtension(yaccSourceName)); Path yaccOutputSource = Yacc.getSourceOutputPath(yaccOutputPrefix); Path yaccOutputHeader = Yacc.getHeaderOutputPath(yaccOutputPrefix); CxxHeaderSourceSpec expected = CxxHeaderSourceSpec.of( ImmutableMap.<Path, SourcePath>of( target.getBasePath().resolve(lexSourceName + ".h"), new BuildTargetSourcePath(lex.getBuildTarget(), lexOutputHeader), target.getBasePath().resolve(yaccSourceName + ".h"), new BuildTargetSourcePath(yacc.getBuildTarget(), yaccOutputHeader)), ImmutableMap.of( lexSourceName + ".cc", CxxSource.of( CxxSource.Type.CXX, new BuildTargetSourcePath(lex.getBuildTarget(), lexOutputSource), ImmutableList.<String>of()), yaccSourceName + ".cc", CxxSource.of( CxxSource.Type.CXX, new BuildTargetSourcePath(yacc.getBuildTarget(), yaccOutputSource), ImmutableList.<String>of()))); assertEquals(expected, actual); }
/** * Generate {@link Lex} and {@link Yacc} rules generating C/C++ sources from the given lex/yacc * sources. * * @return {@link CxxHeaderSourceSpec} containing the generated headers/sources */ public static CxxHeaderSourceSpec createLexYaccBuildRules( BuildRuleParams params, BuildRuleResolver resolver, CxxPlatform cxxPlatform, ImmutableList<String> lexFlags, ImmutableMap<String, SourcePath> lexSrcs, ImmutableList<String> yaccFlags, ImmutableMap<String, SourcePath> yaccSrcs) { if (!lexSrcs.isEmpty() && !cxxPlatform.getLex().isPresent()) { throw new HumanReadableException( "Platform %s must support lex to compile srcs %s", cxxPlatform, lexSrcs); } if (!yaccSrcs.isEmpty() && !cxxPlatform.getYacc().isPresent()) { throw new HumanReadableException( "Platform %s must support yacc to compile srcs %s", cxxPlatform, yaccSrcs); } SourcePathResolver pathResolver = new SourcePathResolver(resolver); ImmutableMap.Builder<String, CxxSource> lexYaccCxxSourcesBuilder = ImmutableMap.builder(); ImmutableMap.Builder<Path, SourcePath> lexYaccHeadersBuilder = ImmutableMap.builder(); // Loop over all lex sources, generating build rule for each one and adding the sources // and headers it generates to our bookkeeping maps. UnflavoredBuildTarget unflavoredBuildTarget = params.getBuildTarget().getUnflavoredBuildTarget(); for (ImmutableMap.Entry<String, SourcePath> ent : lexSrcs.entrySet()) { final String name = ent.getKey(); final SourcePath source = ent.getValue(); BuildTarget target = createLexBuildTarget(unflavoredBuildTarget, name); Path outputSource = getLexSourceOutputPath(unflavoredBuildTarget, name); Path outputHeader = getLexHeaderOutputPath(unflavoredBuildTarget, name); // Create the build rule to run lex on this source and add it to the resolver. Lex lex = new Lex( params.copyWithChanges( target, Suppliers.ofInstance( ImmutableSortedSet.copyOf( pathResolver.filterBuildRuleInputs(ImmutableList.of(source)))), Suppliers.ofInstance(ImmutableSortedSet.<BuildRule>of())), pathResolver, cxxPlatform.getLex().get(), ImmutableList.<String>builder() .addAll(cxxPlatform.getLexFlags()) .addAll(lexFlags) .build(), outputSource, outputHeader, source); resolver.addToIndex(lex); // Record the output source and header as {@link BuildRuleSourcePath} objects. lexYaccCxxSourcesBuilder.put( name + ".cc", CxxSource.of( CxxSource.Type.CXX, new BuildTargetSourcePath(lex.getBuildTarget(), outputSource), ImmutableList.<String>of())); lexYaccHeadersBuilder.put( params.getBuildTarget().getBasePath().resolve(name + ".h"), new BuildTargetSourcePath(lex.getBuildTarget(), outputHeader)); } // Loop over all yaccc sources, generating build rule for each one and adding the sources // and headers it generates to our bookkeeping maps. for (ImmutableMap.Entry<String, SourcePath> ent : yaccSrcs.entrySet()) { final String name = ent.getKey(); final SourcePath source = ent.getValue(); BuildTarget target = createYaccBuildTarget(unflavoredBuildTarget, name); Path outputPrefix = getYaccOutputPrefix(unflavoredBuildTarget, Files.getNameWithoutExtension(name)); // Create the build rule to run yacc on this source and add it to the resolver. Yacc yacc = new Yacc( params.copyWithChanges( target, Suppliers.ofInstance( ImmutableSortedSet.copyOf( pathResolver.filterBuildRuleInputs(ImmutableList.of(source)))), Suppliers.ofInstance(ImmutableSortedSet.<BuildRule>of())), pathResolver, cxxPlatform.getYacc().get(), ImmutableList.<String>builder() .addAll(cxxPlatform.getYaccFlags()) .addAll(yaccFlags) .build(), outputPrefix, source); resolver.addToIndex(yacc); // Record the output source and header as {@link BuildRuleSourcePath} objects. lexYaccCxxSourcesBuilder.put( name + ".cc", CxxSource.of( CxxSource.Type.CXX, new BuildTargetSourcePath( yacc.getBuildTarget(), Yacc.getSourceOutputPath(outputPrefix)), ImmutableList.<String>of())); lexYaccHeadersBuilder.put( params.getBuildTarget().getBasePath().resolve(name + ".h"), new BuildTargetSourcePath(yacc.getBuildTarget(), Yacc.getHeaderOutputPath(outputPrefix))); } return CxxHeaderSourceSpec.of(lexYaccHeadersBuilder.build(), lexYaccCxxSourcesBuilder.build()); }