Skip to content

Commit

Permalink
Make kotlin_home buck config support specifying source path.
Browse files Browse the repository at this point in the history
- Support specifying a source path for kotlin_home buck config
- Simplified and cleaned up logic to look up kotlin home.
- Updated Docs

Resolves facebook#2121

Dependent PR’s:
facebook#2131
facebook#2130
  • Loading branch information
raviagarwal7 committed Dec 20, 2018
1 parent 8b855a3 commit cc94c16
Show file tree
Hide file tree
Showing 13 changed files with 219 additions and 460 deletions.
46 changes: 18 additions & 28 deletions docs/files-and-dirs/buckconfig.soy
Original file line number Diff line number Diff line change
Expand Up @@ -3103,17 +3103,6 @@ or the value could be a custom platform flavor:
{/param}
{/call}

{call buckconfig.entry}
{param section: 'kotlin' /}
{param name: 'kotlinc' /}
{param example_value: '/usr/local/bin/kotlinc' /}
{param description}
The path to the <code>kotlinc</code> compiler executable to use when external compilation is
forced. This setting has no effect by itself and must be paired with the
{sp}{call buckconfig.kotlin_external /} setting.
{/param}
{/call}

{call buckconfig.entry}
{param section: 'kotlin' /}
{param name: 'external' /}
Expand All @@ -3122,16 +3111,13 @@ or the value could be a custom platform flavor:
Forces external compilation via <code>kotlinc</code>. When external compilation is forced the
following heuristics are used to locate the <code>kotlinc</code> executable:
<ul>
<li>If the <code>{call buckconfig.kotlin_kotlinc /}</code> setting is specified, the executable specified by that path
will be used.
</li>
<li>If the {call buckconfig.kotlin_kotlin_home /} path setting is specified, Buck will look
for a <code>bin</code> directory under that path for an executable named
{sp}<code>kotlinc</code>.
for an executable named {sp}<code>kotlinc</code> first under <code>kotlin_home<code> directory
and then under <code>kotlin_home/bin</code> directory.
</li>
<li>If a <code>KOTLIN_HOME</code> environment variable is present, Buck will look for a
{sp}<code>bin</code> directory under that path for an executable named
{sp}<code>kotlinc</code>.
<li>If a <code>KOTLIN_HOME</code> environment variable is present, Buck will look
for an executable named {sp}<code>kotlinc</code> first under <code>$KOTLIN_HOME<code> directory
and then under <code>$KOTLIN_HOME/bin</code> directory.
</li>
<li>Lastly, if none of the above are specified, Buck will look for the <code>kotlinc</code>
{sp}executable in the paths listed in the <code>PATH</code> environment variable.
Expand All @@ -3150,25 +3136,29 @@ or the value could be a custom platform flavor:
assets (executables and JAR files) can be found. This path is used in the following ways:
<ul>
<li>
When in-memory compilation is used, the <code>kotlin-compiler.jar</code> and other related
Kotlin JARs required for compilation are located via this path using the following
heuristics:
When in-memory compilation is used, the <code>kotlin-compiler-embeddable.jar</code> and other
related Kotlin JARs required for compilation are expected to be in <code>libexec/lib</code>
directory under this path. A build target or a relative path to the project root can be
specified here. Other required jars are specified below:
<ul>
<li>
The root of the directory specified by this path is searched.
<code>kotlin-annotation-processing-gradle.jar</code>
</li>
<li>
<code>kotlin-reflect.jar</code>
</li>
<li>
If there is a <code>lib</code> directory under this path, it is searched.
<code>kotlin-stdlib.jar</code>
</li>
<li>
If there is a <code>libexec</code> directory under this path, it is searched.
<code>kotlin-script-runtime.jar</code>
</li>
</ul>
</li>
<li>
If external compilation is called for (see {call buckconfig.kotlin_external /}), a
{sp}<code>bin</code> directory under this directory will be searched to locate the
{sp}<code>kotlinc</code> executable.
If external compilation is called for (see {call buckconfig.kotlin_external /}), Buck will look
for an executable named {sp}<code>kotlinc</code> first under <code>kotlin_home<code> directory
and then under <code>kotlin_home/bin</code> directory.
</li>
</ul>
If this setting is not specified, the location of the Kotlin home directory can be specified
Expand Down
17 changes: 12 additions & 5 deletions src/com/facebook/buck/jvm/kotlin/ExternalKotlinc.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,6 @@
*/
package com.facebook.buck.jvm.kotlin;

import static com.google.common.collect.Iterables.transform;

import com.facebook.buck.core.exceptions.HumanReadableException;
import com.facebook.buck.core.model.BuildTarget;
import com.facebook.buck.core.rulekey.AddToRuleKey;
Expand All @@ -40,13 +38,15 @@
import java.nio.file.Path;
import java.util.Optional;
import java.util.function.Supplier;
import java.util.stream.Collectors;

/** kotlinc implemented as a separate binary. */
public class ExternalKotlinc implements Kotlinc, AddsToRuleKey {

private static final KotlincVersion DEFAULT_VERSION = KotlincVersion.of("unknown version");

private final Path pathToKotlinc;

private final Supplier<KotlincVersion> version;

public ExternalKotlinc(Path pathToKotlinc) {
Expand Down Expand Up @@ -100,6 +100,7 @@ public KotlincVersion getVersion() {
public int buildWithClasspath(
ExecutionContext context,
BuildTarget invokingRule,
ImmutableList<Path> kotlinHomeLibraries,
ImmutableList<String> options,
ImmutableSortedSet<Path> kotlinSourceFilePaths,
Path pathToSrcsList,
Expand All @@ -126,9 +127,10 @@ public int buildWithClasspath(
.add(pathToKotlinc.toString())
.addAll(options)
.addAll(
transform(
expandedSources,
path -> projectFilesystem.resolve(path).toAbsolutePath().toString()))
expandedSources
.stream()
.map(path -> projectFilesystem.resolve(path).toAbsolutePath().toString())
.collect(Collectors.toList()))
.build();

// Run the command
Expand Down Expand Up @@ -189,6 +191,11 @@ public ImmutableList<Path> getAdditionalClasspathEntries(SourcePathResolver sour
return ImmutableList.of();
}

@Override
public ImmutableList<Path> getHomeLibraries(SourcePathResolver sourcePathResolver) {
return ImmutableList.of();
}

@Override
public ImmutableMap<String, String> getEnvironment(SourcePathResolver resolver) {
return ImmutableMap.of();
Expand Down
97 changes: 57 additions & 40 deletions src/com/facebook/buck/jvm/kotlin/JarBackedReflectedKotlinc.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,9 @@

package com.facebook.buck.jvm.kotlin;

import static com.google.common.collect.Iterables.transform;

import com.facebook.buck.core.exceptions.HumanReadableException;
import com.facebook.buck.core.model.BuildTarget;
import com.facebook.buck.core.rulekey.AddToRuleKey;
import com.facebook.buck.core.sourcepath.PathSourcePath;
import com.facebook.buck.core.sourcepath.SourcePath;
import com.facebook.buck.core.sourcepath.resolver.SourcePathResolver;
import com.facebook.buck.io.filesystem.ProjectFilesystem;
Expand All @@ -31,15 +28,14 @@
import com.google.common.base.Joiner;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSortedSet;
import java.io.File;
import java.io.PrintStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URL;
import java.nio.file.Path;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
Expand All @@ -51,7 +47,20 @@ public class JarBackedReflectedKotlinc implements Kotlinc {

private static final String COMPILER_CLASS = "org.jetbrains.kotlin.cli.jvm.K2JVMCompiler";
private static final String EXIT_CODE_CLASS = "org.jetbrains.kotlin.cli.common.ExitCode";
private static final KotlincVersion VERSION = KotlincVersion.of("in memory");

private static final String FOLDER_PREFIX = "libexec/lib";

private static final String KOTLIN_ANNOTATION_PROCESSING =
"kotlin-annotation-processing-gradle.jar";

private static final String KOTLIN_COMPILER_EMBEDDABLE = "kotlin-compiler-embeddable.jar";
private static final String KOTLIN_REFLECT = "kotlin-reflect.jar";
private static final String KOTLIN_SCRIPT_RUNTIME = "kotlin-script-runtime.jar";
private static final String KOTLIN_STDLIB = "kotlin-stdlib.jar";

private static final ImmutableList<String> HOME_LIBRARIES_JAR =
ImmutableList.of(
KOTLIN_COMPILER_EMBEDDABLE, KOTLIN_REFLECT, KOTLIN_SCRIPT_RUNTIME, KOTLIN_STDLIB);

private static final Function<Path, URL> PATH_TO_URL =
p -> {
Expand All @@ -65,22 +74,10 @@ public class JarBackedReflectedKotlinc implements Kotlinc {
// Used to hang onto the KotlinDaemonShim for the life of the buckd process
private static final Map<Set<String>, Object> kotlinShims = new ConcurrentHashMap<>();

@AddToRuleKey private final ImmutableSet<SourcePath> compilerClassPath;
private final Path annotationProcessingClassPath;
private final Path standardLibraryClasspath;

JarBackedReflectedKotlinc(
ImmutableSet<SourcePath> compilerClassPath,
Path annotationProcessingClassPath,
Path standardLibraryClasspath) {
this.compilerClassPath = compilerClassPath;
this.annotationProcessingClassPath = annotationProcessingClassPath;
this.standardLibraryClasspath = standardLibraryClasspath;
}
@AddToRuleKey private final SourcePath kotlinHome;

@Override
public KotlincVersion getVersion() {
return VERSION;
JarBackedReflectedKotlinc(SourcePath kotlinHome) {
this.kotlinHome = kotlinHome;
}

@Override
Expand All @@ -103,12 +100,31 @@ public String getShortName() {

@Override
public Path getAnnotationProcessorPath(SourcePathResolver sourcePathResolver) {
return annotationProcessingClassPath;
return sourcePathResolver
.getAbsolutePath(this.kotlinHome)
.resolve(FOLDER_PREFIX)
.resolve(KOTLIN_ANNOTATION_PROCESSING);
}

@Override
public Path getStdlibPath(SourcePathResolver sourcePathResolver) {
return standardLibraryClasspath;
return sourcePathResolver
.getAbsolutePath(this.kotlinHome)
.resolve(FOLDER_PREFIX)
.resolve(KOTLIN_STDLIB);
}

@Override
public ImmutableList<Path> getHomeLibraries(SourcePathResolver sourcePathResolver) {
return HOME_LIBRARIES_JAR
.stream()
.map(
jar ->
sourcePathResolver
.getAbsolutePath(this.kotlinHome)
.resolve(FOLDER_PREFIX)
.resolve(jar))
.collect(ImmutableList.toImmutableList());
}

@Override
Expand All @@ -118,13 +134,19 @@ public ImmutableList<Path> getAdditionalClasspathEntries(SourcePathResolver sour

@Override
public ImmutableList<String> getCommandPrefix(SourcePathResolver resolver) {
throw new UnsupportedOperationException("In memory kotlinc may not be used externally");
throw new UnsupportedOperationException("Target kotlinc may not be used externally");
}

@Override
public KotlincVersion getVersion() {
throw new UnsupportedOperationException("Target based kotlinc doesn't have a version");
}

@Override
public int buildWithClasspath(
ExecutionContext context,
BuildTarget invokingRule,
ImmutableList<Path> kotlinHomeLibraries,
ImmutableList<String> options,
ImmutableSortedSet<Path> kotlinSourceFilePaths,
Path pathToSrcsList,
Expand All @@ -149,23 +171,23 @@ public int buildWithClasspath(
ImmutableList.<String>builder()
.addAll(options)
.addAll(
transform(
expandedSources,
path -> projectFilesystem.resolve(path).toAbsolutePath().toString()))
expandedSources
.stream()
.map(path -> projectFilesystem.resolve(path).toAbsolutePath().toString())
.collect(Collectors.toList()))
.build();

Set<File> compilerIdPaths =
compilerClassPath
Set<String> kotlinHomeLibrariesStringPaths =
kotlinHomeLibraries
.stream()
.map(p -> ((PathSourcePath) p).getRelativePath())
.map(Path::toFile)
.map(Path::toAbsolutePath)
.map(Path::toString)
.collect(Collectors.toSet());

try {
Object compilerShim =
kotlinShims.computeIfAbsent(
compilerIdPaths.stream().map(File::getAbsolutePath).collect(Collectors.toSet()),
k -> loadCompilerShim(context));
kotlinHomeLibrariesStringPaths, k -> loadCompilerShim(context, kotlinHomeLibraries));

Method compile = compilerShim.getClass().getMethod("exec", PrintStream.class, String[].class);

Expand All @@ -187,20 +209,15 @@ public int buildWithClasspath(
}
}

private Object loadCompilerShim(ExecutionContext context) {
private Object loadCompilerShim(ExecutionContext context, List<Path> kotlinHomeLibraries) {
try {
ClassLoaderCache classLoaderCache = context.getClassLoaderCache();
classLoaderCache.addRef();

ClassLoader classLoader =
classLoaderCache.getClassLoaderForClassPath(
SynchronizedToolProvider.getSystemToolClassLoader(),
ImmutableList.copyOf(
compilerClassPath
.stream()
.map(p -> ((PathSourcePath) p).getRelativePath())
.map(PATH_TO_URL)
.iterator()));
ImmutableList.copyOf(kotlinHomeLibraries.stream().map(PATH_TO_URL).iterator()));

return classLoader.loadClass(COMPILER_CLASS).newInstance();
} catch (Exception ex) {
Expand Down
Loading

0 comments on commit cc94c16

Please sign in to comment.