Skip to content

Commit

Permalink
Basic qsync support in CLion for linux (#7094)
Browse files Browse the repository at this point in the history
Fixes some breaking issues for query sync in CLion. Currently query sync only works with gcc on linux.
  • Loading branch information
LeFrosch authored Dec 16, 2024
1 parent b14a8b2 commit 6db6a26
Show file tree
Hide file tree
Showing 7 changed files with 186 additions and 75 deletions.
8 changes: 6 additions & 2 deletions aspect/build_dependencies.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ def _package_dependencies_impl(target, ctx):
qsync_aars = dep_info.aars.to_list() if dep_info.aars else [],
qsync_gensrcs = dep_info.gensrcs.to_list() if dep_info.gensrcs else [],
cc_headers = dep_info.cc_headers.to_list() if dep_info.cc_headers else [],
cc_info_file = cc_info_file + [dep_info.cc_toolchain_info.file] if dep_info.cc_toolchain_info else [],
cc_info_file = cc_info_file + ([dep_info.cc_toolchain_info.file] if dep_info.cc_toolchain_info else []),
)]

def _write_java_target_info(target, ctx, custom_prefix = ""):
Expand Down Expand Up @@ -213,12 +213,16 @@ def merge_dependencies_info(target, ctx, java_dep_info, cc_dep_info, cc_toolchai

if cc_dep_info and cc_toolchain_dep_info:
test_mode_cc_src_deps = depset(transitive = [cc_dep_info.test_mode_cc_src_deps, cc_toolchain_dep_info.test_mode_cc_src_deps])
cc_toolchain_info = cc_toolchain_dep_info.cc_toolchain_info
elif cc_dep_info:
test_mode_cc_src_deps = cc_dep_info.test_mode_cc_src_deps
cc_toolchain_info = cc_dep_info.cc_toolchain_info
elif cc_toolchain_dep_info:
test_mode_cc_src_deps = cc_toolchain_dep_info.test_mode_cc_src_deps
cc_toolchain_info = cc_toolchain_dep_info.cc_toolchain_info
else:
test_mode_cc_src_deps = None
cc_toolchain_info = None

merged = create_dependencies_info(
label = target.label,
Expand All @@ -229,7 +233,7 @@ def merge_dependencies_info(target, ctx, java_dep_info, cc_dep_info, cc_toolchai
expand_sources = java_dep_info.expand_sources if java_dep_info else None,
cc_compilation_info = cc_dep_info.cc_compilation_info if cc_dep_info else None,
cc_headers = cc_dep_info.cc_headers if cc_dep_info else None,
cc_toolchain_info = cc_toolchain_dep_info.cc_toolchain_info if cc_toolchain_dep_info else None,
cc_toolchain_info = cc_toolchain_info,
test_mode_own_files = java_dep_info.test_mode_own_files if java_dep_info else None,
test_mode_cc_src_deps = test_mode_cc_src_deps,
)
Expand Down
142 changes: 70 additions & 72 deletions base/src/com/google/idea/blaze/base/qsync/BazelDependencyBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -161,78 +161,76 @@ public OutputInfo build(
Optional<BuildDepsStats.Builder> buildDepsStatsBuilder =
BuildDepsStatsScope.fromContext(context);
buildDepsStatsBuilder.ifPresent(stats -> stats.setBlazeBinaryType(invoker.getType()));
try (BuildResultHelper buildResultHelper = invoker.createBuildResultHelper()) {
String includes =
projectDefinition.projectIncludes().stream()
.map(path -> "//" + path)
.collect(joining(","));
String excludes =
projectDefinition.projectExcludes().stream()
.map(path -> "//" + path)
.collect(joining(","));
String aspectLocation = prepareAspect(context);
Set<String> ruleKindsToBuild =
Sets.difference(BlazeQueryParser.ALWAYS_BUILD_RULE_KINDS, handledRuleKinds);
String alwaysBuildParam = Joiner.on(",").join(ruleKindsToBuild);

ImmutableSet<OutputGroup> outputGroups =
languages.stream()
.map(OUTPUT_GROUPS_BY_LANGUAGE::get)
.flatMap(Collection::stream)
.collect(ImmutableSet.toImmutableSet());

ProjectViewSet projectViewSet = ProjectViewManager.getInstance(project).getProjectViewSet();
// TODO This is not SYNC_CONTEXT, but also not OTHER_CONTEXT, we need to decide what kind
// of flags need to be passed here.
List<String> additionalBlazeFlags =
BlazeFlags.blazeFlags(
project,
projectViewSet,
BlazeCommandName.BUILD,
context,
BlazeInvocationContext.OTHER_CONTEXT);

BlazeCommand.Builder builder =
BlazeCommand.builder(invoker, BlazeCommandName.BUILD, project)
.addBlazeFlags(buildTargets.stream().map(Label::toString).collect(toImmutableList()))
.addBlazeFlags(buildResultHelper.getBuildFlags())
.addBlazeFlags(additionalBlazeFlags)
.addBlazeFlags(
String.format(
"--aspects=%1$s%%collect_dependencies,%1$s%%package_dependencies",
aspectLocation))
.addBlazeFlags(String.format("--aspects_parameters=include=%s", includes))
.addBlazeFlags(String.format("--aspects_parameters=exclude=%s", excludes))
.addBlazeFlags(
String.format("--aspects_parameters=always_build_rules=%s", alwaysBuildParam))
.addBlazeFlags("--aspects_parameters=generate_aidl_classes=True")
.addBlazeFlags(
String.format(
"--aspects_parameters=use_generated_srcjars=%s",
buildGeneratedSrcJars.getValue() ? "True" : "False"))
.addBlazeFlags("--noexperimental_run_validations")
.addBlazeFlags("--keep_going");
outputGroups.stream()
.map(g -> "--output_groups=" + g.outputGroupName())
.forEach(builder::addBlazeFlags);
buildDepsStatsBuilder.ifPresent(
stats -> stats.setBuildFlags(builder.build().toArgumentList()));
Instant buildTime = Instant.now();
BlazeBuildOutputs outputs = BazelExecService.instance(project).build(context, builder);
buildDepsStatsBuilder.ifPresent(
stats -> {
stats.setBuildIds(outputs.getBuildIds());
stats.setBepByteConsumed(outputs.bepBytesConsumed);
});

BazelExitCodeException.throwIfFailed(
builder,
outputs.buildResult,
ThrowOption.ALLOW_PARTIAL_SUCCESS,
ThrowOption.ALLOW_BUILD_FAILURE);

return createOutputInfo(outputs, outputGroups, buildTime, context);
}

String includes =
projectDefinition.projectIncludes().stream()
.map(path -> "//" + path)
.collect(joining(","));
String excludes =
projectDefinition.projectExcludes().stream()
.map(path -> "//" + path)
.collect(joining(","));
String aspectLocation = prepareAspect(context);
Set<String> ruleKindsToBuild =
Sets.difference(BlazeQueryParser.ALWAYS_BUILD_RULE_KINDS, handledRuleKinds);
String alwaysBuildParam = Joiner.on(",").join(ruleKindsToBuild);

ImmutableSet<OutputGroup> outputGroups =
languages.stream()
.map(OUTPUT_GROUPS_BY_LANGUAGE::get)
.flatMap(Collection::stream)
.collect(ImmutableSet.toImmutableSet());

ProjectViewSet projectViewSet = ProjectViewManager.getInstance(project).getProjectViewSet();
// TODO This is not SYNC_CONTEXT, but also not OTHER_CONTEXT, we need to decide what kind
// of flags need to be passed here.
List<String> additionalBlazeFlags =
BlazeFlags.blazeFlags(
project,
projectViewSet,
BlazeCommandName.BUILD,
context,
BlazeInvocationContext.OTHER_CONTEXT);

BlazeCommand.Builder builder =
BlazeCommand.builder(invoker, BlazeCommandName.BUILD, project)
.addBlazeFlags(buildTargets.stream().map(Label::toString).collect(toImmutableList()))
.addBlazeFlags(additionalBlazeFlags)
.addBlazeFlags(
String.format(
"--aspects=%1$s%%collect_dependencies,%1$s%%package_dependencies",
aspectLocation))
.addBlazeFlags(String.format("--aspects_parameters=include=%s", includes))
.addBlazeFlags(String.format("--aspects_parameters=exclude=%s", excludes))
.addBlazeFlags(
String.format("--aspects_parameters=always_build_rules=%s", alwaysBuildParam))
.addBlazeFlags("--aspects_parameters=generate_aidl_classes=True")
.addBlazeFlags(
String.format(
"--aspects_parameters=use_generated_srcjars=%s",
buildGeneratedSrcJars.getValue() ? "True" : "False"))
.addBlazeFlags("--noexperimental_run_validations")
.addBlazeFlags("--keep_going");
outputGroups.stream()
.map(g -> "--output_groups=" + g.outputGroupName())
.forEach(builder::addBlazeFlags);
buildDepsStatsBuilder.ifPresent(
stats -> stats.setBuildFlags(builder.build().toArgumentList()));
Instant buildTime = Instant.now();
BlazeBuildOutputs outputs = BazelExecService.instance(project).build(context, builder);
buildDepsStatsBuilder.ifPresent(
stats -> {
stats.setBuildIds(outputs.getBuildIds());
stats.setBepByteConsumed(outputs.bepBytesConsumed);
});

BazelExitCodeException.throwIfFailed(
builder,
outputs.buildResult,
ThrowOption.ALLOW_PARTIAL_SUCCESS,
ThrowOption.ALLOW_BUILD_FAILURE);

return createOutputInfo(outputs, outputGroups, buildTime, context);
}

/**
Expand Down
7 changes: 7 additions & 0 deletions clwb/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -201,12 +201,19 @@ clwb_integration_test(
srcs = ["tests/integrationtests/com/google/idea/blaze/clwb/ExternalIncludesTest.java"],
)

clwb_integration_test(
name = "query_sync_integration_test",
project = "simple",
srcs = ["tests/integrationtests/com/google/idea/blaze/clwb/QuerySyncTest.java"],
)

test_suite(
name = "integration_tests",
tests = [
":llvm_toolchain_integration_test",
":simple_integration_test",
":virtual_includes_integration_test",
":external_includes_integration_test",
":query_sync_integration_test",
],
)
3 changes: 3 additions & 0 deletions clwb/test_defs.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@ def clwb_integration_test(name, project, srcs, deps = []):
# suppressed plugin sets for classic, radler is currently disabled for tests
"-Didea.suppressed.plugins.set.classic=org.jetbrains.plugins.clion.radler,intellij.rider.cpp.debugger,intellij.rider.plugins.clion.radler.cwm",
"-Didea.suppressed.plugins.set.selector=classic",
# define the path to the query sync aspects
"-Dblaze.idea.build_dependencies.bzl.file=aspect/build_dependencies.bzl",
"-Dblaze.idea.build_dependencies_deps.bzl.file=aspect/build_dependencies_deps.bzl",
],
deps = deps + [
":clwb_lib",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package com.google.idea.blaze.clwb;

import static com.google.common.truth.Truth.assertThat;
import static com.google.idea.blaze.clwb.base.Assertions.assertContainsHeader;

import com.google.idea.blaze.clwb.base.BazelVersionRule;
import com.google.idea.blaze.clwb.base.ClwbIntegrationTestCase;
import com.google.idea.blaze.clwb.base.OSRule;
import com.intellij.util.system.OS;
import java.util.concurrent.ExecutionException;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;

@RunWith(JUnit4.class)
public class QuerySyncTest extends ClwbIntegrationTestCase {

// currently query sync only works on linux, TODO: fix mac and windows
@Rule
public final OSRule osRule = new OSRule(OS.Linux);

// query sync requires bazel 6+
@Rule
public final BazelVersionRule bazelRule = new BazelVersionRule(6, 0);

@Test
public void testClwb() throws Exception {
final var success = runQuerySync();
assertThat(success).isTrue();

checkAnalysis();
checkCompiler();
}

private void checkAnalysis() throws ExecutionException {
final var success = enableAnalysisFor(findProjectFile("main/hello-world.cc"));
assertThat(success).isTrue();
}

private void checkCompiler() {
final var compilerSettings = findFileCompilerSettings("main/hello-world.cc");

// TODO: query sync always uses clang : https://github.com/bazelbuild/intellij/issues/7177
// if (SystemInfo.isMac) {
// assertThat(compilerSettings.getCompilerKind()).isEqualTo(ClangCompilerKind.INSTANCE);
// } else if (SystemInfo.isLinux) {
// assertThat(compilerSettings.getCompilerKind()).isEqualTo(GCCCompilerKind.INSTANCE);
// } else if (SystemInfo.isWindows) {
// assertThat(compilerSettings.getCompilerKind()).isEqualTo(MSVCCompilerKind.INSTANCE);
// }

assertContainsHeader("iostream", compilerSettings);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,16 @@
import static com.google.common.truth.Truth.assertThat;

import com.google.idea.blaze.base.async.process.ExternalTask;
import com.google.idea.blaze.base.logging.utils.querysync.QuerySyncActionStatsScope;
import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
import com.google.idea.blaze.base.project.AutoImportProjectOpenProcessor;
import com.google.idea.blaze.base.project.ExtendableBazelProjectCreator;
import com.google.idea.blaze.base.projectview.ProjectView;
import com.google.idea.blaze.base.projectview.ProjectViewSet;
import com.google.idea.blaze.base.projectview.section.sections.TextBlock;
import com.google.idea.blaze.base.projectview.section.sections.TextBlockSection;
import com.google.idea.blaze.base.qsync.QuerySyncManager;
import com.google.idea.blaze.base.qsync.QuerySyncManager.TaskOrigin;
import com.google.idea.blaze.base.scope.BlazeContext;
import com.google.idea.blaze.base.settings.BlazeUserSettings;
import com.google.idea.blaze.base.settings.BuildSystemName;
Expand Down Expand Up @@ -248,6 +251,47 @@ protected BlazeSyncParams.Builder defaultSyncParams() {
.setAddProjectViewTargets(true);
}

protected boolean runQuerySync() {
final var future = QuerySyncManager.getInstance(myProject).onStartup(QuerySyncActionStatsScope.create(getClass(), null));

while (!future.isDone()) {
PlatformTestUtil.dispatchAllInvocationEventsInIdeEventQueue();
}

try {
return future.get();
} catch (ExecutionException e) {
fail("query sync failed " + e.getMessage());
} catch (InterruptedException e) {
fail("query sync was interrupted");
}

return false;
}

protected boolean enableAnalysisFor(VirtualFile file) throws ExecutionException {
final var manager = QuerySyncManager.getInstance(myProject);
final var targets = manager.getTargetsToBuild(file).targets();

final var future = manager.enableAnalysis(
targets,
QuerySyncActionStatsScope.createForFile(getClass(), null, file),
TaskOrigin.USER_ACTION
);

while (!future.isDone()) {
PlatformTestUtil.dispatchAllInvocationEventsInIdeEventQueue();
}

try {
return future.get();
} catch (InterruptedException e) {
fail("enable analysis was interrupted");
}

return false;
}

protected VirtualFile findProjectFile(String relativePath) {
final var file = myProjectRoot.findFileByRelativePath(relativePath);
assertThat(file).isNotNull();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -172,8 +172,8 @@ private File getCompilerExecutable(CcCompilerSettings compilerSettings) {

/** Pre-commits the project update. Should be called from a background thread. */
public void preCommit() {
modifiableOcWorkspace.preCommit();
processCompilerSettings();
modifiableOcWorkspace.preCommit();
}

/** Commits the project update. Must be called from the write thread. */
Expand Down

0 comments on commit 6db6a26

Please sign in to comment.