Keep version info up to date in the CMake build.

Add commands and targets for generating aom_version.h and
aom.pc when necessary.

BUG=aomedia:703

Change-Id: Idc4d8203f950f73f151cbe32806d188bc96a0ee4
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 4c2ec46..51213f5 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -162,6 +162,10 @@
     "${AOM_ROOT}/rate_hist.c"
     "${AOM_ROOT}/rate_hist.h")
 
+set(AOM_PKG_CONFIG_SOURCES "${AOM_CONFIG_DIR}/aom.pc")
+
+set(AOM_VERSION_SOURCES "${AOM_CONFIG_DIR}/aom_version.h")
+
 set(AOM_WEBM_DECODER_SOURCES
     "${AOM_ROOT}/webmdec.cc"
     "${AOM_ROOT}/webmdec.h")
@@ -173,6 +177,48 @@
 include_directories(${AOM_ROOT} ${AOM_CONFIG_DIR})
 
 # Targets
+add_library(aom_version ${AOM_VERSION_SOURCES})
+add_dummy_source_file_to_target(aom_version c)
+add_custom_command(
+  OUTPUT "${AOM_CONFIG_DIR}/aom_version.h"
+  COMMAND ${CMAKE_COMMAND}
+  ARGS -DAOM_CONFIG_DIR=${AOM_CONFIG_DIR}
+    -DAOM_ROOT=${AOM_ROOT}
+    -DGIT_EXECUTABLE=${GIT_EXECUTABLE}
+    -DPERL_EXECUTABLE=${PERL_EXECUTABLE}
+    -P "${AOM_ROOT}/build/cmake/version.cmake"
+  COMMENT "Writing aom_version.h"
+  VERBATIM)
+
+add_custom_target(aom_version_check
+  COMMAND ${CMAKE_COMMAND}
+    -DAOM_CONFIG_DIR=${AOM_CONFIG_DIR}
+    -DAOM_ROOT=${AOM_ROOT}
+    -DGIT_EXECUTABLE=${GIT_EXECUTABLE}
+    -DPERL_EXECUTABLE=${PERL_EXECUTABLE}
+    -P "${AOM_ROOT}/build/cmake/version.cmake"
+  COMMENT "Updating version info if necessary."
+  VERBATIM)
+add_dependencies(aom_version aom_version_check)
+
+if (NOT MSVC)
+  add_library(aom_pc ${AOM_PKG_CONFIG_SOURCES})
+  add_dummy_source_file_to_target(aom_pc c)
+  add_custom_command(
+    OUTPUT "${AOM_CONFIG_DIR}/aom.pc"
+    COMMAND ${CMAKE_COMMAND}
+    ARGS -DAOM_CONFIG_DIR=${AOM_CONFIG_DIR}
+      -DAOM_ROOT=${AOM_ROOT}
+      -DCMAKE_INSTALL_PREFIX=${GIT_EXECUTABLE}
+      -DCMAKE_PROJECT_NAME=${CMAKE_PROJECT_NAME}
+      -DCONFIG_MULTITHREAD=${CONFIG_MULTITHREAD}
+      -DHAVE_PTHREAD_H=${HAVE_PTHREAD_H}
+      -P "${AOM_ROOT}/build/cmake/pkg_config.cmake"
+      COMMENT "Writing aom.pc"
+      VERBATIM)
+endif ()
+add_dependencies(aom_pc aom_version)
+
 # TODO(tomfinegan): Move rtcd target setup where it belongs for each rtcd
 # source.
 add_rtcd_build_step("${AOM_ROOT}/aom_dsp/aom_dsp_rtcd_defs.pl"
@@ -189,6 +235,8 @@
                     "av1_rtcd")
 
 add_library(aom_rtcd OBJECT ${AOM_RTCD_SOURCES})
+add_dependencies(aom_rtcd aom_version)
+
 add_library(aom_encoder_stats OBJECT ${AOM_ENCODER_STATS_SOURCES})
 add_library(aom ${AOM_SOURCES} $<TARGET_OBJECTS:aom_rtcd>)
 
diff --git a/build/cmake/aom_config.c.cmake b/build/cmake/aom_config.c.cmake
index 70bf950..62f0a10 100644
--- a/build/cmake/aom_config.c.cmake
+++ b/build/cmake/aom_config.c.cmake
@@ -10,6 +10,4 @@
  */
 #include "aom/aom_codec.h"
 static const char* const cfg = "${AOM_CMAKE_CONFIG}";
-static const char* const aom_git_hash = "${AOM_GIT_HASH}";
 const char *aom_codec_build_config(void) {return cfg;}
-const char *aom_codec_git_hash(void) {return aom_git_hash;}
diff --git a/build/cmake/aom_configure.cmake b/build/cmake/aom_configure.cmake
index 42ee3c1..9ca89c5 100644
--- a/build/cmake/aom_configure.cmake
+++ b/build/cmake/aom_configure.cmake
@@ -36,6 +36,7 @@
 include("${AOM_ROOT}/build/cmake/aom_optimization.cmake")
 include("${AOM_ROOT}/build/cmake/compiler_flags.cmake")
 include("${AOM_ROOT}/build/cmake/compiler_tests.cmake")
+include("${AOM_ROOT}/build/cmake/util.cmake")
 
 # Build a list of all configurable variables.
 get_cmake_property(cmake_cache_vars CACHE_VARIABLES)
@@ -330,19 +331,8 @@
 
 # Read the current git hash.
 find_package(Git)
-set(AOM_GIT_DESCRIPTION)
-set(AOM_GIT_HASH)
-if (GIT_FOUND)
-  # TODO(tomfinegan): Add build rule so users don't have to re-run cmake to
-  # create accurately versioned cmake builds.
-  execute_process(COMMAND ${GIT_EXECUTABLE}
-                  --git-dir=${AOM_ROOT}/.git rev-parse HEAD
-                  OUTPUT_VARIABLE AOM_GIT_HASH)
-  execute_process(COMMAND ${GIT_EXECUTABLE} --git-dir=${AOM_ROOT}/.git describe
-                  OUTPUT_VARIABLE AOM_GIT_DESCRIPTION ERROR_QUIET)
-  # Consume the newline at the end of the git output.
-  string(STRIP "${AOM_GIT_HASH}" AOM_GIT_HASH)
-  string(STRIP "${AOM_GIT_DESCRIPTION}" AOM_GIT_DESCRIPTION)
+if (NOT GIT_FOUND)
+  message("--- Git missing, version will be read from CHANGELOG.")
 endif ()
 
 configure_file("${AOM_ROOT}/build/cmake/aom_config.c.cmake"
@@ -386,6 +376,7 @@
     OUTPUT_FILE ${AOM_RTCD_HEADER_FILE})
 endforeach()
 
+# TODO(tomfinegan): Move this to aom_optimization.cmake.
 function (add_rtcd_build_step config output source symbol)
   add_custom_command(
     OUTPUT ${output}
@@ -406,44 +397,25 @@
 endfunction ()
 
 # Generate aom_version.h.
-if ("${AOM_GIT_DESCRIPTION}" STREQUAL "")
-  set(AOM_GIT_DESCRIPTION "${AOM_ROOT}/CHANGELOG")
-endif ()
 execute_process(
-  COMMAND ${PERL_EXECUTABLE} "${AOM_ROOT}/build/cmake/aom_version.pl"
-  --version_data=${AOM_GIT_DESCRIPTION}
-  --version_filename=${AOM_CONFIG_DIR}/aom_version.h)
+  COMMAND ${CMAKE_COMMAND}
+  -DAOM_CONFIG_DIR=${AOM_CONFIG_DIR}
+  -DAOM_ROOT=${AOM_ROOT}
+  -DGIT_EXECUTABLE=${GIT_EXECUTABLE}
+  -DPERL_EXECUTABLE=${PERL_EXECUTABLE}
+  -P "${AOM_ROOT}/build/cmake/version.cmake")
 
-# Generate aom.pc (pkg-config file).
 if (NOT MSVC)
-  # Extract the version string from aom_version.h
-  file(STRINGS "${AOM_CONFIG_DIR}/aom_version.h" aom_version
-       REGEX "VERSION_STRING_NOSP")
-  string(REPLACE "#define VERSION_STRING_NOSP \"v" "" aom_version
-         "${aom_version}")
-  string(REPLACE "\"" "" aom_version "${aom_version}")
-
-  # Write pkg-config info.
-  set(prefix "${CMAKE_INSTALL_PREFIX}")
-  set(pkgconfig_file "${AOM_CONFIG_DIR}/aom.pc")
-  string(TOLOWER ${CMAKE_PROJECT_NAME} pkg_name)
-  file(WRITE "${pkgconfig_file}" "# libaom pkg-config.\n")
-  file(APPEND "${pkgconfig_file}" "prefix=${prefix}\n")
-  file(APPEND "${pkgconfig_file}" "exec_prefix=${prefix}/bin\n")
-  file(APPEND "${pkgconfig_file}" "libdir=${prefix}/lib\n")
-  file(APPEND "${pkgconfig_file}" "includedir=${prefix}/include\n\n")
-  file(APPEND "${pkgconfig_file}" "Name: ${pkg_name}\n")
-  file(APPEND "${pkgconfig_file}" "Description: AV1 codec library.\n")
-  file(APPEND "${pkgconfig_file}" "Version: ${aom_version}\n")
-  file(APPEND "${pkgconfig_file}" "Requires:\n")
-  file(APPEND "${pkgconfig_file}" "Conflicts:\n")
-  file(APPEND "${pkgconfig_file}" "Libs: -L${prefix}/lib -l${pkg_name} -lm\n")
-  if (CONFIG_MULTITHREAD AND HAVE_PTHREAD_H)
-    file(APPEND "${pkgconfig_file}" "Libs.private: -lm -lpthread\n")
-  else ()
-    file(APPEND "${pkgconfig_file}" "Libs.private: -lm\n")
-  endif ()
-  file(APPEND "${pkgconfig_file}" "Cflags: -I${prefix}/include\n")
+  # Generate aom.pc (pkg-config file).
+  execute_process(
+    COMMAND ${CMAKE_COMMAND}
+    -DAOM_CONFIG_DIR=${AOM_CONFIG_DIR}
+    -DAOM_ROOT=${AOM_ROOT}
+    -DCMAKE_INSTALL_PREFIX=${GIT_EXECUTABLE}
+    -DCMAKE_PROJECT_NAME=${CMAKE_PROJECT_NAME}
+    -DCONFIG_MULTITHREAD=${CONFIG_MULTITHREAD}
+    -DHAVE_PTHREAD_H=${HAVE_PTHREAD_H}
+    -P "${AOM_ROOT}/build/cmake/pkg_config.cmake")
 endif ()
 
 endif ()  # AOM_BUILD_CMAKE_AOM_CONFIGURE_CMAKE_
diff --git a/build/cmake/pkg_config.cmake b/build/cmake/pkg_config.cmake
new file mode 100644
index 0000000..e350811
--- /dev/null
+++ b/build/cmake/pkg_config.cmake
@@ -0,0 +1,58 @@
+##
+## Copyright (c) 2017, Alliance for Open Media. All rights reserved
+##
+## This source code is subject to the terms of the BSD 2 Clause License and
+## the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
+## was not distributed with this source code in the LICENSE file, you can
+## obtain it at www.aomedia.org/license/software. If the Alliance for Open
+## Media Patent License 1.0 was not distributed with this source code in the
+## PATENTS file, you can obtain it at www.aomedia.org/license/patent.
+##
+cmake_minimum_required(VERSION 3.5)
+
+set(REQUIRED_ARGS
+  "AOM_ROOT" "AOM_CONFIG_DIR" "CMAKE_INSTALL_PREFIX" "CMAKE_PROJECT_NAME"
+  "CONFIG_MULTITHREAD" "HAVE_PTHREAD_H")
+
+foreach (arg ${REQUIRED_ARGS})
+  if ("${${arg}}" STREQUAL "")
+    message(FATAL_ERROR "${arg} must not be empty.")
+  endif ()
+endforeach ()
+
+include("${AOM_ROOT}/build/cmake/util.cmake")
+
+extract_version_string("${AOM_CONFIG_DIR}/aom_version.h" aom_version)
+
+# Create a version string suitable for comparison using the RPM version compare
+# algorithm: strip out everything after the number.
+string(FIND "${aom_version}" "-" dash_pos)
+if (${dash_pos} EQUAL -1)
+  set(package_version "${aom_version}")
+else ()
+  string(SUBSTRING "${aom_version}" 0 ${dash_pos} package_version)
+endif ()
+
+# Write pkg-config info.
+set(prefix "${CMAKE_INSTALL_PREFIX}")
+set(pkgconfig_file "${AOM_CONFIG_DIR}/aom.pc")
+string(TOLOWER ${CMAKE_PROJECT_NAME} pkg_name)
+file(WRITE "${pkgconfig_file}" "# libaom pkg-config.\n")
+file(APPEND "${pkgconfig_file}" "prefix=${prefix}\n")
+file(APPEND "${pkgconfig_file}" "exec_prefix=${prefix}/bin\n")
+file(APPEND "${pkgconfig_file}" "libdir=${prefix}/lib\n")
+file(APPEND "${pkgconfig_file}" "includedir=${prefix}/include\n\n")
+file(APPEND "${pkgconfig_file}" "Name: ${pkg_name}\n")
+file(APPEND "${pkgconfig_file}"
+     "Description: AV1 codec library v${aom_version}.\n")
+file(APPEND "${pkgconfig_file}" "Version: ${package_version}\n")
+file(APPEND "${pkgconfig_file}" "Requires:\n")
+file(APPEND "${pkgconfig_file}" "Conflicts:\n")
+file(APPEND "${pkgconfig_file}" "Libs: -L${prefix}/lib -l${pkg_name} -lm\n")
+if (CONFIG_MULTITHREAD AND HAVE_PTHREAD_H)
+  file(APPEND "${pkgconfig_file}" "Libs.private: -lm -lpthread\n")
+else ()
+  file(APPEND "${pkgconfig_file}" "Libs.private: -lm\n")
+endif ()
+file(APPEND "${pkgconfig_file}" "Cflags: -I${prefix}/include\n")
+
diff --git a/build/cmake/util.cmake b/build/cmake/util.cmake
index 786e342..d6c4322 100644
--- a/build/cmake/util.cmake
+++ b/build/cmake/util.cmake
@@ -47,6 +47,24 @@
   message(WARNING "--- ${warning_message}")
 endfunction ()
 
+# Extracts the version string from $version_file and returns it to the user via
+# $version_string_out_var. To achieve this VERSION_STRING_NOSP is located in
+# $version_file and then everything but the string literal assigned to the
+# variable is removed. Quotes and the leading 'v' are stripped from the
+# returned string.
+function (extract_version_string version_file version_string_out_var)
+  file(STRINGS "${version_file}" aom_version REGEX "VERSION_STRING_NOSP")
+  string(REPLACE "#define VERSION_STRING_NOSP " "" aom_version
+         "${aom_version}")
+  string(REPLACE "\"" "" aom_version "${aom_version}")
+  string(REPLACE " " "" aom_version "${aom_version}")
+  string(FIND "${aom_version}" "v" v_pos)
+  if (${v_pos} EQUAL 0)
+    string(SUBSTRING "${aom_version}" 1 -1 aom_version)
+  endif ()
+  set("${version_string_out_var}" "${aom_version}" PARENT_SCOPE)
+endfunction ()
+
 # Sets CMake compiler launcher to $launcher_name when $launcher_name is found in
 # $PATH. Warns user about ignoring build flag $launcher_flag when $launcher_name
 # is not found in $PATH.
diff --git a/build/cmake/version.cmake b/build/cmake/version.cmake
new file mode 100644
index 0000000..c2b3bdb
--- /dev/null
+++ b/build/cmake/version.cmake
@@ -0,0 +1,55 @@
+##
+## Copyright (c) 2017, Alliance for Open Media. All rights reserved
+##
+## This source code is subject to the terms of the BSD 2 Clause License and
+## the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
+## was not distributed with this source code in the LICENSE file, you can
+## obtain it at www.aomedia.org/license/software. If the Alliance for Open
+## Media Patent License 1.0 was not distributed with this source code in the
+## PATENTS file, you can obtain it at www.aomedia.org/license/patent.
+##
+cmake_minimum_required(VERSION 3.5)
+
+set(REQUIRED_ARGS
+    "AOM_ROOT" "AOM_CONFIG_DIR" "GIT_EXECUTABLE" "PERL_EXECUTABLE")
+
+foreach (arg ${REQUIRED_ARGS})
+  if ("${${arg}}" STREQUAL "")
+    message(FATAL_ERROR "${arg} must not be empty.")
+  endif ()
+endforeach ()
+
+include("${AOM_ROOT}/build/cmake/util.cmake")
+
+# Generate the version string for this run.
+unset(aom_version)
+if (EXISTS "${GIT_EXECUTABLE}")
+  execute_process(COMMAND ${GIT_EXECUTABLE} --git-dir=${AOM_ROOT}/.git describe
+                  OUTPUT_VARIABLE aom_version ERROR_QUIET)
+  string(STRIP "${aom_version}" aom_version)
+
+  # Remove the leading 'v' from the version string.
+  string(FIND "${aom_version}" "v" v_pos)
+  if (${v_pos} EQUAL 0)
+    string(SUBSTRING "${aom_version}" 1 -1 aom_version)
+  endif ()
+endif ()
+
+if ("${aom_version}" STREQUAL "")
+  set(aom_version "${AOM_ROOT}/CHANGELOG")
+endif ()
+
+unset(last_aom_version)
+if (EXISTS "${AOM_CONFIG_DIR}/aom_version.h")
+  extract_version_string("${AOM_CONFIG_DIR}/aom_version.h" last_aom_version)
+endif ()
+
+if (NOT "${aom_version}" STREQUAL "${last_aom_version}")
+  # TODO(tomfinegan): Perl dependency is unnecessary. CMake can do everything
+  # that is done by version.pl on its own (if a bit more verbose...).
+  execute_process(
+    COMMAND ${PERL_EXECUTABLE} "${AOM_ROOT}/build/cmake/version.pl"
+    --version_data=${aom_version}
+    --version_filename=${AOM_CONFIG_DIR}/aom_version.h
+    VERBATIM)
+endif ()
diff --git a/build/cmake/aom_version.pl b/build/cmake/version.pl
similarity index 88%
rename from build/cmake/aom_version.pl
rename to build/cmake/version.pl
index 3412fee..323e178 100755
--- a/build/cmake/aom_version.pl
+++ b/build/cmake/version.pl
@@ -14,6 +14,7 @@
 use 5.010;
 use Getopt::Long;
 
+my $git_desc;
 my $version_data;
 my $version_filename;
 GetOptions('version_data=s' => \$version_data,
@@ -27,6 +28,7 @@
 
 # Determine if $version_data is a filename or a git tag/description.
 my $version_string;
+chomp($version_data);
 if (-r $version_data) {
   # $version_data is the path to the CHANGELOG. Parse the most recent version.
   my $changelog_filename = $version_data;
@@ -45,6 +47,7 @@
   # tagName OR tagName-commitsSinceTag-shortCommitHash
   # In either case we want the first element of the array returned by split.
   $version_string = (split("-", $version_data))[0];
+  $git_desc = $version_data;
 }
 
 if (substr($version_string, 0, 1) eq "v") {
@@ -80,7 +83,19 @@
 EOF
 
 select $version_file;
-print << "EOF";
+if (length($git_desc)) {
+  print << "EOF";
+$lic_block
+#define VERSION_MAJOR $version_major
+#define VERSION_MINOR $version_minor
+#define VERSION_PATCH $version_patch
+#define VERSION_EXTRA \"$version_extra\"
+#define VERSION_PACKED $version_packed
+#define VERSION_STRING_NOSP \"$git_desc\"
+#define VERSION_STRING \" $git_desc\"
+EOF
+} else {
+  print << "EOF";
 $lic_block
 #define VERSION_MAJOR $version_major
 #define VERSION_MINOR $version_minor
@@ -90,4 +105,5 @@
 #define VERSION_STRING_NOSP \"v$version_string\"
 #define VERSION_STRING \" v$version_string\"
 EOF
+}
 close($version_file);