diff --git a/CMakeLists.txt b/CMakeLists.txt
index 2cde0fab5..b58b752d9 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -14,7 +14,13 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
-cmake_minimum_required(VERSION 3.5)
+# Why CMake 3.8?
+# This allows package maintainers to create reproducible builds:
+# > New in version 3.8: If the SOURCE_DATE_EPOCH environment variable is set,
+# > its value will be used instead of the current time.
+# > See https://reproducible-builds.org/specs/source-date-epoch/ for details.
+cmake_minimum_required(VERSION 3.8)
+
project(deskflow C CXX)
include(cmake/Version.cmake)
@@ -25,6 +31,7 @@ include(cmake/Packaging.cmake)
set_version()
configure_definitions()
+configure_build()
configure_libs()
configure_packaging()
diff --git a/ChangeLog b/ChangeLog
index 9dab6d5b4..42e2cafb4 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -14,6 +14,7 @@ Enhancements:
- #7539 Lint and add comment to PR on lint failure
- #7544 Use system deps for `tomlplusplus` and `CLI11`
- #7549 Script to create Python virtual environment (venv)
+- #7547 Use `SOURCE_DATE_EPOCH` for reproducible builds
# 1.16.1
diff --git a/cmake/Build.cmake b/cmake/Build.cmake
index c6d3f729e..e0947df7f 100644
--- a/cmake/Build.cmake
+++ b/cmake/Build.cmake
@@ -13,13 +13,29 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
-if(WIN32)
- message(STATUS "Enabling warnings as errors (MSVC)")
- add_compile_options(/WX)
-elseif(UNIX)
- message(STATUS "Enabling warnings as errors (GNU/Clang)")
- add_compile_options(-Werror)
-endif()
+macro(configure_build)
+ warnings_as_errors()
+ set_build_date()
+endmacro()
+
+macro(warnings_as_errors)
+ if(WIN32)
+ message(STATUS "Enabling warnings as errors (MSVC)")
+ add_compile_options(/WX)
+ elseif(UNIX)
+ message(STATUS "Enabling warnings as errors (GNU/Clang)")
+ add_compile_options(-Werror)
+ endif()
+endmacro()
+
+macro(set_build_date)
+ # Since CMake 3.8.0, `string(TIMESTAMP ...)` respects `SOURCE_DATE_EPOCH` env var if set,
+ # which allows package maintainers to create reproducible builds.
+ # We require CMake 3.8.0 in the root `CMakeLists.txt` for this reason.
+ string(TIMESTAMP BUILD_DATE "%Y-%m-%d" UTC)
+ message(STATUS "Build date: ${BUILD_DATE}")
+ add_definitions(-DBUILD_DATE="${BUILD_DATE}")
+endmacro()
macro(post_config)
diff --git a/src/gui/src/AboutDialog.cpp b/src/gui/src/AboutDialog.cpp
index 36e3c3028..50494ace1 100644
--- a/src/gui/src/AboutDialog.cpp
+++ b/src/gui/src/AboutDialog.cpp
@@ -38,8 +38,8 @@ AboutDialog::AboutDialog(MainWindow *parent)
QString version = QString::fromStdString(deskflow::version());
m_pLabelDeskflowVersion->setText(version);
- QString buildDateString = QString::fromLocal8Bit(__DATE__).simplified();
- QDate buildDate = QLocale("en_US").toDate(buildDateString, "MMM d yyyy");
+ QString buildDateString = QString::fromLocal8Bit(BUILD_DATE).simplified();
+ QDate buildDate = QLocale("en_US").toDate(buildDateString, "yyyy-MM-dd");
m_pLabelBuildDate->setText(
buildDate.toString(QLocale::system().dateFormat(QLocale::LongFormat)));
}
diff --git a/src/lib/common/copyright.h b/src/lib/common/copyright.h
index 4ad3d5cb3..d20e248b9 100644
--- a/src/lib/common/copyright.h
+++ b/src/lib/common/copyright.h
@@ -29,8 +29,8 @@ const auto kCopyrightFormat = //
"Copyright (C) 2002-2009 Chris Schoeneman";
inline std::string copyright() {
- const std::string date = __DATE__;
- const auto year = date.substr(date.size() - 4);
+ const std::string date = BUILD_DATE;
+ const auto year = date.substr(0, 4);
const auto kBufferLength = 256;
std::vector buffer(kBufferLength);
std::snprintf( // NOSONAR