1# - When enabled, stamp the current version on C/C++ sources
2#
3# To set up your source code for proper stamping, start your file
4# with a Doxygen-style comment block, starting with /* and ending with */
5# On a line by itself, with unimportant whitespace, add the standard Doxygen
6# "version" command:
7#  @version xxx
8# or
9#  \version xxx
10#
11# To make sure it works, please do actually put xxx as the current version:
12# when you save, add one of the command below to your cmake build, and run
13# cmake, it should replace xxx with the current version. (It replaces anything
14# between the end of the whitespace after \version and the end of the line
15# with the version that you pass in your build script, so put nothing else
16# on that line!)
17#
18# For <version>, I recommend passing the value of a CMake variable like
19#  ${CPACK_PACKAGE_VERSION}
20# Remember, reduced duplication of information means reduced errors!
21#
22# WARNING!
23# This does edit your source directory, but will only execute if the
24# (hidden/advanced, default OFF) variable ENABLE_VERSION_STAMPING is on.
25#
26# Additionally, it tries to be very careful:
27# - It will not edit files that are outside your source tree
28# - It will only attempt a substitution within the first C-style comment block
29# of your code (that is, the first /* */), but only if // is not found first
30#
31#  stamp_target_with_version(<version> <target_name> [HEADERS_ONLY | <source>...]) -
32#   If no source file is specified, all will be processed.
33#
34#  stamp_sources_with_version(<version> <source> [<source> ...]) -
35#   Use for files not directly associated with a target.
36#
37# Original Author:
38# 2009-2010 Ryan Pavlik <rpavlik@iastate.edu> <abiryan@ryand.net>
39# http://academic.cleardefinition.com
40# Iowa State University HCI Graduate Program/VRAC
41#
42# Copyright Iowa State University 2009-2010.
43# Distributed under the Boost Software License, Version 1.0.
44# (See accompanying file LICENSE_1_0.txt or copy at
45# http://www.boost.org/LICENSE_1_0.txt)
46
47if(__stamp_sources_with_version)
48	return()
49endif()
50set(__stamp_sources_with_version YES)
51
52if(NOT APPLE)
53	option(ENABLE_VERSION_STAMPING
54		"Modify source files to update the version in the comment header. Maintainers only!"
55		OFF)
56	mark_as_advanced(ENABLE_VERSION_STAMPING)
57endif()
58
59# Stash where our data is, at include() time
60get_filename_component(_sswv_mod_dir ${CMAKE_CURRENT_LIST_FILE} PATH)
61
62
63# Internal utility function - not for outside use
64function(_stamp_file_with_version version filename)
65	if(NOT SED_EXECUTABLE)
66		find_program(SED_EXECUTABLE sed)
67		mark_as_advanced(SED_EXECUTABLE)
68	endif()
69	# TODO: fix the sed script on Mac
70	if(SED_EXECUTABLE AND ENABLE_VERSION_STAMPING AND NOT APPLE)
71		get_source_file_property(_abs "${filename}" LOCATION)
72		if(NOT _abs)
73			get_filename_component(_abs "${filename}" ABSOLUTE)
74		endif()
75		file(RELATIVE_PATH _rel "${CMAKE_SOURCE_DIR}" "${_abs}")
76		if(NOT "${_rel}" MATCHES "[.][.]")
77			# Only if this file is in the source tree
78			get_filename_component(_name "${filename}" NAME)
79			set(_in_source_dir YES)
80			# Create the sed script
81			configure_file("${_sswv_mod_dir}/StampSourcesWithVersion.sed.in"
82				"${CMAKE_CURRENT_BINARY_DIR}/stamp-${_name}.sed"
83				@ONLY)
84
85			if(APPLE)
86				set(extendedre_arg -E)
87			else()
88				set(extendedre_arg -r)
89			endif()
90
91			set(sedargs
92				${extendedre_arg}
93				-f
94				"${CMAKE_CURRENT_BINARY_DIR}/stamp-${_name}.sed"
95				${filename})
96
97			# Run the sed script
98			execute_process(COMMAND
99				${SED_EXECUTABLE}
100				${sedargs}
101				OUTPUT_FILE
102				"${CMAKE_CURRENT_BINARY_DIR}/stampedoutput-${_name}.out"
103				WORKING_DIRECTORY
104				"${CMAKE_CURRENT_SOURCE_DIR}")
105
106			# Check to see if changes were made
107			execute_process(COMMAND
108				${CMAKE_COMMAND}
109				-E
110				compare_files
111				"${CMAKE_CURRENT_BINARY_DIR}/stampedoutput-${_name}.out"
112				${filename}
113				WORKING_DIRECTORY
114				"${CMAKE_CURRENT_SOURCE_DIR}"
115				RESULT_VARIABLE
116				files_different
117				OUTPUT_QUIET
118				ERROR_QUIET)
119
120			# if so, run it again, but in-place this time
121			if(files_different)
122				message(STATUS "Stamping file ${_rel} with version ${version}")
123				execute_process(COMMAND
124					${SED_EXECUTABLE}
125					-i
126					${sedargs}
127					OUTPUT_FILE
128					"${CMAKE_CURRENT_BINARY_DIR}/stampedoutput-${_name}.out"
129					WORKING_DIRECTORY
130					"${CMAKE_CURRENT_SOURCE_DIR}")
131			else()
132				message(STATUS "Version stamp up-to-date on file ${_rel}")
133			endif()
134		endif()
135	endif()
136endfunction()
137
138function(stamp_sources_with_version version)
139	foreach(_file ${ARGN})
140		_stamp_file_with_version("${version}" "${_file}")
141	endforeach()
142endfunction()
143
144function(stamp_target_with_version version target_name)
145
146	set(_target_stampables)
147
148	get_target_property(_target_sources ${target_name} SOURCES)
149	foreach(_source ${_target_sources})
150		get_source_file_property(_lang "${_source}" LANGUAGE)
151		get_source_file_property(_loc "${_source}" LOCATION)
152		if("${_lang}" MATCHES "CXX" OR "${_lang}" MATCHES "C")
153			list(APPEND _target_stampables "${_loc}")
154		endif()
155	endforeach()
156
157	set(_src_to_stamp)
158	if("${ARGN}" STREQUAL "HEADERS_ONLY")
159		# We were passed HEADERS_ONLY
160		foreach(_file ${_target_stampables})
161			get_filename_component(_ext "${_file}" EXT)
162			if("${_ext}" MATCHES "[.]([hH]|hpp|HPP|hxx|HXX)$" OR NOT _ext)
163				list(APPEND _src_to_stamp "${_file}")
164			endif()
165		endforeach()
166
167	elseif(ARGN)
168		# We were passed a list of files
169		set(_src_to_stamp ${ARGN})
170
171	else()
172		# We were passed only a target - process all source in the source tree.
173		set(_src_to_stamp ${_target_stampables})
174	endif()
175
176	stamp_sources_with_version(${version} ${_src_to_stamp})
177endfunction()
178
179
180
181