private StepExecutionResult executeCCompilation( ExecutionContext context, ImmutableList.Builder<Path> linkerInputs) throws IOException, InterruptedException { ImmutableList.Builder<String> cCompileFlags = ImmutableList.builder(); cCompileFlags.addAll(ocamlContext.getCCompileFlags()); cCompileFlags.addAll(ocamlContext.getCommonCFlags()); CxxPreprocessorInput cxxPreprocessorInput = ocamlContext.getCxxPreprocessorInput(); for (SourcePath cSrc : ocamlContext.getCInput()) { Path outputPath = ocamlContext.getCOutput(resolver.getAbsolutePath(cSrc)); linkerInputs.add(outputPath); Step compileStep = new OCamlCCompileStep( resolver, filesystem.getRootPath(), new OCamlCCompileStep.Args( cCompilerEnvironment, cCompiler, ocamlContext.getOcamlCompiler().get(), ocamlContext.getOCamlInteropIncludesDir(), outputPath, cSrc, cCompileFlags.build(), cxxPreprocessorInput.getIncludes())); StepExecutionResult compileExecutionResult = compileStep.execute(context); if (!compileExecutionResult.isSuccess()) { return compileExecutionResult; } } return StepExecutionResult.SUCCESS; }
private int executeCCompilation( ExecutionContext context, ImmutableList.Builder<Path> linkerInputs) throws IOException, InterruptedException { ImmutableList.Builder<String> cCompileFlags = ImmutableList.builder(); cCompileFlags.addAll(ocamlContext.getCCompileFlags()); cCompileFlags.addAll(ocamlContext.getCommonCFlags()); CxxPreprocessorInput cxxPreprocessorInput = ocamlContext.getCxxPreprocessorInput(); for (SourcePath cSrc : ocamlContext.getCInput()) { Path outputPath = ocamlContext.getCOutput(resolver.getAbsolutePath(cSrc)); linkerInputs.add(outputPath); Step compileStep = new OCamlCCompileStep( resolver, filesystem.getRootPath(), new OCamlCCompileStep.Args( cCompilerEnvironment, cCompiler, ocamlContext.getOcamlCompiler().get(), outputPath, cSrc, cCompileFlags.build(), ImmutableMap.copyOf(cxxPreprocessorInput.getIncludes().getNameToPathMap()))); int compileExitCode = compileStep.execute(context); if (compileExitCode != 0) { return compileExitCode; } } return 0; }
@Test public void flagsArePropagated() throws Exception { BuildRuleResolver resolver = new BuildRuleResolver(TargetGraph.EMPTY, new DefaultTargetNodeToBuildRuleTransformer()); BuildTarget target = BuildTargetFactory.newInstance("//foo:bar"); BuildRuleParams params = new FakeBuildRuleParamsBuilder(target).build(); Archive archive = Archive.from( target, params, new SourcePathResolver(resolver), DEFAULT_ARCHIVER, ImmutableList.of("-foo"), DEFAULT_RANLIB, ImmutableList.of("-bar"), Archive.Contents.NORMAL, DEFAULT_OUTPUT, ImmutableList.of(new FakeSourcePath("simple.o"))); ImmutableList<Step> steps = archive.getBuildSteps(FakeBuildContext.NOOP_CONTEXT, new FakeBuildableContext()); Step archiveStep = FluentIterable.from(steps).filter(ArchiveStep.class).first().get(); assertThat( archiveStep.getDescription(TestExecutionContext.newInstance()), containsString("-foo")); Step ranlibStep = FluentIterable.from(steps).filter(RanlibStep.class).first().get(); assertThat( ranlibStep.getDescription(TestExecutionContext.newInstance()), containsString("-bar")); }
@Test public void testGetBuildStepsWhenThereAreNoClassesToDex() throws IOException, InterruptedException { JavaLibrary javaLibrary = createMock(JavaLibrary.class); expect(javaLibrary.getClassNamesToHashes()) .andReturn(ImmutableSortedMap.<String, HashCode>of()); BuildContext context = createMock(BuildContext.class); FakeBuildableContext buildableContext = new FakeBuildableContext(); ProjectFilesystem projectFilesystem = createMock(ProjectFilesystem.class); replayAll(); BuildTarget buildTarget = BuildTargetFactory.newInstance("//foo:bar"); BuildRuleParams params = new FakeBuildRuleParamsBuilder(buildTarget).setProjectFilesystem(projectFilesystem).build(); DexProducedFromJavaLibrary preDex = new DexProducedFromJavaLibrary( params, new SourcePathResolver(new BuildRuleResolver()), javaLibrary); List<Step> steps = preDex.getBuildSteps(context, buildableContext); verifyAll(); resetAll(); expect(projectFilesystem.resolve(Paths.get("buck-out/gen/foo"))) .andReturn(Paths.get("/home/user/buck-out/gen/foo")); expect(projectFilesystem.resolve(Paths.get("buck-out/gen/foo/bar.dex.jar"))) .andReturn(Paths.get("/home/user/buck-out/gen/foo/bar.dex.jar")); replayAll(); ExecutionContext executionContext = TestExecutionContext.newBuilder().build(); MoreAsserts.assertSteps( "Do not generate a .dex.jar file.", ImmutableList.of( String.format("rm -f %s", Paths.get("/home/user/buck-out/gen/foo/bar.dex.jar")), String.format("mkdir -p %s", Paths.get("/home/user/buck-out/gen/foo")), "record_empty_dx"), steps, executionContext); verifyAll(); resetAll(); replayAll(); Step recordArtifactAndMetadataStep = steps.get(2); assertThat(recordArtifactAndMetadataStep.getShortName(), startsWith("record_")); int exitCode = recordArtifactAndMetadataStep.execute(executionContext); assertEquals(0, exitCode); verifyAll(); }
@Override public void scale(double factor, Path source, Path destination, ExecutionContext context) throws IOException, InterruptedException { Step convertStep = new BashStep( workingDirectory, "convert", "-adaptive-resize", (int) (factor * 100) + "%", Escaper.escapeAsBashString(source), Escaper.escapeAsBashString(destination)); if (0 != convertStep.execute(context)) { throw new HumanReadableException("Cannot scale " + source + " to " + destination); } }
private StepExecutionResult executeMLBytecodeCompilation( ExecutionContext context, Path workingDirectory, ImmutableList<Path> sortedInput, ImmutableList.Builder<Path> linkerInputs) throws IOException, InterruptedException { MakeCleanDirectoryStep mkDir = new MakeCleanDirectoryStep(filesystem, ocamlContext.getCompileBytecodeOutputDir()); StepExecutionResult mkDirExecutionResult = mkDir.execute(context); if (!mkDirExecutionResult.isSuccess()) { return mkDirExecutionResult; } for (Path inputOutput : sortedInput) { String inputFileName = inputOutput.getFileName().toString(); String outputFileName = inputFileName .replaceFirst(OCamlCompilables.OCAML_ML_REGEX, OCamlCompilables.OCAML_CMO) .replaceFirst(OCamlCompilables.OCAML_RE_REGEX, OCamlCompilables.OCAML_CMO) .replaceFirst(OCamlCompilables.OCAML_MLI_REGEX, OCamlCompilables.OCAML_CMI) .replaceFirst(OCamlCompilables.OCAML_REI_REGEX, OCamlCompilables.OCAML_CMI); Path outputPath = ocamlContext.getCompileBytecodeOutputDir().resolve(outputFileName); if (!outputFileName.endsWith(OCamlCompilables.OCAML_CMI)) { linkerInputs.add(outputPath); } final ImmutableList<String> compileFlags = getCompileFlags(/* isBytecode */ true, /* excludeDeps */ false); Step compileBytecodeStep = new OCamlMLCompileStep( workingDirectory, resolver, new OCamlMLCompileStep.Args( filesystem.getAbsolutifier(), cCompilerEnvironment, cCompiler, ocamlContext.getOcamlBytecodeCompiler().get(), ocamlContext.getOCamlInteropIncludesDir(), outputPath, inputOutput, compileFlags)); StepExecutionResult compileExecutionResult = compileBytecodeStep.execute(context); if (!compileExecutionResult.isSuccess()) { return compileExecutionResult; } } return StepExecutionResult.SUCCESS; }
@Override public int execute(ExecutionContext context) throws IOException, InterruptedException { if (hasGeneratedSources) { int genExitCode = generateSources(context, filesystem.getRootPath()); if (genExitCode != 0) { return genExitCode; } } int depToolExitCode = depToolStep.execute(context); if (depToolExitCode != 0) { return depToolExitCode; } // OCaml requires module A to be present in command line to ocamlopt or ocamlc before // module B if B depends on A. In OCaml circular dependencies are prohibited, so all // dependency relations among modules form DAG. Topologically sorting this graph satisfies the // requirement. // // To get the DAG we launch ocamldep tool which provides the direct dependency information, like // module A depends on modules B, C, D. ImmutableList<Path> sortedInput = sortDependency(depToolStep.getStdout()); ImmutableList.Builder<Path> linkerInputs = ImmutableList.builder(); int mlCompileExitCode = executeMLCompilation(context, filesystem.getRootPath(), sortedInput, linkerInputs); if (mlCompileExitCode != 0) { return mlCompileExitCode; } ImmutableList.Builder<Path> bytecodeLinkerInputs = ImmutableList.builder(); int mlCompileBytecodeExitCode = executeMLCompileBytecode( context, filesystem.getRootPath(), sortedInput, bytecodeLinkerInputs); if (mlCompileBytecodeExitCode != 0) { return mlCompileBytecodeExitCode; } ImmutableList.Builder<Path> cLinkerInputs = ImmutableList.builder(); int cCompileExitCode = executeCCompilation(context, cLinkerInputs); if (cCompileExitCode != 0) { return cCompileExitCode; } ImmutableList<Path> cObjects = cLinkerInputs.build(); linkerInputs.addAll(cObjects); int nativeLinkExitCode = executeLinking(context, linkerInputs.build()); if (nativeLinkExitCode != 0) { return nativeLinkExitCode; } bytecodeLinkerInputs.addAll(cObjects); int bytecodeExitCode = executeBytecodeLinking(context, bytecodeLinkerInputs.build()); if (bytecodeExitCode != 0) { return bytecodeExitCode; } if (!ocamlContext.isLibrary()) { Step debugLauncher = new OCamlDebugLauncherStep( filesystem, resolver, new OCamlDebugLauncherStep.Args( ocamlContext.getOcamlDebug().get(), ocamlContext.getBytecodeOutput(), ocamlContext.getOCamlInput(), ocamlContext.getBytecodeIncludeFlags())); return debugLauncher.execute(context); } else { return 0; } }
@Test public void testGetBuildStepsWhenThereAreClassesToDex() throws IOException, InterruptedException { SourcePathResolver pathResolver = new SourcePathResolver(new BuildRuleResolver()); FakeJavaLibrary javaLibraryRule = new FakeJavaLibrary(BuildTargetFactory.newInstance("//foo:bar"), pathResolver) { @Override public ImmutableSortedMap<String, HashCode> getClassNamesToHashes() { return ImmutableSortedMap.of("com/example/Foo", HashCode.fromString("cafebabe")); } @Override public Sha1HashCode getAbiKey() { return Sha1HashCode.of("f7f34ed13b881c6c6f663533cde4a436ea84435e"); } }; javaLibraryRule.setOutputFile("buck-out/gen/foo/bar.jar"); BuildContext context = createMock(BuildContext.class); FakeBuildableContext buildableContext = new FakeBuildableContext(); replayAll(); ProjectFilesystem filesystem = FakeProjectFilesystem.createJavaOnlyFilesystem("/home/user"); createFiles(filesystem, "buck-out/gen/foo/bar#dex.dex.jar", "buck-out/gen/foo/bar.jar"); BuildTarget buildTarget = BuildTargetFactory.newInstance("//foo:bar#dex"); BuildRuleParams params = new FakeBuildRuleParamsBuilder(buildTarget).setProjectFilesystem(filesystem).build(); DexProducedFromJavaLibrary preDex = new DexProducedFromJavaLibrary(params, pathResolver, javaLibraryRule); List<Step> steps = preDex.getBuildSteps(context, buildableContext); verifyAll(); resetAll(); AndroidPlatformTarget androidPlatformTarget = createMock(AndroidPlatformTarget.class); expect(androidPlatformTarget.getDxExecutable()).andReturn(Paths.get("/usr/bin/dx")); replayAll(); ExecutionContext executionContext = TestExecutionContext.newBuilder() .setAndroidPlatformTargetSupplier(Suppliers.ofInstance(androidPlatformTarget)) .build(); String expectedDxCommand = String.format( "%s --dex --no-optimize --force-jumbo --output %s %s", Paths.get("/usr/bin/dx"), Paths.get("/home/user/buck-out/gen/foo/bar#dex.dex.jar"), Paths.get("/home/user/buck-out/gen/foo/bar.jar")); MoreAsserts.assertSteps( "Generate bar.dex.jar.", ImmutableList.of( String.format("rm -f %s", Paths.get("/home/user/buck-out/gen/foo/bar#dex.dex.jar")), String.format("mkdir -p %s", Paths.get("/home/user/buck-out/gen/foo")), "estimate_linear_alloc", "(cd /home/user && " + expectedDxCommand + ")", "zip-scrub buck-out/gen/foo/bar#dex.dex.jar", "record_dx_success"), steps, executionContext); verifyAll(); resetAll(); replayAll(); ((EstimateLinearAllocStep) steps.get(2)).setLinearAllocEstimateForTesting(250); Step recordArtifactAndMetadataStep = steps.get(5); int exitCode = recordArtifactAndMetadataStep.execute(executionContext); assertEquals(0, exitCode); assertEquals( "The generated .dex.jar file should be in the set of recorded artifacts.", ImmutableSet.of(Paths.get("buck-out/gen/foo/bar#dex.dex.jar")), buildableContext.getRecordedArtifacts()); buildableContext.assertContainsMetadataMapping( DexProducedFromJavaLibrary.LINEAR_ALLOC_KEY_ON_DISK_METADATA, "250"); verifyAll(); }