diff --git a/Help/envvar/CMAKE_CONFIG_DIR.rst b/Help/envvar/CMAKE_CONFIG_DIR.rst new file mode 100644 index 0000000000..1b5f14f129 --- /dev/null +++ b/Help/envvar/CMAKE_CONFIG_DIR.rst @@ -0,0 +1,18 @@ +CMAKE_CONFIG_DIR +---------------- + +.. versionadded:: 3.31 + +.. include:: ENV_VAR.txt + +Specify a CMake user-wide configuration directory for +:manual:`cmake-file-api(7)` queries. + +If this environment variable is not set, the default user-wide +configuration directory is platform-specific: + +- Windows: ``%LOCALAPPDATA%\CMake`` +- macOS: ``$XDG_CONFIG_HOME/CMake`` if set, otherwise + ``$HOME/Library/Application Support/CMake`` +- Linux/Other: ``$XDG_CONFIG_HOME/cmake`` if set, otherwise + ``$HOME/.config/cmake`` diff --git a/Help/manual/cmake-env-variables.7.rst b/Help/manual/cmake-env-variables.7.rst index 68ee79ae7d..b2ceeae2f7 100644 --- a/Help/manual/cmake-env-variables.7.rst +++ b/Help/manual/cmake-env-variables.7.rst @@ -43,8 +43,9 @@ Environment Variables that Control the Build /envvar/CMAKE_BUILD_PARALLEL_LEVEL /envvar/CMAKE_BUILD_TYPE /envvar/CMAKE_COLOR_DIAGNOSTICS - /envvar/CMAKE_CONFIGURATION_TYPES + /envvar/CMAKE_CONFIG_DIR /envvar/CMAKE_CONFIG_TYPE + /envvar/CMAKE_CONFIGURATION_TYPES /envvar/CMAKE_CROSSCOMPILING_EMULATOR /envvar/CMAKE_EXPORT_COMPILE_COMMANDS /envvar/CMAKE_GENERATOR diff --git a/Help/manual/cmake-file-api.7.rst b/Help/manual/cmake-file-api.7.rst index 260030ea96..a4ce5de831 100644 --- a/Help/manual/cmake-file-api.7.rst +++ b/Help/manual/cmake-file-api.7.rst @@ -50,6 +50,10 @@ It has the following subdirectories: Clients may optionally create the ``reply/`` directory at any time and monitor it for the appearance of a new reply index file. +.. versionadded:: 3.31 + Users can add query files to ``api/v1/query`` inside the + :envvar:`CMAKE_CONFIG_DIR` to create user-wide queries for all CMake projects. + v1 Shared Stateless Query Files ------------------------------- diff --git a/Help/manual/cmake.1.rst b/Help/manual/cmake.1.rst index 794ef960b0..586a72e808 100644 --- a/Help/manual/cmake.1.rst +++ b/Help/manual/cmake.1.rst @@ -266,6 +266,14 @@ Options from the top of a binary tree for a CMake project it will dump additional information such as the cache, log files etc. +.. option:: --print-config-dir + + .. versionadded:: 3.31 + + Print CMake config directory for user-wide FileAPI queries. + + See :envvar:`CMAKE_CONFIG_DIR` for more details. + .. option:: --log-level= .. versionadded:: 3.16 diff --git a/Source/cmFileAPI.cxx b/Source/cmFileAPI.cxx index d4a717586d..1f15612210 100644 --- a/Source/cmFileAPI.cxx +++ b/Source/cmFileAPI.cxx @@ -7,9 +7,13 @@ #include #include #include +#include #include #include +#include +#include + #include "cmsys/Directory.hxx" #include "cmsys/FStream.hxx" @@ -29,7 +33,12 @@ cmFileAPI::cmFileAPI(cmake* cm) : CMakeInstance(cm) { this->APIv1 = - this->CMakeInstance->GetHomeOutputDirectory() + "/.cmake/api/v1"; + cmStrCat(this->CMakeInstance->GetHomeOutputDirectory(), "/.cmake/api/v1"); + + if (cm::optional cmakeConfigDir = + cmSystemTools::GetCMakeConfigDirectory()) { + this->UserAPIv1 = cmStrCat(std::move(*cmakeConfigDir), "/api/v1"_s); + } Json::CharReaderBuilder rbuilder; rbuilder["collectComments"] = false; @@ -47,14 +56,24 @@ cmFileAPI::cmFileAPI(cmake* cm) void cmFileAPI::ReadQueries() { - std::string const query_dir = this->APIv1 + "/query"; + std::string const query_dir = cmStrCat(this->APIv1, "/query"); + std::string const user_query_dir = cmStrCat(this->UserAPIv1, "/query"); this->QueryExists = cmSystemTools::FileIsDirectory(query_dir); + if (!this->UserAPIv1.empty()) { + this->QueryExists = + this->QueryExists || cmSystemTools::FileIsDirectory(user_query_dir); + } if (!this->QueryExists) { return; } // Load queries at the top level. std::vector queries = cmFileAPI::LoadDir(query_dir); + if (!this->UserAPIv1.empty()) { + std::vector user_queries = cmFileAPI::LoadDir(user_query_dir); + std::move(user_queries.begin(), user_queries.end(), + std::back_inserter(queries)); + } // Read the queries and save for later. for (std::string& query : queries) { diff --git a/Source/cmFileAPI.h b/Source/cmFileAPI.h index 1c13d7b6b1..ace19ee98c 100644 --- a/Source/cmFileAPI.h +++ b/Source/cmFileAPI.h @@ -61,6 +61,9 @@ private: /** The api/v1 directory location. */ std::string APIv1; + /** api/v1 directory in the user's shared CMake config directory. */ + std::string UserAPIv1; + /** The set of files we have just written to the reply directory. */ std::unordered_set ReplyFiles; diff --git a/Source/cmakemain.cxx b/Source/cmakemain.cxx index 69b5a1692f..408e5d215e 100644 --- a/Source/cmakemain.cxx +++ b/Source/cmakemain.cxx @@ -71,7 +71,7 @@ const cmDocumentationEntry cmDocumentationUsageNote = { "Run 'cmake --help' for more information." }; -const cmDocumentationEntry cmDocumentationOptions[33] = { +const cmDocumentationEntry cmDocumentationOptions[34] = { { "--preset ,--preset=", "Specify a configure preset." }, { "--list-presets[=]", "List available presets." }, { "--workflow []", "Run a workflow preset." }, @@ -90,6 +90,8 @@ const cmDocumentationEntry cmDocumentationOptions[33] = { "Generate graphviz of dependencies, see CMakeGraphVizOptions.cmake for " "more." }, { "--system-information [file]", "Dump information about this system." }, + { "--print-config-dir", + "Print CMake config directory for user-wide FileAPI queries." }, { "--log-level=", "Set the verbosity of messages from CMake files. " "--loglevel is also accepted for backward compatibility reasons." }, diff --git a/Tests/RunCMake/CMakeLists.txt b/Tests/RunCMake/CMakeLists.txt index 4e0e12c649..3ae7a8126c 100644 --- a/Tests/RunCMake/CMakeLists.txt +++ b/Tests/RunCMake/CMakeLists.txt @@ -408,6 +408,7 @@ if(CMAKE_USE_SYSTEM_JSONCPP) endif() add_RunCMake_test(FileAPI -DPython_EXECUTABLE=${Python_EXECUTABLE} -DCMAKE_CXX_COMPILER_ID=${CMAKE_CXX_COMPILER_ID}) +add_RunCMake_test(ConfigDir) add_RunCMake_test(FindBoost) add_RunCMake_test(FindLua) add_RunCMake_test(FindOpenGL) diff --git a/Tests/RunCMake/ConfigDir/CMakeLists.txt b/Tests/RunCMake/ConfigDir/CMakeLists.txt new file mode 100644 index 0000000000..dda37d8bc5 --- /dev/null +++ b/Tests/RunCMake/ConfigDir/CMakeLists.txt @@ -0,0 +1,3 @@ +cmake_minimum_required(VERSION 3.30) +project(${RunCMake_TEST} NONE) +include(${RunCMake_TEST}.cmake) diff --git a/Tests/RunCMake/ConfigDir/RunCMakeTest.cmake b/Tests/RunCMake/ConfigDir/RunCMakeTest.cmake new file mode 100644 index 0000000000..e5df208901 --- /dev/null +++ b/Tests/RunCMake/ConfigDir/RunCMakeTest.cmake @@ -0,0 +1,6 @@ +include(RunCMake) + +set(ENV{CMAKE_CONFIG_DIR} ${CMAKE_CURRENT_LIST_DIR}/config) +set(RunCMake-check-file check-reply.cmake) +run_cmake(config) +unset(RunCMake-check-file) diff --git a/Tests/RunCMake/ConfigDir/check-reply.cmake b/Tests/RunCMake/ConfigDir/check-reply.cmake new file mode 100644 index 0000000000..6e0ecf9ddf --- /dev/null +++ b/Tests/RunCMake/ConfigDir/check-reply.cmake @@ -0,0 +1,3 @@ +if (NOT EXISTS ${RunCMake_TEST_BINARY_DIR}/.cmake/api/v1/reply) + set(RunCMake_TEST_FAILED "Failed to read FileAPI query from user config directory") +endif() diff --git a/Tests/RunCMake/ConfigDir/config.cmake b/Tests/RunCMake/ConfigDir/config.cmake new file mode 100644 index 0000000000..e69de29bb2 diff --git a/Tests/RunCMake/ConfigDir/config/api/v1/query/codemodel-v2 b/Tests/RunCMake/ConfigDir/config/api/v1/query/codemodel-v2 new file mode 100644 index 0000000000..e69de29bb2