summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt6
-rw-r--r--addon/doxywizard/CMakeLists.txt6
-rw-r--r--cmake/git_watcher.cmake213
-rw-r--r--src/CMakeLists.txt10
-rw-r--r--src/configimpl.l7
-rw-r--r--src/doxygen.cpp29
-rw-r--r--src/gitversion.cpp.in14
-rw-r--r--src/version.h2
-rw-r--r--src/version.py23
9 files changed, 301 insertions, 9 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 6bf9246..c116bbb 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -11,7 +11,7 @@
# Documents produced by Doxygen are derivative works derived from the
# input used in their production; they are not affected by this license.
-cmake_minimum_required(VERSION 3.1.3)
+cmake_minimum_required(VERSION 3.2)
project(doxygen)
option(build_wizard "Build the GUI frontend for doxygen." OFF)
@@ -110,6 +110,10 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE ${EXECUTABLE_OUTPUT_PATH})
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_MINSIZEREL ${EXECUTABLE_OUTPUT_PATH})
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELWITHDEBINFO ${EXECUTABLE_OUTPUT_PATH})
+# setup information for git version handling
+set(PRE_CONFIGURE_GIT_VERSION_FILE "${CMAKE_SOURCE_DIR}/src/gitversion.cpp.in")
+set(POST_CONFIGURE_GIT_VERSION_FILE "${GENERATED_SRC}/gitversion.cpp")
+
# gather lang codes for translation
file(GLOB lang_files RELATIVE "${CMAKE_SOURCE_DIR}/src" "${CMAKE_SOURCE_DIR}/src/translator_??.h")
if (english_only) # user only wants English
diff --git a/addon/doxywizard/CMakeLists.txt b/addon/doxywizard/CMakeLists.txt
index a89864d..c61c737 100644
--- a/addon/doxywizard/CMakeLists.txt
+++ b/addon/doxywizard/CMakeLists.txt
@@ -57,8 +57,10 @@ CONTENT "#ifndef SETTINGS_H
set_source_files_properties(${GENERATED_SRC_WIZARD}/settings.h PROPERTIES GENERATED 1)
# generate version.cpp
-file(GENERATE OUTPUT ${GENERATED_SRC_WIZARD}/version.cpp
- CONTENT "char versionString[]=\"${VERSION}\";"
+add_custom_command(
+ COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_SOURCE_DIR}/src/version.py ${VERSION} > ${GENERATED_SRC_WIZARD}/version.cpp
+ DEPENDS ${CMAKE_SOURCE_DIR}/VERSION ${CMAKE_SOURCE_DIR}/src/version.py
+ OUTPUT ${GENERATED_SRC_WIZARD}/version.cpp
)
set_source_files_properties(${GENERATED_SRC_WIZARD}/version.cpp PROPERTIES GENERATED 1)
diff --git a/cmake/git_watcher.cmake b/cmake/git_watcher.cmake
new file mode 100644
index 0000000..6447b86
--- /dev/null
+++ b/cmake/git_watcher.cmake
@@ -0,0 +1,213 @@
+# git_watcher.cmake
+#
+# License: MIT
+# Source: https://raw.githubusercontent.com/andrew-hardin/cmake-git-version-tracking/master/git_watcher.cmake
+
+
+# This file defines the functions and targets needed to monitor
+# the state of a git repo. If the state changes (e.g. a commit is made),
+# then a file gets reconfigured.
+#
+# The behavior of this script can be modified by defining any of these variables:
+#
+# PRE_CONFIGURE_GIT_VERSION_FILE (REQUIRED)
+# -- The path to the file that'll be configured.
+#
+# POST_CONFIGURE_GIT_VERSION_FILE (REQUIRED)
+# -- The path to the configured PRE_CONFIGURE_GIT_VERSION_FILE.
+#
+# GIT_STATE_FILE (OPTIONAL)
+# -- The path to the file used to store the previous build's git state.
+# Defaults to the current binary directory.
+#
+# GIT_WORKING_DIR (OPTIONAL)
+# -- The directory from which git commands will be run.
+# Defaults to the directory with the top level CMakeLists.txt.
+#
+# GIT_EXECUTABLE (OPTIONAL)
+# -- The path to the git executable. It'll automatically be set if the
+# user doesn't supply a path.
+#
+# Script design:
+# - This script was designed similar to a Python application
+# with a Main() function. I wanted to keep it compact to
+# simplify "copy + paste" usage.
+#
+# - This script is made to operate in two CMake contexts:
+# 1. Configure time context (when build files are created).
+# 2. Build time context (called via CMake -P)
+# If you see something odd (e.g. the NOT DEFINED clauses),
+# consider that it can run in one of two contexts.
+
+# Short hand for converting paths to absolute.
+macro(PATH_TO_ABSOLUTE var_name)
+ get_filename_component(${var_name} "${${var_name}}" ABSOLUTE)
+endmacro()
+
+# Check that a required variable is set.
+macro(CHECK_REQUIRED_VARIABLE var_name)
+ if(NOT DEFINED ${var_name})
+ message(FATAL_ERROR "The \"${var_name}\" variable must be defined.")
+ endif()
+ PATH_TO_ABSOLUTE(${var_name})
+endmacro()
+
+# Check that an optional variable is set, or, set it to a default value.
+macro(CHECK_OPTIONAL_VARIABLE var_name default_value)
+ if(NOT DEFINED ${var_name})
+ set(${var_name} ${default_value})
+ endif()
+ PATH_TO_ABSOLUTE(${var_name})
+endmacro()
+
+CHECK_REQUIRED_VARIABLE(PRE_CONFIGURE_GIT_VERSION_FILE)
+CHECK_REQUIRED_VARIABLE(POST_CONFIGURE_GIT_VERSION_FILE)
+CHECK_OPTIONAL_VARIABLE(GIT_STATE_FILE "${GENERATED_SRC}/git_state")
+#CHECK_REQUIRED_VARIABLE(GIT_STATE_FILE)
+CHECK_OPTIONAL_VARIABLE(GIT_WORKING_DIR "${CMAKE_SOURCE_DIR}")
+
+# Check the optional git variable.
+# If it's not set, we'll try to find it using the CMake packaging system.
+if(NOT DEFINED GIT_EXECUTABLE)
+ find_package(Git QUIET REQUIRED)
+endif()
+CHECK_REQUIRED_VARIABLE(GIT_EXECUTABLE)
+
+
+
+# Function: GitStateChangedAction
+# Description: this function is executed when the state of the git
+# repo changes (e.g. a commit is made).
+function(GitStateChangedAction _state_as_list)
+ # Set variables by index, then configure the file w/ these variables defined.
+ LIST(GET _state_as_list 0 GIT_RETRIEVED_STATE)
+ LIST(GET _state_as_list 1 GIT_HEAD_SHA1)
+ LIST(GET _state_as_list 2 GIT_IS_DIRTY)
+ configure_file("${PRE_CONFIGURE_GIT_VERSION_FILE}" "${POST_CONFIGURE_GIT_VERSION_FILE}" @ONLY)
+endfunction()
+
+
+
+# Function: GetGitState
+# Description: gets the current state of the git repo.
+# Args:
+# _working_dir (in) string; the directory from which git commands will be executed.
+# _state (out) list; a collection of variables representing the state of the
+# repository (e.g. commit SHA).
+function(GetGitState _working_dir _state)
+
+ # Get the hash for HEAD.
+ set(_success "true")
+ execute_process(COMMAND
+ "${GIT_EXECUTABLE}" rev-parse --verify HEAD
+ WORKING_DIRECTORY "${_working_dir}"
+ RESULT_VARIABLE res
+ OUTPUT_VARIABLE _hashvar
+ ERROR_QUIET
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+ if(NOT res EQUAL 0)
+ set(_success "false")
+ set(_hashvar "GIT-NOTFOUND")
+ endif()
+
+ # Get whether or not the working tree is dirty.
+ execute_process(COMMAND
+ "${GIT_EXECUTABLE}" status --porcelain
+ WORKING_DIRECTORY "${_working_dir}"
+ RESULT_VARIABLE res
+ OUTPUT_VARIABLE out
+ ERROR_QUIET
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+ if(NOT res EQUAL 0)
+ set(_success "false")
+ set(_dirty "false")
+ else()
+ if(NOT "${out}" STREQUAL "")
+ set(_dirty "true")
+ else()
+ set(_dirty "false")
+ endif()
+ endif()
+
+ # Return a list of our variables to the parent scope.
+ set(${_state} ${_success} ${_hashvar} ${_dirty} PARENT_SCOPE)
+endfunction()
+
+
+
+# Function: CheckGit
+# Description: check if the git repo has changed. If so, update the state file.
+# Args:
+# _working_dir (in) string; the directory from which git commands will be ran.
+# _state_changed (out) bool; whether or no the state of the repo has changed.
+# _state (out) list; the repository state as a list (e.g. commit SHA).
+function(CheckGit _working_dir _state_changed _state)
+
+ # Get the current state of the repo.
+ GetGitState("${_working_dir}" state)
+
+ # Set the output _state variable.
+ # (Passing by reference in CMake is awkward...)
+ set(${_state} ${state} PARENT_SCOPE)
+
+ # Check if the state has changed compared to the backup on disk.
+ if(EXISTS "${GIT_STATE_FILE}")
+ file(READ "${GIT_STATE_FILE}" OLD_HEAD_CONTENTS)
+ if(OLD_HEAD_CONTENTS STREQUAL "${state}")
+ # State didn't change.
+ set(${_state_changed} "false" PARENT_SCOPE)
+ return()
+ endif()
+ endif()
+
+ # The state has changed.
+ # We need to update the state file on disk.
+ # Future builds will compare their state to this file.
+ file(WRITE "${GIT_STATE_FILE}" "${state}")
+ set(${_state_changed} "true" PARENT_SCOPE)
+endfunction()
+
+
+
+# Function: SetupGitMonitoring
+# Description: this function sets up custom commands that make the build system
+# check the state of git before every build. If the state has
+# changed, then a file is configured.
+function(SetupGitMonitoring)
+ add_custom_target(check_git_repository
+ ALL
+ DEPENDS ${PRE_CONFIGURE_GIT_VERSION_FILE}
+ BYPRODUCTS ${POST_CONFIGURE_GIT_VERSION_FILE}
+ COMMENT "Checking the git repository for changes..."
+ COMMAND
+ ${CMAKE_COMMAND}
+ -D_BUILD_TIME_CHECK_GIT=TRUE
+ -DGIT_WORKING_DIR=${GIT_WORKING_DIR}
+ -DGIT_EXECUTABLE=${GIT_EXECUTABLE}
+ -DGIT_STATE_FILE=${GIT_STATE_FILE}
+ -DPRE_CONFIGURE_GIT_VERSION_FILE=${PRE_CONFIGURE_GIT_VERSION_FILE}
+ -DPOST_CONFIGURE_GIT_VERSION_FILE=${POST_CONFIGURE_GIT_VERSION_FILE}
+ -P "${CMAKE_CURRENT_LIST_FILE}")
+endfunction()
+
+
+
+# Function: Main
+# Description: primary entry-point to the script. Functions are selected based
+# on whether it's configure or build time.
+function(Main)
+ if(_BUILD_TIME_CHECK_GIT)
+ # Check if the repo has changed.
+ # If so, run the change action.
+ CheckGit("${GIT_WORKING_DIR}" did_change state)
+ if(did_change)
+ GitStateChangedAction("${state}")
+ endif()
+ else()
+ # >> Executes at configure time.
+ SetupGitMonitoring()
+ endif()
+endfunction()
+
+# And off we go...
+Main()
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 92a302a..9539228 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -1,5 +1,7 @@
# vim:ts=4:sw=4:expandtab:autoindent:
+include(${CMAKE_SOURCE_DIR}/cmake/git_watcher.cmake)
+
include_directories(
${CMAKE_SOURCE_DIR}/qtools
${CMAKE_SOURCE_DIR}/libmd5
@@ -31,8 +33,10 @@ set_source_files_properties(${GENERATED_SRC}/settings.h PROPERTIES GENERATED 1)
# generate version.cpp
-file(GENERATE OUTPUT ${GENERATED_SRC}/version.cpp
- CONTENT "char versionString[]=\"${VERSION}\";"
+add_custom_command(
+ COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_SOURCE_DIR}/src/version.py ${VERSION} > ${GENERATED_SRC}/version.cpp
+ DEPENDS ${CMAKE_SOURCE_DIR}/VERSION ${CMAKE_SOURCE_DIR}/src/version.py
+ OUTPUT ${GENERATED_SRC}/version.cpp
)
set_source_files_properties(${GENERATED_SRC}/version.cpp PROPERTIES GENERATED 1)
@@ -137,6 +141,7 @@ add_library(_doxygen STATIC
${GENERATED_SRC}/settings.h
${GENERATED_SRC}/layout_default.xml.h
${GENERATED_SRC}/version.cpp
+ ${POST_CONFIGURE_GIT_VERSION_FILE}
${GENERATED_SRC}/ce_parse.h
${GENERATED_SRC}/configvalues.h
${GENERATED_SRC}/resources.cpp
@@ -240,6 +245,7 @@ add_library(_doxygen STATIC
docbookvisitor.cpp
docbookgen.cpp
)
+add_dependencies( _doxygen check_git_repository )
add_executable(doxygen main.cpp)
diff --git a/src/configimpl.l b/src/configimpl.l
index 644250f..321ca5c 100644
--- a/src/configimpl.l
+++ b/src/configimpl.l
@@ -964,7 +964,12 @@ void ConfigImpl::writeTemplate(FTextStream &t,bool sl,bool upd)
void ConfigImpl::compareDoxyfile(FTextStream &t)
{
- t << "# Difference with default Doxyfile " << versionString << endl;
+ t << "# Difference with default Doxyfile " << versionString;
+ if (strlen(gitVersionString))
+ {
+ t << " (" << gitVersionString << ")";
+ }
+ t << endl;
QListIterator<ConfigOption> it = iterator();
ConfigOption *option;
for (;(option=it.current());++it)
diff --git a/src/doxygen.cpp b/src/doxygen.cpp
index 99878a5..aabb688 100644
--- a/src/doxygen.cpp
+++ b/src/doxygen.cpp
@@ -9927,7 +9927,14 @@ static void devUsage()
static void usage(const char *name)
{
- msg("Doxygen version %s\nCopyright Dimitri van Heesch 1997-2015\n\n",versionString);
+ if (strlen(gitVersionString))
+ {
+ msg("Doxygen version %s (%s)\nCopyright Dimitri van Heesch 1997-2015\n\n",versionString,gitVersionString);
+ }
+ else
+ {
+ msg("Doxygen version %s\nCopyright Dimitri van Heesch 1997-2015\n\n",versionString);
+ }
msg("You can use doxygen in a number of ways:\n\n");
msg("1) Use doxygen to generate a template configuration file:\n");
msg(" %s [-s] -g [configName]\n\n",name);
@@ -9982,6 +9989,8 @@ void initDoxygen()
setlocale(LC_CTYPE,"C"); // to get isspace(0xA0)==0, needed for UTF-8
setlocale(LC_NUMERIC,"C");
+ correctGitVersion();
+
portable_correct_path();
Doxygen::runningTime.start();
@@ -10387,7 +10396,14 @@ void readConfiguration(int argc, char **argv)
g_dumpSymbolMap = TRUE;
break;
case 'v':
- msg("%s\n",versionString);
+ if (strlen(gitVersionString))
+ {
+ msg("%s (%s)\n",versionString,gitVersionString);
+ }
+ else
+ {
+ msg("%s\n",versionString);
+ }
cleanUpDoxygen();
exit(0);
break;
@@ -10399,7 +10415,14 @@ void readConfiguration(int argc, char **argv)
}
else if (qstrcmp(&argv[optind][2],"version")==0)
{
- msg("%s\n",versionString);
+ if (strlen(gitVersionString))
+ {
+ msg("%s (%s)\n",versionString,gitVersionString);
+ }
+ else
+ {
+ msg("%s\n",versionString);
+ }
cleanUpDoxygen();
exit(0);
}
diff --git a/src/gitversion.cpp.in b/src/gitversion.cpp.in
new file mode 100644
index 0000000..cbb9b13
--- /dev/null
+++ b/src/gitversion.cpp.in
@@ -0,0 +1,14 @@
+#include <string.h>
+
+char gitVersionString[]="@GIT_HEAD_SHA1@";
+
+/* - On some systems git is not installed or
+ * installed on a place whete FindGit.cmake cannot find it
+ * - No git information is present (no .git directory)
+ * in those cases clear the gitVersionString (would have string GIT-NOTFOUND).
+ */
+void correctGitVersion(void)
+{
+ if (!strcmp(gitVersionString, "GIT-NOTFOUND")) gitVersionString[0] = '\0';
+}
+
diff --git a/src/version.h b/src/version.h
index 16bf9df..09d1b4f 100644
--- a/src/version.h
+++ b/src/version.h
@@ -19,5 +19,7 @@
#define VERSION_H
extern char versionString[];
+extern char gitVersionString[];
+void correctGitVersion(void);
#endif
diff --git a/src/version.py b/src/version.py
new file mode 100644
index 0000000..4aedee0
--- /dev/null
+++ b/src/version.py
@@ -0,0 +1,23 @@
+#!/usr/bin/python
+# python script to generate version.cpp from first argument
+#
+# Copyright (C) 1997-2018 by Dimitri van Heesch.
+#
+# Permission to use, copy, modify, and distribute this software and its
+# documentation under the terms of the GNU General Public License is hereby
+# granted. No representations are made about the suitability of this software
+# for any purpose. It is provided "as is" without express or implied warranty.
+# See the GNU General Public License for more details.
+#
+# Documents produced by Doxygen are derivative works derived from the
+# input used in their production; they are not affected by this license.
+#
+import sys
+
+def main():
+ if len(sys.argv)<2:
+ sys.exit('Usage: %s <version>' % sys.argv[0])
+ print('char versionString[]="%s";' % sys.argv[1])
+
+if __name__ == '__main__':
+ main()