diff options
-rw-r--r-- | CMakeLists.txt | 6 | ||||
-rw-r--r-- | addon/doxywizard/CMakeLists.txt | 6 | ||||
-rw-r--r-- | cmake/git_watcher.cmake | 213 | ||||
-rw-r--r-- | src/CMakeLists.txt | 10 | ||||
-rw-r--r-- | src/configimpl.l | 7 | ||||
-rw-r--r-- | src/doxygen.cpp | 29 | ||||
-rw-r--r-- | src/gitversion.cpp.in | 14 | ||||
-rw-r--r-- | src/version.h | 2 | ||||
-rw-r--r-- | src/version.py | 23 |
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() |