-
Notifications
You must be signed in to change notification settings - Fork 29.7k
Build hooks: Don't require toolchain for unit tests #178954
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code Review
This pull request modifies the build hooks to not require a native toolchain for unit tests, which is a great improvement for developers on macOS and Linux. The changes are logical and well-implemented by allowing toolchain discovery functions to return null instead of throwing errors when a toolchain isn't found for flutter test. The new tests are also comprehensive. I have a couple of suggestions to improve documentation and ensure consistent behavior across platforms.
packages/flutter_tools/lib/src/isolated/native_assets/linux/native_assets.dart
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🙏 🙏 @simolus3 ! 10/10 PR with such detailed comments and the tests! 🚀
|
@simolus3 is there a way now (e.g. option) to force disable native asset compilation for flutter tests? If not, then having clang installed might have a negative impact on tests performance and they might behave differently depending on where they are run. At least if I understand correctly the native modules are compiled when the buildtools are found, aren't they? |
There isn't, and (as mentioned in the issue) I don't think there should be one. If a package has a build hook, it can expect that hook to run whenever the package is used. So having an option to not run hooks would easily break packages (I know you want to mock the package anyways, but this still violates assumptions).
We still unconditionally invoke build hooks. It's just that if we don't find a compiler toolchain, we will let each hook worry about finding a compiler on its own (if it needs one). Previously, we'd immediately fail the build instead. The |
My problem is: when more packages start to use build hooks (see there are a couple of them already example projects), then running any flutter test will build all the assets no matter whether I use them or not (overhead; a benchmark would be nice to have). The assumption for testing is that no matter where/when I run tests, they must behave the same. If not, then the tests are flaky. Seems like native assets (so flutter 3.38) might make all tests flaky according to your explanation as they will compile and use native assets if they can, otherwise they just run without them (so the output depends on the runner env). If I change the download url in your code by an invalid one (similar to when the right one is down or blocked), then running You may say caching the downloaded stuff would minimize the likelihood of this happening, but as I see outputDirectoryShared points to the project's
This looks like a very big security hole tbh. Npm has already been there. So now any package can start to download anything from the net (as I see there is no central repository for these; e.g. sqlite tries to download from Github, but this is up to the plugin authors what do they use and if they check checksums after downloading) and execute basically anything when building a flutter app or just running its tests without any visible indicator? Even transient dependencies can do this? Sorry for being picky, but I just realized these things the hard way after upgrading a prod project to 3.38. I'm not blaming you (or anyone) for any of these. I'm not involved in the native assets/code_assets developments, so I can't really recommend good/optimal solutions for my problems, sadly all I can do is to highlight my concerns which may look rude (not intended), but I still want to make them transparent. I don't think this PR could/should fix the mentioned core issues, just saying that this PR only improves the situation if I intentionally don't install A breaking change entry is definitely missing for 3.38 regarding this native assets/hooks topic. |
Please continue the discussion on a relevant issue:
At the risk of repeating myself. This was already the situation with plugins when doing
The final goal is to have the assets hosted on pub as well: In the meantime, package authors can use the approaches listed in:
This was already the case with Flutter plugins, you can shell out to arbitrary scripts from the Gradle/CocoaPods/SPM build scripts. (And various packages were doing this to run shell scripts to download prebuilt dylibs.) Build hooks equalize the If you have specific feature requests please file them on dart-lang/native where most of the shared code (between Dart and Flutter) for build hooks lives. Let's keep the discussion on this issue to the issue that this PR is solving, we are unanimous that this PR is an improvement over the pre-PR situation! |
This PR seems reasonable to me; unconditionally failing due to lack of a tool we are likely not to need is clearly not ideal behavior. I'm happy to discuss the general topic further on a relevant issue.
That's also not related to this PR, but to save the trouble of filing a new issue that will be closed: adding new, opt-in functionality is by definition not a breaking change. There might need to be more guidance to package authors about how to adopt it without affecting clients, but that's not the same thing. |
flutter/flutter@7b98d50...022b155 2025-11-27 [email protected] Make tree green again by fixing lints (flutter/flutter#179186) 2025-11-26 [email protected] Add shared Darwin implementation for plugins (flutter/flutter#176495) 2025-11-26 [email protected] Fixed changing supportedLocales fails to update the locale (flutter/flutter#178526) 2025-11-26 [email protected] [ Tool ] Remove --no-sandbox when launching web apps on Chrome device (flutter/flutter#178670) 2025-11-26 [email protected] Build hooks: Don't require toolchain for unit tests (flutter/flutter#178954) 2025-11-26 [email protected] Fix a small typo in `HandlerCompat.java` docs (flutter/flutter#178595) 2025-11-26 [email protected] Roll Fuchsia Linux SDK from nzuAxCJGeJbkZCTkr... to _e9MNK4nfBOrERVP_... (flutter/flutter#179130) 2025-11-26 [email protected] Make sure that a CupertinoActivityIndicator doesn't crash in 0x0 envi… (flutter/flutter#178565) 2025-11-26 [email protected] [native assets] Bump minimum iOS version from 12 to 13 (flutter/flutter#179079) 2025-11-26 [email protected] Documents and fixes behavior when clipping background filter fragment shader (flutter/flutter#178940) 2025-11-26 [email protected] Replace the hardcoded link with an actual link tag in `PlatformChannel.java` docs (flutter/flutter#178588) 2025-11-26 [email protected] Roll Packages from cc3dca6 to 5d8d954 (5 revisions) (flutter/flutter#179140) 2025-11-26 [email protected] Add more templates that the UIScene migrator can match against (flutter/flutter#179044) 2025-11-26 [email protected] Remove deprecated activeColor in `dynamic_content_color.0.dart` example (flutter/flutter#178961) 2025-11-26 [email protected] Remove deprecated `activeColor` in `decorated_sliver.1.dart` example (flutter/flutter#178959) 2025-11-26 [email protected] Small refactor in `PlayStoreDeferredComponentManager.java` (flutter/flutter#178586) 2025-11-26 [email protected] Roll Dart SDK from 9e605f706cdf to 1d8dc04bd1d7 (4 revisions) (flutter/flutter#179080) 2025-11-26 [email protected] Fix error when generating pt_BR localizations (flutter/flutter#175832) 2025-11-26 [email protected] Roll Fuchsia Test Scripts from JUeFbA8y0E-_pj-bg... to MHF-UAfO6sVKqSEYk... (flutter/flutter#179151) 2025-11-26 [email protected] Add flutter_lints to samples (flutter/flutter#179091) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-packages Please CC [email protected],[email protected] on the revert to ensure that a human is aware of the problem. To file a bug in Packages: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://issues.skia.org/issues/new?component=1389291&template=1850622 Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md
|
Failed to create CP due to merge conflicts. |
To ensure build hooks emit code assets that are compatible with the main app, Flutter tools pass a `CCompilerConfig` toolchain configuration object to hooks. This is generally what we want, hooks on macOS should use the same `clang` from XCode as the one used to compile the app and native Flutter plugins for instance. In some cases however, we need to run hooks without necessarily compiling a full Flutter app with native sources. A good example for this is `flutter test`, which runs unit / widget tests in a regular Dart VM without embedding it in a Flutter application. So since `flutter test` wouldn't invoke a native compiler, running build hooks shouldn't fail if the expected toolchain is missing. Currently however, `flutter test` tries to resolve a compiler toolchain for the host platform. Doing that on Windows already allows not passing a `CCompilerConfig` if VSCode wasn't found, but on macOS and Linux, this crashes. This fixes the issue by allowing those methods to return `null` instead of throwing. They still throw by default, but for the test target they are configured to not pass a toolchain to hooks if none could be resolved. This means that hooks not invoking the provided toolchain (say because they're only downloading native artifacts instead) would now work, whereas previously `flutter test` would crash if no toolchian was found. This closes flutter#178715 (but only the part shared in the original issue description, @dcharkes suggested fixing a similar issue in the same PR but that is _not_ done here).
To ensure build hooks emit code assets that are compatible with the main app, Flutter tools pass a `CCompilerConfig` toolchain configuration object to hooks. This is generally what we want, hooks on macOS should use the same `clang` from XCode as the one used to compile the app and native Flutter plugins for instance. In some cases however, we need to run hooks without necessarily compiling a full Flutter app with native sources. A good example for this is `flutter test`, which runs unit / widget tests in a regular Dart VM without embedding it in a Flutter application. So since `flutter test` wouldn't invoke a native compiler, running build hooks shouldn't fail if the expected toolchain is missing. Currently however, `flutter test` tries to resolve a compiler toolchain for the host platform. Doing that on Windows already allows not passing a `CCompilerConfig` if VSCode wasn't found, but on macOS and Linux, this crashes. This fixes the issue by allowing those methods to return `null` instead of throwing. They still throw by default, but for the test target they are configured to not pass a toolchain to hooks if none could be resolved. This means that hooks not invoking the provided toolchain (say because they're only downloading native artifacts instead) would now work, whereas previously `flutter test` would crash if no toolchian was found. This closes flutter#178715 (but only the part shared in the original issue description, @dcharkes suggested fixing a similar issue in the same PR but that is _not_ done here).
) ### Issue Link: #178954 (beta CP: #179211) ### Impact Description: Running `flutter test` on Linux or MacOS which does not have a `clang` starts failing on projects that target only Android otherwise (and do not require a Linux or MacOS toolchain) when there are build hooks anywhere in the dependencies. This PR changes the behavior for `flutter test` to only pass `clang` and friends if they are installed. This means that _if_ a Linux/MacOS toolchain is installed on the system, it will be used for both `flutter run -d Linux`/`MacOS` and `flutter test` (so that the same native compiler is used), but if it's not installed on the system both `flutter run -d AndroidDevice` and `flutter test` run successfully. This means end users don't have to go modify their systems/CIs to install Linux/MacOS toolchains for Android projects. ### Changelog Description: [flutter/178954] Fixes running `flutter test` on Linux/MacOS for Android projects with build hooks without the desktop native tooling installed. ### Workaround: All end users have to install `clang` and `ldd` on Linux/MacOS hosts and CI bots. ### Risk: What is the risk level of this cherry-pick? It changes the flow in Flutter tools from throwing an error to returning a nullable value. ### Test Coverage: Are you confident that your fix is well-tested by automated tests? ### Validation Steps: On a Linux and MacOS system, make a Flutter app that only targets Android. Add a build hook. And ensure there's no `clang` on the `PATH` (Can be verified by `flutter doctor -v` finding no tooling for Flutter desktop). Run `flutter test` and it shouldn't fail due to `clang` not being installed. For MacOS, XCode needs to not be installed.
To ensure build hooks emit code assets that are compatible with the main app, Flutter tools pass a `CCompilerConfig` toolchain configuration object to hooks. This is generally what we want, hooks on macOS should use the same `clang` from XCode as the one used to compile the app and native Flutter plugins for instance. In some cases however, we need to run hooks without necessarily compiling a full Flutter app with native sources. A good example for this is `flutter test`, which runs unit / widget tests in a regular Dart VM without embedding it in a Flutter application. So since `flutter test` wouldn't invoke a native compiler, running build hooks shouldn't fail if the expected toolchain is missing. Currently however, `flutter test` tries to resolve a compiler toolchain for the host platform. Doing that on Windows already allows not passing a `CCompilerConfig` if VSCode wasn't found, but on macOS and Linux, this crashes. This fixes the issue by allowing those methods to return `null` instead of throwing. They still throw by default, but for the test target they are configured to not pass a toolchain to hooks if none could be resolved. This means that hooks not invoking the provided toolchain (say because they're only downloading native artifacts instead) would now work, whereas previously `flutter test` would crash if no toolchian was found. This closes flutter#178715 (but only the part shared in the original issue description, @dcharkes suggested fixing a similar issue in the same PR but that is _not_ done here).
To ensure build hooks emit code assets that are compatible with the main app, Flutter tools pass a
CCompilerConfigtoolchain configuration object to hooks. This is generally what we want, hooks on macOS should use the sameclangfrom XCode as the one used to compile the app and native Flutter plugins for instance.In some cases however, we need to run hooks without necessarily compiling a full Flutter app with native sources. A good example for this is
flutter test, which runs unit / widget tests in a regular Dart VM without embedding it in a Flutter application. So sinceflutter testwouldn't invoke a native compiler, running build hooks shouldn't fail if the expected toolchain is missing.Currently however,
flutter testtries to resolve a compiler toolchain for the host platform. Doing that on Windows already allows not passing aCCompilerConfigif VSCode wasn't found, but on macOS and Linux, this crashes. This fixes the issue by allowing those methods to returnnullinstead of throwing. They still throw by default, but for the test target they are configured to not pass a toolchain to hooks if none could be resolved. This means that hooks not invoking the provided toolchain (say because they're only downloading native artifacts instead) would now work, whereas previouslyflutter testwould crash if no toolchian was found.This closes #178715 (but only the part shared in the original issue description, @dcharkes suggested fixing a similar issue in the same PR but that is not done here).