-
Notifications
You must be signed in to change notification settings - Fork 757
[cmake] Add support for defining feature flags #4582
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
base: main
Are you sure you want to change the base?
Conversation
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #4582 +/- ##
=======================================
Coverage 87.19% 87.19%
=======================================
Files 249 249
Lines 14276 14276
=======================================
Hits 12446 12446
Misses 1830 1830 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
37bd9b6 to
7e9db1e
Compare
CMakeLists.txt
Outdated
| if(GIT_RELEASE) | ||
| set(NEW_VERSION ${GIT_RELEASE}) | ||
| elseif(GIT_VERSION_MATCH AND MULTIPASS_BUILD_LABEL) | ||
| set(NEW_VERSION ${GIT_TAG}.${CMAKE_MATCH_1}.${MULTIPASS_BUILD_LABEL}+${CMAKE_MATCH_2}) |
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.
And, apply the -noff suffix after the hash.
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.
Should we do this automatically based on the state of MP_ALLOW_OPTIONAL_FEATURES, or maybe just add a new option like MP_VERSION_SUFFIX that we can set in CI? The former is simpler, but wouldn't account for a build with some feature flags enabled and others disabled. (I'm not sure we want that just yet, but it could come in handy if we want to publish Snaps for testing a given feature.)
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 think it should correspond with the state of MP_ALLOW_OPTIONAL_FEATURES so that a generated package is in line with how cmake configured the build. See my other comment for more context.
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.
Good point @jimporter! How about multipass_feature requiring a short suffix when declaring the feature, then append all suffixes? It could become long with multiple features... :/ Maybe just join all enabled feature names and generate a 4 char hash or something?
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.
@sharder996 Ok, I've shuffled things around so that versioning.cmake can automatically set the -noff suffix for us.
@ricab I didn't add this extra bit, since after thinking it over, it's (hopefully) just a theoretical problem for now. While we might do local builds with certain optional features on or off, I don't think we'll be distributing them anywhere.
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.
@ricab Ok, I added a -custom suffix any time the feature flag set doesn't match the defaults. It checks ${FEATURE}_AVAILABLE, and if any feature is available but not enabled, it counts as a custom build. (Note that when disabling MP_ALLOW_OPTIONAL_FEATURES, all the features are marked unavailable, so that doesn't count as "custom".)
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 sounds good, thanks a lot!
To confirm, that means:
- no suffix in a proper release → no feature flags enabled
- no suffix in outside release (dev) → all feature flags enabled
-noffsuffix → no feature flags, outside releasecustomsuffix → any other option.
Is this correct?
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.
@ricab Close: release versions never get a suffix (so technically, you could make a custom release build that doesn't have the custom suffix). There might be some benefit in adding a suffix in non-default cases, but I don't think we'd actually do that (and I'm not 100% sure adding a suffix is the right thing to do in this hypothetical situation anyway).
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.
OK, that makes sense to me too. We retain the ability to tweak a release as we choose, but FF are disabled by default.
Do you think it's worth sticking a corrected version of the topics above in https://github.com/canonical/mp-dev-wiki?
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.
Sure, I can try and update that. It looks like there's still some documentation about the open-source vs "full" variants of Multipass in there, so that's probably the first thing to update.
88dc231 to
8560325
Compare
|
|
||
| macro(feature_flag option doc) | ||
| if(${ARGC} GREATER 2) | ||
| cmake_dependent_option(${option} "${doc}" ON "MP_ALLOW_OPTIONAL_FEATURES;${ARGV2}" OFF) |
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.
Is it possible to make this override cached variables? For example, if I configure a build directory while on a release branch, MP_ALLOW_OPTIONAL_FEATURES=OFF, as expected. However if I reconfigure that build directory with my own development branch, MP_ALLOW_OPTIONAL_FEATURES won't switch on. I have to do it manually with -DMP_ALLOW_OPTIONAL_FEATURES=ON.
8560325 to
9b83115
Compare
sharder996
left a comment
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.
@jimporter Did something change in your most recent rebase? I'm noticing some things that I think were here and are now missing. For example, MP_DISABLE_ALL_FEATURES doesn't seem to exist in the code and:
% cmake -Bbuild -H. -GNinja -DMULTIPASS_ENABLE_FLUTTER_GUI=OFF -DMP_DISABLE_ALL_FEATURES=ON
-- APPLEVZ_ENABLED = ON
-- AVAILABILITY_ZONES_ENABLED = ON
Also, I think the -noff part of the version is missing.
% cmake -Bbuild -H. -GNinja -DMULTIPASS_ENABLE_FLUTTER_GUI=OFF
-- APPLEVZ_ENABLED = ON
-- AVAILABILITY_ZONES_ENABLED = ON
...
-- Setting version to: 1.17.0-dev.1346+g9b831154.mac
-- Setting semantic version to: 1.17.0-dev.1346
-- Setting build number to: 2609058132
And, I still see the case where cached variables aren't being overwritten (as per my previous comment).
From some prior discussions (I think in meetings last year), I changed this variable to be
This should work if you pass
I'm not sure how to fix this part though. I'll do some more digging to see if there's a workaround, but CMake's documentation on this doesn't address this case from what I can see. |
|
Thanks for the reminder 😄 last year's discussions are still a little fuzzy. Regardless, I think the PR description is/was outdated. I think that part looks good. As for cached variables, it would be really nice if we could figure out how to override them. Otherwise, it would make it confusing when you tell cmake to do one thing and it does another. Summoning the cmake guru, @xmkg, to see if maybe he has some ideas. |
9b83115 to
88f4edb
Compare
I have something that I think works for this now. It makes it harder to set this in the CMake GUI, but I'm not sure if we can get that and selectively-cache the value like this version is doing now. |
Ok, I think this is on the right track now. A default build turns on optional features: A subsequent re-configure turns all features off: But, going back to a default build does not turn the feature back on: |
As far as I can tell from the CMake documentation and how I'm not exactly a fan of this behavior and find CMake's cache variables a bit confusing from a user PoV, but this does seem like what the CMake maintainers intend to happen. |
sharder996
left a comment
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.
Ok, at least we tried. Otherwise, I think this looks good and is in a good state to add any of the additional features we talked about in the spec.
So the behavior you've described is exactly how cached variables supposed to behave, but that's not ideal for our use case. AFAICT we want to be able to: a) Determine a default Part a is already addressed, but part b is not. There are two ways to solve this: 1-) At build time:
2-) Use the User-exposed option is a separate CMake variable so we can determine if and when we should invalidate the if(DEFINED MP_ALLOW_OPTIONAL_FEATURES)
# User is explicitly overriding -- use that value.
set(MP_ALLOW_OPTIONAL_FEATURES_INTERNAL "${MP_ALLOW_OPTIONAL_FEATURES}" CACHE INTERNAL
"allow optional features" FORCE)
# The variables passed via -D are automatically cached, so it's up to us to remove
# the transient variable from the cache
unset(MP_ALLOW_OPTIONAL_FEATURES)
unset(MP_ALLOW_OPTIONAL_FEATURES CACHE)
else()
# Unset the previously cached variable as a good measure so we can re-determine its value.
unset(MP_ALLOW_OPTIONAL_FEATURES_INTERNAL CACHE)
# Otherwise, just temporarily set its value based on whether we're on a release branch. This way,
# if we change branches, the value will automatically update.
is_release_branch(GIT_IS_RELEASE_BRANCH)
if(GIT_IS_RELEASE_BRANCH)
set(MP_ALLOW_OPTIONAL_FEATURES_INTERNAL OFF)
else()
message(STATUS "in feature branch")
set(MP_ALLOW_OPTIONAL_FEATURES_INTERNAL ON)
endif()
endif()
macro(feature_flag option doc)
if(${ARGC} GREATER 2)
cmake_dependent_option(${option} "${doc}" ON "MP_ALLOW_OPTIONAL_FEATURES_INTERNAL;${ARGV2}" OFF)
else()
cmake_dependent_option(${option} "${doc}" ON MP_ALLOW_OPTIONAL_FEATURES_INTERNAL OFF)
endif()
endmacro()Passing an argument via @sharder996 with the patch above your initial example becomes: Initial configure: ❯ cmake -S . -B build
-- in feature branch
-- MP_ALLOW_OPTIONAL_FEATURES_INTERNAL = ON
-- APPLEVZ_ENABLED = OFF
-- AVAILABILITY_ZONES_ENABLED = ONUser override: ❯ cmake -S . -B build -DMP_ALLOW_OPTIONAL_FEATURES=OFF
-- MP_ALLOW_OPTIONAL_FEATURES_INTERNAL = OFF
-- APPLEVZ_ENABLED = OFF
-- AVAILABILITY_ZONES_ENABLED = OFFNo-arg reconfigure: ❯ cmake -S . -B build
-- in feature branch
-- MP_ALLOW_OPTIONAL_FEATURES_INTERNAL = ON
-- APPLEVZ_ENABLED = OFF
-- AVAILABILITY_ZONES_ENABLED = ONLet me know if the behavior above is what you had in mind. |
|
@xmkg Typo? Both
|
I'm in Linux so it can't be enabled: feature_flag(APPLEVZ_ENABLED "AppleVZ backend" APPLE)(Note the APPLE prerequisite) |
|
@xmkg Only odd behavior I found with your patch is: |
I can't reproduce it on my end: ❯ cmake -Bbuild -H. -DMP_ALLOW_OPTIONAL_FEATURES=OFF -DAPPLEVZ_ENABLED=ON
-- MP_ALLOW_OPTIONAL_FEATURES (before processing) = OFF
-- MP_ALLOW_OPTIONAL_FEATURES =
-- MP_ALLOW_OPTIONAL_FEATURES_INTERNAL = OFF
-- APPLEVZ_ENABLED = OFF
-- AVAILABILITY_ZONES_ENABLED = OFFYou might need to nuke the build folder if the variable is already cached (from the previous runs with the older behavior). Below is with ON for completeness: ❯ cmake -Bbuild -H. -DMP_ALLOW_OPTIONAL_FEATURES=ON -DAPPLEVZ_ENABLED=ON
-- MP_ALLOW_OPTIONAL_FEATURES (before processing) = ON
-- MP_ALLOW_OPTIONAL_FEATURES =
-- MP_ALLOW_OPTIONAL_FEATURES_INTERNAL = ON
-- APPLEVZ_ENABLED = OFF
-- AVAILABILITY_ZONES_ENABLED = ON |
|
Alright, up to @jimporter and other reviewers what they think. I know its not unheard of to have other weird behavior when re-configuring build directories, so we don't have to get too fancy. |
I mean, it should be consistent in behavior once you've done a clean build with the patch. I recall observing the same and the issue disappeared after configuring it from scratch. If it's flaky, let me know because that's an issue :) |
|
@xmkg I'll use a different flag to remove the platform ambiguity. I guess the surprising part to me is that |
To me, the name sounds like it's a prerequisite for all the optional flags, but I'm not sure if that was the intent. Maybe @jimporter can clarify that part. |
|
@xmkg I agree with your point on semantics. I just don't see an easy way of only enabling one feature flag. |
|
@sharder996 I don't have a strong preference here, so feel free to overrule me, but for caching variables, I like option (1) from @xmkg's comment (using
Right. This is a "disable all" flag, as opposed to setting the default value for feature flags. Since the number of active feature flags will probably be small, and in most cases we probably want to enable/disable all features (or maybe occasionally disable a single feature), I think this covers the practical cases we care about. Having some I don't mind the idea of changing these semantics, though I'm not sure it'll come up in practice to make it worth the extra complexity. In practice, I imagine we'll mostly avoid setting feature flags (including |
|
Ok, so the current scenarios that work are:
The scenario that I thought might be missing was:
Regardless, my approval still stands and I'm fine either way. |
xmkg
left a comment
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, thanks Jim! Also thanks for tidying up the CMake code, it looks much better.
|
Hey @jimporter, I would love an answer on my questions/suggestion above regarding versions. Other than that, you have two approvals so I'd skip review if that is OK with you. |
820fa6b to
7e8cff3
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.
Pull request overview
This PR introduces a CMake-based feature flag system to control optional features in Multipass, with automatic disabling on release branches. The system includes a macro for defining feature flags, logic to detect release branches, and version string modifications to indicate feature status.
Changes:
- Added
feature_flagmacro to define optional features that can be individually toggled or disabled in bulk - Introduced
MP_ALLOW_OPTIONAL_FEATURESoption that automatically disables on release branches - Modified version strings to append
-noffor-customsuffixes to indicate feature configuration (except for release builds)
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| src/cmake/versioning.cmake | New file containing refactored version determination logic with feature flag status in version strings |
| src/cmake/feature-flag.cmake | New file implementing the feature flag macro and custom feature detection |
| src/cmake/environment-utils.cmake | Added is_release_branch function to detect if currently on a release branch |
| feature-flags.cmake | New file defining example feature flags (APPLEVZ_ENABLED, AVAILABILITY_ZONES_ENABLED) |
| CMakeLists.txt | Integrated feature flag system, added status messages, and refactored versioning code into separate module |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
7e8cff3 to
8af9c88
Compare
sharder996
left a comment
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!
Not sure what, if anything has changed since @xmkg's last review, but feel free to hit the merge button if its just a rebase.
@sharder996 This commit is the only new bit: 8af9c88 |
We can use this to determine the default value of `MP_ALLOW_OPTIONAL_FEATURES`.
This ensures that when we don't set MP_ALLOW_OPTIONAL_FEATURES explicitly, our CMake configuration doesn't cache the value, allowing us to automatically update it based on the Git branch state.
8af9c88 to
81d649e
Compare
|
@jimporter I noticed an issue with snap packages. Snapcraft only allow a version length of 32 characters. The extra suffixes are pushing it over that limit. We might have to do something similar to what we do in Windows where the package version is slightly truncated, but the internal version as reported by multipassd is the full version. |
|
@sharder996 Good catch! What do you think about this latest change? I adjusted how we get version info for Snapcraft by making a |
This resolves an issue where our full versions generated in PRs is too long for Snap (which restricts version identifiers to 32 characters)
7692c0a to
3a7c385
Compare
|
Looks good! I like that you were able to combine it with the GUI. One other thing, though 😄 When I define a feature flag, say |
Description
This adds a
feature_flagmacro in CMake that we can use to define feature flags, plus an option (MP_DISABLE_ALL_FEATURES) to disable them all in one go. We can then set this flag in the CI for our release branches (and nightly builds).Related Issue(s)
Testing
Use the demo commit here to try out setting some feature flags, e.g.
cmake .. -DAVAILABILITY_ZONES_ENABLED=OFForcmake .. -DMP_ALLOW_OPTIONAL_FEATURES=OFF.Checklist