diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 0000000..a274006
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1,2 @@
+# we add a generated ChangeLog to the tarball
+/ChangeLog export-ignore
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 82b26b7..db06e11 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,119 +1,128 @@
 # CMakeLists.txt for QGpgME
 # Copyright 2025 g10 Code GmbH
 # Software engineering by Carl Schwan <carl.schwan@gnupg.com>
 # Software engineering by Ingo Klöcker <dev@ingo-kloecker.de>
 #
 # This file is part of QGpgME, the Qt API binding for GpgME.
 #
 # QGpgME is free software; you can redistribute it and/or modify it
 # under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 2 of the License, or
 # (at your option) any later version.
 #
 # QGpgME is distributed in the hope that it will be useful,
 # but WITHOUT ANY WARRANTY; without even the implied warranty of
 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 # General Public License for more details.
 #
 # You should have received a copy of the GNU General Public License
 # along with this program; if not, see <https://gnu.org/licenses/>.
 # SPDX-License-Identifier: GPL-2.0-or-later
 
 cmake_minimum_required(VERSION 3.16 FATAL_ERROR)
 
 set(FULL_VERSION "2.0.0")
 
 string(REGEX MATCH "^[0-9]+.[0-9]+.[0-9]+" cmake_compat_version ${FULL_VERSION})
 project(qgpgme VERSION ${cmake_compat_version})
 
 set(VERSION_MAJOR ${PROJECT_VERSION_MAJOR})
 set(VERSION_MINOR ${PROJECT_VERSION_MINOR})
 set(VERSION_MICRO ${PROJECT_VERSION_PATCH})
 
 # LT Version numbers, remember to change them just *before* a release.
 #   (Code changed:			REVISION++)
 #   (Interfaces added/removed/changed:	CURRENT++, REVISION=0)
 #   (Interfaces added:			AGE++)
 #   (Interfaces removed:		AGE=0)
 set(LIBQGPGME_LT_CURRENT "22")
 set(LIBQGPGME_LT_AGE "7")
 set(LIBQGPGME_LT_REVISION "0")
 math(EXPR LIBQGPGME_SOVERSION "${LIBQGPGME_LT_CURRENT} - ${LIBQGPGME_LT_AGE}")
 
 set(GPG_ERROR_REQUIRED_VERSION "1.47")
 set(GPGME_REQUIRED_VERSION "1.24.2")
 set(GPGMEPP_REQUIRED_VERSION "${VERSION_MAJOR}.${VERSION_MINOR}.0")
 set(QT5_REQUIRED_VERSION "5.15.0")
 set(QT6_REQUIRED_VERSION "6.5.0")
 
 option(QGPGME_BUILD_QT5 "Build for Qt5" ON)
 option(QGPGME_BUILD_QT6 "Build for Qt6" ON)
 
 set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules ${CMAKE_MODULE_PATH})
 
 include(G10CMakeSettings)
 
 include(G10AddDistTargets)
+include(G10AddGenChangeLogTarget)
 include(G10CompilerSettings)
 include(G10GetFullVersion)
 include(ECMGenerateHeaders)
 include(ECMUninstallTarget)
 include(FeatureSummary)
 include(GNUInstallDirs)
 
 set(CMAKE_AUTOMOC ON)
 set(CMAKE_AUTORCC ON)
 
 find_package(LibGpgError ${GPG_ERROR_REQUIRED_VERSION})
 set_package_properties(LibGpgError PROPERTIES TYPE REQUIRED)
 find_package(Gpgme ${GPGME_REQUIRED_VERSION})
 set_package_properties(Gpgme PROPERTIES TYPE REQUIRED)
 find_package(Gpgmepp ${GPGMEPP_REQUIRED_VERSION} CONFIG)
 set_package_properties(Gpgmepp PROPERTIES DESCRIPTION "GpgME++ library" URL "https://www.gnupg.org" TYPE REQUIRED)
 
 g10_get_full_version(TAG_PREFIX gpgmeqt)
 
 # create the VERSION file
 find_package(Git QUIET)
 if (GIT_FOUND AND EXISTS "${CMAKE_SOURCE_DIR}/.git")
     # get the current commit ID
     execute_process(COMMAND ${GIT_EXECUTABLE} rev-parse --verify HEAD
                     WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
                     OUTPUT_VARIABLE commit_id
     )
     string(STRIP "${commit_id}" commit_id) # strip trailing whitespace
     file(WRITE "${CMAKE_BINARY_DIR}/VERSION" "${G10_FULL_VERSION}\n${commit_id}\n")
 elseif(EXISTS "${CMAKE_SOURCE_DIR}/VERSION")
     configure_file("${CMAKE_SOURCE_DIR}/VERSION" "VERSION" COPYONLY)
 else()
     file(WRITE "${CMAKE_BINARY_DIR}/VERSION" "${G10_FULL_VERSION}\nunknown\n")
 endif()
 
+# start ChangeLog at import from KDE in gpgme repo
+g10_add_gen_changelog_target(
+    SINCE "2016-03-08T00:00:00"
+    FOOTER "${CMAKE_SOURCE_DIR}/build-aux/git-log-footer"
+)
+
 set(EXTRA_DIST
+    "${CMAKE_BINARY_DIR}/ChangeLog"
     "${CMAKE_BINARY_DIR}/VERSION"
 )
 g10_add_dist_targets(
     VERSION "${G10_FULL_VERSION}"
     ARCHIVE_FORMAT "tar.xz"
     EXTRA_FILES ${EXTRA_DIST}
 )
+add_dependencies(dist gen-ChangeLog)
 
 if(QGPGME_BUILD_QT5)
     set(QT_MAJOR_VERSION 5)
     find_package(Qt5 ${QT5_REQUIRED_VERSION} REQUIRED COMPONENTS Core)
     add_subdirectory(src 5/src)
     if(BUILD_TESTING)
         add_subdirectory(tests 5/tests)
     endif()
 endif()
 
 if(QGPGME_BUILD_QT6)
     set(QT_MAJOR_VERSION 6)
     find_package(Qt6 ${QT6_REQUIRED_VERSION} CONFIG REQUIRED Core CoreTools)
     add_subdirectory(src 6/src)
     if(BUILD_TESTING)
         add_subdirectory(tests 6/tests)
     endif()
 endif()
 
 feature_summary(WHAT ALL FATAL_ON_MISSING_REQUIRED_PACKAGES)
diff --git a/cmake/modules/G10AddGenChangeLogTarget.cmake b/cmake/modules/G10AddGenChangeLogTarget.cmake
new file mode 100644
index 0000000..5d5a682
--- /dev/null
+++ b/cmake/modules/G10AddGenChangeLogTarget.cmake
@@ -0,0 +1,91 @@
+# Copyright 2025 g10 Code GmbH
+# Software engineering by Ingo Klöcker <dev@ingo-kloecker.de>
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# 1. Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+#    notice, this list of conditions and the following disclaimer in the
+#    documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# SPDX-License-Identifier: BSD-2-Clause
+
+#[=======================================================================[.rst:
+G10AddGenChangeLogTarget
+------------------------
+
+Add custom target ``gen-ChangeLog`` for generating a ChangeLog file.
+
+::
+
+  g10_add_gen_changelog_target(
+..       [SINCE <date>]
+..       [FOOTER <file>]
+  )
+
+# This function adds a custom target named ``gen-ChangeLog`` to the project
+# which can be used to generate a ChangeLog file from the commit log messages.
+# ``gitlog-to-changelog`` is used for generating the ChangeLog. It can be
+# found in the gnupg repository.
+#
+# If ``SINCE`` is given then its value is passed to ``git log`` to start the
+# ChangeLog at this date.
+#
+# If ``FOOTER`` is given then the content of the given file is appended to
+# the generated ChangeLog.
+#]=======================================================================]
+
+# save the location of the header template while CMAKE_CURRENT_LIST_DIR
+# has the value we want
+set(_G10_GENERATE_CHANGELOG_TEMPLATE "${CMAKE_CURRENT_LIST_DIR}/g10_generate_ChangeLog.cmake.in")
+
+function(G10_ADD_GEN_CHANGELOG_TARGET)
+    if(TARGET gen-ChangeLog)
+        # gen-ChangeLog target is already defined
+        return()
+    endif()
+
+    set(options)
+    set(one_value_keywords SINCE FOOTER)
+    set(multi_value_keywords)
+
+    cmake_parse_arguments(PARSE_ARGV 0 arg "${options}" "${one_value_keywords}" "${multi_value_keywords}")
+
+    if(arg_UNPARSED_ARGUMENTS)
+        message(FATAL_ERROR "Unknown keywords given to G10_ADD_GEN_CHANGELOG_TARGET(): \"${arg_UNPARSED_ARGUMENTS}\"")
+    endif()
+
+    if(arg_SINCE)
+        set(changelog_since ${arg_SINCE})
+    endif()
+    if(arg_FOOTER)
+        set(changelog_footer ${arg_FOOTER})
+    endif()
+
+    configure_file(
+        "${_G10_GENERATE_CHANGELOG_TEMPLATE}"
+        "${CMAKE_BINARY_DIR}/g10_generate_ChangeLog.cmake"
+        IMMEDIATE
+        @ONLY
+    )
+
+    add_custom_target(gen-ChangeLog
+        COMMENT "Generating ChangeLog..."
+        COMMAND "${CMAKE_COMMAND}" -P "${CMAKE_BINARY_DIR}/g10_generate_ChangeLog.cmake"
+        WORKING_DIRECTORY "${CMAKE_BINARY_DIR}"
+    )
+endfunction()
diff --git a/cmake/modules/g10_generate_ChangeLog.cmake.in b/cmake/modules/g10_generate_ChangeLog.cmake.in
new file mode 100644
index 0000000..d26fd88
--- /dev/null
+++ b/cmake/modules/g10_generate_ChangeLog.cmake.in
@@ -0,0 +1,51 @@
+# Copyright 2025 g10 Code GmbH
+# Software engineering by Ingo Klöcker <dev@ingo-kloecker.de>
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# 1. Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+#    notice, this list of conditions and the following disclaimer in the
+#    documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# SPDX-License-Identifier: BSD-2-Clause
+
+find_package(Git QUIET REQUIRED)
+if(NOT EXISTS "@CMAKE_SOURCE_DIR@/.git")
+    message(FATAL_ERROR "Cannot generate ChangeLog without git repo.")
+endif()
+
+find_program(GITLOG_TO_CHANGELOG gitlog-to-changelog)
+if(GITLOG_TO_CHANGELOG STREQUAL "GITLOG_TO_CHANGELOG-NOTFOUND")
+    message(FATAL_ERROR "Could not find gitlog-to-changelog. A suitable gitlog-to-changelog script can be found in GnuPG master.")
+endif()
+
+if(NOT "@changelog_footer@" STREQUAL "")
+    file(READ @changelog_footer@ footer)
+endif()
+if(NOT "@changelog_since@" STREQUAL "")
+    set(since_args --since "@changelog_since@")
+endif()
+execute_process(
+    COMMAND "${GITLOG_TO_CHANGELOG}" --append-dot --tear-off ${since_args}
+    OUTPUT_FILE @CMAKE_BINARY_DIR@/ChangeLog
+    WORKING_DIRECTORY "@CMAKE_SOURCE_DIR@"
+    COMMAND_ERROR_IS_FATAL ANY
+)
+if(footer)
+    file(APPEND @CMAKE_BINARY_DIR@/ChangeLog "${footer}")
+endif()