diff --git a/CMakeLists.txt b/CMakeLists.txt
index 8480c19cb63498036b762d96f45cbad3096c3673..abb1255236a6eed93c7e8bb89c21045d9d97c56a 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -2,19 +2,53 @@ cmake_minimum_required(VERSION 3.16.0)
 
 project(qt6ct LANGUAGES CXX)
 
+include(GNUInstallDirs)
+
+CONFIGURE_FILE(
+  "${CMAKE_CURRENT_SOURCE_DIR}/cmake_uninstall.cmake.in"
+  "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake"
+  IMMEDIATE @ONLY)
+
+ADD_CUSTOM_TARGET(uninstall
+  "${CMAKE_COMMAND}" -P "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake")
+
 set(CMAKE_CXX_STANDARD 11)
 set(CMAKE_CXX_STANDARD_REQUIRED ON)
-
+set(CMAKE_CXX_VISIBILITY_PRESET hidden)
+set(CMAKE_VISIBILITY_INLINES_HIDDEN 1)
 set(CMAKE_AUTOMOC ON)
 set(CMAKE_AUTORCC ON)
 set(CMAKE_AUTOUIC ON)
 
-find_package(Qt6 COMPONENTS BuildInternals Core Concurrent Gui REQUIRED)
-find_package(Qt6 COMPONENTS Widgets)
+ADD_DEFINITIONS(-DQT_DISABLE_DEPRECATED_BEFORE=0x060000 -DUSE_WIDGETS)
+
+find_package(Qt6 COMPONENTS BuildInternals Widgets Concurrent LinguistTools REQUIRED)
+
+get_target_property(QT_QTPATHS_EXECUTABLE Qt6::qtpaths IMPORTED_LOCATION)
+get_target_property(QT_LRELEASE_EXECUTABLE Qt6::lrelease IMPORTED_LOCATION)
+
+if(QT_QTPATHS_EXECUTABLE)
+    message(STATUS "Found qtpaths executable: " ${QT_QTPATHS_EXECUTABLE})
+    execute_process(COMMAND ${QT_QTPATHS_EXECUTABLE} -query QT_INSTALL_PLUGINS OUTPUT_VARIABLE PLUGINDIR OUTPUT_STRIP_TRAILING_WHITESPACE)
+    message(STATUS "Plugin path: " ${PLUGINDIR})
+else()
+    message(FATAL_ERROR "Could NOT find qtpaths executable")
+endif()
+
+if(QT_LRELEASE_EXECUTABLE)
+    message(STATUS "Found lrelease executable: " ${QT_LRELEASE_EXECUTABLE})
+    message(STATUS "Generating translations ...")
+    execute_process(COMMAND find ${CMAKE_CURRENT_SOURCE_DIR} -name *.ts COMMAND xargs ${QT_LRELEASE_EXECUTABLE} -silent)
+else()
+    message(FATAL_ERROR "Could NOT find lrelease executable")
+endif()
 
 add_subdirectory(src/qt6ct)
-#add_subdirectory(qt6ct-qtplugin)
-#add_subdirectory(qt6ct-style)
+add_subdirectory(src/qt6ct-qtplugin)
+add_subdirectory(src/qt6ct-style)
+
+install(DIRECTORY qss DESTINATION ${CMAKE_INSTALL_DATADIR})
+install(DIRECTORY colors DESTINATION ${CMAKE_INSTALL_DATADIR})
 
 if(UNIX)
     add_custom_target(distclean @echo cleaning for source distribution)
@@ -51,6 +85,6 @@ if(UNIX)
         ARGS ${CMAKE_CURRENT_BINARY_DIR} -name *_automoc.dir | xargs rm -rf
         COMMAND rm
         ARGS -rf ${CMAKE_CURRENT_BINARY_DIR}/doc/html
-        TARGET  distclean
+        TARGET distclean
     )
 endif(UNIX)
diff --git a/cmake_uninstall.cmake.in b/cmake_uninstall.cmake.in
new file mode 100644
index 0000000000000000000000000000000000000000..6790f7f1515bc339b97424e18b38acd5e5b530aa
--- /dev/null
+++ b/cmake_uninstall.cmake.in
@@ -0,0 +1,17 @@
+IF(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt")
+  MESSAGE(FATAL_ERROR "Cannot find install manifest: \"@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt\"")
+ENDIF(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt")
+
+FILE(READ "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt" files)
+STRING(REGEX REPLACE "\n" ";" files "${files}")
+FOREACH(file ${files})
+  MESSAGE(STATUS "Uninstalling \"$ENV{DESTDIR}${file}\"")
+    EXEC_PROGRAM(
+      rm ARGS "-rf \"$ENV{DESTDIR}${file}\""
+      OUTPUT_VARIABLE rm_out
+      RETURN_VALUE rm_retval
+      )
+    IF(NOT "${rm_retval}" STREQUAL 0)
+      MESSAGE(FATAL_ERROR "Problem when removing \"$ENV{DESTDIR}${file}\"")
+    ENDIF(NOT "${rm_retval}" STREQUAL 0)
+ENDFOREACH(file)
diff --git a/src/qt6ct-qtplugin/CMakeLists.txt b/src/qt6ct-qtplugin/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..ed3172d9fc834f987b608aa1e65c6dbd18b5cb0d
--- /dev/null
+++ b/src/qt6ct-qtplugin/CMakeLists.txt
@@ -0,0 +1,14 @@
+project(qt6ct-qtplugin)
+
+set(app_SRCS
+  main.cpp
+  qt6ctplatformtheme.cpp
+  ../qt6ct/qt6ct.cpp
+)
+
+include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../)
+
+add_library(qt6ct-qtplugin MODULE ${app_SRCS})
+set_target_properties(qt6ct-qtplugin PROPERTIES OUTPUT_NAME qt6ct)
+target_link_libraries(qt6ct-qtplugin PRIVATE Qt6::Widgets Qt6::GuiPrivate)
+install(TARGETS qt6ct-qtplugin DESTINATION ${PLUGINDIR}/platformthemes)
diff --git a/src/qt6ct-style/CMakeLists.txt b/src/qt6ct-style/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..9abf80aeb0c68e65111de3c0671d87e64d36088b
--- /dev/null
+++ b/src/qt6ct-style/CMakeLists.txt
@@ -0,0 +1,14 @@
+project(qt6ct-style)
+
+add_definitions(-DUSE_WIDGETS)
+
+set(app_SRCS
+  plugin.cpp
+  qt6ctproxystyle.cpp
+)
+
+include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../)
+
+add_library(qt6ct-style MODULE ${app_SRCS})
+target_link_libraries(qt6ct-style PRIVATE Qt6::Widgets)
+install(TARGETS qt6ct-style DESTINATION ${PLUGINDIR}/styles)
diff --git a/src/qt6ct/CMakeLists.txt b/src/qt6ct/CMakeLists.txt
index 4e5df1abb507a3f724b9860c07cced9bfa4feffb..0ce57cb1dc3bca56bf23b2b0d79e5c5b0212cb91 100644
--- a/src/qt6ct/CMakeLists.txt
+++ b/src/qt6ct/CMakeLists.txt
@@ -1,7 +1,5 @@
 project(app)
 
-add_definitions(-DUSE_WIDGETS)
-
 set(app_SRCS
   appearancepage.cpp
   fontconfigdialog.cpp
@@ -25,7 +23,10 @@ set(app_SRCS
   previewform.ui
   qsseditordialog.ui
   qsspage.ui
+  translations/translations.qrc
 )
 
 add_executable(qt6ct ${app_SRCS})
 target_link_libraries(qt6ct PRIVATE Qt6::Widgets Qt6::Concurrent Qt6::WidgetsPrivate)
+install(TARGETS qt6ct DESTINATION ${CMAKE_INSTALL_BINDIR})
+install(FILES qt6ct.desktop DESTINATION ${CMAKE_INSTALL_DATADIR}/applications)