diff --git a/tools/cmake/common/__init__.py b/tools/cmake/common/__init__.py index ed02b39e44d..01b6243897f 100644 --- a/tools/cmake/common/__init__.py +++ b/tools/cmake/common/__init__.py @@ -121,7 +121,8 @@ def run_cmake( self.assertNotEqual(result.returncode, 0) actual_error = result.stderr.decode("utf-8") self.assertTrue( - error_contains in actual_error, f"Actual error: {actual_error}" + error_contains in actual_error, + f"\n\nWanted: {error_contains}\n\nActual: {actual_error}", ) else: self.assertEqual(result.returncode, 0) diff --git a/tools/cmake/common/preset.cmake b/tools/cmake/common/preset.cmake index e36539d5eab..0d453c4b1ba 100644 --- a/tools/cmake/common/preset.cmake +++ b/tools/cmake/common/preset.cmake @@ -104,3 +104,23 @@ macro(load_build_preset) # For now, just continue if the preset file is not set. In the future, we will # try to determine a preset file. endmacro() + + +# Check if the required options are set. +function(check_required_options_on) + cmake_parse_arguments( + ARG + "" + "IF_ON" + "REQUIRES" + ${ARGN} + ) + + if(${${ARG_IF_ON}}) + foreach(required ${ARG_REQUIRES}) + if(NOT ${${required}}) + message(FATAL_ERROR "Use of '${ARG_IF_ON}' requires '${required}'") + endif() + endforeach() + endif() +endfunction() diff --git a/tools/cmake/common/preset_test.py b/tools/cmake/common/preset_test.py index d56cc3bb04a..87ccc74db7b 100644 --- a/tools/cmake/common/preset_test.py +++ b/tools/cmake/common/preset_test.py @@ -319,3 +319,100 @@ def test_set_overridable_option_with_cli_override(self): ) self.run_cmake(cmake_args=["-DEXECUTORCH_TEST_MESSAGE='from the cli'"]) self.assert_cmake_cache("EXECUTORCH_TEST_MESSAGE", "from the cli", "STRING") + + def test_check_required_options_on_if_on_off(self): + """Test that when IF_ON is OFF, no checks are performed.""" + + _cmake_lists_txt = """ + cmake_minimum_required(VERSION 3.24) + project(test_preset) + include(${PROJECT_SOURCE_DIR}/preset.cmake) + + set(FEATURE_FLAG OFF) + set(REQUIRED_OPTION1 OFF) + set(REQUIRED_OPTION2 OFF) + + check_required_options_on( + IF_ON + FEATURE_FLAG + REQUIRES + REQUIRED_OPTION1 + REQUIRED_OPTION2 + ) + """ + self.create_workspace({"CMakeLists.txt": _cmake_lists_txt}) + self.run_cmake() # Should succeed + + def test_check_required_options_on_all_required_on(self): + """Test that when IF_ON is ON and all required options are ON, no error occurs.""" + + _cmake_lists_txt = """ + cmake_minimum_required(VERSION 3.24) + project(test_preset) + include(${PROJECT_SOURCE_DIR}/preset.cmake) + + set(FEATURE_FLAG ON) + set(REQUIRED_OPTION1 ON) + set(REQUIRED_OPTION2 ON) + + check_required_options_on( + IF_ON + FEATURE_FLAG + REQUIRES + REQUIRED_OPTION1 + REQUIRED_OPTION2 + ) + """ + self.create_workspace({"CMakeLists.txt": _cmake_lists_txt}) + self.run_cmake() + + def test_check_required_options_on_one_required_off(self): + """Test that when IF_ON is ON but one required option is OFF, a fatal error occurs.""" + + _cmake_lists_txt = """ + cmake_minimum_required(VERSION 3.24) + project(test_preset) + include(${PROJECT_SOURCE_DIR}/preset.cmake) + + set(FEATURE_FLAG ON) + set(REQUIRED_OPTION1 ON) + set(REQUIRED_OPTION2 OFF) + + check_required_options_on( + IF_ON + FEATURE_FLAG + REQUIRES + REQUIRED_OPTION1 + REQUIRED_OPTION2 + ) + """ + self.create_workspace({"CMakeLists.txt": _cmake_lists_txt}) + self.run_cmake( + error_contains="Use of 'FEATURE_FLAG' requires 'REQUIRED_OPTION2'" + ) + + def test_check_required_options_on_multiple_required_off(self): + """Test that when IF_ON is ON but multiple required options are OFF, a fatal error occurs for the first one.""" + + _cmake_lists_txt = """ + cmake_minimum_required(VERSION 3.24) + project(test_preset) + include(${PROJECT_SOURCE_DIR}/preset.cmake) + + set(FEATURE_FLAG ON) + set(REQUIRED_OPTION1 OFF) + set(REQUIRED_OPTION2 OFF) + + # This should cause a fatal error + check_required_options_on( + IF_ON + FEATURE_FLAG + REQUIRES + REQUIRED_OPTION1 + REQUIRED_OPTION2 + ) + """ + self.create_workspace({"CMakeLists.txt": _cmake_lists_txt}) + self.run_cmake( + error_contains="Use of 'FEATURE_FLAG' requires 'REQUIRED_OPTION1'" + )