-
Notifications
You must be signed in to change notification settings - Fork 1.7k
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
mtest: fix rebuilding correct target list before running tests #10413
base: master
Are you sure you want to change the base?
Conversation
The first and second commits fix fundamentally very different things, and I'm not actually 100% sure about the first one at all. In @bonzini's original implementation of #7902 it may or may not have been intentional to have a bare |
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #10413 +/- ##
==========================================
- Coverage 68.75% 68.43% -0.33%
==========================================
Files 406 406
Lines 87646 87652 +6
Branches 19486 19488 +2
==========================================
- Hits 60260 59982 -278
- Misses 22848 23080 +232
- Partials 4538 4590 +52 ☔ View full report in Codecov by Sentry. |
Have not gone through the implementation yet, but for the record the conceptual ideas I had were the following:
Basically no matter what the user does, Meson would take care of ensuring that all dependencies are up to date. If said dependencies are set up incorrectly then that is a bug in the build files and the user's responsibility to fix. Similarly using |
Yeah, the question is, what constitutes "all dependencies"?
In theory, per the description above, this only counts when running individual tests. There is no way to run the full testsuite while assuming that dependencies are set up correctly and only rebuilding whatever is necessary for "all the tests". In reality, the referenced PR actually enabled that workflow. Run This PR removes that capability by making |
Just to be sure, here is the same thing said in a different way: If you set up a fresh build dir and run either |
Does that mean that it no longer builds |
Sorry, that was bad wording, tweaked. This PR changes the behavior of Currently |
|
||
runner = find_program('runner.py') | ||
exe1 = executable('main1', 'main.c') | ||
exe2 = executable('main2', 'main.c') |
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.
For completeness one of these two should have build_by_default: false
.
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.
That's not really what I'm testing here, I'm testing that meson test
needs to build "all". I'm not testing what is included in "all".
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.
But it is relevant for this. Rebuilding needs to work even if the end user has tagged a test executable as build_by_default: false
so we should test it.
It was intentional. Not changing the behavior of
I'm not sure why that would be the case. If you want to compile everything and run the tests, that would be a I don't really care what My suggestion is to add |
My suggestion is to remove mcompile.py without a replacement, I'm not fond of any suggestion that involves making it even more confusingly inconsistent and badly designed than the current disaster.
Well, that's a problem. Not because I don't like the idea -- in fact I agree with you and think @jpakkane is completely wrong. But because quite plainly no one understood the change, and it wasn't documented behavior.
This sentence basically feels to me like the underlying attitude is "I managed to pull the wool over your eyes for 18 months before you noticed". I don't think there's anything telling about the fact that it took 18 months for anyone to notice the intended purpose of that change. It also took 18 months to notice the unintended bug that built potentially 5k unwanted translation units for a test that legitimately has no dependencies. All it really says is that no one is using the functionality you added, for better or for worse. What I'd actually like to see as the outcome of this PR, is a discussion about what mtest should really do, and document the conclusion so that people know what behavior to expect. |
I agree it's a problem that The fact that However, I don't see what you mean by "no one understood the change". The issue that you point out (" The reason why it is much better than what you make it sound like, is that —see
And ninja was invoked with arguments, i.e. requesting to only build the test program:
The broken case will happen when you have a test script that takes care of running the executable, and the test script makes assumptions on the path to the executable. Then indeed you would have a test with no dependencies, and that triggers the incorrect build of the default target. But it's a corner case and not the common one.
Sorry if that's how it came across. What I meant is simply that developers are probably not using
That seems quite a jump. Did you miss that dependencies come from more than just |
Again, I actually like the idea of But the actual PR and release notes was described as having that effect for I asked @jpakkane whether that was expected for I discovered this as a side effect of discovering that a test without any dependencies rebuilt the entire project.
My test case explicitly makes use of such dependencies. It tests that a The thing that I think perhaps people aren't actually using, is "bisecting projects other than qemu with something other than What I think is that actually using the full power of the tools is relatively rare, and the relatively few people doing it also tend to spend a lot of time making sure their test definitions are correct, and are unlikely to notice edge cases, so... Saying that nobody complained about the interactions of a uncommon workflow is not really a defense for functionality that apparently the lead developer doesn't like. Any more than it's a defense for the bug you didn't notice because it's uncommon for you to have tests that don't depend on anything. Instead of discussing whether people noticed or should have noticed, why don't we just discuss whether, in a bubble, it's the desired behavior? And then document it, fair and square and out in the open so it's no longer a matter of confusion or disagreement. |
Alright, opinion time. The I posit that this is also why IMO If people want to run something that goes to extra lengths to rebuild everything you might need but forgot to say you need, then that exists, and it's called |
Okay, for that I also can guarantee that people are using it - there are a couple totally unrelated to qemu (or libvirt) even in the pull request itself.
That would be retconning, but it's sensible retconning and I agree with it. So, anyway we agree on both the desired outcome and the way to reach it (commit the second patch and document the rest). Any improvements to |
@eli-schwartz are you going to adjust the PR or perhaps open another one? |
@@ -1666,9 +1666,10 @@ def doit(self) -> int: | |||
raise RuntimeError('Test harness object can only be used once.') | |||
self.is_run = True | |||
tests = self.get_tests() | |||
rebuild_only_tests = tests if self.options.args else [] |
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.
nitpick: I think this line could go after the if not tests: return 0
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.
LGTM. Would be helpful to me if we could get it in the next release.
Inconsistency in the original implementation of commit 79e2c52. If an explicit list of targets is passed on the CLI, then that is passed to rebuild_deps. If not, we pass every loaded test to rebuild_deps instead. This means we cannot distinguish between "trying to run all tests" and "trying to run specific tests". We then load all the deps for all tests, and try to build them all as explicit arguments to the underlying ninja. There are two situations where this falls flat: - given underspecified deps - given all (selected?) tests legitimately happen to have no dependencies In both cases, we calculate that there are no deps to rebuild, we run ninja without any targets, and this invokes the default "all" rule and maybe builds a few thousand targets that this specific test run does not need. Additionally, in large projects which define many tests with many dependencies, we could end up overflowing ARG_MAX when processing *all* tests. Instead, pass no tests to rebuild_deps. We then specially handle this by directly running the relevant ninja target for "all test deps", which is overall more elegant than specifying many many dependencies by name. Given a subset of tests to guarantee the freshness of, we instead skip running ninja at all if there are indeed no test dependencies.
When running `ninja all` we shouldn't build testsuite programs as these might not be wanted e.g. in order to just install the project. We do want them to be built when running `ninja test`. Since meson 0.63 we actually have a dedicated ninja alias for test dependencies -- move these from the "all" rule to the dedicated test/benchmark rules.
45f3478
to
95c2b9c
Compare
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.
I reworded the release notes, but otherwise looks great.
The `ninja test` / `meson test` rules have been reworked to no longer force | ||
tests to be built unnecessarily. The correct, guaranteed workflow for this has | ||
been to either run `ninja test` or `meson test`, both of which rebuild | ||
dependencies on demand. *Also* building test-only binaries as part of | ||
installing the project (`ninja && ninja install`) was unnecessary and has no | ||
use case. | ||
|
||
Some users might have been relying on the "all" target building test | ||
dependencies in combination with `meson test --no-rebuild` in order to skip | ||
calling out to ninja when running tests. The `--no-rebuild` option has always | ||
been intended for expert usage -- you must provide your own guarantees that it | ||
will work -- and it should be noted that this change means test programs are no | ||
longer guaranteed to have been built, depending on whether those test programs | ||
were *also* defined to build by default / marked as installable. The desired | ||
behavior of building test programs in a separate stage can be restored by | ||
building `ninja all meson-test-prereq` (or `meson-benchmark-prereq` for running | ||
benchmarks), as these prereq targets have been available since meson 0.63.0. |
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.
ninja test
behavior did not have substantial changes though, did it? Instead the change was in ninja all
(removing meson-test-prereq meson-benchmark-prereq
) and meson test
(removing the invocation of ninja
with no arguments).
The `ninja test` / `meson test` rules have been reworked to no longer force | |
tests to be built unnecessarily. The correct, guaranteed workflow for this has | |
been to either run `ninja test` or `meson test`, both of which rebuild | |
dependencies on demand. *Also* building test-only binaries as part of | |
installing the project (`ninja && ninja install`) was unnecessary and has no | |
use case. | |
Some users might have been relying on the "all" target building test | |
dependencies in combination with `meson test --no-rebuild` in order to skip | |
calling out to ninja when running tests. The `--no-rebuild` option has always | |
been intended for expert usage -- you must provide your own guarantees that it | |
will work -- and it should be noted that this change means test programs are no | |
longer guaranteed to have been built, depending on whether those test programs | |
were *also* defined to build by default / marked as installable. The desired | |
behavior of building test programs in a separate stage can be restored by | |
building `ninja all meson-test-prereq` (or `meson-benchmark-prereq` for running | |
benchmarks), as these prereq targets have been available since meson 0.63.0. | |
`meson test` and the `ninja all` rule have been reworked to no longer force | |
unnecessary rebuilds. | |
`meson test` was invoking `ninja all` due to a bug if the chosen set of tests | |
had no build dependencies. The behavior is now the same as when tests do | |
have build dependencies, i.e. to only build the actual set of targets that are | |
used by the test. This change could cause failures when upgrading to Meson | |
1.7.0, if the dependencies are not specified correctly in meson.build. | |
`ninja all` does not rebuild all tests anymore; it should be noted that this | |
change means test programs are no longer guaranteed to have been | |
built, depending on whether those test programs were *also* defined | |
to build by default / marked as installable. This avoids building test-only | |
binaries as part of installing the project (`ninja && ninja install`), which | |
is unnecessary and has no use case. Some users might have been | |
relying on the "all" target building test dependencies in combination | |
with `meson test --no-rebuild` in order to skip calling out to ninja when | |
running tests. The correct, guaranteed workflow for this has always been | |
to run either `ninja test` or `ninja && meson test`, both of which rebuild | |
dependencies on demand. | |
If you wish to build test programs and dependencies in a separate stage, | |
you can restore this behavior with `ninja all meson-test-prereq` (or | |
`meson-benchmark-prereq` for benchmarks), as these prereq targets | |
have been available since meson 0.63.0. |
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.
Thanks for looking at the wording. I have one critique in particular:
Some users might have been
relying on the "all" target building test dependencies in combination
with `meson test --no-rebuild` in order to skip calling out to ninja when
running tests. The correct, guaranteed workflow for this has always been
to run either `ninja test` or `ninja && meson test`, both of which rebuild
dependencies on demand.
In my version, the use of --no-rebuild was defined as "expert usage" in order to lead into the discussion about meson-test-prereq.
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.
Yeah, I removed it because my version was already longer and the "expert usage" part didn't really add much. However, the part where there is no guarantee that test dependencies are present is worthwhile. A rephrase could be to break the paragraph before "Some users" and segue into this:
Some users might have been relying on the "all" target building test
dependencies in combination with `meson test --no-rebuild` in order to
skip calling out to ninja when running tests. This might break with this
change because, when given `--no-rebuild`, Meson provides no guarantee
that test dependencies are present and up to date. The recommended
workflow is to use either `ninja test` or `ninja && meson test` but, if you
wish to build test programs and dependencies in a separate stage, you can
use for example `ninja all meson-test-prereq meson-benchmark-prereq`
before `meson test --no-rebuild`. These prereq targets have been available
since meson 0.63.0.
Regression in the original implementation of commit 79e2c52.
If an explicit list of targets is passed on the CLI, then that is passed to rebuild_deps. If not, we pass every loaded test to rebuild_deps instead. This means we cannot distinguish between "trying to run all tests" and "trying to run specific tests". We then load all the deps for all tests, and try to build them all as explicit arguments to the underlying ninja.
This is usually papered over by people running
ninja test
, which depends on "all" anyway as a prerequisite for invoking the underlyingmeson test --no-rebuild --print-errorlogs
, however, instead runningmeson setup builddir && meson test -C builddir
with under-specified test deps would actually build a handful of deps and not anything else, then fail.The reverse problem occurs when manually specifying a target on the CLI, which does not have any test deps. Since we calculated that there are no deps to rebuild, we run ninja without any targets, and this invokes the default "all" rule and maybe builds a few thousand targets that this specific test does not need.