`cmake_policy` get overwritten by `cmake_minimum_required()`

I have the usecase that I want to include a subproject, and set some variables for options of that subproject. With policy 0077 set to new, I can do that. However I am experiencing some problems, that somehow setting the policy gets overwritten by the cmake_minimum_required of the subpreject.
I narrowed it to a minimal example:

CMakeLists.txt

cmake_minimum_required(VERSION 3.15)

project(base)

cmake_policy(SET CMP0077 NEW)
cmake_policy(GET CMP0077 _POLICY_0077)
message(STATUS "POLICY is ${_POLICY_0077}")

set(MY_OPTION OFF)

add_subdirectory(project)

project/CMakeLists.txt

cmake_minimum_required(VERSION 3.5)

project(my_proj)

cmake_policy(GET CMP0077 _POLICY_0077)
message(STATUS "POLICY is ${_POLICY_0077}")

option(MY_OPTION ON)
message(STATUS "MY_OPTION ${MY_OPTION}")

Running CMake prints:

-- POLICY is NEW
-- POLICY is
CMake Warning (dev) at project/CMakeLists.txt:8 (option):
  Policy CMP0077 is not set: option() honors normal variables.  Run "cmake
  --help-policy CMP0077" for policy details.  Use the cmake_policy command to
  set the policy and suppress this warning.

  For compatibility with older versions of CMake, option is clearing the
  normal variable 'MY_OPTION'.
This warning is for project developers.  Use -Wno-dev to suppress it.
-- MY_OPTION OFF

I would expect that setting the policy in the top level CMake file would persist over all files included with add_subdirectory().
Thus I would expect that CMake should twice print POLICY is NEW, and not only once.
Obviously, I cannot change the project/CMakeLists.txt when including e.g. a thirdparty library or such.

And the weirdest thing is, that apparently, it does actually honor the variable, since the output prints “OFF”.
Any thougths?

Yes, the docs mention that:

The cmake_minimum_required(VERSION) command implicitly invokes the cmake_policy(VERSION) command to specify that the current project code is written for the given range of CMake versions.

so it can “unset” policies that you have set to NEW within its policy scope (which doesn’t necessarily match directory or function scope).

Ok, so then what exactly is the policy_scope?

And one thing especially strikes me: while the warning suggests that the option is honored (which would result in MY_OPTION ON), the CMake output MY_OPTION OFF suggests that the variable is honored instead.

So what now? Why is there a warning if it doesn’t behave according to the warning, or am I getting things wrong here?

Honestly, I can’t say that I really understand it either. I know that cmake_policy(PUSH) and cmake_policy(POP). They’re also “sticky” to function/macro definitions rather than inheriting. Generally, I avoid calling cmake_minimum_required more than once in a project if at all possible, but when importing third party code, it gets patched (for various reasons) anyways, so it’s “just another thing to do” there.

Cache behavior on first vs. second configure is very odd. I suspect that’s where the behavior actually gets confusing. See this issue for discussion on (finally) changing this behavior.

Thanks for clarifying. Any idea what to do when i can’t patch the subproject? Probably the old “overwrite with a macro” trick?

macro(cmake_minimum_required)
endmacro()

Though I do hate that approach (and obiously, only re/un-define after the first call). We ofthen do that “trick” with redefining the find_package command, to opt in / out on submole builds.

However, my usecase is a bit special here, as I will be generating the top level CMake file.
Maybe I can get around this by instead using the new CMakePresets.json file. Then I won’t need to set variables to override options, but instead pass options through the CMakePresets.json file.

Depending on your CMake version this might help:
https://cmake.org/cmake/help/latest/variable/CMAKE_PROJECT_PROJECT-NAME_INCLUDE_BEFORE.html