From 1168879d6d5b79b15e18dce03a37912c00abf62d Mon Sep 17 00:00:00 2001
From: outfoxxed <outfoxxed@outfoxxed.me>
Date: Mon, 4 Nov 2024 14:13:37 -0800
Subject: [PATCH] build: only install necessary qml module files

---
 CMakeLists.txt                                | 20 +----
 cmake/install-qml-module.cmake                | 89 +++++++++++++++++++
 src/core/CMakeLists.txt                       |  2 +
 src/dbus/dbusmenu/CMakeLists.txt              |  2 +
 src/io/CMakeLists.txt                         |  2 +
 src/services/greetd/CMakeLists.txt            |  2 +
 src/services/mpris/CMakeLists.txt             |  2 +
 src/services/notifications/CMakeLists.txt     |  2 +
 src/services/pam/CMakeLists.txt               |  2 +
 src/services/pipewire/CMakeLists.txt          |  2 +
 src/services/status_notifier/CMakeLists.txt   |  2 +
 src/services/upower/CMakeLists.txt            |  2 +
 src/wayland/CMakeLists.txt                    |  2 +
 src/wayland/hyprland/CMakeLists.txt           |  2 +
 .../hyprland/focus_grab/CMakeLists.txt        |  2 +
 .../hyprland/global_shortcuts/CMakeLists.txt  |  2 +
 src/wayland/hyprland/ipc/CMakeLists.txt       |  2 +
 .../toplevel_management/CMakeLists.txt        |  2 +
 src/wayland/wlr_layershell/CMakeLists.txt     |  2 +
 src/widgets/CMakeLists.txt                    |  2 +
 src/window/CMakeLists.txt                     |  2 +
 src/x11/CMakeLists.txt                        |  2 +
 22 files changed, 130 insertions(+), 19 deletions(-)
 create mode 100644 cmake/install-qml-module.cmake

diff --git a/CMakeLists.txt b/CMakeLists.txt
index e142ae57..4014cce2 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -64,8 +64,7 @@ boption(SERVICE_GREETD "Greetd" ON)
 boption(SERVICE_UPOWER "UPower" ON)
 boption(SERVICE_NOTIFICATIONS "Notifications" ON)
 
-set(INSTALL_QMLDIR "" CACHE STRING "QML install dir")
-set(INSTALL_QML_PREFIX "" CACHE STRING "QML install prefix")
+include(cmake/install-qml-module.cmake)
 
 add_compile_options(-Wall -Wextra)
 
@@ -157,23 +156,6 @@ if (USE_JEMALLOC)
 	target_link_libraries(quickshell PRIVATE ${JEMALLOC_LIBRARIES})
 endif()
 
-if ("${INSTALL_QMLDIR}" STREQUAL "" AND "${INSTALL_QML_PREFIX}" STREQUAL "")
-	message(WARNING "Neither INSTALL_QMLDIR nor INSTALL_QML_PREFIX is set. QML modules will not be installed.")
-else()
-	if ("${INSTALL_QMLDIR}" STREQUAL "")
-		set(INSTALLDIR "${CMAKE_INSTALL_PREFIX}/${INSTALL_QML_PREFIX}")
-	else()
-		set(INSTALLDIR "${INSTALL_QMLDIR}")
-	endif()
-
-	message(STATUS "QML install dir: ${INSTALLDIR}")
-	install(
-		DIRECTORY ${CMAKE_BINARY_DIR}/qml_modules/
-		DESTINATION ${INSTALLDIR}
-		FILES_MATCHING PATTERN "*"
-	)
-endif()
-
 install(CODE "
 	execute_process(
 		COMMAND ${CMAKE_COMMAND} -E create_symlink \
diff --git a/cmake/install-qml-module.cmake b/cmake/install-qml-module.cmake
new file mode 100644
index 00000000..5c95531c
--- /dev/null
+++ b/cmake/install-qml-module.cmake
@@ -0,0 +1,89 @@
+set(INSTALL_QMLDIR "" CACHE STRING "QML install dir")
+set(INSTALL_QML_PREFIX "" CACHE STRING "QML install prefix")
+
+# There doesn't seem to be a standard cross-distro qml install path.
+if ("${INSTALL_QMLDIR}" STREQUAL "" AND "${INSTALL_QML_PREFIX}" STREQUAL "")
+	message(WARNING "Neither INSTALL_QMLDIR nor INSTALL_QML_PREFIX is set. QML modules will not be installed.")
+else()
+	if ("${INSTALL_QMLDIR}" STREQUAL "")
+		set(QML_FULL_INSTALLDIR "${CMAKE_INSTALL_PREFIX}/${INSTALL_QML_PREFIX}")
+	else()
+		set(QML_FULL_INSTALLDIR "${INSTALL_QMLDIR}")
+	endif()
+
+	message(STATUS "QML install dir: ${QML_FULL_INSTALLDIR}")
+endif()
+
+# Install a given target as a QML module. This is mostly pulled from ECM, as there does not seem
+# to be an official way to do it.
+# see https://github.com/KDE/extra-cmake-modules/blob/fe0f606bf7f222e36f7560fd7a2c33ef993e23bb/modules/ECMQmlModule6.cmake#L160
+function(install_qml_module arg_TARGET)
+	if (NOT DEFINED QML_FULL_INSTALLDIR)
+		return()
+	endif()
+
+	qt_query_qml_module(${arg_TARGET}
+		URI module_uri
+		VERSION module_version
+		PLUGIN_TARGET module_plugin_target
+		TARGET_PATH module_target_path
+		QMLDIR module_qmldir
+		TYPEINFO module_typeinfo
+		QML_FILES module_qml_files
+		RESOURCES module_resources
+	)
+
+  set(module_dir "${QML_FULL_INSTALLDIR}/${module_target_path}")
+
+  if (NOT TARGET "${module_plugin_target}")
+    message(FATAL_ERROR "install_qml_modules called for a target without a plugin")
+  endif()
+
+	get_target_property(target_type "${arg_TARGET}" TYPE)
+	if (NOT "${target_type}" STREQUAL "STATIC_LIBRARY")
+		install(
+			TARGETS "${arg_TARGET}"
+			LIBRARY DESTINATION "${module_dir}"
+			RUNTIME DESTINATION "${module_dir}"
+		)
+
+		install(
+			TARGETS "${module_plugin_target}"
+			LIBRARY DESTINATION "${module_dir}"
+			RUNTIME DESTINATION "${module_dir}"
+		)
+	endif()
+
+  install(FILES "${module_qmldir}" DESTINATION "${module_dir}")
+  install(FILES "${module_typeinfo}" DESTINATION "${module_dir}")
+
+  # Install QML files
+  list(LENGTH module_qml_files num_files)
+  if (NOT "${module_qml_files}" MATCHES "NOTFOUND" AND ${num_files} GREATER 0)
+    qt_query_qml_module(${arg_TARGET} QML_FILES_DEPLOY_PATHS qml_files_deploy_paths)
+
+    math(EXPR last_index "${num_files} - 1")
+    foreach(i RANGE 0 ${last_index})
+      list(GET module_qml_files       ${i} src_file)
+      list(GET qml_files_deploy_paths ${i} deploy_path)
+      get_filename_component(dst_name "${deploy_path}" NAME)
+      get_filename_component(dest_dir "${deploy_path}" DIRECTORY)
+      install(FILES "${src_file}" DESTINATION "${module_dir}/${dest_dir}" RENAME "${dst_name}")
+    endforeach()
+  endif()
+
+  # Install resources
+  list(LENGTH module_resources num_files)
+  if (NOT "${module_resources}" MATCHES "NOTFOUND" AND ${num_files} GREATER 0)
+    qt_query_qml_module(${arg_TARGET} RESOURCES_DEPLOY_PATHS resources_deploy_paths)
+
+    math(EXPR last_index "${num_files} - 1")
+    foreach(i RANGE 0 ${last_index})
+      list(GET module_resources       ${i} src_file)
+      list(GET resources_deploy_paths ${i} deploy_path)
+      get_filename_component(dst_name "${deploy_path}" NAME)
+      get_filename_component(dest_dir "${deploy_path}" DIRECTORY)
+      install(FILES "${src_file}" DESTINATION "${module_dir}/${dest_dir}" RENAME "${dst_name}")
+    endforeach()
+  endif()
+endfunction()
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 8d50f1f5..62f29425 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -49,6 +49,8 @@ qt_add_qml_module(quickshell-core
 	DEFAULT_IMPORTS Quickshell._Window
 )
 
+install_qml_module(quickshell-core)
+
 target_link_libraries(quickshell-core PRIVATE ${QT_DEPS} CLI11::CLI11)
 
 qs_pch(quickshell-core)
diff --git a/src/dbus/dbusmenu/CMakeLists.txt b/src/dbus/dbusmenu/CMakeLists.txt
index 9e4885a8..f9e4446c 100644
--- a/src/dbus/dbusmenu/CMakeLists.txt
+++ b/src/dbus/dbusmenu/CMakeLists.txt
@@ -20,6 +20,8 @@ qt_add_qml_module(quickshell-dbusmenu
 	DEPENDENCIES QtQml Quickshell
 )
 
+install_qml_module(quickshell-dbusmenu)
+
 # dbus headers
 target_include_directories(quickshell-dbusmenu PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
 
diff --git a/src/io/CMakeLists.txt b/src/io/CMakeLists.txt
index 54cfac00..1d936d17 100644
--- a/src/io/CMakeLists.txt
+++ b/src/io/CMakeLists.txt
@@ -21,6 +21,8 @@ qt_add_qml_module(quickshell-io
 		FileView.qml
 )
 
+install_qml_module(quickshell-io)
+
 target_link_libraries(quickshell-io PRIVATE ${QT_DEPS})
 target_link_libraries(quickshell-io-init PRIVATE ${QT_DEPS})
 
diff --git a/src/services/greetd/CMakeLists.txt b/src/services/greetd/CMakeLists.txt
index 349d28ce..870f8085 100644
--- a/src/services/greetd/CMakeLists.txt
+++ b/src/services/greetd/CMakeLists.txt
@@ -9,6 +9,8 @@ qt_add_qml_module(quickshell-service-greetd
 	DEPENDENCIES QtQml
 )
 
+install_qml_module(quickshell-service-greetd)
+
 target_link_libraries(quickshell-service-greetd PRIVATE ${QT_DEPS})
 
 qs_pch(quickshell-service-greetd)
diff --git a/src/services/mpris/CMakeLists.txt b/src/services/mpris/CMakeLists.txt
index f87edecc..505df7a6 100644
--- a/src/services/mpris/CMakeLists.txt
+++ b/src/services/mpris/CMakeLists.txt
@@ -33,6 +33,8 @@ qt_add_qml_module(quickshell-service-mpris
 	DEPENDENCIES QtQml Quickshell
 )
 
+install_qml_module(quickshell-service-mpris)
+
 target_link_libraries(quickshell-service-mpris PRIVATE ${QT_DEPS} quickshell-dbus)
 target_link_libraries(quickshell PRIVATE quickshell-service-mprisplugin)
 
diff --git a/src/services/notifications/CMakeLists.txt b/src/services/notifications/CMakeLists.txt
index 23f4d692..4ba8d3cc 100644
--- a/src/services/notifications/CMakeLists.txt
+++ b/src/services/notifications/CMakeLists.txt
@@ -23,6 +23,8 @@ qt_add_qml_module(quickshell-service-notifications
 	DEPENDENCIES QtQml Quickshell
 )
 
+install_qml_module(quickshell-service-notifications)
+
 target_link_libraries(quickshell-service-notifications PRIVATE ${QT_DEPS} quickshell-dbus)
 target_link_libraries(quickshell PRIVATE quickshell-service-notificationsplugin)
 
diff --git a/src/services/pam/CMakeLists.txt b/src/services/pam/CMakeLists.txt
index a55da739..f9d017e7 100644
--- a/src/services/pam/CMakeLists.txt
+++ b/src/services/pam/CMakeLists.txt
@@ -11,6 +11,8 @@ qt_add_qml_module(quickshell-service-pam
 	DEPENDENCIES QtQml
 )
 
+install_qml_module(quickshell-service-pam)
+
 target_link_libraries(quickshell-service-pam PRIVATE ${QT_DEPS} pam ${PAM_LIBRARIES})
 
 qs_pch(quickshell-service-pam)
diff --git a/src/services/pipewire/CMakeLists.txt b/src/services/pipewire/CMakeLists.txt
index 8c33e644..bb74a078 100644
--- a/src/services/pipewire/CMakeLists.txt
+++ b/src/services/pipewire/CMakeLists.txt
@@ -19,6 +19,8 @@ qt_add_qml_module(quickshell-service-pipewire
 	DEPENDENCIES QtQml Quickshell
 )
 
+install_qml_module(quickshell-service-pipewire)
+
 target_link_libraries(quickshell-service-pipewire PRIVATE ${QT_DEPS} PkgConfig::pipewire)
 
 qs_pch(quickshell-service-pipewire)
diff --git a/src/services/status_notifier/CMakeLists.txt b/src/services/status_notifier/CMakeLists.txt
index bc8918d0..20de11a1 100644
--- a/src/services/status_notifier/CMakeLists.txt
+++ b/src/services/status_notifier/CMakeLists.txt
@@ -44,6 +44,8 @@ qt_add_qml_module(quickshell-service-statusnotifier
 	DEPENDENCIES QtQml Quickshell Quickshell.DBusMenu
 )
 
+install_qml_module(quickshell-service-statusnotifier)
+
 target_link_libraries(quickshell-service-statusnotifier PRIVATE ${QT_DEPS} quickshell-dbus quickshell-dbusmenuplugin)
 target_link_libraries(quickshell PRIVATE quickshell-service-statusnotifierplugin)
 
diff --git a/src/services/upower/CMakeLists.txt b/src/services/upower/CMakeLists.txt
index e600f8c7..e913a550 100644
--- a/src/services/upower/CMakeLists.txt
+++ b/src/services/upower/CMakeLists.txt
@@ -33,6 +33,8 @@ qt_add_qml_module(quickshell-service-upower
 	DEPENDENCIES QtQml Quickshell
 )
 
+install_qml_module(quickshell-service-upower)
+
 target_link_libraries(quickshell-service-upower PRIVATE ${QT_DEPS} quickshell-dbus)
 target_link_libraries(quickshell PRIVATE quickshell-service-upowerplugin)
 
diff --git a/src/wayland/CMakeLists.txt b/src/wayland/CMakeLists.txt
index ccb31b07..19e74b90 100644
--- a/src/wayland/CMakeLists.txt
+++ b/src/wayland/CMakeLists.txt
@@ -110,6 +110,8 @@ qt_add_qml_module(quickshell-wayland
 	IMPORTS ${WAYLAND_MODULES}
 )
 
+install_qml_module(quickshell-wayland)
+
 qs_pch(quickshell-wayland)
 qs_pch(quickshell-waylandplugin)
 qs_pch(quickshell-wayland-init)
diff --git a/src/wayland/hyprland/CMakeLists.txt b/src/wayland/hyprland/CMakeLists.txt
index be2f0c59..59458fe6 100644
--- a/src/wayland/hyprland/CMakeLists.txt
+++ b/src/wayland/hyprland/CMakeLists.txt
@@ -25,6 +25,8 @@ qt_add_qml_module(quickshell-hyprland
 	IMPORTS ${HYPRLAND_MODULES}
 )
 
+install_qml_module(quickshell-hyprland)
+
 qs_pch(quickshell-hyprland)
 qs_pch(quickshell-hyprlandplugin)
 
diff --git a/src/wayland/hyprland/focus_grab/CMakeLists.txt b/src/wayland/hyprland/focus_grab/CMakeLists.txt
index a17436ef..0fd1f85e 100644
--- a/src/wayland/hyprland/focus_grab/CMakeLists.txt
+++ b/src/wayland/hyprland/focus_grab/CMakeLists.txt
@@ -10,6 +10,8 @@ qt_add_qml_module(quickshell-hyprland-focus-grab
 	DEPENDENCIES QtQml Quickshell
 )
 
+install_qml_module(quickshell-hyprland-focus-grab)
+
 wl_proto(quickshell-hyprland-focus-grab
 	hyprland-focus-grab-v1
 	"${CMAKE_CURRENT_SOURCE_DIR}/hyprland-focus-grab-v1.xml"
diff --git a/src/wayland/hyprland/global_shortcuts/CMakeLists.txt b/src/wayland/hyprland/global_shortcuts/CMakeLists.txt
index cebaa652..d2314177 100644
--- a/src/wayland/hyprland/global_shortcuts/CMakeLists.txt
+++ b/src/wayland/hyprland/global_shortcuts/CMakeLists.txt
@@ -10,6 +10,8 @@ qt_add_qml_module(quickshell-hyprland-global-shortcuts
 	DEPENDENCIES QtQml
 )
 
+install_qml_module(quickshell-hyprland-global-shortcuts)
+
 wl_proto(quickshell-hyprland-global-shortcuts
 	hyprland-global-shortcuts-v1
 	"${CMAKE_CURRENT_SOURCE_DIR}/hyprland-global-shortcuts-v1.xml"
diff --git a/src/wayland/hyprland/ipc/CMakeLists.txt b/src/wayland/hyprland/ipc/CMakeLists.txt
index c2e32888..367fa8f4 100644
--- a/src/wayland/hyprland/ipc/CMakeLists.txt
+++ b/src/wayland/hyprland/ipc/CMakeLists.txt
@@ -11,6 +11,8 @@ qt_add_qml_module(quickshell-hyprland-ipc
 	DEPENDENCIES QtQml Quickshell
 )
 
+install_qml_module(quickshell-hyprland-ipc)
+
 target_link_libraries(quickshell-hyprland-ipc PRIVATE ${QT_DEPS})
 
 qs_pch(quickshell-hyprland-ipc)
diff --git a/src/wayland/toplevel_management/CMakeLists.txt b/src/wayland/toplevel_management/CMakeLists.txt
index 6ea0c254..01c9d756 100644
--- a/src/wayland/toplevel_management/CMakeLists.txt
+++ b/src/wayland/toplevel_management/CMakeLists.txt
@@ -10,6 +10,8 @@ qt_add_qml_module(quickshell-wayland-toplevel-management
 	DEPENDENCIES QtQml Quickshell Quickshell.Wayland
 )
 
+install_qml_module(quickshell-wayland-toplevel-management)
+
 wl_proto(quickshell-wayland-toplevel-management
 	wlr-foreign-toplevel-management-unstable-v1
 	"${CMAKE_CURRENT_SOURCE_DIR}/wlr-foreign-toplevel-management-unstable-v1.xml"
diff --git a/src/wayland/wlr_layershell/CMakeLists.txt b/src/wayland/wlr_layershell/CMakeLists.txt
index d5439f60..640b7ec2 100644
--- a/src/wayland/wlr_layershell/CMakeLists.txt
+++ b/src/wayland/wlr_layershell/CMakeLists.txt
@@ -12,6 +12,8 @@ qt_add_qml_module(quickshell-wayland-layershell
 	DEPENDENCIES QtQuick Quickshell
 )
 
+install_qml_module(quickshell-wayland-layershell)
+
 wl_proto(quickshell-wayland-layershell wlr-layer-shell-unstable-v1 "${CMAKE_CURRENT_SOURCE_DIR}/wlr-layer-shell-unstable-v1.xml")
 target_link_libraries(quickshell-wayland-layershell PRIVATE ${QT_DEPS} wayland-client)
 
diff --git a/src/widgets/CMakeLists.txt b/src/widgets/CMakeLists.txt
index ac3682fa..06671b13 100644
--- a/src/widgets/CMakeLists.txt
+++ b/src/widgets/CMakeLists.txt
@@ -7,6 +7,8 @@ qt_add_qml_module(quickshell-widgets
 		IconImage.qml
 )
 
+install_qml_module(quickshell-widgets)
+
 qs_pch(quickshell-widgets)
 qs_pch(quickshell-widgetsplugin)
 
diff --git a/src/window/CMakeLists.txt b/src/window/CMakeLists.txt
index 7b140946..e7dd1977 100644
--- a/src/window/CMakeLists.txt
+++ b/src/window/CMakeLists.txt
@@ -12,6 +12,8 @@ qt_add_qml_module(quickshell-window
 	DEPENDENCIES QtQuick Quickshell
 )
 
+install_qml_module(quickshell-window)
+
 add_library(quickshell-window-init OBJECT init.cpp)
 
 target_link_libraries(quickshell-window PRIVATE ${QT_DEPS} Qt6::QuickPrivate)
diff --git a/src/x11/CMakeLists.txt b/src/x11/CMakeLists.txt
index 2da30238..d1079d29 100644
--- a/src/x11/CMakeLists.txt
+++ b/src/x11/CMakeLists.txt
@@ -10,6 +10,8 @@ qt_add_qml_module(quickshell-x11
 	VERSION 0.1
 )
 
+install_qml_module(quickshell-x11)
+
 add_library(quickshell-x11-init OBJECT init.cpp)
 
 target_link_libraries(quickshell-x11 PRIVATE ${QT_DEPS} ${XCB_LIBRARIES})