diff --git a/configure.json b/configure.json
new file mode 100644
index 0000000000000000000000000000000000000000..cd111df837e33aef048263753c89774f7286b764
--- /dev/null
+++ b/configure.json
@@ -0,0 +1,5 @@
+{
+    "subconfigs": [
+        "src/qdoc"
+    ]
+}
diff --git a/qttools.pro b/qttools.pro
index b87dcea5979072442e5067ed179cba6a10799405..58c33f27cacc16d2f4baed83ef3264e8868eb181 100644
--- a/qttools.pro
+++ b/qttools.pro
@@ -1,2 +1 @@
-load(qt_find_clang)
 load(qt_parts)
diff --git a/src/qdoc/configure.json b/src/qdoc/configure.json
new file mode 100644
index 0000000000000000000000000000000000000000..6b757737c22326752c58cd4b55c9339ad5b1eed8
--- /dev/null
+++ b/src/qdoc/configure.json
@@ -0,0 +1,43 @@
+{
+    "module": "qdoc",
+    "tests": {
+        "libclang": {
+            "label": "libclang",
+            "test": "libclang",
+            "type": "libclang"
+        }
+    },
+    "features": {
+        "qdoc": {
+            "label": "QDoc",
+            "condition": "tests.libclang",
+            "output": [
+                "privateFeature",
+                { "type": "varAssign", "name": "CLANG_LIBS", "value": "tests.libclang.libs" },
+                { "type": "varAssign", "name": "CLANG_INCLUDEPATH", "value": "tests.libclang.includepath" },
+                { "type": "varAssign", "name": "CLANG_LIBDIR", "value": "tests.libclang.libdir" },
+                { "type": "varAssign", "name": "CLANG_DEFINES", "value": "tests.libclang.defines" },
+                { "type": "varAssign", "name": "CLANG_VERSION", "value": "tests.libclang.version" }
+            ]
+        }
+    },
+    "report": [
+        {
+            "type": "warning",
+            "condition": "!features.qdoc",
+            "message": "QDoc will not be compiled, probably because libclang could not be located. This means that you cannot build the Qt documentation.
+
+Either ensure that llvm-config is in your PATH environment variable, or set LLVM_INSTALL_DIR to the location of your llvm installation.
+On Linux systems you may be able to install libclang from a package. On macOS you could use Homebrew's llvm package.
+On Windows you need to set LLVM_INSTALL_DIR to the installation path."
+        }
+    ],
+    "summary": [
+        {
+            "section": "Qt Tools",
+            "entries": [
+                "qdoc"
+            ]
+        }
+    ]
+}
diff --git a/mkspecs/features/qt_find_clang.prf b/src/qdoc/configure.pri
similarity index 94%
rename from mkspecs/features/qt_find_clang.prf
rename to src/qdoc/configure.pri
index 5f97751266cd1374adfbba466250c94d43108f0b..859bd3731e0a0ea480fd2440591b3918a44aec4b 100644
--- a/mkspecs/features/qt_find_clang.prf
+++ b/src/qdoc/configure.pri
@@ -1,5 +1,3 @@
-config_clang_done: return()
-
 defineReplace(extractVersion)      { return($$replace(1, ^(\\d+\\.\\d+\\.\\d+)(svn)?$, \\1)) }
 defineReplace(extractMajorVersion) { return($$replace(1, ^(\\d+)\\.\\d+\\.\\d+(svn)?$, \\1)) }
 defineReplace(extractMinorVersion) { return($$replace(1, ^\\d+\\.(\\d+)\\.\\d+(svn)?$, \\1)) }
@@ -39,10 +37,9 @@ defineReplace(findLLVMVersionFromLibDir) {
     return($$candidateVersion)
 }
 
-isEmpty(QDOC_USE_STATIC_LIBCLANG): QDOC_USE_STATIC_LIBCLANG = $$(QDOC_USE_STATIC_LIBCLANG)
-cache(QDOC_USE_STATIC_LIBCLANG)
+defineTest(qtConfTest_libclang) {
+    isEmpty(QDOC_USE_STATIC_LIBCLANG): QDOC_USE_STATIC_LIBCLANG = $$(QDOC_USE_STATIC_LIBCLANG)
 
-for(_, $$list(_)) { # just a way to break easily
     equals(QMAKE_HOST.os, Windows) {
         # on Windows we have only two host compilers, MSVC or mingw. The former we never
         # use for cross-compilation where it isn't also the target compiler. The latter
@@ -66,8 +63,7 @@ for(_, $$list(_)) { # just a way to break easily
         clangInstallDir = $$replace(LLVM_INSTALL_DIR, _ARCH_, 32)
     isEmpty(LLVM_INSTALL_DIR) {
         win32 {
-            log("Set the LLVM_INSTALL_DIR environment variable to configure clang location (required to build qdoc).$$escape_expand(\\n)")
-            break()
+            return(false)
         }
         macos {
             # Default to homebrew llvm on macOS. The CLANG_VERSION test below will complain if missing.
@@ -92,16 +88,14 @@ for(_, $$list(_)) { # just a way to break easily
     isEmpty(CLANG_VERSION) {
         !isEmpty(LLVM_INSTALL_DIR): \
             error("Cannot determine clang version at $${clangInstallDir}.")
-        log("Set the LLVM_INSTALL_DIR environment variable to configure clang location.$$escape_expand(\\n)")
-        break()
+        return(false)
     }
 
     LIBCLANG_MAIN_HEADER = $$CLANG_INCLUDEPATH/clang-c/Index.h
     !exists($$LIBCLANG_MAIN_HEADER) {
         !isEmpty(LLVM_INSTALL_DIR): \
             error("Cannot find libclang's main header file, candidate: $${LIBCLANG_MAIN_HEADER}.")
-        log("Set the LLVM_INSTALL_DIR environment variable to configure clang location.$$escape_expand(\\n)")
-        break()
+        return(false)
     }
 
     !contains(QMAKE_DEFAULT_LIBDIRS, $$CLANG_LIBDIR): CLANG_LIBS = -L$${CLANG_LIBDIR}
@@ -319,15 +313,31 @@ for(_, $$list(_)) { # just a way to break easily
     !versionIsAtLeast($$CLANG_VERSION, "3.9.0") {
         log("LLVM/Clang version >= 3.9.0 required, version provided: $${CLANG_VERSION}.$$escape_expand(\\n)")
         log("Clang was found in $${clangInstallDir}. Set the LLVM_INSTALL_DIR environment variable to override.$$escape_expand(\\n)")
-        break()
+        return(false)
     }
 
-    cache(CLANG_LIBS)
-    cache(CLANG_INCLUDEPATH)
-    cache(CLANG_LIBDIR)
-    cache(CLANG_DEFINES)
-    cache(CLANG_VERSION)
-    cache(CONFIG, add, $$list(config_clang))
+    $${1}.libs = $$CLANG_LIBS
+    export($${1}.libs)
+    $${1}.cache += libs
+
+    $${1}.includepath = $$CLANG_INCLUDEPATH
+    export($${1}.includepath)
+    $${1}.cache += includepath
+
+    $${1}.libdir = $$CLANG_LIBDIR
+    export($${1}.libdir)
+    $${1}.cache += libdir
+
+    $${1}.defines = $$CLANG_DEFINES
+    export($${1}.defines)
+    $${1}.cache += defines
+
+    $${1}.version = $$CLANG_VERSION
+    export($${1}.version)
+    $${1}.cache += version
+
+    export($${1}.cache)
+
+    return(true)
 }
 
-cache(CONFIG, add, $$list(config_clang_done))
diff --git a/src/qdoc/qdoc.pro b/src/qdoc/qdoc.pro
index bc543c1e83ea992bd7ad96fe0f61a819c2f84354..3c88e26433cfa3470da729235d582394b3d3c3d3 100644
--- a/src/qdoc/qdoc.pro
+++ b/src/qdoc/qdoc.pro
@@ -11,6 +11,8 @@ qtHaveModule(qmldevtools-private) {
     DEFINES += QT_NO_DECLARATIVE
 }
 
+include($$OUT_PWD/qtqdoc-config.pri)
+
 LIBS += $$CLANG_LIBS
 !contains(QMAKE_DEFAULT_INCDIRS, $$CLANG_INCLUDEPATH): INCLUDEPATH += $$CLANG_INCLUDEPATH
 DEFINES += $$CLANG_DEFINES
diff --git a/src/src.pro b/src/src.pro
index 7a1af007805675eafcc480ff04d9a82ccc3127dd..c954cf98a20fd14a103a6e87deb9b8f94c48456d 100644
--- a/src/src.pro
+++ b/src/src.pro
@@ -23,7 +23,9 @@ qtConfig(library) {
     !android|android_app: SUBDIRS += qtplugininfo
 }
 
-config_clang: qtConfig(thread): SUBDIRS += qdoc
+include($$OUT_PWD/qdoc/qtqdoc-config.pri)
+QT_FOR_CONFIG += qdoc-private
+qtConfig(qdoc): qtConfig(thread): SUBDIRS += qdoc
 
 !android|android_app: SUBDIRS += qtpaths