Søren Gjesse | c4e5e93 | 2017-09-04 17:01:23 +0200 | [diff] [blame] | 1 | // Copyright (c) 2017, the R8 project authors. Please see the AUTHORS file |
| 2 | // for details. All rights reserved. Use of this source code is governed by a |
| 3 | // BSD-style license that can be found in the LICENSE file. |
| 4 | package com.android.tools.r8; |
| 5 | |
Ian Zerny | 1c6f954 | 2022-03-02 13:46:25 +0100 | [diff] [blame] | 6 | import com.android.tools.r8.dump.DumpOptions; |
clementbera | 75174ac | 2019-09-04 09:14:44 +0200 | [diff] [blame] | 7 | import com.android.tools.r8.errors.CompilationError; |
Ian Zerny | 113faac | 2017-12-14 12:58:23 +0100 | [diff] [blame] | 8 | import com.android.tools.r8.errors.Unreachable; |
clementbera | 75174ac | 2019-09-04 09:14:44 +0200 | [diff] [blame] | 9 | import com.android.tools.r8.graph.DexItemFactory; |
Ian Zerny | 8f3ba44 | 2020-03-11 16:32:27 +0100 | [diff] [blame] | 10 | import com.android.tools.r8.inspector.Inspector; |
Clément Béra | 24cb20a | 2022-02-17 09:30:14 +0000 | [diff] [blame] | 11 | import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibrarySpecification; |
| 12 | import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibrarySpecificationParser; |
Clément Béra | 752cac1 | 2022-02-23 13:38:58 +0000 | [diff] [blame] | 13 | import com.android.tools.r8.ir.desugar.desugaredlibrary.humanspecification.HumanDesugaredLibrarySpecification; |
clementbera | 75174ac | 2019-09-04 09:14:44 +0200 | [diff] [blame] | 14 | import com.android.tools.r8.origin.Origin; |
Christoffer Quist Adamsen | dafb046 | 2022-09-01 12:37:09 +0200 | [diff] [blame] | 15 | import com.android.tools.r8.profile.art.ArtProfileConsumer; |
| 16 | import com.android.tools.r8.profile.art.ArtProfileForRewriting; |
| 17 | import com.android.tools.r8.profile.art.ArtProfileProvider; |
Christoffer Quist Adamsen | 4b3614b | 2022-08-23 11:14:25 +0200 | [diff] [blame] | 18 | import com.android.tools.r8.startup.StartupProfileProvider; |
Mikaël Peltier | 20c9ca7 | 2017-10-03 10:09:39 +0200 | [diff] [blame] | 19 | import com.android.tools.r8.utils.AndroidApiLevel; |
Søren Gjesse | c4e5e93 | 2017-09-04 17:01:23 +0200 | [diff] [blame] | 20 | import com.android.tools.r8.utils.AndroidApp; |
Søren Gjesse | 75a0979 | 2021-04-07 12:41:33 +0200 | [diff] [blame] | 21 | import com.android.tools.r8.utils.DumpInputFlags; |
Søren Gjesse | c4e5e93 | 2017-09-04 17:01:23 +0200 | [diff] [blame] | 22 | import com.android.tools.r8.utils.FileUtils; |
Søren Gjesse | 9a7876d | 2020-01-13 14:32:26 +0100 | [diff] [blame] | 23 | import com.android.tools.r8.utils.InternalOptions.DesugarState; |
Christoffer Quist Adamsen | cbb6a80 | 2023-03-02 14:33:25 +0100 | [diff] [blame] | 24 | import com.android.tools.r8.utils.ListUtils; |
Morten Krogh-Jespersen | 58c98a9 | 2023-05-01 12:18:10 +0200 | [diff] [blame] | 25 | import com.android.tools.r8.utils.PartitionMapZipContainer; |
Christoffer Quist Adamsen | 0a3c16e | 2023-02-15 14:34:44 +0100 | [diff] [blame] | 26 | import com.android.tools.r8.utils.ProgramConsumerUtils; |
Yohann Roussel | 9a8d437 | 2017-11-21 14:36:44 +0100 | [diff] [blame] | 27 | import com.android.tools.r8.utils.Reporter; |
Søren Gjesse | 943389f | 2020-03-13 10:40:25 +0100 | [diff] [blame] | 28 | import com.android.tools.r8.utils.ThreadUtils; |
Søren Gjesse | c4e5e93 | 2017-09-04 17:01:23 +0200 | [diff] [blame] | 29 | import java.nio.file.Path; |
Ian Zerny | d01e99e | 2018-01-04 09:38:36 +0100 | [diff] [blame] | 30 | import java.util.ArrayList; |
Christoffer Quist Adamsen | 4b3614b | 2022-08-23 11:14:25 +0200 | [diff] [blame] | 31 | import java.util.Arrays; |
Ian Zerny | 8f3ba44 | 2020-03-11 16:32:27 +0100 | [diff] [blame] | 32 | import java.util.Collection; |
| 33 | import java.util.Collections; |
Ian Zerny | d01e99e | 2018-01-04 09:38:36 +0100 | [diff] [blame] | 34 | import java.util.List; |
Alan Leung | 4b5db8e | 2019-07-23 13:53:10 -0700 | [diff] [blame] | 35 | import java.util.function.BiPredicate; |
Ian Zerny | 8f3ba44 | 2020-03-11 16:32:27 +0100 | [diff] [blame] | 36 | import java.util.function.Consumer; |
Søren Gjesse | 95fce5f | 2019-12-16 10:33:51 +0100 | [diff] [blame] | 37 | import java.util.function.Function; |
Søren Gjesse | c4e5e93 | 2017-09-04 17:01:23 +0200 | [diff] [blame] | 38 | |
| 39 | /** |
| 40 | * Base class for commands and command builders for compiler applications/tools which besides an |
Ian Zerny | 850f13d | 2018-01-04 11:25:38 +0100 | [diff] [blame] | 41 | * Android application (and optional main-dex list) also configure compilation output, compilation |
| 42 | * mode and min API level. |
Ian Zerny | afb08e1 | 2018-01-08 14:22:58 +0100 | [diff] [blame] | 43 | * |
| 44 | * <p>For concrete builders, see for example {@link D8Command.Builder} and {@link |
| 45 | * R8Command.Builder}. |
Søren Gjesse | c4e5e93 | 2017-09-04 17:01:23 +0200 | [diff] [blame] | 46 | */ |
Mathias Rav | 3fb4a3a | 2018-05-29 15:41:36 +0200 | [diff] [blame] | 47 | @Keep |
Ian Zerny | 850f13d | 2018-01-04 11:25:38 +0100 | [diff] [blame] | 48 | public abstract class BaseCompilerCommand extends BaseCommand { |
Søren Gjesse | c4e5e93 | 2017-09-04 17:01:23 +0200 | [diff] [blame] | 49 | |
Søren Gjesse | c4e5e93 | 2017-09-04 17:01:23 +0200 | [diff] [blame] | 50 | private final CompilationMode mode; |
Ian Zerny | 113faac | 2017-12-14 12:58:23 +0100 | [diff] [blame] | 51 | private final ProgramConsumer programConsumer; |
Mads Ager | d9ae2a8 | 2018-11-29 13:01:55 +0100 | [diff] [blame] | 52 | private final StringConsumer mainDexListConsumer; |
Søren Gjesse | c4e5e93 | 2017-09-04 17:01:23 +0200 | [diff] [blame] | 53 | private final int minApiLevel; |
Yohann Roussel | 9a8d437 | 2017-11-21 14:36:44 +0100 | [diff] [blame] | 54 | private final Reporter reporter; |
Søren Gjesse | 9a7876d | 2020-01-13 14:32:26 +0100 | [diff] [blame] | 55 | private final DesugarState desugarState; |
Alan Leung | 4b5db8e | 2019-07-23 13:53:10 -0700 | [diff] [blame] | 56 | private final boolean includeClassesChecksum; |
Yohann Roussel | 2284bc8 | 2018-04-26 15:45:35 +0200 | [diff] [blame] | 57 | private final boolean optimizeMultidexForLinearAlloc; |
Alan Leung | 4b5db8e | 2019-07-23 13:53:10 -0700 | [diff] [blame] | 58 | private final BiPredicate<String, Long> dexClassChecksumFilter; |
Søren Gjesse | 99e8a74 | 2020-01-07 13:59:38 +0100 | [diff] [blame] | 59 | private final List<AssertionsConfiguration> assertionsConfiguration; |
Ian Zerny | 8f3ba44 | 2020-03-11 16:32:27 +0100 | [diff] [blame] | 60 | private final List<Consumer<Inspector>> outputInspections; |
Søren Gjesse | 75a0979 | 2021-04-07 12:41:33 +0200 | [diff] [blame] | 61 | private final int threadCount; |
| 62 | private final DumpInputFlags dumpInputFlags; |
Ian Zerny | b23c47c | 2021-10-06 08:00:19 +0200 | [diff] [blame] | 63 | private final MapIdProvider mapIdProvider; |
Ian Zerny | 1433d58 | 2021-10-12 09:44:48 +0200 | [diff] [blame] | 64 | private final SourceFileProvider sourceFileProvider; |
Ian Zerny | bbd2392 | 2022-06-07 10:33:31 +0200 | [diff] [blame] | 65 | private final boolean isAndroidPlatformBuild; |
Christoffer Quist Adamsen | dafb046 | 2022-09-01 12:37:09 +0200 | [diff] [blame] | 66 | private final List<ArtProfileForRewriting> artProfilesForRewriting; |
Christoffer Quist Adamsen | 4b3614b | 2022-08-23 11:14:25 +0200 | [diff] [blame] | 67 | private final List<StartupProfileProvider> startupProfileProviders; |
Ian Zerny | 7744006 | 2022-08-26 13:49:08 +0200 | [diff] [blame] | 68 | private final ClassConflictResolver classConflictResolver; |
Ian Zerny | d9bd076 | 2023-03-24 16:46:18 +0100 | [diff] [blame] | 69 | private final CancelCompilationChecker cancelCompilationChecker; |
Søren Gjesse | c4e5e93 | 2017-09-04 17:01:23 +0200 | [diff] [blame] | 70 | |
| 71 | BaseCompilerCommand(boolean printHelp, boolean printVersion) { |
| 72 | super(printHelp, printVersion); |
Ian Zerny | 7efd28d | 2017-12-12 09:17:42 +0100 | [diff] [blame] | 73 | programConsumer = null; |
Mads Ager | d9ae2a8 | 2018-11-29 13:01:55 +0100 | [diff] [blame] | 74 | mainDexListConsumer = null; |
Mads Ager | 642e757 | 2017-10-03 15:43:09 +0200 | [diff] [blame] | 75 | mode = null; |
| 76 | minApiLevel = 0; |
Morten Krogh-Jespersen | ff59ed3 | 2018-10-08 15:15:57 +0200 | [diff] [blame] | 77 | reporter = new Reporter(); |
Søren Gjesse | 9a7876d | 2020-01-13 14:32:26 +0100 | [diff] [blame] | 78 | desugarState = DesugarState.ON; |
Alan Leung | 4b5db8e | 2019-07-23 13:53:10 -0700 | [diff] [blame] | 79 | includeClassesChecksum = false; |
Yohann Roussel | 2284bc8 | 2018-04-26 15:45:35 +0200 | [diff] [blame] | 80 | optimizeMultidexForLinearAlloc = false; |
Alan Leung | 4b5db8e | 2019-07-23 13:53:10 -0700 | [diff] [blame] | 81 | dexClassChecksumFilter = (name, checksum) -> true; |
Søren Gjesse | 99e8a74 | 2020-01-07 13:59:38 +0100 | [diff] [blame] | 82 | assertionsConfiguration = new ArrayList<>(); |
Ian Zerny | 8f3ba44 | 2020-03-11 16:32:27 +0100 | [diff] [blame] | 83 | outputInspections = null; |
Søren Gjesse | 943389f | 2020-03-13 10:40:25 +0100 | [diff] [blame] | 84 | threadCount = ThreadUtils.NOT_SPECIFIED; |
Søren Gjesse | 75a0979 | 2021-04-07 12:41:33 +0200 | [diff] [blame] | 85 | dumpInputFlags = DumpInputFlags.noDump(); |
Ian Zerny | b23c47c | 2021-10-06 08:00:19 +0200 | [diff] [blame] | 86 | mapIdProvider = null; |
Ian Zerny | 1433d58 | 2021-10-12 09:44:48 +0200 | [diff] [blame] | 87 | sourceFileProvider = null; |
Ian Zerny | bbd2392 | 2022-06-07 10:33:31 +0200 | [diff] [blame] | 88 | isAndroidPlatformBuild = false; |
Christoffer Quist Adamsen | dafb046 | 2022-09-01 12:37:09 +0200 | [diff] [blame] | 89 | artProfilesForRewriting = null; |
Christoffer Quist Adamsen | 4b3614b | 2022-08-23 11:14:25 +0200 | [diff] [blame] | 90 | startupProfileProviders = null; |
Ian Zerny | 7744006 | 2022-08-26 13:49:08 +0200 | [diff] [blame] | 91 | classConflictResolver = null; |
Ian Zerny | d9bd076 | 2023-03-24 16:46:18 +0100 | [diff] [blame] | 92 | cancelCompilationChecker = null; |
Søren Gjesse | c4e5e93 | 2017-09-04 17:01:23 +0200 | [diff] [blame] | 93 | } |
| 94 | |
| 95 | BaseCompilerCommand( |
| 96 | AndroidApp app, |
Søren Gjesse | c4e5e93 | 2017-09-04 17:01:23 +0200 | [diff] [blame] | 97 | CompilationMode mode, |
Ian Zerny | 7efd28d | 2017-12-12 09:17:42 +0100 | [diff] [blame] | 98 | ProgramConsumer programConsumer, |
Mads Ager | d9ae2a8 | 2018-11-29 13:01:55 +0100 | [diff] [blame] | 99 | StringConsumer mainDexListConsumer, |
Mads Ager | 642e757 | 2017-10-03 15:43:09 +0200 | [diff] [blame] | 100 | int minApiLevel, |
Yohann Roussel | 9a8d437 | 2017-11-21 14:36:44 +0100 | [diff] [blame] | 101 | Reporter reporter, |
Søren Gjesse | 9a7876d | 2020-01-13 14:32:26 +0100 | [diff] [blame] | 102 | DesugarState desugarState, |
Søren Gjesse | ad54aa5 | 2019-07-16 15:30:01 +0200 | [diff] [blame] | 103 | boolean optimizeMultidexForLinearAlloc, |
Alan Leung | 4b5db8e | 2019-07-23 13:53:10 -0700 | [diff] [blame] | 104 | boolean includeClassesChecksum, |
Søren Gjesse | 95fce5f | 2019-12-16 10:33:51 +0100 | [diff] [blame] | 105 | BiPredicate<String, Long> dexClassChecksumFilter, |
Ian Zerny | 8f3ba44 | 2020-03-11 16:32:27 +0100 | [diff] [blame] | 106 | List<AssertionsConfiguration> assertionsConfiguration, |
Søren Gjesse | 943389f | 2020-03-13 10:40:25 +0100 | [diff] [blame] | 107 | List<Consumer<Inspector>> outputInspections, |
Søren Gjesse | 75a0979 | 2021-04-07 12:41:33 +0200 | [diff] [blame] | 108 | int threadCount, |
Ian Zerny | b23c47c | 2021-10-06 08:00:19 +0200 | [diff] [blame] | 109 | DumpInputFlags dumpInputFlags, |
Ian Zerny | 1433d58 | 2021-10-12 09:44:48 +0200 | [diff] [blame] | 110 | MapIdProvider mapIdProvider, |
Ian Zerny | bbd2392 | 2022-06-07 10:33:31 +0200 | [diff] [blame] | 111 | SourceFileProvider sourceFileProvider, |
Christoffer Quist Adamsen | 4b3614b | 2022-08-23 11:14:25 +0200 | [diff] [blame] | 112 | boolean isAndroidPlatformBuild, |
Christoffer Quist Adamsen | dafb046 | 2022-09-01 12:37:09 +0200 | [diff] [blame] | 113 | List<ArtProfileForRewriting> artProfilesForRewriting, |
Ian Zerny | 7744006 | 2022-08-26 13:49:08 +0200 | [diff] [blame] | 114 | List<StartupProfileProvider> startupProfileProviders, |
Ian Zerny | d9bd076 | 2023-03-24 16:46:18 +0100 | [diff] [blame] | 115 | ClassConflictResolver classConflictResolver, |
| 116 | CancelCompilationChecker cancelCompilationChecker) { |
Søren Gjesse | c4e5e93 | 2017-09-04 17:01:23 +0200 | [diff] [blame] | 117 | super(app); |
Søren Gjesse | c4e5e93 | 2017-09-04 17:01:23 +0200 | [diff] [blame] | 118 | assert minApiLevel > 0; |
Ian Zerny | 7efd28d | 2017-12-12 09:17:42 +0100 | [diff] [blame] | 119 | assert mode != null; |
Søren Gjesse | c4e5e93 | 2017-09-04 17:01:23 +0200 | [diff] [blame] | 120 | this.mode = mode; |
Ian Zerny | 7efd28d | 2017-12-12 09:17:42 +0100 | [diff] [blame] | 121 | this.programConsumer = programConsumer; |
Mads Ager | d9ae2a8 | 2018-11-29 13:01:55 +0100 | [diff] [blame] | 122 | this.mainDexListConsumer = mainDexListConsumer; |
Søren Gjesse | c4e5e93 | 2017-09-04 17:01:23 +0200 | [diff] [blame] | 123 | this.minApiLevel = minApiLevel; |
Yohann Roussel | 9a8d437 | 2017-11-21 14:36:44 +0100 | [diff] [blame] | 124 | this.reporter = reporter; |
Søren Gjesse | 9a7876d | 2020-01-13 14:32:26 +0100 | [diff] [blame] | 125 | this.desugarState = desugarState; |
Yohann Roussel | 2284bc8 | 2018-04-26 15:45:35 +0200 | [diff] [blame] | 126 | this.optimizeMultidexForLinearAlloc = optimizeMultidexForLinearAlloc; |
Alan Leung | 4b5db8e | 2019-07-23 13:53:10 -0700 | [diff] [blame] | 127 | this.includeClassesChecksum = includeClassesChecksum; |
| 128 | this.dexClassChecksumFilter = dexClassChecksumFilter; |
Søren Gjesse | 95fce5f | 2019-12-16 10:33:51 +0100 | [diff] [blame] | 129 | this.assertionsConfiguration = assertionsConfiguration; |
Ian Zerny | 8f3ba44 | 2020-03-11 16:32:27 +0100 | [diff] [blame] | 130 | this.outputInspections = outputInspections; |
Søren Gjesse | 943389f | 2020-03-13 10:40:25 +0100 | [diff] [blame] | 131 | this.threadCount = threadCount; |
Søren Gjesse | 75a0979 | 2021-04-07 12:41:33 +0200 | [diff] [blame] | 132 | this.dumpInputFlags = dumpInputFlags; |
Ian Zerny | b23c47c | 2021-10-06 08:00:19 +0200 | [diff] [blame] | 133 | this.mapIdProvider = mapIdProvider; |
Ian Zerny | 1433d58 | 2021-10-12 09:44:48 +0200 | [diff] [blame] | 134 | this.sourceFileProvider = sourceFileProvider; |
Ian Zerny | bbd2392 | 2022-06-07 10:33:31 +0200 | [diff] [blame] | 135 | this.isAndroidPlatformBuild = isAndroidPlatformBuild; |
Christoffer Quist Adamsen | dafb046 | 2022-09-01 12:37:09 +0200 | [diff] [blame] | 136 | this.artProfilesForRewriting = artProfilesForRewriting; |
Christoffer Quist Adamsen | 4b3614b | 2022-08-23 11:14:25 +0200 | [diff] [blame] | 137 | this.startupProfileProviders = startupProfileProviders; |
Ian Zerny | 7744006 | 2022-08-26 13:49:08 +0200 | [diff] [blame] | 138 | this.classConflictResolver = classConflictResolver; |
Ian Zerny | d9bd076 | 2023-03-24 16:46:18 +0100 | [diff] [blame] | 139 | this.cancelCompilationChecker = cancelCompilationChecker; |
Søren Gjesse | c4e5e93 | 2017-09-04 17:01:23 +0200 | [diff] [blame] | 140 | } |
| 141 | |
Ian Zerny | afb08e1 | 2018-01-08 14:22:58 +0100 | [diff] [blame] | 142 | /** |
| 143 | * Get the compilation mode, e.g., {@link CompilationMode#DEBUG} or {@link |
| 144 | * CompilationMode#RELEASE}. |
| 145 | */ |
Søren Gjesse | c4e5e93 | 2017-09-04 17:01:23 +0200 | [diff] [blame] | 146 | public CompilationMode getMode() { |
| 147 | return mode; |
| 148 | } |
| 149 | |
Ian Zerny | afb08e1 | 2018-01-08 14:22:58 +0100 | [diff] [blame] | 150 | /** Get the minimum API level to compile against. */ |
Søren Gjesse | c4e5e93 | 2017-09-04 17:01:23 +0200 | [diff] [blame] | 151 | public int getMinApiLevel() { |
| 152 | return minApiLevel; |
| 153 | } |
| 154 | |
Clément Béra | 64a3c4c | 2020-11-10 08:16:17 +0000 | [diff] [blame] | 155 | void dumpBaseCommandOptions(DumpOptions.Builder builder) { |
| 156 | builder |
Christoffer Quist Adamsen | 0a3c16e | 2023-02-15 14:34:44 +0100 | [diff] [blame] | 157 | .setBackend(ProgramConsumerUtils.getBackend(programConsumer)) |
Clément Béra | 64a3c4c | 2020-11-10 08:16:17 +0000 | [diff] [blame] | 158 | .setCompilationMode(getMode()) |
| 159 | .setMinApi(getMinApiLevel()) |
| 160 | .setOptimizeMultidexForLinearAlloc(isOptimizeMultidexForLinearAlloc()) |
| 161 | .setThreadCount(getThreadCount()) |
Christoffer Quist Adamsen | 9b0a997 | 2022-08-26 13:38:54 +0200 | [diff] [blame] | 162 | .setDesugarState(getDesugarState()) |
Christoffer Quist Adamsen | cbb6a80 | 2023-03-02 14:33:25 +0100 | [diff] [blame] | 163 | .setArtProfileProviders( |
| 164 | ListUtils.map( |
| 165 | getArtProfilesForRewriting(), ArtProfileForRewriting::getArtProfileProvider)) |
Christoffer Quist Adamsen | 9b0a997 | 2022-08-26 13:38:54 +0200 | [diff] [blame] | 166 | .setStartupProfileProviders(getStartupProfileProviders()); |
Ian Zerny | e72cb78 | 2022-06-07 12:47:56 +0200 | [diff] [blame] | 167 | if (getAndroidPlatformBuild()) { |
| 168 | builder.setAndroidPlatformBuild(true); |
| 169 | } |
Clément Béra | 64a3c4c | 2020-11-10 08:16:17 +0000 | [diff] [blame] | 170 | } |
| 171 | |
Ian Zerny | afb08e1 | 2018-01-08 14:22:58 +0100 | [diff] [blame] | 172 | /** |
| 173 | * Get the program consumer that will receive the compilation output. |
| 174 | * |
| 175 | * <p>Note that the concrete consumer reference is final, the consumer itself is likely stateful. |
| 176 | */ |
Ian Zerny | 7efd28d | 2017-12-12 09:17:42 +0100 | [diff] [blame] | 177 | public ProgramConsumer getProgramConsumer() { |
| 178 | return programConsumer; |
Søren Gjesse | c4e5e93 | 2017-09-04 17:01:23 +0200 | [diff] [blame] | 179 | } |
| 180 | |
Mads Ager | d9ae2a8 | 2018-11-29 13:01:55 +0100 | [diff] [blame] | 181 | /** |
| 182 | * Get the main dex list consumer that will receive the final complete main dex list. |
| 183 | */ |
| 184 | public StringConsumer getMainDexListConsumer() { |
| 185 | return mainDexListConsumer; |
| 186 | } |
| 187 | |
Ian Zerny | afb08e1 | 2018-01-08 14:22:58 +0100 | [diff] [blame] | 188 | /** Get the use-desugaring state. True if enabled, false otherwise. */ |
Yohann Roussel | d258010 | 2017-10-09 15:17:14 +0200 | [diff] [blame] | 189 | public boolean getEnableDesugaring() { |
Søren Gjesse | 9a7876d | 2020-01-13 14:32:26 +0100 | [diff] [blame] | 190 | return desugarState == DesugarState.ON; |
| 191 | } |
| 192 | |
| 193 | DesugarState getDesugarState() { |
| 194 | return desugarState; |
Mads Ager | dbcc4ec | 2017-10-06 11:32:18 +0200 | [diff] [blame] | 195 | } |
| 196 | |
Ian Zerny | b23c47c | 2021-10-06 08:00:19 +0200 | [diff] [blame] | 197 | public MapIdProvider getMapIdProvider() { |
| 198 | return mapIdProvider; |
| 199 | } |
| 200 | |
Ian Zerny | 1433d58 | 2021-10-12 09:44:48 +0200 | [diff] [blame] | 201 | public SourceFileProvider getSourceFileProvider() { |
| 202 | return sourceFileProvider; |
| 203 | } |
| 204 | |
Alan Leung | 4b5db8e | 2019-07-23 13:53:10 -0700 | [diff] [blame] | 205 | /** True if the output dex files has checksum information encoded in it. False otherwise. */ |
| 206 | public boolean getIncludeClassesChecksum() { |
| 207 | return includeClassesChecksum; |
| 208 | } |
| 209 | |
| 210 | /** Filter used to skip parsing of certain class in a dex file. */ |
| 211 | public BiPredicate<String, Long> getDexClassChecksumFilter() { |
| 212 | return dexClassChecksumFilter; |
| 213 | } |
| 214 | |
Yohann Roussel | 2284bc8 | 2018-04-26 15:45:35 +0200 | [diff] [blame] | 215 | /** |
| 216 | * If true, legacy multidex partitioning will be optimized to reduce LinearAlloc usage during |
| 217 | * Dalvik DexOpt. |
| 218 | */ |
| 219 | public boolean isOptimizeMultidexForLinearAlloc() { |
| 220 | return optimizeMultidexForLinearAlloc; |
| 221 | } |
| 222 | |
Søren Gjesse | 99e8a74 | 2020-01-07 13:59:38 +0100 | [diff] [blame] | 223 | public List<AssertionsConfiguration> getAssertionsConfiguration() { |
Ian Zerny | 8f3ba44 | 2020-03-11 16:32:27 +0100 | [diff] [blame] | 224 | return Collections.unmodifiableList(assertionsConfiguration); |
| 225 | } |
| 226 | |
| 227 | public Collection<Consumer<Inspector>> getOutputInspections() { |
| 228 | return Collections.unmodifiableList(outputInspections); |
Søren Gjesse | 95fce5f | 2019-12-16 10:33:51 +0100 | [diff] [blame] | 229 | } |
| 230 | |
Søren Gjesse | 943389f | 2020-03-13 10:40:25 +0100 | [diff] [blame] | 231 | /** Get the number of threads to use for the compilation. */ |
| 232 | public int getThreadCount() { |
| 233 | return threadCount; |
| 234 | } |
| 235 | |
Ian Zerny | bbd2392 | 2022-06-07 10:33:31 +0200 | [diff] [blame] | 236 | public boolean getAndroidPlatformBuild() { |
| 237 | return isAndroidPlatformBuild; |
| 238 | } |
| 239 | |
Christoffer Quist Adamsen | dafb046 | 2022-09-01 12:37:09 +0200 | [diff] [blame] | 240 | List<ArtProfileForRewriting> getArtProfilesForRewriting() { |
| 241 | return artProfilesForRewriting; |
Christoffer Quist Adamsen | c5a31ec | 2022-09-01 11:36:04 +0200 | [diff] [blame] | 242 | } |
| 243 | |
Christoffer Quist Adamsen | 4b3614b | 2022-08-23 11:14:25 +0200 | [diff] [blame] | 244 | List<StartupProfileProvider> getStartupProfileProviders() { |
| 245 | return startupProfileProviders; |
| 246 | } |
| 247 | |
Ian Zerny | 7744006 | 2022-08-26 13:49:08 +0200 | [diff] [blame] | 248 | ClassConflictResolver getClassConflictResolver() { |
| 249 | return classConflictResolver; |
| 250 | } |
| 251 | |
Ian Zerny | d9bd076 | 2023-03-24 16:46:18 +0100 | [diff] [blame] | 252 | public CancelCompilationChecker getCancelCompilationChecker() { |
| 253 | return cancelCompilationChecker; |
| 254 | } |
| 255 | |
Søren Gjesse | 75a0979 | 2021-04-07 12:41:33 +0200 | [diff] [blame] | 256 | DumpInputFlags getDumpInputFlags() { |
| 257 | return dumpInputFlags; |
| 258 | } |
| 259 | |
Ian Zerny | afb08e1 | 2018-01-08 14:22:58 +0100 | [diff] [blame] | 260 | Reporter getReporter() { |
| 261 | return reporter; |
| 262 | } |
Søren Gjesse | ad54aa5 | 2019-07-16 15:30:01 +0200 | [diff] [blame] | 263 | |
Ian Zerny | afb08e1 | 2018-01-08 14:22:58 +0100 | [diff] [blame] | 264 | /** |
| 265 | * Base builder for compilation commands. |
| 266 | * |
| 267 | * @param <C> Command the builder is building, e.g., {@link R8Command} or {@link D8Command}. |
| 268 | * @param <B> Concrete builder extending this base, e.g., {@link R8Command.Builder} or {@link |
| 269 | * D8Command.Builder}. |
| 270 | */ |
Mathias Rav | 3fb4a3a | 2018-05-29 15:41:36 +0200 | [diff] [blame] | 271 | @Keep |
Ian Zerny | afb08e1 | 2018-01-08 14:22:58 +0100 | [diff] [blame] | 272 | public abstract static class Builder<C extends BaseCompilerCommand, B extends Builder<C, B>> |
Søren Gjesse | c4e5e93 | 2017-09-04 17:01:23 +0200 | [diff] [blame] | 273 | extends BaseCommand.Builder<C, B> { |
| 274 | |
Ian Zerny | 113faac | 2017-12-14 12:58:23 +0100 | [diff] [blame] | 275 | private ProgramConsumer programConsumer = null; |
Mads Ager | d9ae2a8 | 2018-11-29 13:01:55 +0100 | [diff] [blame] | 276 | private StringConsumer mainDexListConsumer = null; |
Søren Gjesse | c4e5e93 | 2017-09-04 17:01:23 +0200 | [diff] [blame] | 277 | private Path outputPath = null; |
Ian Zerny | 113faac | 2017-12-14 12:58:23 +0100 | [diff] [blame] | 278 | // TODO(b/70656566): Remove default output mode when deprecated API is removed. |
Ian Zerny | ef028f5 | 2018-01-08 14:23:17 +0100 | [diff] [blame] | 279 | private OutputMode outputMode = OutputMode.DexIndexed; |
Ian Zerny | 113faac | 2017-12-14 12:58:23 +0100 | [diff] [blame] | 280 | |
Søren Gjesse | c4e5e93 | 2017-09-04 17:01:23 +0200 | [diff] [blame] | 281 | private CompilationMode mode; |
Mathias Rav | 86d2602 | 2018-03-16 10:13:34 +0100 | [diff] [blame] | 282 | private int minApiLevel = 0; |
Søren Gjesse | 943389f | 2020-03-13 10:40:25 +0100 | [diff] [blame] | 283 | private int threadCount = ThreadUtils.NOT_SPECIFIED; |
Søren Gjesse | 4cdd55d | 2020-01-16 10:59:24 +0100 | [diff] [blame] | 284 | protected DesugarState desugarState = DesugarState.ON; |
Morten Krogh-Jespersen | 034a0df | 2023-04-24 15:22:10 +0200 | [diff] [blame] | 285 | private final List<StringResource> desugaredLibrarySpecificationResources = new ArrayList<>(); |
Alan Leung | 4b5db8e | 2019-07-23 13:53:10 -0700 | [diff] [blame] | 286 | private boolean includeClassesChecksum = false; |
Yohann Roussel | 2284bc8 | 2018-04-26 15:45:35 +0200 | [diff] [blame] | 287 | private boolean optimizeMultidexForLinearAlloc = false; |
Alan Leung | 4b5db8e | 2019-07-23 13:53:10 -0700 | [diff] [blame] | 288 | private BiPredicate<String, Long> dexClassChecksumFilter = (name, checksum) -> true; |
Morten Krogh-Jespersen | 034a0df | 2023-04-24 15:22:10 +0200 | [diff] [blame] | 289 | private final List<AssertionsConfiguration> assertionsConfiguration = new ArrayList<>(); |
| 290 | private final List<Consumer<Inspector>> outputInspections = new ArrayList<>(); |
Morten Krogh-Jespersen | 946bea9 | 2021-03-18 20:29:42 +0100 | [diff] [blame] | 291 | protected StringConsumer proguardMapConsumer = null; |
Morten Krogh-Jespersen | 034a0df | 2023-04-24 15:22:10 +0200 | [diff] [blame] | 292 | protected PartitionMapConsumer partitionMapConsumer = null; |
Christoffer Quist Adamsen | 0626830 | 2022-06-28 12:35:16 +0200 | [diff] [blame] | 293 | private DumpInputFlags dumpInputFlags = DumpInputFlags.getDefault(); |
Ian Zerny | b23c47c | 2021-10-06 08:00:19 +0200 | [diff] [blame] | 294 | private MapIdProvider mapIdProvider = null; |
Ian Zerny | 1433d58 | 2021-10-12 09:44:48 +0200 | [diff] [blame] | 295 | private SourceFileProvider sourceFileProvider = null; |
Ian Zerny | bbd2392 | 2022-06-07 10:33:31 +0200 | [diff] [blame] | 296 | private boolean isAndroidPlatformBuild = false; |
Morten Krogh-Jespersen | 034a0df | 2023-04-24 15:22:10 +0200 | [diff] [blame] | 297 | private final List<ArtProfileForRewriting> artProfilesForRewriting = new ArrayList<>(); |
| 298 | private final List<StartupProfileProvider> startupProfileProviders = new ArrayList<>(); |
Ian Zerny | 7744006 | 2022-08-26 13:49:08 +0200 | [diff] [blame] | 299 | private ClassConflictResolver classConflictResolver = null; |
Ian Zerny | d9bd076 | 2023-03-24 16:46:18 +0100 | [diff] [blame] | 300 | private CancelCompilationChecker cancelCompilationChecker = null; |
Søren Gjesse | c4e5e93 | 2017-09-04 17:01:23 +0200 | [diff] [blame] | 301 | |
Ian Zerny | e09adb7 | 2018-05-08 11:12:12 +0200 | [diff] [blame] | 302 | abstract CompilationMode defaultCompilationMode(); |
| 303 | |
Ian Zerny | afb08e1 | 2018-01-08 14:22:58 +0100 | [diff] [blame] | 304 | Builder(DiagnosticsHandler diagnosticsHandler) { |
| 305 | super(diagnosticsHandler); |
Ian Zerny | e09adb7 | 2018-05-08 11:12:12 +0200 | [diff] [blame] | 306 | mode = defaultCompilationMode(); |
Søren Gjesse | c4e5e93 | 2017-09-04 17:01:23 +0200 | [diff] [blame] | 307 | } |
| 308 | |
| 309 | // Internal constructor for testing. |
Yohann Roussel | 9a8d437 | 2017-11-21 14:36:44 +0100 | [diff] [blame] | 310 | Builder(AndroidApp app) { |
| 311 | super(AndroidApp.builder(app)); |
Ian Zerny | e09adb7 | 2018-05-08 11:12:12 +0200 | [diff] [blame] | 312 | mode = defaultCompilationMode(); |
Søren Gjesse | 8fb83c8 | 2017-12-01 08:00:10 +0100 | [diff] [blame] | 313 | } |
| 314 | |
Christoffer Quist Adamsen | 0eef4b0 | 2018-08-01 10:29:47 +0200 | [diff] [blame] | 315 | // Internal constructor for testing. |
| 316 | Builder(AndroidApp app, DiagnosticsHandler diagnosticsHandler) { |
| 317 | super(AndroidApp.builder(app, new Reporter(diagnosticsHandler))); |
| 318 | mode = defaultCompilationMode(); |
| 319 | } |
| 320 | |
Stephan Herhut | 7e3d204 | 2017-10-18 14:12:23 +0200 | [diff] [blame] | 321 | /** |
| 322 | * Get current compilation mode. |
| 323 | */ |
Søren Gjesse | c4e5e93 | 2017-09-04 17:01:23 +0200 | [diff] [blame] | 324 | public CompilationMode getMode() { |
| 325 | return mode; |
| 326 | } |
| 327 | |
Stephan Herhut | 7e3d204 | 2017-10-18 14:12:23 +0200 | [diff] [blame] | 328 | /** |
| 329 | * Set compilation mode. |
| 330 | */ |
Søren Gjesse | c4e5e93 | 2017-09-04 17:01:23 +0200 | [diff] [blame] | 331 | public B setMode(CompilationMode mode) { |
| 332 | assert mode != null; |
| 333 | this.mode = mode; |
| 334 | return self(); |
| 335 | } |
| 336 | |
Stephan Herhut | 7e3d204 | 2017-10-18 14:12:23 +0200 | [diff] [blame] | 337 | /** |
Ian Zerny | 113faac | 2017-12-14 12:58:23 +0100 | [diff] [blame] | 338 | * Get the output path. |
| 339 | * |
| 340 | * @return Current output path, null if no output path-and-mode have been set. |
| 341 | * @see #setOutput(Path, OutputMode) |
Stephan Herhut | 7e3d204 | 2017-10-18 14:12:23 +0200 | [diff] [blame] | 342 | */ |
Søren Gjesse | c4e5e93 | 2017-09-04 17:01:23 +0200 | [diff] [blame] | 343 | public Path getOutputPath() { |
| 344 | return outputPath; |
| 345 | } |
| 346 | |
Stephan Herhut | 7e3d204 | 2017-10-18 14:12:23 +0200 | [diff] [blame] | 347 | /** |
| 348 | * Get the output mode. |
Ian Zerny | 113faac | 2017-12-14 12:58:23 +0100 | [diff] [blame] | 349 | * |
| 350 | * @return Currently set output mode, null if no output path-and-mode have been set. |
| 351 | * @see #setOutput(Path, OutputMode) |
Stephan Herhut | 7e3d204 | 2017-10-18 14:12:23 +0200 | [diff] [blame] | 352 | */ |
Søren Gjesse | c4e5e93 | 2017-09-04 17:01:23 +0200 | [diff] [blame] | 353 | public OutputMode getOutputMode() { |
| 354 | return outputMode; |
| 355 | } |
| 356 | |
Ian Zerny | 113faac | 2017-12-14 12:58:23 +0100 | [diff] [blame] | 357 | /** |
| 358 | * Get the program consumer. |
| 359 | * |
| 360 | * @return The currently set program consumer, null if no program consumer or output |
clementbera | 75174ac | 2019-09-04 09:14:44 +0200 | [diff] [blame] | 361 | * path-and-mode is set, e.g., neither {@link #setProgramConsumer} nor {@link #setOutput} |
| 362 | * have been called. |
Ian Zerny | 113faac | 2017-12-14 12:58:23 +0100 | [diff] [blame] | 363 | */ |
| 364 | public ProgramConsumer getProgramConsumer() { |
| 365 | return programConsumer; |
| 366 | } |
| 367 | |
| 368 | /** |
Morten Krogh-Jespersen | 946bea9 | 2021-03-18 20:29:42 +0100 | [diff] [blame] | 369 | * Set an output destination to which proguard-map content should be written. |
| 370 | * |
| 371 | * <p>This is a short-hand for setting a {@link StringConsumer.FileConsumer} using {@link |
| 372 | * #setProguardMapConsumer}. Note that any subsequent call to this method or {@link |
| 373 | * #setProguardMapConsumer} will override the previous setting. |
| 374 | * |
| 375 | * @param proguardMapOutput File-system path to write output at. |
| 376 | */ |
| 377 | B setProguardMapOutputPath(Path proguardMapOutput) { |
| 378 | assert proguardMapOutput != null; |
| 379 | return setProguardMapConsumer(new StringConsumer.FileConsumer(proguardMapOutput)); |
| 380 | } |
| 381 | |
| 382 | /** |
| 383 | * Set a consumer for receiving the proguard-map content. |
| 384 | * |
| 385 | * <p>Note that any subsequent call to this method or {@link #setProguardMapOutputPath} will |
| 386 | * override the previous setting. |
| 387 | * |
| 388 | * @param proguardMapConsumer Consumer to receive the content once produced. |
| 389 | */ |
| 390 | B setProguardMapConsumer(StringConsumer proguardMapConsumer) { |
| 391 | this.proguardMapConsumer = proguardMapConsumer; |
| 392 | return self(); |
| 393 | } |
| 394 | |
| 395 | /** |
Morten Krogh-Jespersen | 034a0df | 2023-04-24 15:22:10 +0200 | [diff] [blame] | 396 | * Set an output destination to which partition-map content should be written. |
| 397 | * |
| 398 | * <p>This is a short-hand for setting a {@link PartitionMapConsumer} using {@link |
| 399 | * #setPartitionMapConsumer}. Note that any subsequent call to this method or {@link |
| 400 | * #setPartitionMapConsumer} will override the previous setting. |
| 401 | * |
| 402 | * @param partitionMapOutput File-system path to write output at. |
| 403 | */ |
Morten Krogh-Jespersen | 8c36ac8 | 2023-04-25 09:25:32 +0200 | [diff] [blame] | 404 | public B setPartitionMapOutputPath(Path partitionMapOutput) { |
Morten Krogh-Jespersen | 034a0df | 2023-04-24 15:22:10 +0200 | [diff] [blame] | 405 | assert partitionMapOutput != null; |
Morten Krogh-Jespersen | 58c98a9 | 2023-05-01 12:18:10 +0200 | [diff] [blame] | 406 | return setPartitionMapConsumer( |
| 407 | PartitionMapZipContainer.createPartitionMapZipContainerConsumer(partitionMapOutput)); |
Morten Krogh-Jespersen | 034a0df | 2023-04-24 15:22:10 +0200 | [diff] [blame] | 408 | } |
| 409 | |
| 410 | /** |
| 411 | * Set a consumer for receiving the partition map content. |
| 412 | * |
| 413 | * <p>Note that any subsequent call to this method or {@link #setPartitionMapOutputPath} will |
| 414 | * override the previous setting. |
| 415 | * |
| 416 | * @param partitionMapConsumer Consumer to receive the content once produced. |
| 417 | */ |
Morten Krogh-Jespersen | 8c36ac8 | 2023-04-25 09:25:32 +0200 | [diff] [blame] | 418 | public B setPartitionMapConsumer(PartitionMapConsumer partitionMapConsumer) { |
Morten Krogh-Jespersen | 034a0df | 2023-04-24 15:22:10 +0200 | [diff] [blame] | 419 | this.partitionMapConsumer = partitionMapConsumer; |
| 420 | return self(); |
| 421 | } |
| 422 | |
| 423 | /** |
Mads Ager | d9ae2a8 | 2018-11-29 13:01:55 +0100 | [diff] [blame] | 424 | * Get the main dex list consumer that will receive the final complete main dex list. |
| 425 | */ |
| 426 | public StringConsumer getMainDexListConsumer() { |
| 427 | return mainDexListConsumer; |
| 428 | } |
| 429 | |
| 430 | /** |
Alan Leung | 4b5db8e | 2019-07-23 13:53:10 -0700 | [diff] [blame] | 431 | * Filter used to skip parsing of certain class in a dex file. |
| 432 | */ |
| 433 | public BiPredicate<String, Long> getDexClassChecksumFilter() { |
| 434 | return dexClassChecksumFilter; |
| 435 | } |
| 436 | |
| 437 | /** |
Yohann Roussel | 2284bc8 | 2018-04-26 15:45:35 +0200 | [diff] [blame] | 438 | * If set to true, legacy multidex partitioning will be optimized to reduce LinearAlloc usage |
| 439 | * during Dalvik DexOpt. Has no effect when compiling for a target with native multidex support |
| 440 | * or without main dex list specification. |
| 441 | */ |
| 442 | public B setOptimizeMultidexForLinearAlloc(boolean optimizeMultidexForLinearAlloc) { |
| 443 | this.optimizeMultidexForLinearAlloc = optimizeMultidexForLinearAlloc; |
| 444 | return self(); |
| 445 | } |
| 446 | |
| 447 | /** |
| 448 | * If true, legacy multidex partitioning will be optimized to reduce LinearAlloc usage during |
| 449 | * Dalvik DexOpt. |
| 450 | */ |
| 451 | protected boolean isOptimizeMultidexForLinearAlloc() { |
| 452 | return optimizeMultidexForLinearAlloc; |
| 453 | } |
| 454 | |
| 455 | /** |
Ian Zerny | 113faac | 2017-12-14 12:58:23 +0100 | [diff] [blame] | 456 | * Set the program consumer. |
| 457 | * |
| 458 | * <p>Setting the program consumer will override any previous set consumer or any previous set |
| 459 | * output path & mode. |
| 460 | * |
| 461 | * @param programConsumer Program consumer to set as current. A null argument will clear the |
| 462 | * program consumer / output. |
| 463 | */ |
| 464 | public B setProgramConsumer(ProgramConsumer programConsumer) { |
| 465 | // Setting an explicit program consumer resets any output-path/mode setup. |
| 466 | outputPath = null; |
| 467 | outputMode = null; |
| 468 | this.programConsumer = programConsumer; |
| 469 | return self(); |
| 470 | } |
| 471 | |
| 472 | /** |
Mads Ager | d9ae2a8 | 2018-11-29 13:01:55 +0100 | [diff] [blame] | 473 | * Set an output destination to which main-dex-list content should be written. |
| 474 | * |
| 475 | * <p>This is a short-hand for setting a {@link StringConsumer.FileConsumer} using {@link |
| 476 | * #setMainDexListConsumer}. Note that any subsequent call to this method or {@link |
| 477 | * #setMainDexListConsumer} will override the previous setting. |
| 478 | * |
| 479 | * @param mainDexListOutputPath File-system path to write output at. |
| 480 | */ |
| 481 | public B setMainDexListOutputPath(Path mainDexListOutputPath) { |
| 482 | mainDexListConsumer = new StringConsumer.FileConsumer(mainDexListOutputPath); |
| 483 | return self(); |
| 484 | } |
| 485 | |
| 486 | /** |
| 487 | * Set a consumer for receiving the main-dex-list content. |
| 488 | * |
| 489 | * <p>Note that any subsequent call to this method or {@link #setMainDexListOutputPath} will |
| 490 | * override the previous setting. |
| 491 | * |
| 492 | * @param mainDexListConsumer Consumer to receive the content once produced. |
| 493 | */ |
| 494 | public B setMainDexListConsumer(StringConsumer mainDexListConsumer) { |
| 495 | this.mainDexListConsumer = mainDexListConsumer; |
| 496 | return self(); |
| 497 | } |
| 498 | |
| 499 | /** |
Ian Zerny | 113faac | 2017-12-14 12:58:23 +0100 | [diff] [blame] | 500 | * Set the output path-and-mode. |
| 501 | * |
| 502 | * <p>Setting the output path-and-mode will override any previous set consumer or any previous |
| 503 | * output path-and-mode, and implicitly sets the appropriate program consumer to write the |
| 504 | * output. |
| 505 | * |
| 506 | * @param outputPath Path to write the output to. Must be an archive or and existing directory. |
| 507 | * @param outputMode Mode in which to write the output. |
| 508 | */ |
| 509 | public B setOutput(Path outputPath, OutputMode outputMode) { |
Søren Gjesse | 4d01502 | 2018-09-14 13:26:57 +0200 | [diff] [blame] | 510 | return setOutput(outputPath, outputMode, false); |
| 511 | } |
| 512 | |
| 513 | // This is only public in R8Command. |
| 514 | protected B setOutput(Path outputPath, OutputMode outputMode, boolean includeDataResources) { |
Ian Zerny | 113faac | 2017-12-14 12:58:23 +0100 | [diff] [blame] | 515 | assert outputPath != null; |
| 516 | assert outputMode != null; |
Ian Zerny | 113faac | 2017-12-14 12:58:23 +0100 | [diff] [blame] | 517 | this.outputPath = outputPath; |
| 518 | this.outputMode = outputMode; |
Søren Gjesse | 4d01502 | 2018-09-14 13:26:57 +0200 | [diff] [blame] | 519 | programConsumer = createProgramOutputConsumer(outputPath, outputMode, includeDataResources); |
Ian Zerny | 113faac | 2017-12-14 12:58:23 +0100 | [diff] [blame] | 520 | return self(); |
| 521 | } |
| 522 | |
Alan Leung | 4b5db8e | 2019-07-23 13:53:10 -0700 | [diff] [blame] | 523 | /** |
| 524 | * Setting a dex class filter. |
| 525 | * |
| 526 | * A filter is a function that given a name of a class and a checksum can return false the user |
| 527 | * decides to skip parsing and ignore that class in the dex file. |
| 528 | */ |
| 529 | public B setDexClassChecksumFilter(BiPredicate<String, Long> filter) { |
| 530 | assert filter != null; |
| 531 | this.dexClassChecksumFilter = filter; |
| 532 | return self(); |
| 533 | } |
| 534 | |
Søren Gjesse | 7320ce5 | 2018-05-07 15:45:22 +0200 | [diff] [blame] | 535 | protected InternalProgramOutputPathConsumer createProgramOutputConsumer( |
Ian Zerny | 113faac | 2017-12-14 12:58:23 +0100 | [diff] [blame] | 536 | Path path, |
Søren Gjesse | 7320ce5 | 2018-05-07 15:45:22 +0200 | [diff] [blame] | 537 | OutputMode mode, |
| 538 | boolean consumeDataResources) { |
Ian Zerny | ef028f5 | 2018-01-08 14:23:17 +0100 | [diff] [blame] | 539 | if (mode == OutputMode.DexIndexed) { |
Ian Zerny | 113faac | 2017-12-14 12:58:23 +0100 | [diff] [blame] | 540 | return FileUtils.isArchive(path) |
Søren Gjesse | 7320ce5 | 2018-05-07 15:45:22 +0200 | [diff] [blame] | 541 | ? new DexIndexedConsumer.ArchiveConsumer(path, consumeDataResources) |
| 542 | : new DexIndexedConsumer.DirectoryConsumer(path, consumeDataResources); |
Ian Zerny | 113faac | 2017-12-14 12:58:23 +0100 | [diff] [blame] | 543 | } |
Alan Leung | f21b09b | 2018-09-10 16:20:25 -0700 | [diff] [blame] | 544 | if (mode == OutputMode.DexFilePerClass) { |
| 545 | if (FileUtils.isArchive(path)) { |
| 546 | return new DexFilePerClassFileConsumer.ArchiveConsumer(path, consumeDataResources) { |
| 547 | @Override |
| 548 | public boolean combineSyntheticClassesWithPrimaryClass() { |
| 549 | return false; |
| 550 | } |
| 551 | }; |
| 552 | } else { |
| 553 | return new DexFilePerClassFileConsumer.DirectoryConsumer(path, consumeDataResources) { |
| 554 | @Override |
| 555 | public boolean combineSyntheticClassesWithPrimaryClass() { |
| 556 | return false; |
| 557 | } |
| 558 | }; |
| 559 | } |
| 560 | } |
Ian Zerny | ef028f5 | 2018-01-08 14:23:17 +0100 | [diff] [blame] | 561 | if (mode == OutputMode.DexFilePerClassFile) { |
Ian Zerny | 113faac | 2017-12-14 12:58:23 +0100 | [diff] [blame] | 562 | return FileUtils.isArchive(path) |
Søren Gjesse | 7320ce5 | 2018-05-07 15:45:22 +0200 | [diff] [blame] | 563 | ? new DexFilePerClassFileConsumer.ArchiveConsumer(path, consumeDataResources) |
| 564 | : new DexFilePerClassFileConsumer.DirectoryConsumer(path, consumeDataResources); |
Ian Zerny | 113faac | 2017-12-14 12:58:23 +0100 | [diff] [blame] | 565 | } |
Ian Zerny | ef028f5 | 2018-01-08 14:23:17 +0100 | [diff] [blame] | 566 | if (mode == OutputMode.ClassFile) { |
Ian Zerny | 113faac | 2017-12-14 12:58:23 +0100 | [diff] [blame] | 567 | return FileUtils.isArchive(path) |
Søren Gjesse | 7320ce5 | 2018-05-07 15:45:22 +0200 | [diff] [blame] | 568 | ? new ClassFileConsumer.ArchiveConsumer(path, consumeDataResources) |
| 569 | : new ClassFileConsumer.DirectoryConsumer(path, consumeDataResources); |
Ian Zerny | 113faac | 2017-12-14 12:58:23 +0100 | [diff] [blame] | 570 | } |
| 571 | throw new Unreachable("Unexpected output mode: " + mode); |
Ian Zerny | 7efd28d | 2017-12-12 09:17:42 +0100 | [diff] [blame] | 572 | } |
| 573 | |
Ian Zerny | afb08e1 | 2018-01-08 14:22:58 +0100 | [diff] [blame] | 574 | /** Get the minimum API level (aka SDK version). */ |
Søren Gjesse | c4e5e93 | 2017-09-04 17:01:23 +0200 | [diff] [blame] | 575 | public int getMinApiLevel() { |
Mathias Rav | 86d2602 | 2018-03-16 10:13:34 +0100 | [diff] [blame] | 576 | return isMinApiLevelSet() ? minApiLevel : AndroidApiLevel.getDefault().getLevel(); |
| 577 | } |
| 578 | |
| 579 | boolean isMinApiLevelSet() { |
| 580 | return minApiLevel != 0; |
Søren Gjesse | c4e5e93 | 2017-09-04 17:01:23 +0200 | [diff] [blame] | 581 | } |
| 582 | |
Ian Zerny | afb08e1 | 2018-01-08 14:22:58 +0100 | [diff] [blame] | 583 | /** Set the minimum required API level (aka SDK version). */ |
Søren Gjesse | c4e5e93 | 2017-09-04 17:01:23 +0200 | [diff] [blame] | 584 | public B setMinApiLevel(int minApiLevel) { |
Mathias Rav | 86d2602 | 2018-03-16 10:13:34 +0100 | [diff] [blame] | 585 | if (minApiLevel <= 0) { |
| 586 | getReporter().error("Invalid minApiLevel: " + minApiLevel); |
| 587 | } else { |
| 588 | this.minApiLevel = minApiLevel; |
| 589 | } |
Søren Gjesse | c4e5e93 | 2017-09-04 17:01:23 +0200 | [diff] [blame] | 590 | return self(); |
| 591 | } |
| 592 | |
Ian Zerny | baaad9f | 2018-01-09 07:45:24 +0100 | [diff] [blame] | 593 | @Deprecated |
Yohann Roussel | d258010 | 2017-10-09 15:17:14 +0200 | [diff] [blame] | 594 | public B setEnableDesugaring(boolean enableDesugaring) { |
Søren Gjesse | 9a7876d | 2020-01-13 14:32:26 +0100 | [diff] [blame] | 595 | this.desugarState = enableDesugaring ? DesugarState.ON : DesugarState.OFF; |
Yohann Roussel | d258010 | 2017-10-09 15:17:14 +0200 | [diff] [blame] | 596 | return self(); |
| 597 | } |
| 598 | |
Ian Zerny | baaad9f | 2018-01-09 07:45:24 +0100 | [diff] [blame] | 599 | /** |
| 600 | * Force disable desugaring. |
| 601 | * |
| 602 | * <p>There are a few use cases where it makes sense to force disable desugaring, such as: |
| 603 | * <ul> |
| 604 | * <li>if all inputs are known to be at most Java 7; or |
| 605 | * <li>if a separate desugar tool has been used prior to compiling with D8. |
| 606 | * </ul> |
| 607 | * |
| 608 | * <p>Note that even for API 27, desugaring is still required for closures support on ART. |
| 609 | */ |
| 610 | public B setDisableDesugaring(boolean disableDesugaring) { |
Søren Gjesse | 9a7876d | 2020-01-13 14:32:26 +0100 | [diff] [blame] | 611 | this.desugarState = disableDesugaring ? DesugarState.OFF : DesugarState.ON; |
Ian Zerny | baaad9f | 2018-01-09 07:45:24 +0100 | [diff] [blame] | 612 | return self(); |
| 613 | } |
| 614 | |
| 615 | /** Is desugaring forcefully disabled. */ |
| 616 | public boolean getDisableDesugaring() { |
Søren Gjesse | 9a7876d | 2020-01-13 14:32:26 +0100 | [diff] [blame] | 617 | return desugarState == DesugarState.OFF; |
| 618 | } |
| 619 | |
| 620 | DesugarState getDesugaringState() { |
| 621 | return desugarState; |
Mads Ager | dbcc4ec | 2017-10-06 11:32:18 +0200 | [diff] [blame] | 622 | } |
| 623 | |
Ian Zerny | b23c47c | 2021-10-06 08:00:19 +0200 | [diff] [blame] | 624 | /** Set a custom provider for defining the map id for the build. */ |
| 625 | public B setMapIdProvider(MapIdProvider mapIdProvider) { |
| 626 | this.mapIdProvider = mapIdProvider; |
| 627 | return self(); |
| 628 | } |
| 629 | |
| 630 | public MapIdProvider getMapIdProvider() { |
| 631 | return mapIdProvider; |
| 632 | } |
| 633 | |
Ian Zerny | 1433d58 | 2021-10-12 09:44:48 +0200 | [diff] [blame] | 634 | /** Set a custom provider for defining source-file attributes for classes. */ |
| 635 | public B setSourceFileProvider(SourceFileProvider sourceFileProvider) { |
| 636 | this.sourceFileProvider = sourceFileProvider; |
| 637 | return self(); |
| 638 | } |
| 639 | |
| 640 | public SourceFileProvider getSourceFileProvider() { |
| 641 | return sourceFileProvider; |
| 642 | } |
| 643 | |
Søren Gjesse | bffd4ad | 2019-09-06 13:05:19 +0200 | [diff] [blame] | 644 | @Deprecated |
| 645 | public B addSpecialLibraryConfiguration(String configuration) { |
| 646 | return addDesugaredLibraryConfiguration(configuration); |
| 647 | } |
| 648 | |
clementbera | 75174ac | 2019-09-04 09:14:44 +0200 | [diff] [blame] | 649 | /** Desugared library configuration */ |
| 650 | // Configuration "default" is for testing only and support will be dropped. |
| 651 | public B addDesugaredLibraryConfiguration(String configuration) { |
Clément Béra | ddd19a1 | 2021-12-09 08:14:53 +0000 | [diff] [blame] | 652 | this.desugaredLibrarySpecificationResources.add( |
clementbera | 75174ac | 2019-09-04 09:14:44 +0200 | [diff] [blame] | 653 | StringResource.fromString(configuration, Origin.unknown())); |
Søren Gjesse | 9561222 | 2019-07-16 11:42:31 +0200 | [diff] [blame] | 654 | return self(); |
| 655 | } |
| 656 | |
clementbera | 75174ac | 2019-09-04 09:14:44 +0200 | [diff] [blame] | 657 | /** Desugared library configuration */ |
| 658 | public B addDesugaredLibraryConfiguration(StringResource configuration) { |
Clément Béra | ddd19a1 | 2021-12-09 08:14:53 +0000 | [diff] [blame] | 659 | this.desugaredLibrarySpecificationResources.add(configuration); |
clementbera | 75174ac | 2019-09-04 09:14:44 +0200 | [diff] [blame] | 660 | return self(); |
| 661 | } |
| 662 | |
Clément Béra | 24cb20a | 2022-02-17 09:30:14 +0000 | [diff] [blame] | 663 | DesugaredLibrarySpecification getDesugaredLibraryConfiguration( |
clementbera | 79854ab | 2019-09-24 14:47:06 +0200 | [diff] [blame] | 664 | DexItemFactory factory, boolean libraryCompilation) { |
Clément Béra | ddd19a1 | 2021-12-09 08:14:53 +0000 | [diff] [blame] | 665 | if (desugaredLibrarySpecificationResources.isEmpty()) { |
Clément Béra | 752cac1 | 2022-02-23 13:38:58 +0000 | [diff] [blame] | 666 | return HumanDesugaredLibrarySpecification.empty(); |
clementbera | 75174ac | 2019-09-04 09:14:44 +0200 | [diff] [blame] | 667 | } |
Clément Béra | ddd19a1 | 2021-12-09 08:14:53 +0000 | [diff] [blame] | 668 | if (desugaredLibrarySpecificationResources.size() > 1) { |
clementbera | 75174ac | 2019-09-04 09:14:44 +0200 | [diff] [blame] | 669 | throw new CompilationError("Only one desugared library configuration is supported."); |
| 670 | } |
Clément Béra | ddd19a1 | 2021-12-09 08:14:53 +0000 | [diff] [blame] | 671 | StringResource desugaredLibrarySpecificationResource = |
| 672 | desugaredLibrarySpecificationResources.get(0); |
Clément Béra | 24cb20a | 2022-02-17 09:30:14 +0000 | [diff] [blame] | 673 | return DesugaredLibrarySpecificationParser.parseDesugaredLibrarySpecification( |
| 674 | desugaredLibrarySpecificationResource, |
| 675 | factory, |
| 676 | getReporter(), |
| 677 | libraryCompilation, |
| 678 | getMinApiLevel()); |
clementbera | 75174ac | 2019-09-04 09:14:44 +0200 | [diff] [blame] | 679 | } |
| 680 | |
clementbera | 5dcde34 | 2019-09-04 14:56:30 +0200 | [diff] [blame] | 681 | boolean hasDesugaredLibraryConfiguration() { |
Clément Béra | ddd19a1 | 2021-12-09 08:14:53 +0000 | [diff] [blame] | 682 | return !desugaredLibrarySpecificationResources.isEmpty(); |
Søren Gjesse | ad54aa5 | 2019-07-16 15:30:01 +0200 | [diff] [blame] | 683 | } |
| 684 | |
Alan Leung | 4b5db8e | 2019-07-23 13:53:10 -0700 | [diff] [blame] | 685 | /** Encodes checksum for each class when generating dex files. */ |
| 686 | public B setIncludeClassesChecksum(boolean enabled) { |
| 687 | this.includeClassesChecksum = enabled; |
| 688 | return self(); |
| 689 | } |
| 690 | |
Søren Gjesse | 943389f | 2020-03-13 10:40:25 +0100 | [diff] [blame] | 691 | /** Set the number of threads to use for the compilation */ |
| 692 | B setThreadCount(int threadCount) { |
| 693 | if (threadCount <= 0) { |
| 694 | getReporter().error("Invalid threadCount: " + threadCount); |
| 695 | } else { |
| 696 | this.threadCount = threadCount; |
| 697 | } |
| 698 | return self(); |
| 699 | } |
| 700 | |
| 701 | int getThreadCount() { |
| 702 | return threadCount; |
| 703 | } |
| 704 | |
Alan Leung | 4b5db8e | 2019-07-23 13:53:10 -0700 | [diff] [blame] | 705 | /** Encodes the checksums into the dex output. */ |
| 706 | public boolean getIncludeClassesChecksum() { |
| 707 | return includeClassesChecksum; |
| 708 | } |
| 709 | |
Søren Gjesse | 99e8a74 | 2020-01-07 13:59:38 +0100 | [diff] [blame] | 710 | List<AssertionsConfiguration> getAssertionsConfiguration() { |
| 711 | return assertionsConfiguration; |
| 712 | } |
| 713 | |
Søren Gjesse | 95fce5f | 2019-12-16 10:33:51 +0100 | [diff] [blame] | 714 | /** Configure compile time assertion enabling through a {@link AssertionsConfiguration}. */ |
| 715 | public B addAssertionsConfiguration( |
| 716 | Function<AssertionsConfiguration.Builder, AssertionsConfiguration> |
| 717 | assertionsConfigurationGenerator) { |
Søren Gjesse | 99e8a74 | 2020-01-07 13:59:38 +0100 | [diff] [blame] | 718 | assertionsConfiguration.add( |
| 719 | assertionsConfigurationGenerator.apply(AssertionsConfiguration.builder(getReporter()))); |
Søren Gjesse | 95fce5f | 2019-12-16 10:33:51 +0100 | [diff] [blame] | 720 | return self(); |
| 721 | } |
| 722 | |
Ian Zerny | bbd2392 | 2022-06-07 10:33:31 +0200 | [diff] [blame] | 723 | /** |
| 724 | * Configure the present build as a "Android platform build". |
| 725 | * |
| 726 | * <p>A platform build, is a build where the runtime "bootclasspath" is known at compile time. |
| 727 | * In other words, the specified <i>min-api</i> is also known to be the <i>max-api</i>. In this |
| 728 | * mode the compiler will disable various features that provide support for newer runtimes as |
| 729 | * well as disable workarounds for older runtimes. |
| 730 | */ |
| 731 | public B setAndroidPlatformBuild(boolean isAndroidPlatformBuild) { |
| 732 | this.isAndroidPlatformBuild = isAndroidPlatformBuild; |
| 733 | return self(); |
| 734 | } |
| 735 | |
| 736 | public boolean getAndroidPlatformBuild() { |
| 737 | return isAndroidPlatformBuild; |
| 738 | } |
| 739 | |
Christoffer Quist Adamsen | dafb046 | 2022-09-01 12:37:09 +0200 | [diff] [blame] | 740 | /** |
| 741 | * Add an ART profiles that should be rewritten to match the residual application. The ART |
| 742 | * profile is given to the compiler by the {@link ArtProfileProvider} and passed back to the |
| 743 | * {@link ArtProfileConsumer} at the end of compilation when the ART profile has been fully |
| 744 | * rewritten to match the residual application. |
| 745 | */ |
| 746 | public B addArtProfileForRewriting( |
| 747 | ArtProfileProvider artProfileProvider, ArtProfileConsumer residualArtProfileProvider) { |
| 748 | artProfilesForRewriting.add( |
| 749 | new ArtProfileForRewriting(artProfileProvider, residualArtProfileProvider)); |
Christoffer Quist Adamsen | c5a31ec | 2022-09-01 11:36:04 +0200 | [diff] [blame] | 750 | return self(); |
| 751 | } |
| 752 | |
Christoffer Quist Adamsen | dafb046 | 2022-09-01 12:37:09 +0200 | [diff] [blame] | 753 | List<ArtProfileForRewriting> getArtProfilesForRewriting() { |
| 754 | return artProfilesForRewriting; |
Christoffer Quist Adamsen | c5a31ec | 2022-09-01 11:36:04 +0200 | [diff] [blame] | 755 | } |
| 756 | |
Christoffer Quist Adamsen | 4b3614b | 2022-08-23 11:14:25 +0200 | [diff] [blame] | 757 | B addStartupProfileProviders(StartupProfileProvider... startupProfileProviders) { |
| 758 | return addStartupProfileProviders(Arrays.asList(startupProfileProviders)); |
| 759 | } |
| 760 | |
| 761 | B addStartupProfileProviders(Collection<StartupProfileProvider> startupProfileProviders) { |
| 762 | this.startupProfileProviders.addAll(startupProfileProviders); |
| 763 | return self(); |
| 764 | } |
| 765 | |
| 766 | List<StartupProfileProvider> getStartupProfileProviders() { |
| 767 | return startupProfileProviders; |
| 768 | } |
| 769 | |
Christoffer Quist Adamsen | 0626830 | 2022-06-28 12:35:16 +0200 | [diff] [blame] | 770 | /** |
Ian Zerny | d9bd076 | 2023-03-24 16:46:18 +0100 | [diff] [blame] | 771 | * Set a cancellation checker. |
| 772 | * |
| 773 | * <p>The cancellation checker will be periodically called to check if the compilation should be |
| 774 | * cancelled before completion. |
| 775 | */ |
| 776 | public B setCancelCompilationChecker(CancelCompilationChecker checker) { |
| 777 | this.cancelCompilationChecker = checker; |
| 778 | return self(); |
| 779 | } |
| 780 | |
| 781 | public CancelCompilationChecker getCancelCompilationChecker() { |
| 782 | return cancelCompilationChecker; |
| 783 | } |
| 784 | |
| 785 | /** |
Christoffer Quist Adamsen | 0626830 | 2022-06-28 12:35:16 +0200 | [diff] [blame] | 786 | * Allow to skip to dump into file and dump into directory instruction, this is primarily used |
| 787 | * for chained compilation in L8 so there are no duplicated dumps. |
| 788 | */ |
| 789 | B skipDump() { |
| 790 | dumpInputFlags = DumpInputFlags.noDump(); |
| 791 | return self(); |
| 792 | } |
| 793 | |
Søren Gjesse | 75a0979 | 2021-04-07 12:41:33 +0200 | [diff] [blame] | 794 | B dumpInputToFile(Path file) { |
| 795 | dumpInputFlags = DumpInputFlags.dumpToFile(file); |
| 796 | return self(); |
| 797 | } |
| 798 | |
| 799 | B dumpInputToDirectory(Path directory) { |
| 800 | dumpInputFlags = DumpInputFlags.dumpToDirectory(directory); |
| 801 | return self(); |
| 802 | } |
| 803 | |
| 804 | DumpInputFlags getDumpInputFlags() { |
| 805 | return dumpInputFlags; |
| 806 | } |
| 807 | |
Benoit Lamarche | 2aae320 | 2017-10-11 11:01:06 +0200 | [diff] [blame] | 808 | @Override |
Ian Zerny | afb08e1 | 2018-01-08 14:22:58 +0100 | [diff] [blame] | 809 | void validate() { |
| 810 | Reporter reporter = getReporter(); |
Ian Zerny | d01e99e | 2018-01-04 09:38:36 +0100 | [diff] [blame] | 811 | if (mode == null) { |
| 812 | reporter.error("Expected valid compilation mode, was null"); |
| 813 | } |
Yohann Roussel | 9a8d437 | 2017-11-21 14:36:44 +0100 | [diff] [blame] | 814 | FileUtils.validateOutputFile(outputPath, reporter); |
Ian Zerny | ef028f5 | 2018-01-08 14:23:17 +0100 | [diff] [blame] | 815 | if (getProgramConsumer() == null) { |
| 816 | // This is never the case for a command-line parse, so we report using API references. |
| 817 | reporter.error("A ProgramConsumer or Output is required for compilation"); |
| 818 | } |
Ian Zerny | d01e99e | 2018-01-04 09:38:36 +0100 | [diff] [blame] | 819 | List<Class> programConsumerClasses = new ArrayList<>(3); |
| 820 | if (programConsumer instanceof DexIndexedConsumer) { |
| 821 | programConsumerClasses.add(DexIndexedConsumer.class); |
| 822 | } |
| 823 | if (programConsumer instanceof DexFilePerClassFileConsumer) { |
| 824 | programConsumerClasses.add(DexFilePerClassFileConsumer.class); |
| 825 | } |
| 826 | if (programConsumer instanceof ClassFileConsumer) { |
| 827 | programConsumerClasses.add(ClassFileConsumer.class); |
| 828 | } |
| 829 | if (programConsumerClasses.size() > 1) { |
| 830 | StringBuilder builder = new StringBuilder() |
| 831 | .append("Invalid program consumer.") |
| 832 | .append(" A program consumer can implement at most one consumer type but ") |
| 833 | .append(programConsumer.getClass().getName()) |
| 834 | .append(" implements types:"); |
| 835 | for (Class clazz : programConsumerClasses) { |
| 836 | builder.append(" ").append(clazz.getName()); |
| 837 | } |
| 838 | reporter.error(builder.toString()); |
| 839 | } |
Søren Gjesse | 3ceb1b0 | 2020-01-13 16:07:10 +0100 | [diff] [blame] | 840 | if (getMinApiLevel() > AndroidApiLevel.LATEST.getLevel()) { |
Christoffer Quist Adamsen | 09063b4 | 2021-11-15 15:43:38 +0100 | [diff] [blame] | 841 | if (getMinApiLevel() != AndroidApiLevel.ANDROID_PLATFORM.getLevel()) { |
Søren Gjesse | 3ceb1b0 | 2020-01-13 16:07:10 +0100 | [diff] [blame] | 842 | reporter.warning( |
| 843 | "An API level of " |
| 844 | + getMinApiLevel() |
| 845 | + " is not supported by this compiler. Please use an API level of " |
| 846 | + AndroidApiLevel.LATEST.getLevel() |
| 847 | + " or earlier"); |
| 848 | } |
| 849 | } |
Ian Zerny | a09cdc9 | 2022-08-29 14:31:26 +0200 | [diff] [blame] | 850 | if (hasDesugaredLibraryConfiguration() && getAndroidPlatformBuild()) { |
| 851 | reporter.error("Android platform builds cannot use desugared library"); |
| 852 | } |
Yohann Roussel | 9a8d437 | 2017-11-21 14:36:44 +0100 | [diff] [blame] | 853 | super.validate(); |
Søren Gjesse | c4e5e93 | 2017-09-04 17:01:23 +0200 | [diff] [blame] | 854 | } |
Ian Zerny | 8f3ba44 | 2020-03-11 16:32:27 +0100 | [diff] [blame] | 855 | |
| 856 | /** |
| 857 | * Add an inspection of the output program. |
| 858 | * |
| 859 | * <p>On a successful compilation the inspection is guaranteed to be called with inspectors that |
| 860 | * combined cover all of the output program. The inspections may be called multiple times with |
| 861 | * inspectors that have overlapping content (eg, classes synthesized based on multiple inputs |
| 862 | * can lead to this). Any overlapping content will be consistent, e.g., the inspection of type T |
| 863 | * will be the same (equality, not identify) as any other inspection of type T. |
| 864 | * |
| 865 | * <p>There is no guarantee of the order inspections are called or on which thread they are |
| 866 | * called. |
| 867 | * |
| 868 | * <p>The validity of an {@code Inspector} and all of its sub-inspectors, eg, |
| 869 | * {@MethodInspector}, is that of the callback. If any inspector object escapes the scope of the |
| 870 | * callback, the behavior of that inspector is undefined. |
| 871 | * |
| 872 | * @param inspection Inspection callback receiving inspectors denoting parts of the output. |
| 873 | */ |
Søren Gjesse | 9e1f8c5 | 2020-12-21 10:42:09 +0100 | [diff] [blame] | 874 | public B addOutputInspection(Consumer<Inspector> inspection) { |
Ian Zerny | 8f3ba44 | 2020-03-11 16:32:27 +0100 | [diff] [blame] | 875 | outputInspections.add(inspection); |
Søren Gjesse | 9e1f8c5 | 2020-12-21 10:42:09 +0100 | [diff] [blame] | 876 | return self(); |
Ian Zerny | 8f3ba44 | 2020-03-11 16:32:27 +0100 | [diff] [blame] | 877 | } |
| 878 | |
| 879 | List<Consumer<Inspector>> getOutputInspections() { |
| 880 | return outputInspections; |
| 881 | } |
Ian Zerny | 7744006 | 2022-08-26 13:49:08 +0200 | [diff] [blame] | 882 | |
| 883 | /** |
| 884 | * Set a conflict resolver to determine which class definition to use in case of duplicates. |
| 885 | * |
| 886 | * <p>If no resolver is set, the compiler will fail compilation in case of duplicates. |
| 887 | * |
| 888 | * @param resolver Resolver for choosing between duplicate classes. |
| 889 | */ |
| 890 | public B setClassConflictResolver(ClassConflictResolver resolver) { |
| 891 | this.classConflictResolver = resolver; |
| 892 | return self(); |
| 893 | } |
| 894 | |
| 895 | ClassConflictResolver getClassConflictResolver() { |
| 896 | return classConflictResolver; |
| 897 | } |
Søren Gjesse | c4e5e93 | 2017-09-04 17:01:23 +0200 | [diff] [blame] | 898 | } |
Søren Gjesse | c4e5e93 | 2017-09-04 17:01:23 +0200 | [diff] [blame] | 899 | } |