Skip to content

[WIP] [BUILD] Add Gradle build support and replace Maven in CI#11576

Closed
liuneng1994 wants to merge 53 commits into
apache:mainfrom
liuneng1994:gradle-build-support
Closed

[WIP] [BUILD] Add Gradle build support and replace Maven in CI#11576
liuneng1994 wants to merge 53 commits into
apache:mainfrom
liuneng1994:gradle-build-support

Conversation

@liuneng1994

@liuneng1994 liuneng1994 commented Feb 6, 2026

Copy link
Copy Markdown
Contributor

What changes are proposed in this pull request?

Add a complete Gradle build system that coexists with the existing Maven build. CI workflows for Spark UT (velox_backend_x86.yml, velox_backend_enhanced.yml) remain on Maven.

Gradle Build System:

  • Root Gradle configuration with version catalog (libs.versions.toml)
  • Convention plugins for common patterns (Scala, shading, native, spotless)
  • All core modules with proper dependencies
  • Multi-version support (Spark 3.3-4.1, Scala 2.12/2.13, Java 8-21)
  • Backend selection (Velox, ClickHouse) via -Pbackend property
  • Native C++ build integration via Gradle tasks (full Velox build pipeline)
  • Dependency shading with Shadow plugin
  • ScalaTest integration for running non-ut test suites via Gradle
  • Common Spark and test dependencies centralized in convention plugins

Default configuration: Spark 4.1, Scala 2.13, Java 17, Velox backend

Spark UT: Gradle Limitations (why Maven is kept for gluten-ut)

Running gluten-ut tests via Gradle was attempted with a per-suite JVM forking approach (ScalaTestPerSuiteAction) but failed due to the following issues:

  1. LOCATION_ALREADY_EXISTS errors from shared spark-warehouse directories: Parallel suite JVMs all resolve getClass.getResource("/") to the same test-classes dir, causing Spark's managed table creation to fail with warehouse directory collisions. Even with per-suite working directories (gluten.test.workDir), the classpath-based resource resolution in GlutenTestsBaseTrait.basePath makes true isolation difficult.

  2. Excessive memory consumption: Per-suite JVM forking with the required 4g heap per JVM scales linearly (e.g., 6 forks × 4g = 24GB+), exceeding CI runner memory limits. Reducing parallelism defeats the purpose of per-suite forking.

  3. Spark's JVM-global state leaking: Spark uses JVM-global singletons (SparkContext, daemon threads, native library loading) that leak between suites in a shared JVM. The gradle-scalatest plugin's default Runner -R <dir> mode runs all suites in one JVM, causing failures when one suite's SparkContext is not properly stopped before the next suite starts.

  4. Tag filtering complexity: ScalaTest tag annotations are class-level but per-test Tag objects (e.g., test("name", MyTag)) only produce runtime-visible metadata, requiring constant pool scanning heuristics for class-level pre-filtering that is fragile and incomplete.

Maven's scalatest-maven-plugin handles these issues with battle-tested process isolation, making it the pragmatic choice for gluten-ut. Non-ut modules (backends-velox, gluten-ras, shims, etc.) continue to run tests via Gradle successfully.

Usage examples:

./gradlew build                              # Default build
./gradlew build -PsparkVersion=3.5           # Spark 3.5
./gradlew build -Pbackend=clickhouse         # ClickHouse backend
./gradlew build -Pdelta=true -Piceberg=true  # With optional modules

# Run specific test suites (non-ut modules)
./gradlew :backends-velox:test --tests "org.apache.spark.sql.execution.VeloxParquetReadSuite"

# CI helper script (translates Maven args to Gradle)
bash dev/ci-gradle-build.sh -Pspark-3.5 -Pjava-8 -Pbackends-velox -DskipTests

# Native C++ build (replaces dev/builddeps-veloxbe.sh)
./gradlew :backends-velox:buildNativeAll     # Full pipeline: fetch + build Velox + build Gluten C++
./gradlew :backends-velox:buildNative        # Just rebuild Gluten C++ (if Velox already built)

# Native build with options
./gradlew :backends-velox:buildNativeAll -PnativeBuildType=Debug -PenableS3=ON -PnativeBuildTests=ON

Native build Gradle tasks

Task Description
getVelox Fetch Velox source code (skips if already present)
buildVelox Build the Velox C++ library (skips if already built)
configureNative Configure CMake for Gluten C++ (skips if already configured)
buildNative Build libgluten.so + libvelox.so
buildNativeAll Full pipeline: all of the above

Configurable properties: -PveloxHome=, -PnativeBuildType=Debug|Release, -PnativeThreads=N, -PenableHdfs=ON, -PenableS3=ON, -PenableGcs=ON, -PenableAbfs=ON, -PenableQat=ON, -PenableGpu=ON, -PnativeBuildTests=ON, -PnativeBuildBenchmarks=ON


Key Gradle build fixes (Maven compatibility)

Several fixes were needed to match Maven's behavior in Gradle:

Issue Root Cause Fix
No Spark Shim Provider found when switching Spark versions generateBuildInfo task had no declared inputs; Gradle cached stale gluten-build-info.properties Added inputs.property() declarations for sparkVersion, scalaVersion, etc.
VeloxParquetWriteSuite failures in Spark 3.3 Shim's FileFormatWriter not loaded before Spark's own version Reorder test classpath: project outputs before external JARs
VeloxExpandSuite NPE in CI Leaked SparkContext from prior suite in shared JVM forkEvery = 1 — fork new JVM per test class (matches Maven)
Symbol literal deprecation errors in Scala 2.13 Scala 2.13 -Wconf rules not matching Maven config Added -Wconf:cat=deprecation&msg=symbol literal is deprecated:s
Assertion failures in Spark's UnsafeRow Gradle enables assertions by default; Maven does not enableAssertions = false in test configuration
Test resource path mismatches Gradle separates classes/resources; Maven merges them Redirect test resources to Scala classes directory
ARM native lib FileNotFoundException Gradle mapped aarch64arm64; JNI loader uses raw aarch64 Changed Gradle mapping to aarch64 to match Maven and JNI
Checkstyle ${config_loc} not set in Maven Maven's checkstyle plugin doesn't auto-set ${config_loc} like Gradle does Added <propertyExpansion> to pom.xml; Gradle uses configDirectory

How was this patch tested?

  • Compilation verified across Spark 3.3, 3.4, 3.5, 4.0, 4.1 with corresponding Scala/Java versions
  • Full CI run on all three Velox workflows (x86, enhanced, arm) — all jobs passing
  • Non-ut test suite isolation verified with gradle-scalatest plugin
  • Native build tasks verified: task chain executes correctly, onlyIf guards skip already-built artifacts
  • CI helper script tested across all Spark/Java/Scala matrix combinations
  • gluten-ut tests verified disabled in Gradle (enabled = false), run via Maven in CI

Was this patch authored or co-authored using generative AI tooling?

Generated-by: Claude Opus 4 (Anthropic)

liuneng1994 and others added 4 commits May 15, 2023 10:18
Add a complete Gradle build system that coexists with the existing Maven
build. This enables developers to choose their preferred build tool while
maintaining full feature parity.

Features:
- Root Gradle configuration with version catalog (libs.versions.toml)
- Convention plugins for common patterns (Scala, shading, native, spotless)
- All core modules with proper dependencies
- Multi-version support (Spark 3.3-4.1, Scala 2.12/2.13, Java 8-21)
- Backend selection (Velox, ClickHouse) via -Pbackend property
- Native C++ build integration via CMake
- Dependency shading with Shadow plugin

Default configuration: Spark 4.1, Scala 2.13, Java 17, Velox backend

Usage examples:
- ./gradlew build                              # Default build
- ./gradlew build -PsparkVersion=3.5           # Spark 3.5
- ./gradlew build -Pbackend=clickhouse         # ClickHouse backend
- ./gradlew build -Pdelta=true -Piceberg=true  # With optional modules

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Feb 6, 2026

Copy link
Copy Markdown

Run Gluten Clickhouse CI on x86

Fix test dependencies and configuration to enable running ScalaTest
suites via Gradle. Add scalatest plugin to backends-velox, include
missing test dependencies (javafaker, flexmark, spark-common-utils),
and apply Kotlin formatting fixes from spotless.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Feb 6, 2026

Copy link
Copy Markdown

Run Gluten Clickhouse CI on x86

@philo-he philo-he left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the PR. Not sure if we need to add this support, especially considering the maintenance efforts for the two build tools' configurations.

cc @zhouyuan @zhztheplayer @FelixYBW

- Derive scalaVersion from scalaBinaryVersion when overridden via -P
- Use Java-version-aware Caffeine dependency (2.9.3 for Java 8, 3.1.8
  for Java 11+) matching Maven behavior
- Add scalatest plugin dependency to convention plugins
- Propagate compileOnly dependencies to testImplementation scope

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Feb 6, 2026

Copy link
Copy Markdown

Run Gluten Clickhouse CI on x86

@liuneng1994 liuneng1994 changed the title [MINOR] Add Gradle build support alongside Maven [BUILD] Add Gradle build support alongside Maven Feb 6, 2026
Add full native build task chain to backends-velox:
- getVelox: Fetch Velox source code
- buildVelox: Build the Velox C++ library
- configureNative: Configure CMake for Gluten C++
- buildNative: Build libgluten.so + libvelox.so
- buildNativeAll: Convenience task for full pipeline

All tasks support configurable properties (veloxHome, nativeBuildType,
nativeThreads, enableHdfs, enableS3, etc.) and include onlyIf guards
to skip already-completed steps.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Feb 6, 2026

Copy link
Copy Markdown

Run Gluten Clickhouse CI on x86

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Feb 6, 2026

Copy link
Copy Markdown

Run Gluten Clickhouse CI on x86

Add backends-velox test JARs, Spark test JARs, and library-specific
test dependencies to delta, iceberg, hudi, paimon modules so their
test suites (extending WholeStageTransformerSuite) can compile.
Fix spotless formatting in gluten-uniffle.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Feb 6, 2026

Copy link
Copy Markdown

Run Gluten Clickhouse CI on x86

These are Gradle internal cache files that should not be version
controlled. The .gitignore entry already exists but only prevents
new files from being added; tracked files need explicit removal.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Feb 6, 2026

Copy link
Copy Markdown

Run Gluten Clickhouse CI on x86

Replace overly broad 'gradle' entry (which would ignore the entire
gradle/ source directory) with proper entries:
- .gradle/ - Gradle cache directories (anywhere in tree)
- gradlew, gradlew.bat - Gradle wrapper scripts (if generated)

Remove redundant per-file entries that are now covered by .gradle/.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Feb 6, 2026

Copy link
Copy Markdown

Run Gluten Clickhouse CI on x86

Remove ~430 lines of duplication across 30 build files:
- Remove redundant protoc config (already in gluten.protobuf plugin)
- Remove redundant ShadowJar config (already in gluten.shading plugin)
- Remove redundant scala-library compileOnly (already in convention plugin)
- Remove redundant JavaCompile config from root (already in convention plugin)
- Remove unused variables (antlr4Version, hadoopVersion, scalaVersion, etc.)
- Simplify optional module includes with map-based loop
- Merge duplicate sparkProperties branches (4.0 and 4.1 are identical)
- Extract gitOutput helper in generateBuildInfo
- Make spark-common-utils conditional (Spark 4.0+ only)

Verified: all Spark versions (3.4, 3.5, 4.0, 4.1) build successfully.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Feb 6, 2026

Copy link
Copy Markdown

Run Gluten Clickhouse CI on x86

liuneng1994 and others added 2 commits February 10, 2026 15:01
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Move duplicated Spark compile-only deps (spark-sql, spark-core,
spark-catalyst, spark-hive), common test deps (scalatest, junit),
and Spark test JARs into gluten.scala-library convention plugin.

Removes ~200 lines of boilerplate across 11 module build files.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

Run Gluten Clickhouse CI on x86

Add spotless-plugin-gradle 6.25.0 with the same rules as Maven's
spotless-maven-plugin: google-java-format for Java, scalafmt 3.8.3
for Scala, import ordering, license headers, and toggleOffOn support.

The plugin is conditionally loaded based on the build JDK:
- JDK 8: no-op (Spotless requires Java 11+)
- JDK 11-16: google-java-format 1.7
- JDK 17+: google-java-format 1.17.0

GlutenSpotless.kt is excluded from compilation on JDK < 11 to avoid
classpath issues, and invoked via reflection from the convention plugin.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

Run Gluten Clickhouse CI on x86

Spotless enforces minimum google-java-format versions per JDK (1.8 for
JDK 11, 1.10.0 for JDK 17). Using 1.17.0 universally satisfies all
constraints and produces consistent formatting across JDKs.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

Run Gluten Clickhouse CI on x86

The extractIncludeProto task scans the entire compile classpath for
.proto files, which can block indefinitely due to network issues or
dependency cache locks. A 5-minute timeout ensures the build fails
with a clear error instead of hanging.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

Run Gluten Clickhouse CI on x86

@FelixYBW

Copy link
Copy Markdown
Contributor

Thanks for the PR. Not sure if we need to add this support, especially considering the maintenance efforts for the two build tools' configurations.

cc @zhouyuan @zhztheplayer @FelixYBW

If Gradle is much better than Maven, we needn't maintain Maven anymore.

…Proto blocking

- Add gluten.scalatest to 14 modules that had test sources but were not
  executing them: gluten-core, gluten-substrait, gluten-arrow, gluten-delta,
  gluten-iceberg, gluten-hudi, gluten-paimon, backends-clickhouse,
  gluten-ut/test, and gluten-ut/spark33-41.
- Fix extractIncludeProto root cause: disconnect compileProtoPath from the
  full compile classpath (600+ JARs) and add only protobuf-java, so proto
  extraction scans just 1 JAR instead of the entire dependency tree.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

Run Gluten Clickhouse CI on x86

…Every support

The gradle-scalatest plugin replaced Gradle's Test task with a single javaexec()
call that ran all suites in one JVM, ignoring forkEvery=1. This caused
SparkContext leaks between suites. Switch to JUnit 5 Platform with ScalaTest's
junit-5-9 engine so Gradle's built-in Test task handles forking correctly.

Add AbstractClassExcludeSpec to filter abstract classes and traits from test
discovery by reading ACC_ABSTRACT from class file headers.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

Run Gluten Clickhouse CI on x86

The ScalaTest JUnit 5 engine does not support JUnit Platform's
includeTags/excludeTags, so tag filtering was silently broken.
Replace with TagExcludeSpec that scans class file constant pools
for annotation type descriptors at the Gradle test scanning level.

Make gluten-ut modules opt-in via -Pspark-ut=true to match Maven's
-Pspark-ut profile, and translate the flag in ci-gradle-build.sh.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

Run Gluten Clickhouse CI on x86

Test code navigates from classpath root to source tree via relative
paths like getClass.getResource("/").getPath + "../../../src/...".
This breaks with Gradle's 4-level output dir (build/classes/scala/test/)
vs Maven's 2-level (target/test-classes/). The build/src -> ../src
symlink was only in backends-velox; move it to gluten.scala-conventions
so all modules (including gluten-ut) get it automatically.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

Run Gluten Clickhouse CI on x86

GenerateExample is a string-based ScalaTest Tag object, not a
@TagAnnotation annotation. TagExcludeSpec can only filter annotation-
based tags via class file constant pool scanning. Translate the
GenerateExample tagsToInclude to a --tests class name filter in
ci-gradle-build.sh since the ScalaTest JUnit 5 engine doesn't
support method-level tag filtering either.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

Run Gluten Clickhouse CI on x86

…ation

Switch from JUnit 5 Platform (scalatestplus junit-5-9 engine + forkEvery=1)
to the gradle-scalatest plugin with a custom ScalaTestPerSuiteAction that
invokes `org.scalatest.tools.Runner -s <Suite>` in a separate javaexec per
test suite class. This achieves per-suite JVM isolation without JUnit,
preventing Spark's JVM-global state (SparkContext, daemon threads) from
leaking between suites.

Key changes:
- Add gradle-scalatest plugin (0.32) dependency and apply it in the
  gluten.scalatest convention plugin
- Create ScalaTestPerSuiteAction with bytecode-level suite discovery
  (superclass chain walking), class-level tag exclusion via constant pool
  scanning, and per-test tag include/exclude via Runner's -n/-l flags
- Remove JUnit 5 runtime dependencies (junit-5-9, junit-jupiter-engine,
  junit-vintage-engine, junit-4-13) from backends-velox
- Remove GenerateExample special-case in CI script (now handled natively
  by Runner's -n flag)
- Clean up redundant comments across build.gradle.kts files

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

Run Gluten Clickhouse CI on x86

Only gluten-ut modules need per-suite JVM isolation because they extend
Spark's own test suites (SharedSparkSession) which leak JVM-global state
(SparkContext, daemon threads, shutdown hooks) between suites.

Other modules (backends-velox, gluten-ras, etc.) keep the gradle-scalatest
plugin's default single-JVM behavior (Runner -R <dir>), matching Maven's
scalatest-maven-plugin. This avoids breaking tests like VeloxRasSuite that
depend on native libraries loaded by earlier suites within the same JVM.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

Run Gluten Clickhouse CI on x86

Use a bounded thread pool to run multiple suite JVMs concurrently,
controlled by Gradle's maxParallelForks property. Set maxParallelForks=3
for gluten-ut modules (GitHub Actions runner: 4 vCPUs, 16 GB RAM; each
suite JVM uses ~4 GB heap, so 3 parallel forks use ~12 GB).

When maxParallelForks=1 (default for non-ut modules), execution remains
sequential with no thread pool overhead.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

Run Gluten Clickhouse CI on x86

Pass task.environment to each javaexec call so that any environment
variables configured on the Test task are inherited by forked suite JVMs.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

Run Gluten Clickhouse CI on x86

@liuneng1994

Copy link
Copy Markdown
Contributor Author

Closing: Gradle build system works for compilation and non-ut module tests, but running gluten-ut (Spark UT) via Gradle has fundamental issues with Spark's JVM-global state, spark-warehouse directory collisions in parallel forks, and excessive memory consumption. CI workflows for Spark UT will remain on Maven.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants