Skip to content

Support the use of CTest launchers#109

Merged
steve-downey merged 2 commits intobemanproject:mainfrom
purpleKarrot:use-launchers
Mar 30, 2025
Merged

Support the use of CTest launchers#109
steve-downey merged 2 commits intobemanproject:mainfrom
purpleKarrot:use-launchers

Conversation

@purpleKarrot
Copy link
Copy Markdown
Contributor

This reverts commit a885d77.

The rationale given in the original commit is not convincing.

It assumes that users may be confused when a target called test is not unconditionally available. There are two problems
with that:

  1. The recommended approach by CMake is to include(CTest), which internally defines an option called BUILD_TESTING and then conditionally invokes enable_testing() based on this option. Hence, the fact that the test target is conditionally available is pretty standard.

  2. The test target is called test for makefile generators only. It has a different name for IDE generators like VS and Xcode. That means cmake --build build --target test is not a portable way to execute the test target anyway.

CMake recommends to include(CTest) in the top-level CMakeLists.txt.
Including this module has the following side effects:

  • It defines an option called BUILD_TESTING.
  • It includes CTestUseLaunchers.
  • It invokes enable_testing() if BUILD_TESTING is ON.
  • It searches for version control systems and dynamic analysis checkers and defines a bunch of build targets for CI.

If those additional build targets are not desired, a project may define its own condition on which it invokes enable_testing().

However, CTestUseLaunchers should always be included. Otherwise, setting CTEST_USE_LAUNCHERS in a CTest script results in the error message:

CMake Error: CTEST_USE_LAUNCHERS is enabled, but the RULE_LAUNCH_COMPILE global property is not defined.
Did you forget to include(CTest) in the toplevel CMakeLists.txt ?

@neatudarius
Copy link
Copy Markdown
Member

@purpleKarrot , thanks for contributions inside the Beman Project!

@bretbrownjr , can you please review this?

@bretbrownjr
Copy link
Copy Markdown
Member

I'm missing something in all of the CMake arcana.

Bottom, line I wouldn't call myself opposed to this change, but it's hard to approve and merge without more documentation and education for Beman contributors. I really like the thought and expertise that went into this PR, though.

So just to reiterate what I think is required of us. I think we should intentionally and cleanly support a test workflow. I don't think conditionally defining test hooks is the best way to do that. It's a lot cleaner to conditionally build tests but to unconditionally provide the hooks. Why? Because there's no standard and widely adopted mechanism or workflow to query a CMake project about whether there are tests or not. So it's best to let the user just run tests and let the xUnit results and CTest output convey the outcome of that action.

As to the justification in a885d77, most users use the default Unix Makefiles generator or one of the Ninja generators, and all of those define a test target. The commit is justifying itself in terms of those popular workflows that are familiar to the typical Beman contributors. And those are the workflows mechanically supported because they are wired up in CI, so I think that's good justification, even if there are other workflows in question. I think editing the commit to be more pedantically encompassing isn't worth it at this point, but maybe we should update the Beman Standard in more detail to document explicitly which CMake and CTest workflows we use and support?

As to enable_testing() versus include(CTest), I'm aware of include(CTest) and the recommendation to use it. I don't object to replacing enable_testing() with that if we all like that better, but I do have a minor quibble about how it clutters up the project's build targets with certain generators (i.e., output from ninja -t targets all includes a lot of often irrelevant targets to support CTest features). I'm not a huge fan of BUILD_TESTING to conflate the building of tests and the act of wiring them up to the test target, but I guess I don't mind using it in the literal sense to disable building of tests. But to reiterate, I'm not convinced we should use it in the more encompassing sense to control existence of test hooks.

As to the proposed commit, I have concerns about using CTestUseLaunchers, mainly because it's an arcane feature that needs to be better explained and documented at a minimum. I think it's fair to say that this isn't typical CMake style or even a pattern espoused in the latest upstream CMake docs or in Professional CMake (though maybe I missed something in there). Normally my bar for unusual or surprising code is to justify it in a comment, but the CTestUseLaunchers docs aren't helpful because they assume the reader knows a lot of specifics about various CTest details and workflows. It's also unclear if any of th described mechanisms and features are important to CMake build-and-test workflows (i.e., what is currently used in CI and docs) and how many are important to CDash or CMake-as-a-scripting-language workflows (which we are not supporting in this project so far). I'm not aware of a published tutorial or explainer of CTestUseLaunchers we could link to otherwise.

For similar reasons (i.e., explaining surprising or important code), I have similar concerns about intentionally moving enable_testing() inside the BEMAN_EXEMPLAR_BUILD_TESTS conditional. If it's incorrect to put that line somewhere else, that fact is not self-evident, so a justification comment of some sort is warranted. Again, it could be with a link for more info -- perhaps to an entry in a newly improved Beman Standard or some other developer documentation.

@steve-downey
Copy link
Copy Markdown
Member

https://github.com/search?q=%22include%28CTestUseLaunchers%29%22&type=code shows 382 hits, many of which are forks of the same video project, or cmake itself or cmake docs.

If it's useful, are we using it?

@bretbrownjr
Copy link
Copy Markdown
Member

@purpleKarrot Just checking in on this. I'm interested in this PR still. It sounds like you might have some ideas worth considering. We're looking for more explanation to proceed with this change.

If it's easier to have a more interactive discussion, we have a Discourse that supports both forum posts and interactive chatting. Feel free to bring this up there.

@camio
Copy link
Copy Markdown
Member

camio commented Mar 14, 2025

@purpleKarrot's rationale makes sense to me. The standard way to run tests in CMake projects is using the ctest executable. My understanding is that this patch will allow the ctest command to operate properly without confusingly marking this project as having testing enabled.

@purpleKarrot purpleKarrot requested a review from a team March 14, 2025 22:26
@camio
Copy link
Copy Markdown
Member

camio commented Mar 28, 2025

Hey @purpleKarrot, this PR was reviewed positively a couple of weeks ago. You should be able to merge it yourself but we can do it on your behalf if you like.

This reverts commit a885d77.

The rationale given in the original commit is not convincing.

It assumes that users may be confused when a target called
`test` is not unconditionally available.  There are problems
with that:

1. The recommended approach by CMake is to `include(CTest)`,
   which internally defines an option called `BUILD_TESTING` and
   then *conditionally* invokes `enable_testing()` based on this
   option.  Hence, the fact that the test target is conditionally
   available is pretty standard.

2. The test target is called `test` for makefile generators only.
   It has a different name for IDE generators like VS and Xcode.
   That means `cmake --build build --target test` is not a
   portable way to execute the test target anyway.

3. Invoking tests with `cmake --build build --target test` is not
   a good recommendation to execute the tests, because there is
   no easy way to use parallelization. A better recommendation is
   `ctest -j $(nproc)`.
CMake recommends to `include(CTest)` in the top-level CMakeLists.txt.
Including this module has the following side effects:

* It defines an option called `BUILD_TESTING`.
* It includes `CTestUseLaunchers`.
* It invokes `enable_testing()` if `BUILD_TESTING` is ON.
* It searches for version control systems and dynamic analysis
  checkers and defines a bunch of build targets for CI.

If those additional build targets are not desired, a project
may define its own condition on which it invokes `enable_testing()`.

However, `CTestUseLaunchers` should always be included.
Otherwise, setting `CTEST_USE_LAUNCHERS` in a CTest script results in
the error message:

```
CMake Error: CTEST_USE_LAUNCHERS is enabled, but the RULE_LAUNCH_COMPILE
global property is not defined.
Did you forget to include(CTest) in the toplevel CMakeLists.txt ?
```
@purpleKarrot
Copy link
Copy Markdown
Contributor Author

Hey @purpleKarrot, this PR was reviewed positively a couple of weeks ago. You should be able to merge it yourself but we can do it on your behalf if you like.

I see options to rebase and close, but no option to merge. Please do it or give me permission.

@steve-downey
Copy link
Copy Markdown
Member

I see options to rebase and close, but no option to merge. Please do it or give me permission.

Permission changes scare me more than merging. While we're sorting out the right bits, I'm hitting the "Merge pull request" button.

@steve-downey steve-downey merged commit e350d94 into bemanproject:main Mar 30, 2025
67 checks passed
@bretbrownjr bretbrownjr mentioned this pull request Apr 21, 2025
1 task
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.

5 participants