Skip to content

Conversation

@arnavsharma990
Copy link
Contributor

Fixes #1747

This PR adds a new documentation page explaining best practices for using
Scalafix in cross-compiled Scala 2 and Scala 3 projects.

It covers:

  • Why Scalafix config fails across different Scala versions
  • How to structure a shared base.conf plus per-version overrides
  • Using the “include” pattern for shared configuration
  • SBT configuration to automatically pick the correct config file
  • CLI/CI examples for selecting per-version configs
  • Ideas for future improvements (conditional config, include support, etc.)

This is a documentation-only update.

@arnavsharma990
Copy link
Contributor Author

Could someone please approve the workflow run so CI can start?

@tgodzik @ckipp01

@tgodzik
Copy link
Contributor

tgodzik commented Nov 26, 2025

CI is no really needed, since this is just a doc, but it might take a while before we review in detail though.

@arnavsharma990
Copy link
Contributor Author

okay got it

Copy link
Collaborator

@bjaglin bjaglin left a comment

Choose a reason for hiding this comment

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

Thanks for taking the time to write that down, docs are very important! Have a look at my suggestions, I think the doc could be a bit more concise.

Also, I think the amount of people using the CLI is very low, so I wonder if we couldn't just make a paragraph explaining the sbt setup in the main page (which is sbt-centric)?

Comment on lines 9 to 10
Scala 3 compilation unit is processed, and vice versa. Until Scalafix grows
conditional configuration, the safest way to avoid those failures is to split
Copy link
Collaborator

Choose a reason for hiding this comment

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

There is no plan to do conditional configuration so the "Until" can be misleading. IMHO, documentation should be about what's available.

Comment on lines 15 to 16
* Scala 2 only flags such as `-Ywarn-unused-import` or SemanticDB options using
`-P:semanticdb` are rejected by Scala 3.
Copy link
Collaborator

Choose a reason for hiding this comment

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

How is that impacting the configuration file? That looks like a build tool concern to me.

Comment on lines 127 to 128
* Isolate risky scalac options (`-Wunused`, `-Ywarn-unused-import`, `-P:semanticdb`)
inside each version-specific file or sbt setting.
Copy link
Collaborator

Choose a reason for hiding this comment

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

Same comment as above - scalac-options are not part of the config so I don't understand that part

Comment on lines 132 to 144
### Looking ahead

Issue [#1747](https://github.com/scalacenter/scalafix/issues/1747) tracks better
ergonomics for cross compilation. Potential improvements include:

* Conditional configuration blocks directly inside `.scalafix.conf` (for example
`if scalaVersion.startsWith("3.")`).
* First-class support for including multiple files via CLI flags.
* Allowing rule selection based on the detected input Scala dialect.

Until those land, the include-based layout above is the recommended, battle-tested
approach.

Copy link
Collaborator

Choose a reason for hiding this comment

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

I don't think we should advertize potential improvements in the docs, as it's unclear if there is a need for it, especially as 2.x is on its way out and scalafix is kept updated but no-one is actively adding features to it. As a matter of fact, I was hoping to close #1747 with this doc update.

```
### Multiple values for CLI flags
Copy link
Collaborator

Choose a reason for hiding this comment

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

this is merged, you can rebase against main


rules += RemoveUnused

// Scala 2 only compilers flags or rule settings
Copy link
Collaborator

Choose a reason for hiding this comment

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

As mentioned elsewhere, we should focus on compatibility (it's not necessarily about compiler flags but it can be new language features - although that's mostly for community rules, that you don't mention)

Suggested change
// Scala 2 only compilers flags or rule settings
// Scala 2 only rules or rule settings

Comment on lines 29 to 30
├── project/
│ └── build config…
Copy link
Collaborator

Choose a reason for hiding this comment

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

Irrelevant? also, build.sbt is at the root

@arnavsharma990
Copy link
Contributor Author

Thanks for the thorough review! I’ve applied all requested changes:
– Consistent use of “cross-building”
– Removed speculative/future language
– Added a Limitations section
– Clarified build-tool vs config responsibilities
– Updated CLI examples to use defaults
– Sidebar added
– Renamed file to cross-building.md and updated translations

Verified locally with sbt ci-docs and yarn start.
Everything renders correctly. PTAL!
Screenshot 2025-11-28 at 2 29 18 PM

Screenshot 2025-11-28 at 2 47 01 PM

@bjaglin
Copy link
Collaborator

bjaglin commented Dec 10, 2025

@arnavsharma990 did you forget to push?

- Rename file to cross-building.md for URL consistency
- Replace 'cross-compilation' with 'cross-building' throughout
- Remove speculative/future-looking sections
- Add Limitations section explaining no conditional config support
- Clarify that scalac/semanticdb flags belong in build tool
- Update CLI examples to use defaults from config file
- Add sidebar entry under Usage section
- Update translations in en.json
@arnavsharma990 arnavsharma990 force-pushed the issue-1747-docs-cross-compilation branch from bf4a709 to 42fe994 Compare December 10, 2025 11:19
Copilot AI review requested due to automatic review settings December 10, 2025 11:19
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR adds comprehensive documentation for using Scalafix in cross-compiled Scala 2 and Scala 3 projects, addressing issue #1747. It introduces best practices for managing version-specific configurations.

  • Explains why separate configuration files are needed for different Scala versions
  • Provides concrete examples of file layouts using HOCON's include pattern
  • Shows how to wire version-specific configs in sbt, CLI, and CI environments

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated no comments.

File Description
website/sidebars.json Adds "cross-building" entry to the Usage section navigation
website/i18n/en.json Adds internationalization title entry for the new cross-building page
docs/users/cross-building.md New comprehensive guide covering configuration splitting, file organization, sbt setup, CLI usage, and recommendations for cross-compiled projects

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@arnavsharma990
Copy link
Contributor Author

@bjaglin Sorry, I somehow forgot to push earlier , I’ve pushed the updates now. PTAL

Comment on lines +130 to +137
## Recommendations

* Keep rules that truly work on both versions inside `common.conf`.
* Manage scalac and SemanticDB flags inside the build tool per target; Scalafix
configs focus solely on rules and rule-specific settings.
* Document in `README.md` or `CONTRIBUTING.md` which rules run on which Scala
version to reduce confusion for new contributors.

Copy link
Collaborator

Choose a reason for hiding this comment

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

the first item is already mentioned above and the 2 last are not related to scalafix, so I would simply drop that

Suggested change
## Recommendations
* Keep rules that truly work on both versions inside `common.conf`.
* Manage scalac and SemanticDB flags inside the build tool per target; Scalafix
configs focus solely on rules and rule-specific settings.
* Document in `README.md` or `CONTRIBUTING.md` which rules run on which Scala
version to reduce confusion for new contributors.

HOCON syntax supports nested includes, so feel free to create the hierarchy that
matches your team conventions.

## Selecting the right config in sbt
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
## Selecting the right config in sbt
## Selecting the right configuration file
### sbt

Comment on lines +33 to +41
the HOCON `include` syntax. One convenient layout is:

```
.
└── scalafix/
├── common.conf
├── scala2.conf
└── scala3.conf
```
Copy link
Collaborator

Choose a reason for hiding this comment

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

In most OSS projects I have seen, files are at the root, where .scalafix.conf is looked up by default - I think adding an extra directory complicates discovery.

https://github.com/search?q=.scalafix-scala3.conf&type=code

What about flatteing the layour here and across the doc?

  • .scalafix-common.conf
  • .scalafix-scala2.conf
  • .scalafix-scala3.conf

Comment on lines +6 to +28
Cross-building the same codebase with Scala 2.13 and Scala 3.3+ is common, but
it collides with how Scalafix resolves rules and compiler options. A rule or
build-tool flag that only works on Scala 2 can crash Scalafix when the Scala 3
compilation unit is processed, and vice versa. Split your configuration per
Scala version and let the build tool wire the right file.

## Why separate configs are required today

* Scala 2 only scalac flags such as `-Ywarn-unused-import` or SemanticDB options
using `-P:semanticdb` belong in the build tool. Those settings differ per
target and cannot be inferred by Scalafix.
* Some built-in or community rules rely on compiler symbols present only in a
single Scala major version.
* The CLI currently ingests a single `.scalafix.conf`; there is no per-target
override like sbt’s `CrossVersion`.

## Limitations

Scalafix cannot conditionally toggle rules or scalac options based on the input
Scala version. Provide a separate config file per Scala version and have sbt,
mill, or your CLI invocation choose the right file along with the correct
compiler flags. See [issue #1747](https://github.com/scalacenter/scalafix/issues/1747)
for additional background.
Copy link
Collaborator

Choose a reason for hiding this comment

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

I still find this quite hard to follow since it mixes context/rationale, problem and solution space. Here is an attempt at doing this with one paragraph for each:

In a codebase cross-building against several binary versions of Scala, it is advised to run Scalafix several times, for each Scala version. That allows to cover version-specific files and to benefit from compiler diagnostics from several Scala versions for common files.

However, since rules can be specific or only support a subset of features for a given Scala version, a different set of rules or rule features might have to be selected for each run, in order to avoid failing the entire run and preventing relevant rules to run.

Since nothing in the current API allows rules to advertize their limitations programmatically to Scalafix, this page explains how to do it manually.

Comment on lines +55 to +77
`scala2.conf`
```scala
include "common.conf"

rules += RemoveUnused

// Scala 2 only rule settings
RemoveUnused {
imports = true
}
```

`scala3.conf`
```scala
include "common.conf"

rules += LeakingImplicitClassVal

// Scala 3 specific tweaks go here
OrganizeImports {
groupedImports = Keep
}
```
Copy link
Collaborator

Choose a reason for hiding this comment

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

Are these configuration files solving real limitations as described in the intro? AFAIK RemoveUnused.imports is fine with Scala 3 and LeakingImplicitClassVal is not related to Scala 3 (more to Scala 3 actually).

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Better support for cross compilation

3 participants