summaryrefslogtreecommitdiff
path: root/cmake
diff options
context:
space:
mode:
authorAdam <Adam@anope.org>2010-07-15 22:55:02 -0400
committerAdam <Adam@anope.org>2010-07-15 22:55:02 -0400
commita22f8d3b2de88b9bb6f80f0c2780846ae23ab389 (patch)
treea2fdf570868896a787df8a1169951b0028e68d6b /cmake
parent43b1e43afb85639485e36d24da351dc0f121be6e (diff)
Moved some files and diretories around, made cmake skip files it knows it can't compile because of missing dependices.
Diffstat (limited to 'cmake')
-rw-r--r--cmake/Anope.cmake540
-rw-r--r--cmake/NSIS.template.in825
-rw-r--r--cmake/ReadFile.cmake5
3 files changed, 1370 insertions, 0 deletions
diff --git a/cmake/Anope.cmake b/cmake/Anope.cmake
new file mode 100644
index 000000000..97734199f
--- /dev/null
+++ b/cmake/Anope.cmake
@@ -0,0 +1,540 @@
+###############################################################################
+# strip_string(<input string> <output string>)
+#
+# A macro to handle stripping the leading and trailing spaces from a string,
+# uses string(STRIP) if using CMake 2.6.x or better, otherwise uses
+# string(REGEX REPLACE).
+###############################################################################
+macro(strip_string INPUT_STRING OUTPUT_STRING)
+ if(CMAKE26_OR_BETTER)
+ # For CMake 2.6.x or better, we can just use the STRIP sub-command of string()
+ string(STRIP ${INPUT_STRING} ${OUTPUT_STRING})
+ else(CMAKE26_OR_BETTER)
+ # For CMake 2.4.x, we will have to use the REGEX REPLACE sub-command of string() instead
+ # First check if the input string is empty or not
+ if (${INPUT_STRING} STREQUAL "")
+ set(${OUTPUT_STRING} "")
+ else(${INPUT_STRING} STREQUAL "")
+ # Determine if the string is entirely empty or not
+ string(REGEX MATCH "^[ \t]*$" EMPTY_STRING "${INPUT_STRING}")
+ if(EMPTY_STRING)
+ set(${OUTPUT_STRING} "")
+ else(EMPTY_STRING)
+ # We detect if there is any leading whitespace and remove any if there is
+ string(SUBSTRING "${INPUT_STRING}" 0 1 FIRST_CHAR)
+ if(FIRST_CHAR STREQUAL " " OR FIRST_CHAR STREQUAL "\t")
+ string(REGEX REPLACE "^[ \t]+" "" TEMP_STRING "${INPUT_STRING}")
+ else(FIRST_CHAR STREQUAL " " OR FIRST_CHAR STREQUAL "\t")
+ set(TEMP_STRING "${INPUT_STRING}")
+ endif(FIRST_CHAR STREQUAL " " OR FIRST_CHAR STREQUAL "\t")
+ # Next we detect if there is any trailing whitespace and remove any if there is
+ string(LENGTH "${TEMP_STRING}" STRING_LEN)
+ math(EXPR STRING_LEN "${STRING_LEN} - 1")
+ string(SUBSTRING "${TEMP_STRING}" ${STRING_LEN} 1 LAST_CHAR)
+ if(LAST_CHAR STREQUAL " " OR LAST_CHAR STREQUAL "\t")
+ string(REGEX REPLACE "[ \t]+$" "" ${OUTPUT_STRING} "${TEMP_STRING}")
+ else(LAST_CHAR STREQUAL " " OR LAST_CHAR STREQUAL "\t")
+ set(${OUTPUT_STRING} "${TEMP_STRING}")
+ endif(LAST_CHAR STREQUAL " " OR LAST_CHAR STREQUAL "\t")
+ endif(EMPTY_STRING)
+ endif(${INPUT_STRING} STREQUAL "")
+ endif(CMAKE26_OR_BETTER)
+endmacro(strip_string)
+
+###############################################################################
+# append_to_list(<list> <args>...)
+#
+# A macro to handle appending to lists, uses list(APPEND) if using CMake 2.4.2
+# or better, otherwise uses set() instead.
+###############################################################################
+macro(append_to_list LIST)
+ if(CMAKE242_OR_BETTER)
+ # For CMake 2.4.2 or better, we can just use the APPEND sub-command of list()
+ list(APPEND ${LIST} ${ARGN})
+ else(CMAKE242_OR_BETTER)
+ # For CMake 2.4.x before 2.4.2, we have to do this manually use set() instead
+ set(${LIST} ${${LIST}} ${ARGN})
+ endif(CMAKE242_OR_BETTER)
+endmacro(append_to_list)
+
+###############################################################################
+# find_in_list(<list> <value> <output variable>)
+#
+# A macro to handle searching within a list, will store the result in the
+# given <output variable>, uses list(FIND) if using CMake 2.6.x or better
+# (or CMake 2.4.8 or better), otherwise it iterates through the list to find
+# the item.
+###############################################################################
+macro(find_in_list LIST ITEM_TO_FIND FOUND)
+ if(CMAKE248_OR_BETTER)
+ # For CMake 2.4.8 or better, we can use the FIND sub-command of list()
+ list(FIND ${LIST} ${ITEM_TO_FIND} ITEM_FOUND)
+ else(CMAKE248_OR_BETTER)
+ # For CMake 2.4.x before 2.4.8, we have to do this ourselves (NOTE: This is very slow due to a lack of break() as well)
+ # Firstly we set the position to -1 indicating nothing found, we also use a temporary position
+ set(ITEM_FOUND -1)
+ set(POS 0)
+ # Iterate through the list
+ foreach(ITEM ${${LIST}})
+ # If the item we are looking at is the item we are trying to find, set that we've found the item
+ if(${ITEM} STREQUAL ${ITEM_TO_FIND})
+ set(ITEM_FOUND ${POS})
+ endif(${ITEM} STREQUAL ${ITEM_TO_FIND})
+ # Increase the position value by 1
+ math(EXPR POS "${POS} + 1")
+ endforeach(ITEM)
+ endif(CMAKE248_OR_BETTER)
+ # Set the given FOUND variable to the result
+ set(${FOUND} ${ITEM_FOUND})
+endmacro(find_in_list)
+
+###############################################################################
+# remove_list_duplicates(<list>)
+#
+# A macro to handle removing duplicates from a list, uses
+# list(REMOVE_DUPLICATES) if using CMake 2.6.x or better, otherwise it uses
+# a slower method of creating a temporary list and only adding to it when
+# a duplicate item hasn't been found.
+###############################################################################
+macro(remove_list_duplicates LIST)
+ if(CMAKE26_OR_BETTER)
+ # For CMake 2.6.x or better, this can be done automatically
+ list(REMOVE_DUPLICATES ${LIST})
+ else(CMAKE26_OR_BETTER)
+ # For CMake 2.4.x, we have to do this ourselves, firstly we'll clear a temporary list
+ set(NEW_LIST)
+ # Iterate through the old list
+ foreach(ITEM ${${LIST}})
+ # Check if the item is in the new list
+ find_in_list(NEW_LIST ${ITEM} FOUND_ITEM)
+ if(FOUND_ITEM EQUAL -1)
+ # If the item was not found, append it to the list
+ append_to_list(NEW_LIST ${ITEM})
+ endif(FOUND_ITEM EQUAL -1)
+ endforeach(ITEM)
+ # Replace the old list with the new list
+ set(${LIST} ${NEW_LIST})
+ endif(CMAKE26_OR_BETTER)
+endmacro(remove_list_duplicates)
+
+###############################################################################
+# remove_item_from_list(<list> <value>)
+#
+# A macro to handle removing a value from a list, uses list(REMOVE_ITEM) in
+# both cases, but can remove the value itself using CMake 2.4.2 or better,
+# while older versions use a slower method of iterating the list to find the
+# index of the value to remove.
+###############################################################################
+macro(remove_item_from_list LIST VALUE)
+ if(CMAKE242_OR_BETTER)
+ # For CMake 2.4.2 or better, this can be done automatically
+ list(REMOVE_ITEM ${LIST} ${VALUE})
+ else(CMAKE242_OR_BETTER)
+ # For CMake 2.4.x before 2.4.2, we have to do this ourselves, firstly we set the index and a variable to indicate if the item was found
+ set(INDEX 0)
+ set(FOUND FALSE)
+ # Iterate through the old list
+ foreach(ITEM ${${LIST}})
+ # If the item hasn't been found yet, but the current item is the same, remove it
+ if(NOT FOUND)
+ if(ITEM STREQUAL ${VALUE})
+ set(FOUND TRUE)
+ list(REMOVE_ITEM ${LIST} ${INDEX})
+ endif(ITEM STREQUAL ${VALUE})
+ endif(NOT FOUND)
+ # Increase the index value by 1
+ math(EXPR INDEX "${INDEX} + 1")
+ endforeach(ITEM)
+ endif(CMAKE242_OR_BETTER)
+endmacro(remove_item_from_list)
+
+###############################################################################
+# sort_list(<list>)
+#
+# A macro to handle sorting a list, uses list(SORT) if using CMake 2.4.4 or
+# better, otherwise it uses a slower method of creating a temporary list and
+# adding elements in alphabetical order.
+###############################################################################
+macro(sort_list LIST)
+ if(CMAKE244_OR_BETTER)
+ # For CMake 2.4.4 or better, this can be done automatically
+ list(SORT ${LIST})
+ else(CMAKE244_OR_BETTER)
+ # For CMake 2.4.x before 2.4.4, we have to do this ourselves, firstly we'll create a teporary list
+ set(NEW_LIST)
+ # Iterate through the old list
+ foreach(ITEM ${${LIST}})
+ # Temporary index position for the new list, as well as temporary value to store if the item was ever found
+ set(INDEX 0)
+ set(FOUND FALSE)
+ # Iterate through the new list
+ foreach(NEW_ITEM ${NEW_LIST})
+ # Compare the items, only if nothing was found before
+ if(NOT FOUND)
+ if(NEW_ITEM STRGREATER "${ITEM}")
+ set(FOUND TRUE)
+ list(INSERT NEW_LIST ${INDEX} ${ITEM})
+ endif(NEW_ITEM STRGREATER "${ITEM}")
+ endif(NOT FOUND)
+ # Increase the index value by 1
+ math(EXPR INDEX "${INDEX} + 1")
+ endforeach(NEW_ITEM)
+ # If the item was never found, just append it to the end
+ if(NOT FOUND)
+ append_to_list(NEW_LIST ${ITEM})
+ endif(NOT FOUND)
+ endforeach(ITEM)
+ # Replace the old list with the new list
+ set(${LIST} ${NEW_LIST})
+ endif(CMAKE244_OR_BETTER)
+endmacro(sort_list)
+
+###############################################################################
+# read_from_file(<filename> <regex> <output variable>)
+#
+# A macro to handle reading specific lines from a file, uses file(STRINGS) if
+# using CMake 2.6.x or better, otherwise we read in the entire file and
+# perform a string(REGEX MATCH) on each line of the file instead. This
+# macro can also be used to read in all the lines of a file if REGEX is set
+# to "".
+###############################################################################
+macro(read_from_file FILE REGEX STRINGS)
+ if(CMAKE26_OR_BETTER)
+ # For CMake 2.6.x or better, we can just use the STRINGS sub-command to get the lines that match the given regular expression (if one is given, otherwise get all lines)
+ if(REGEX STREQUAL "")
+ file(STRINGS ${FILE} RESULT)
+ else(REGEX STREQUAL "")
+ file(STRINGS ${FILE} RESULT REGEX ${REGEX})
+ endif(REGEX STREQUAL "")
+ else(CMAKE26_OR_BETTER)
+ # For CMake 2.4.x, we need to do this manually, firstly we read the file in
+ execute_process(COMMAND ${CMAKE_COMMAND} -DFILE:STRING=${FILE} -P ${Anope_SOURCE_DIR}/ReadFile.cmake ERROR_VARIABLE ALL_STRINGS)
+ # Next we replace all newlines with semicolons
+ string(REGEX REPLACE "\n" ";" ALL_STRINGS ${ALL_STRINGS})
+ if(REGEX STREQUAL "")
+ # For no regular expression, just set the result to all the lines
+ set(RESULT ${ALL_STRINGS})
+ else(REGEX STREQUAL "")
+ # Clear the result list
+ set(RESULT)
+ # Iterate through all the lines of the file
+ foreach(STRING ${ALL_STRINGS})
+ # Check for a match against the given regular expression
+ string(REGEX MATCH ${REGEX} STRING_MATCH ${STRING})
+ # If we had a match, append the match to the list
+ if(STRING_MATCH)
+ append_to_list(RESULT ${STRING})
+ endif(STRING_MATCH)
+ endforeach(STRING)
+ endif(REGEX STREQUAL "")
+ endif(CMAKE26_OR_BETTER)
+ # Set the given STRINGS variable to the result
+ set(${STRINGS} ${RESULT})
+endmacro(read_from_file)
+
+###############################################################################
+# extract_include_filename(<line> <output variable> [<optional output variable of quote type>])
+#
+# This macro will take a #include line and extract the filename.
+###############################################################################
+macro(extract_include_filename INCLUDE FILENAME)
+ # Strip the leading and trailing spaces from the include line
+ strip_string(${INCLUDE} INCLUDE_STRIPPED)
+ # Make sure to only do the following if there is a string
+ if(INCLUDE_STRIPPED STREQUAL "")
+ set(FILE "")
+ else(INCLUDE_STRIPPED STREQUAL "")
+ # Extract the filename including the quotes or angle brackets
+ string(REGEX REPLACE "^.*([\"<].*[\">]).*$" "\\1" FILE "${INCLUDE_STRIPPED}")
+ # If an optional 3rd argument is given, we'll store if the quote style was quoted or angle bracketed
+ if(${ARGC} GREATER 2)
+ string(SUBSTRING ${FILE} 0 1 QUOTE)
+ if(QUOTE STREQUAL "<")
+ set(${ARGV2} "angle brackets")
+ else(QUOTE STREQUAL "<")
+ set(${ARGV2} "quotes")
+ endif(QUOTE STREQUAL "<")
+ endif(${ARGC} GREATER 2)
+ # Now remove the quotes or angle brackets
+ string(REGEX REPLACE "^[\"<](.*)[\">]$" "\\1" FILE "${FILE}")
+ endif(INCLUDE_STRIPPED STREQUAL "")
+ # Set the filename to the the given variable
+ set(${FILENAME} "${FILE}")
+endmacro(extract_include_filename)
+
+###############################################################################
+# find_includes(<source filename> <output variable>)
+#
+# This macro will search through a file for #include lines, regardless of
+# whitespace, but only returns the lines that are valid for the current
+# platform CMake is running on.
+###############################################################################
+macro(find_includes SRC INCLUDES)
+ # Read all lines from the file that start with #, regardless of whitespace before the #
+ read_from_file(${SRC} "^[ \t]*#.*$" LINES)
+ # Set that any #include lines found are valid, and create temporary variables for the last found #ifdef/#ifndef
+ set(VALID_LINE TRUE)
+ set(LAST_DEF)
+ set(LAST_CHECK)
+ # Create an empty include list
+ set(INCLUDES_LIST)
+ # Iterate through all the # lines
+ foreach(LINE ${LINES})
+ # Search for #ifdef, #ifndef, #else, #endif, and #include
+ string(REGEX MATCH "^[ \t]*#[ \t]*ifdef[ \t]*.*$" FOUND_IFDEF ${LINE})
+ string(REGEX MATCH "^[ \t]*#[ \t]*ifndef[ \t]*.*$" FOUND_IFNDEF ${LINE})
+ string(REGEX MATCH "^[ \t]*#[ \t]*else.*$" FOUND_ELSE ${LINE})
+ string(REGEX MATCH "^[ \t]*#[ \t]*endif.*$" FOUND_ENDIF ${LINE})
+ string(REGEX MATCH "^[ \t]*#[ \t]*include[ \t]*[\"<].*[\">][\ t]*.*$" FOUND_INCLUDE ${LINE})
+ # If we found a #ifdef on the line, extract the data after the #ifdef and set if the lines after it are valid based on the variables in CMake
+ if(FOUND_IFDEF)
+ # Extract the define
+ string(REGEX REPLACE "^[ \t]*#[ \t]*ifdef[ \t]*(.*)$" "\\1" DEFINE ${LINE})
+ # Replace _WIN32 with WIN32, so we can check if the WIN32 variable of CMake is set instead of _WIN32
+ if(DEFINE STREQUAL "_WIN32")
+ set(DEFINE WIN32)
+ endif(DEFINE STREQUAL "_WIN32")
+ # Set the last define to this one, and set the last check to true, so when #else is encountered, we can do an opposing check
+ set(LAST_DEF ${DEFINE})
+ set(LAST_CHECK TRUE)
+ # If the define is true (it either exists or is a non-false result), the lines following will be checked, otherwise they will be skipped
+ if(${DEFINE})
+ set(VALID_LINE TRUE)
+ else(${DEFINE})
+ set(VALID_LINE FALSE)
+ endif(${DEFINE})
+ else(FOUND_IFDEF)
+ # If we found a #ifndef on the line, the same thing as #ifdef is done, except with the checks in the opposite direction
+ if(FOUND_IFNDEF)
+ # Extract the define
+ string(REGEX REPLACE "^[ \t]*#[ \t]*ifndef[ \t]*(.*)$" "\\1" DEFINE ${LINE})
+ # Replace _WIN32 with WIN32, so we can check if the WIN32 variable of CMake is set instead of _WIN32
+ if(DEFINE STREQUAL "_WIN32")
+ set(DEFINE WIN32)
+ endif(DEFINE STREQUAL "_WIN32")
+ # Set the last define to this one, and set the last check to false, so when #else is encountered, we can do an opposing check
+ set(LAST_DEF ${DEFINE})
+ set(LAST_CHECK FALSE)
+ # If the define is not true (it either doesn't exists or is a false result), the lines following will be checked, otherwise they will be skipped
+ if(${DEFINE})
+ set(VALID_LINE FALSE)
+ else(${DEFINE})
+ set(VALUE_LINE TRUE)
+ endif(${DEFINE})
+ else(FOUND_IFNDEF)
+ # If we found a #else on the line, we check the last define in the opposite direction
+ if(FOUND_ELSE)
+ # When LAST_CHECK is true, we were inside a #ifdef, now act as if we are entering a #ifndef section by doing an opposing check
+ if(LAST_CHECK)
+ if(${LAST_DEF})
+ set(VALID_LINE FALSE)
+ else(${LAST_DEF})
+ set(VALID_LINE TRUE)
+ endif(${LAST_DEF})
+ # When LAST_CHECK is false, we were inside a #ifndef, now act as if we are entering a #ifdef section by doing an opposing check
+ else(LAST_CHECK)
+ if(${LAST_DEF})
+ set(VALID_LINE TRUE)
+ else(${LAST_DEF})
+ set(VALID_LINE FALSE)
+ endif(${LAST_DEF})
+ endif(LAST_CHECK)
+ else(FOUND_ELSE)
+ # If we found a #endif on the line, we'll assume everything following the line is valid until we meet another one of the above lines
+ if(FOUND_ENDIF)
+ set(VALID_LINE TRUE)
+ else(FOUND_ENDIF)
+ # If we found a #include on the line, add the entire line to the list of includes unless the line isn't valid
+ if(FOUND_INCLUDE)
+ if(VALID_LINE)
+ append_to_list(INCLUDES_LIST "${LINE}")
+ endif(VALID_LINE)
+ endif(FOUND_INCLUDE)
+ endif(FOUND_ENDIF)
+ endif(FOUND_ELSE)
+ endif(FOUND_IFNDEF)
+ endif(FOUND_IFDEF)
+ endforeach(LINE)
+ set(${INCLUDES} ${INCLUDES_LIST})
+endmacro(find_includes)
+
+###############################################################################
+# calculate_depends(<source filename> <output variable set to TRUE on fail> [<optional output variable for includes>])
+#
+# This macro is used in most of the src (sub)directories to calculate the
+# header file dependencies for the given source file.
+###############################################################################
+macro(calculate_depends SRC SKIP)
+ # Temporarily set that we didn't get a 2nd argument before we actually check if we did get one or not
+ set(CHECK_ANGLE_INCLUDES FALSE)
+ # Check for a second argument
+ if(${ARGC} GREATER 1)
+ set(CHECK_ANGLE_INCLUDES TRUE)
+ endif(${ARGC} GREATER 1)
+ # Find all the lines in the given source file that have any form of #include on them, regardless of whitespace, but only if they are valid for the platform we are on
+ find_includes(${SRC} INCLUDES)
+ # Reset the list of headers to empty
+ set(HEADERS)
+ # Reset skip
+ set(${SKIP} FALSE)
+ # Iterate through the strings containing #include (if any)
+ foreach(INCLUDE ${INCLUDES})
+ # Extract the filename from the #include line
+ extract_include_filename(${INCLUDE} FILENAME QUOTE_TYPE)
+ if(QUOTE_TYPE STREQUAL "angle brackets")
+ # The following checks will only be done if there was a request for angle includes to be checked
+ if(CHECK_ANGLE_INCLUDES)
+ # Find the path of the include file
+ if(DEFAULT_INCLUDE_DIRS OR WSDK_PATH OR DEFINED $ENV{VCINSTALLDIR})
+ find_path(FOUND_${FILENAME}_INCLUDE NAMES ${FILENAME} PATHS ${DEFAULT_INCLUDE_DIRS} ${WSDK_PATH}/include $ENV{VCINSTALLDIR}/include)
+ else(DEFAULT_INCLUDE_DIRS OR WSDK_PATH OR DEFINED $ENV{VCINSTALLDIR})
+ find_path(FOUND_${FILENAME}_INCLUDE NAMES ${FILENAME})
+ endif(DEFAULT_INCLUDE_DIRS OR WSDK_PATH OR DEFINED $ENV{VCINSTALLDIR})
+ # If the include file was found, add it's path to the list of include paths, but only if it doesn't already exist and isn't in the defaults for the compiler
+ if(FOUND_${FILENAME}_INCLUDE)
+ find_in_list(DEFAULT_INCLUDE_DIRS "${FOUND_${FILENAME}_INCLUDE}" FOUND_IN_DEFAULTS)
+ if(FOUND_IN_DEFAULTS EQUAL -1)
+ find_in_list(${ARGV1} "${FOUND_${FILENAME}_INCLUDE}" FOUND_IN_INCLUDES)
+ if(FOUND_IN_INCLUDES EQUAL -1)
+ append_to_list(${ARGV1} "${FOUND_${FILENAME}_INCLUDE}")
+ endif(FOUND_IN_INCLUDES EQUAL -1)
+ endif(FOUND_IN_DEFAULTS EQUAL -1)
+ else(FOUND_${FILENAME}_INCLUDE)
+ set(${SKIP} TRUE)
+ message("${SRC} needs header file ${FILENAME} but we were unable to locate that header file! Check that the header file is within the search path of your OS.")
+ endif(FOUND_${FILENAME}_INCLUDE)
+ endif(CHECK_ANGLE_INCLUDES)
+ endif(QUOTE_TYPE STREQUAL "angle brackets")
+ endforeach(INCLUDE)
+endmacro(calculate_depends)
+
+###############################################################################
+# calculate_libraries(<source filename> <output variable set to TRUE on fail> <output variable for linker flags> <output variable for extra depends>)
+#
+# This macro is used in most of the module (sub)directories to calculate the
+# library dependencies for the given source file.
+###############################################################################
+macro(calculate_libraries SRC SKIP SRC_LDFLAGS EXTRA_DEPENDS)
+ # Set up a temporary LDFLAGS for this file
+ set(THIS_LDFLAGS "${LDFLAGS}")
+ # Reset extra dependencies
+ set(EXTRA_DEPENDENCIES)
+ # Reset library paths
+ set(LIBRARY_PATHS)
+ # Reset libraries
+ set(LIBRARIES)
+ # Default to not skipping this file
+ set(${SKIP} FALSE)
+ # Check to see if there are any lines matching: /* RequiredLibraries: [something] */
+ read_from_file(${SRC} "/\\\\*[ \t]*RequiredLibraries:[ \t]*.*[ \t]*\\\\*/" REQUIRED_LIBRARIES)
+ # Iterate through those lines
+ foreach(REQUIRED_LIBRARY ${REQUIRED_LIBRARIES})
+ # Strip off the /* RequiredLibraries: and */ from the line
+ string(REGEX REPLACE "/\\*[ \t]*RequiredLibraries:[ \t]*([^ \t]*)[ \t]*\\*/" "\\1" REQUIRED_LIBRARY ${REQUIRED_LIBRARY})
+ # Replace all commas with semicolons
+ string(REGEX REPLACE "," ";" REQUIRED_LIBRARY ${REQUIRED_LIBRARY})
+ # Iterate through the libraries given
+ foreach(LIBRARY ${REQUIRED_LIBRARY})
+ # Locate the library to see if it exists
+ if(DEFAULT_LIBRARY_DIRS OR WSDK_PATH OR DEFINED $ENV{VCINSTALLDIR})
+ find_library(FOUND_${LIBRARY}_LIBRARY NAMES ${LIBRARY} PATHS ${DEFAULT_LIBRARY_DIRS} ${WSDK_PATH}/lib $ENV{VCINSTALLDIR}/lib)
+ else(DEFAULT_LIBRARY_DIRS OR WSDK_PATH OR DEFINED $ENV{VCINSTALLDIR})
+ find_library(FOUND_${LIBRARY}_LIBRARY NAMES ${LIBRARY})
+ endif(DEFAULT_LIBRARY_DIRS OR WSDK_PATH OR DEFINED $ENV{VCINSTALLDIR})
+ # If the library was found, we will add it to the linker flags
+ if(FOUND_${LIBRARY}_LIBRARY)
+ # Get the path only of the library, to add it to linker flags
+ get_filename_component(LIBRARY_PATH ${FOUND_${LIBRARY}_LIBRARY} PATH)
+ if(MSVC)
+ # For Visual Studio, instead of editing the linker flags, we'll add the library to a separate list of extra dependencies
+ append_to_list(EXTRA_DEPENDENCIES "${FOUND_${LIBRARY}_LIBRARY}")
+ else(MSVC)
+ # For all others, add the library paths and libraries
+ append_to_list(LIBRARY_PATHS "${LIBRARY_PATH}")
+ append_to_list(LIBRARIES "${LIBRARY}")
+ endif(MSVC)
+ else(FOUND_${LIBRARY}_LIBRARY)
+ # Skip this file
+ set(${SKIP} TRUE)
+ # In the case of the library not being found, we fatally error so CMake stops trying to generate
+ message("${SRC} needs library ${LIBRARY} but we were unable to locate that library! Check that the library is within the search path of your OS.")
+ endif(FOUND_${LIBRARY}_LIBRARY)
+ endforeach(LIBRARY)
+ endforeach(REQUIRED_LIBRARY)
+ if(NOT ${SKIP})
+ # Remove duplicates from the library paths
+ if(LIBRARY_PATHS)
+ remove_list_duplicates(LIBRARY_PATHS)
+ endif(LIBRARY_PATHS)
+ # Remove diplicates from the libraries
+ if(LIBRARIES)
+ remove_list_duplicates(LIBRARIES)
+ endif(LIBRARIES)
+ # Iterate through library paths and add them to the linker flags
+ foreach(LIBRARY_PATH ${LIBRARY_PATHS})
+ find_in_list(DEFAULT_LIBRARY_DIRS "${LIBRARY_PATH}" FOUND_IN_DEFAULTS)
+ if(FOUND_IN_DEFAULTS EQUAL -1)
+ set(THIS_LDFLAGS "${THIS_LDFLAGS} -L${LIBRARY_PATH}")
+ endif(FOUND_IN_DEFAULTS EQUAL -1)
+ endforeach(LIBRARY_PATH)
+ # Iterate through libraries and add them to the linker flags
+ foreach(LIBRARY ${LIBRARIES})
+ set(THIS_LDFLAGS "${THIS_LDFLAGS} -l${LIBRARY}")
+ endforeach(LIBRARY)
+ set(${SRC_LDFLAGS} "${THIS_LDFLAGS}")
+ set(${EXTRA_DEPENDS} "${EXTRA_DEPENDENCIES}")
+ endif(NOT ${SKIP})
+endmacro(calculate_libraries)
+
+###############################################################################
+# check_functions(<source filename> <output variable set to TRUE on success>)
+#
+# This macro is used in most of the module (sub)directories to calculate the
+# fcuntion dependencies for the given source file.
+###############################################################################
+macro(check_functions SRC SUCCESS)
+ # Default to true
+ set(${SUCCESS} TRUE)
+ # Check to see if there are any lines matching: /* RequiredFunctions: [something] */
+ read_from_file(${SRC} "/\\\\*[ \t]*RequiredFunctions:[ \t]*.*[ \t]*\\\\*/" REQUIRED_FUNCTIONS)
+ # Iterate through those lines
+ foreach(REQUIRED_FUNCTION ${REQUIRED_FUNCTIONS})
+ # Strip off the /* RequiredFunctions: and */ from the line
+ string(REGEX REPLACE "/\\*[ \t]*RequiredFunctions:[ \t]*([^ \t]*)[ \t]*\\*/" "\\1" REQUIRED_FUNCTION ${REQUIRED_FUNCTION})
+ # Replace all commas with semicolons
+ string(REGEX REPLACE "," ";" REQUIRED_FUNCTION ${REQUIRED_FUNCTION})
+ # Iterate through the functions given
+ foreach(FUNCTION ${REQUIRED_FUNCTION})
+ # Check if the function exists
+ check_function_exists(${REQUIRED_FUNCTION} HAVE_${REQUIRED_FUNCTION})
+ # If we don't have the function warn the user and set SUCCESS to FALSE
+ if(NOT HAVE_${REQUIRED_FUNCTION})
+ message("${SRC} needs function ${REQUIRED_FUNCTION} but we were unable to locate that function!")
+ set(${SUCCESS} FALSE)
+ endif(NOT HAVE_${REQUIRED_FUNCTION})
+ endforeach(FUNCTION)
+ endforeach(REQUIRED_FUNCTION)
+endmacro(check_functions)
+
+###############################################################################
+# add_to_cpack_ignored_files(<item> [TRUE])
+#
+# A macro to update the environment variable CPACK_IGNORED_FILES which
+# contains a list of files for CPack to ignore. If the optional 2nd argument
+# of TRUE is given, periods will be converted to \\. for CPack.
+###############################################################################
+macro(add_to_cpack_ignored_files ITEM)
+ # Temporary copy of the orignal item
+ set(REAL_ITEM "${ITEM}")
+ # If we have 2+ arguments, assume that the second one was something like TRUE (doesn't matter really) and convert periods so they will be \\. for CPack
+ if(${ARGC} GREATER 1)
+ string(REPLACE "." "\\\\." REAL_ITEM ${REAL_ITEM})
+ endif(${ARGC} GREATER 1)
+ # If the environment variable is already defined, just tack the item to the end
+ if(DEFINED ENV{CPACK_IGNORED_FILES})
+ set(ENV{CPACK_IGNORED_FILES} "$ENV{CPACK_IGNORED_FILES};${REAL_ITEM}")
+ # Otherwise set the environment variable to the item
+ else(DEFINED ENV{CPACK_IGNORED_FILES})
+ set(ENV{CPACK_IGNORED_FILES} "${REAL_ITEM}")
+ endif(DEFINED ENV{CPACK_IGNORED_FILES})
+endmacro(add_to_cpack_ignored_files)
diff --git a/cmake/NSIS.template.in b/cmake/NSIS.template.in
new file mode 100644
index 000000000..a9c91a2b7
--- /dev/null
+++ b/cmake/NSIS.template.in
@@ -0,0 +1,825 @@
+; CPack install script designed for a nmake build
+
+;--------------------------------
+; You must define these values
+
+ !define VERSION "@CPACK_PACKAGE_VERSION@"
+ !define INST_DIR "@CPACK_TEMPORARY_DIRECTORY@"
+
+;--------------------------------
+;Variables
+
+ Var MUI_TEMP
+ Var STARTMENU_FOLDER
+ Var SV_ALLUSERS
+ Var START_MENU
+ Var DO_NOT_ADD_TO_PATH
+ Var ADD_TO_PATH_ALL_USERS
+ Var ADD_TO_PATH_CURRENT_USER
+ Var INSTALL_DESKTOP
+
+;--------------------------------
+;Include Modern UI
+
+ !include "MUI2.nsh"
+
+ ;Default installation folder
+ InstallDir "$PROGRAMFILES\@CPACK_PACKAGE_INSTALL_DIRECTORY@"
+
+;--------------------------------
+;General
+
+ ;Name and file
+ Name "@CPACK_PACKAGE_NAME@ @CPACK_PACKAGE_VERSION@"
+ OutFile "@CPACK_TOPLEVEL_DIRECTORY@/@CPACK_OUTPUT_FILE_NAME@"
+
+ ;Set compression
+ SetCompressor @CPACK_NSIS_COMPRESSOR@
+
+@CPACK_NSIS_DEFINES@
+
+ !include Sections.nsh
+
+;--- Component support macros: ---
+; The code for the add/remove functionality is from:
+; http://nsis.sourceforge.net/Add/Remove_Functionality
+; It has been modified slightly and extended to provide
+; inter-component dependencies.
+Var AR_SecFlags
+Var AR_RegFlags
+@CPACK_NSIS_SECTION_SELECTED_VARS@
+
+; Loads the "selected" flag for the section named SecName into the
+; variable VarName.
+!macro LoadSectionSelectedIntoVar SecName VarName
+ SectionGetFlags ${${SecName}} $${VarName}
+ IntOp $${VarName} $${VarName} & ${SF_SELECTED} ;Turn off all other bits
+!macroend
+
+; Loads the value of a variable... can we get around this?
+!macro LoadVar VarName
+ IntOp $R0 0 + $${VarName}
+!macroend
+
+; Sets the value of a variable
+!macro StoreVar VarName IntValue
+ IntOp $${VarName} 0 + ${IntValue}
+!macroend
+
+!macro InitSection SecName
+ ; This macro reads component installed flag from the registry and
+ ;changes checked state of the section on the components page.
+ ;Input: section index constant name specified in Section command.
+
+ ClearErrors
+ ;Reading component status from registry
+ ReadRegDWORD $AR_RegFlags HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_NAME@\Components\${SecName}" "Installed"
+ IfErrors "default_${SecName}"
+ ;Status will stay default if registry value not found
+ ;(component was never installed)
+ IntOp $AR_RegFlags $AR_RegFlags & ${SF_SELECTED} ;Turn off all other bits
+ SectionGetFlags ${${SecName}} $AR_SecFlags ;Reading default section flags
+ IntOp $AR_SecFlags $AR_SecFlags & 0xFFFE ;Turn lowest (enabled) bit off
+ IntOp $AR_SecFlags $AR_RegFlags | $AR_SecFlags ;Change lowest bit
+
+ ; Note whether this component was installed before
+ !insertmacro StoreVar ${SecName}_was_installed $AR_RegFlags
+ IntOp $R0 $AR_RegFlags & $AR_RegFlags
+
+ ;Writing modified flags
+ SectionSetFlags ${${SecName}} $AR_SecFlags
+
+ "default_${SecName}:"
+ !insertmacro LoadSectionSelectedIntoVar ${SecName} ${SecName}_selected
+!macroend
+
+!macro FinishSection SecName
+ ; This macro reads section flag set by user and removes the section
+ ;if it is not selected.
+ ;Then it writes component installed flag to registry
+ ;Input: section index constant name specified in Section command.
+
+ SectionGetFlags ${${SecName}} $AR_SecFlags ;Reading section flags
+ ;Checking lowest bit:
+ IntOp $AR_SecFlags $AR_SecFlags & ${SF_SELECTED}
+ IntCmp $AR_SecFlags 1 "leave_${SecName}"
+ ;Section is not selected:
+ ;Calling Section uninstall macro and writing zero installed flag
+ !insertmacro "Remove_${${SecName}}"
+ WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_NAME@\Components\${SecName}" \
+ "Installed" 0
+ Goto "exit_${SecName}"
+
+ "leave_${SecName}:"
+ ;Section is selected:
+ WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_NAME@\Components\${SecName}" \
+ "Installed" 1
+
+ "exit_${SecName}:"
+!macroend
+
+!macro RemoveSection SecName
+ ; This macro is used to call section's Remove_... macro
+ ;from the uninstaller.
+ ;Input: section index constant name specified in Section command.
+
+ !insertmacro "Remove_${${SecName}}"
+!macroend
+
+; Determine whether the selection of SecName changed
+!macro MaybeSelectionChanged SecName
+ !insertmacro LoadVar ${SecName}_selected
+ SectionGetFlags ${${SecName}} $R1
+ IntOp $R1 $R1 & ${SF_SELECTED} ;Turn off all other bits
+
+ ; See if the status has changed:
+ IntCmp $R0 $R1 "${SecName}_unchanged"
+ !insertmacro LoadSectionSelectedIntoVar ${SecName} ${SecName}_selected
+
+ IntCmp $R1 ${SF_SELECTED} "${SecName}_was_selected"
+ !insertmacro "Deselect_required_by_${SecName}"
+ goto "${SecName}_unchanged"
+
+ "${SecName}_was_selected:"
+ !insertmacro "Select_${SecName}_depends"
+
+ "${SecName}_unchanged:"
+!macroend
+;--- End of Add/Remove macros ---
+
+;--------------------------------
+;Interface Settings
+
+ !define MUI_ABORTWARNING
+
+;----------------------------------------
+; based upon a script of "Written by KiCHiK 2003-01-18 05:57:02"
+;----------------------------------------
+!verbose 3
+!include "WinMessages.NSH"
+!verbose 4
+
+;====================================================
+; get_NT_environment
+; Returns: the selected environment
+; Output : head of the stack
+;====================================================
+!macro select_NT_profile UN
+Function ${UN}select_NT_profile
+ StrCmp $ADD_TO_PATH_ALL_USERS "1" 0 environment_single
+ DetailPrint "Selected environment for all users"
+ Push "all"
+ Return
+ environment_single:
+ DetailPrint "Selected environment for current user only."
+ Push "current"
+ Return
+FunctionEnd
+!macroend
+!insertmacro select_NT_profile ""
+!insertmacro select_NT_profile "un."
+;----------------------------------------------------
+!define NT_current_env 'HKCU "Environment"'
+!define NT_all_env 'HKLM "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"'
+
+!ifndef WriteEnvStr_RegKey
+ !ifdef ALL_USERS
+ !define WriteEnvStr_RegKey \
+ 'HKLM "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"'
+ !else
+ !define WriteEnvStr_RegKey 'HKCU "Environment"'
+ !endif
+!endif
+
+; AddToPath - Adds the given dir to the search path.
+; Input - head of the stack
+; Note - Win9x systems requires reboot
+
+Function AddToPath
+ Exch $0
+ Push $1
+ Push $2
+ Push $3
+
+ # don't add if the path doesn't exist
+ IfFileExists "$0\*.*" "" AddToPath_done
+
+ ReadEnvStr $1 PATH
+ Push "$1;"
+ Push "$0;"
+ Call StrStr
+ Pop $2
+ StrCmp $2 "" "" AddToPath_done
+ Push "$1;"
+ Push "$0\;"
+ Call StrStr
+ Pop $2
+ StrCmp $2 "" "" AddToPath_done
+ GetFullPathName /SHORT $3 $0
+ Push "$1;"
+ Push "$3;"
+ Call StrStr
+ Pop $2
+ StrCmp $2 "" "" AddToPath_done
+ Push "$1;"
+ Push "$3\;"
+ Call StrStr
+ Pop $2
+ StrCmp $2 "" "" AddToPath_done
+
+ Call IsNT
+ Pop $1
+ StrCmp $1 1 AddToPath_NT
+ ; Not on NT
+ StrCpy $1 $WINDIR 2
+ FileOpen $1 "$1\autoexec.bat" a
+ FileSeek $1 -1 END
+ FileReadByte $1 $2
+ IntCmp $2 26 0 +2 +2 # DOS EOF
+ FileSeek $1 -1 END # write over EOF
+ FileWrite $1 "$\r$\nSET PATH=%PATH%;$3$\r$\n"
+ FileClose $1
+ SetRebootFlag true
+ Goto AddToPath_done
+
+ AddToPath_NT:
+ ReadRegStr $1 ${WriteEnvStr_RegKey} "PATH"
+ StrCmp $1 "" AddToPath_NTdoIt
+ Push $1
+ Call Trim
+ Pop $1
+ StrCpy $0 "$1;$0"
+ AddToPath_NTdoIt:
+ WriteRegExpandStr ${WriteEnvStr_RegKey} "PATH" $0
+ SendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} 0 "STR:Environment" /TIMEOUT=5000
+
+ AddToPath_done:
+ Pop $3
+ Pop $2
+ Pop $1
+ Pop $0
+FunctionEnd
+
+
+; RemoveFromPath - Remove a given dir from the path
+; Input: head of the stack
+
+Function un.RemoveFromPath
+ Exch $0
+ Push $1
+ Push $2
+ Push $3
+ Push $4
+ Push $5
+ Push $6
+
+ IntFmt $6 "%c" 26 # DOS EOF
+
+ Call un.IsNT
+ Pop $1
+ StrCmp $1 1 unRemoveFromPath_NT
+ ; Not on NT
+ StrCpy $1 $WINDIR 2
+ FileOpen $1 "$1\autoexec.bat" r
+ GetTempFileName $4
+ FileOpen $2 $4 w
+ GetFullPathName /SHORT $0 $0
+ StrCpy $0 "SET PATH=%PATH%;$0"
+ Goto unRemoveFromPath_dosLoop
+
+ unRemoveFromPath_dosLoop:
+ FileRead $1 $3
+ StrCpy $5 $3 1 -1 # read last char
+ StrCmp $5 $6 0 +2 # if DOS EOF
+ StrCpy $3 $3 -1 # remove DOS EOF so we can compare
+ StrCmp $3 "$0$\r$\n" unRemoveFromPath_dosLoopRemoveLine
+ StrCmp $3 "$0$\n" unRemoveFromPath_dosLoopRemoveLine
+ StrCmp $3 "$0" unRemoveFromPath_dosLoopRemoveLine
+ StrCmp $3 "" unRemoveFromPath_dosLoopEnd
+ FileWrite $2 $3
+ Goto unRemoveFromPath_dosLoop
+ unRemoveFromPath_dosLoopRemoveLine:
+ SetRebootFlag true
+ Goto unRemoveFromPath_dosLoop
+
+ unRemoveFromPath_dosLoopEnd:
+ FileClose $2
+ FileClose $1
+ StrCpy $1 $WINDIR 2
+ Delete "$1\autoexec.bat"
+ CopyFiles /SILENT $4 "$1\autoexec.bat"
+ Delete $4
+ Goto unRemoveFromPath_done
+
+ unRemoveFromPath_NT:
+ ReadRegStr $1 ${WriteEnvStr_RegKey} "PATH"
+ StrCpy $5 $1 1 -1 # copy last char
+ StrCmp $5 ";" +2 # if last char != ;
+ StrCpy $1 "$1;" # append ;
+ Push $1
+ Push "$0;"
+ Call un.StrStr ; Find `$0;` in $1
+ Pop $2 ; pos of our dir
+ StrCmp $2 "" unRemoveFromPath_done
+ ; else, it is in path
+ # $0 - path to add
+ # $1 - path var
+ StrLen $3 "$0;"
+ StrLen $4 $2
+ StrCpy $5 $1 -$4 # $5 is now the part before the path to remove
+ StrCpy $6 $2 "" $3 # $6 is now the part after the path to remove
+ StrCpy $3 $5$6
+
+ StrCpy $5 $3 1 -1 # copy last char
+ StrCmp $5 ";" 0 +2 # if last char == ;
+ StrCpy $3 $3 -1 # remove last char
+
+ WriteRegExpandStr ${WriteEnvStr_RegKey} "PATH" $3
+ SendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} 0 "STR:Environment" /TIMEOUT=5000
+
+ unRemoveFromPath_done:
+ Pop $6
+ Pop $5
+ Pop $4
+ Pop $3
+ Pop $2
+ Pop $1
+ Pop $0
+FunctionEnd
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; Uninstall sutff
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+###########################################
+# Utility Functions #
+###########################################
+
+;====================================================
+; IsNT - Returns 1 if the current system is NT, 0
+; otherwise.
+; Output: head of the stack
+;====================================================
+; IsNT
+; no input
+; output, top of the stack = 1 if NT or 0 if not
+;
+; Usage:
+; Call IsNT
+; Pop $R0
+; ($R0 at this point is 1 or 0)
+
+!macro IsNT un
+Function ${un}IsNT
+ Push $0
+ ReadRegStr $0 HKLM "SOFTWARE\Microsoft\Windows NT\CurrentVersion" CurrentVersion
+ StrCmp $0 "" 0 IsNT_yes
+ ; we are not NT.
+ Pop $0
+ Push 0
+ Return
+
+ IsNT_yes:
+ ; NT!!!
+ Pop $0
+ Push 1
+FunctionEnd
+!macroend
+!insertmacro IsNT ""
+!insertmacro IsNT "un."
+
+; StrStr
+; input, top of stack = string to search for
+; top of stack-1 = string to search in
+; output, top of stack (replaces with the portion of the string remaining)
+; modifies no other variables.
+;
+; Usage:
+; Push "this is a long ass string"
+; Push "ass"
+; Call StrStr
+; Pop $R0
+; ($R0 at this point is "ass string")
+
+!macro StrStr un
+Function ${un}StrStr
+Exch $R1 ; st=haystack,old$R1, $R1=needle
+ Exch ; st=old$R1,haystack
+ Exch $R2 ; st=old$R1,old$R2, $R2=haystack
+ Push $R3
+ Push $R4
+ Push $R5
+ StrLen $R3 $R1
+ StrCpy $R4 0
+ ; $R1=needle
+ ; $R2=haystack
+ ; $R3=len(needle)
+ ; $R4=cnt
+ ; $R5=tmp
+ loop:
+ StrCpy $R5 $R2 $R3 $R4
+ StrCmp $R5 $R1 done
+ StrCmp $R5 "" done
+ IntOp $R4 $R4 + 1
+ Goto loop
+done:
+ StrCpy $R1 $R2 "" $R4
+ Pop $R5
+ Pop $R4
+ Pop $R3
+ Pop $R2
+ Exch $R1
+FunctionEnd
+!macroend
+!insertmacro StrStr ""
+!insertmacro StrStr "un."
+
+Function Trim ; Added by Pelaca
+ Exch $R1
+ Push $R2
+Loop:
+ StrCpy $R2 "$R1" 1 -1
+ StrCmp "$R2" " " RTrim
+ StrCmp "$R2" "$\n" RTrim
+ StrCmp "$R2" "$\r" RTrim
+ StrCmp "$R2" ";" RTrim
+ GoTo Done
+RTrim:
+ StrCpy $R1 "$R1" -1
+ Goto Loop
+Done:
+ Pop $R2
+ Exch $R1
+FunctionEnd
+
+Function ConditionalAddToRegisty
+ Pop $0
+ Pop $1
+ StrCmp "$0" "" ConditionalAddToRegisty_EmptyString
+ WriteRegStr SHCTX "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_NAME@" \
+ "$1" "$0"
+ ;MessageBox MB_OK "Set Registry: '$1' to '$0'"
+ DetailPrint "Set install registry entry: '$1' to '$0'"
+ ConditionalAddToRegisty_EmptyString:
+FunctionEnd
+
+;--------------------------------
+
+!ifdef CPACK_USES_DOWNLOAD
+Function DownloadFile
+ IfFileExists $INSTDIR\* +2
+ CreateDirectory $INSTDIR
+ Pop $0
+
+ ; Skip if already downloaded
+ IfFileExists $INSTDIR\$0 0 +2
+ Return
+
+ StrCpy $1 "@CPACK_DOWNLOAD_SITE@"
+
+ try_again:
+ NSISdl::download "$1/$0" "$INSTDIR\$0"
+
+ Pop $1
+ StrCmp $1 "success" success
+ StrCmp $1 "Cancelled" cancel
+ MessageBox MB_OK "Download failed: $1"
+ cancel:
+ Return
+ success:
+FunctionEnd
+!endif
+
+;--------------------------------
+; Installation types
+@CPACK_NSIS_INSTALLATION_TYPES@
+
+;--------------------------------
+; Component sections
+@CPACK_NSIS_COMPONENT_SECTIONS@
+
+;--------------------------------
+; Define some macro setting for the gui
+@CPACK_NSIS_INSTALLER_MUI_ICON_CODE@
+@CPACK_NSIS_INSTALLER_ICON_CODE@
+@CPACK_NSIS_INSTALLER_MUI_COMPONENTS_DESC@
+
+;--------------------------------
+;Pages
+ !define MUI_LANGDLL_REGISTRY_ROOT "SHCTX"
+ !define MUI_LANGDLL_REGISTRY_KEY "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_NAME@"
+ !define MUI_LANGDLL_REGISTRY_VALUENAME "NSIS:Language"
+
+ !insertmacro MUI_PAGE_WELCOME
+
+ !insertmacro MUI_PAGE_LICENSE "@CPACK_RESOURCE_FILE_LICENSE@"
+ !insertmacro MUI_PAGE_DIRECTORY
+
+ ;Start Menu Folder Page Configuration
+ !define MUI_STARTMENUPAGE_REGISTRY_ROOT "SHCTX"
+ !define MUI_STARTMENUPAGE_REGISTRY_KEY "Software\@CPACK_PACKAGE_VENDOR@\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@"
+ !define MUI_STARTMENUPAGE_REGISTRY_VALUENAME "Start Menu Folder"
+ !insertmacro MUI_PAGE_STARTMENU Application $STARTMENU_FOLDER
+
+ @CPACK_NSIS_PAGE_COMPONENTS@
+
+ !insertmacro MUI_PAGE_INSTFILES
+
+ !define MUI_FINISHPAGE_SHOWREADME "$INSTDIR\docs\README.txt"
+ !insertmacro MUI_PAGE_FINISH
+
+ !insertmacro MUI_UNPAGE_CONFIRM
+ !insertmacro MUI_UNPAGE_INSTFILES
+
+;--------------------------------
+;Languages
+
+ !insertmacro MUI_LANGUAGE "Dutch"
+ !insertmacro MUI_LANGUAGE "English"
+ !insertmacro MUI_LANGUAGE "French"
+ !insertmacro MUI_LANGUAGE "German"
+ !insertmacro MUI_LANGUAGE "Italian"
+ !insertmacro MUI_LANGUAGE "Portuguese"
+ !insertmacro MUI_LANGUAGE "Spanish"
+
+;--------------------------------
+;Installer Sections
+
+Section "-Core installation"
+ ;Use the entire tree produced by the INSTALL target. Keep the
+ ;list of directories here in sync with the RMDir commands below.
+ SetOutPath "$INSTDIR"
+ @CPACK_NSIS_FULL_INSTALL@
+
+ ;Store installation folder
+ WriteRegStr SHCTX "Software\@CPACK_PACKAGE_VENDOR@\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@" "" $INSTDIR
+
+ ;Create uninstaller
+ WriteUninstaller "$INSTDIR\Uninstall.exe"
+ Push "DisplayName"
+ Push "@CPACK_NSIS_DISPLAY_NAME@"
+ Call ConditionalAddToRegisty
+ Push "DisplayVersion"
+ Push "@CPACK_PACKAGE_VERSION@"
+ Call ConditionalAddToRegisty
+ Push "Publisher"
+ Push "@CPACK_PACKAGE_VENDOR@"
+ Call ConditionalAddToRegisty
+ Push "UninstallString"
+ Push "$INSTDIR\Uninstall.exe"
+ Call ConditionalAddToRegisty
+ Push "NoRepair"
+ Push "1"
+ Call ConditionalAddToRegisty
+
+ !ifdef CPACK_NSIS_ADD_REMOVE
+ ;Create add/remove functionality
+ Push "ModifyPath"
+ Push "$INSTDIR\AddRemove.exe"
+ Call ConditionalAddToRegisty
+ !else
+ Push "NoModify"
+ Push "1"
+ Call ConditionalAddToRegisty
+ !endif
+
+ ; Optional registration
+ Push "DisplayIcon"
+ Push "$INSTDIR\@CPACK_NSIS_INSTALLED_ICON_NAME@"
+ Call ConditionalAddToRegisty
+ Push "HelpLink"
+ Push "@CPACK_NSIS_HELP_LINK@"
+ Call ConditionalAddToRegisty
+ Push "URLInfoAbout"
+ Push "@CPACK_NSIS_URL_INFO_ABOUT@"
+ Call ConditionalAddToRegisty
+ Push "Contact"
+ Push "@CPACK_NSIS_CONTACT@"
+ Call ConditionalAddToRegisty
+ !insertmacro MUI_STARTMENU_WRITE_BEGIN Application
+
+ ;Create shortcuts
+ CreateDirectory "$SMPROGRAMS\$STARTMENU_FOLDER"
+@CPACK_NSIS_CREATE_ICONS@
+@CPACK_NSIS_CREATE_ICONS_EXTRA@
+ CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\Uninstall.lnk" "$INSTDIR\Uninstall.exe"
+
+ ; Write special uninstall registry entries
+ Push "StartMenu"
+ Push "$STARTMENU_FOLDER"
+ Call ConditionalAddToRegisty
+ Push "DoNotAddToPath"
+ Push "$DO_NOT_ADD_TO_PATH"
+ Call ConditionalAddToRegisty
+ Push "AddToPathAllUsers"
+ Push "$ADD_TO_PATH_ALL_USERS"
+ Call ConditionalAddToRegisty
+ Push "AddToPathCurrentUser"
+ Push "$ADD_TO_PATH_CURRENT_USER"
+ Call ConditionalAddToRegisty
+ Push "InstallToDesktop"
+ Push "$INSTALL_DESKTOP"
+ Call ConditionalAddToRegisty
+
+@CPACK_NSIS_EXTRA_INSTALL_COMMANDS@
+
+ !insertmacro MUI_STARTMENU_WRITE_END
+
+SectionEnd
+
+;--------------------------------
+; determine admin versus local install
+Function un.onInit
+
+ ClearErrors
+ UserInfo::GetName
+ IfErrors noLM
+ Pop $0
+ UserInfo::GetAccountType
+ Pop $1
+ StrCmp $1 "Admin" 0 +3
+ SetShellVarContext all
+ ;MessageBox MB_OK 'User "$0" is in the Admin group'
+ Goto done
+ StrCmp $1 "Power" 0 +3
+ SetShellVarContext all
+ ;MessageBox MB_OK 'User "$0" is in the Power Users group'
+ Goto done
+
+ noLM:
+ ;Get installation folder from registry if available
+
+ done:
+
+ !insertmacro MUI_UNGETLANGUAGE
+FunctionEnd
+
+;--- Add/Remove callback functions: ---
+!macro SectionList MacroName
+ ;This macro used to perform operation on multiple sections.
+ ;List all of your components in following manner here.
+@CPACK_NSIS_COMPONENT_SECTION_LIST@
+!macroend
+
+Section -FinishComponents
+ ;Removes unselected components and writes component status to registry
+ !insertmacro SectionList "FinishSection"
+
+!ifdef CPACK_NSIS_ADD_REMOVE
+ ; Get the name of the installer executable
+ System::Call 'kernel32::GetModuleFileNameA(i 0, t .R0, i 1024) i r1'
+ StrCpy $R3 $R0
+
+ ; Strip off the last 13 characters, to see if we have AddRemove.exe
+ StrLen $R1 $R0
+ IntOp $R1 $R0 - 13
+ StrCpy $R2 $R0 13 $R1
+ StrCmp $R2 "AddRemove.exe" addremove_installed
+
+ ; We're not running AddRemove.exe, so install it
+ CopyFiles $R3 $INSTDIR\AddRemove.exe
+
+ addremove_installed:
+!endif
+SectionEnd
+;--- End of Add/Remove callback functions ---
+
+;--------------------------------
+; Component dependencies
+Function .onSelChange
+ !insertmacro SectionList MaybeSelectionChanged
+FunctionEnd
+
+;--------------------------------
+;Uninstaller Section
+
+Section "Uninstall"
+ ReadRegStr $START_MENU SHCTX \
+ "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_NAME@" "StartMenu"
+ ;MessageBox MB_OK "Start menu is in: $START_MENU"
+ ReadRegStr $DO_NOT_ADD_TO_PATH SHCTX \
+ "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_NAME@" "DoNotAddToPath"
+ ReadRegStr $ADD_TO_PATH_ALL_USERS SHCTX \
+ "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_NAME@" "AddToPathAllUsers"
+ ReadRegStr $ADD_TO_PATH_CURRENT_USER SHCTX \
+ "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_NAME@" "AddToPathCurrentUser"
+ ;MessageBox MB_OK "Add to path: $DO_NOT_ADD_TO_PATH all users: $ADD_TO_PATH_ALL_USERS"
+ ReadRegStr $INSTALL_DESKTOP SHCTX \
+ "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_NAME@" "InstallToDesktop"
+ ;MessageBox MB_OK "Install to desktop: $INSTALL_DESKTOP "
+
+@CPACK_NSIS_EXTRA_UNINSTALL_COMMANDS@
+
+ ;Remove files we installed.
+ ;Keep the list of directories here in sync with the File commands above.
+@CPACK_NSIS_DELETE_FILES@
+@CPACK_NSIS_DELETE_DIRECTORIES@
+
+!ifdef CPACK_NSIS_ADD_REMOVE
+ ;Remove the add/remove program
+ Delete "$INSTDIR\AddRemove.exe"
+!endif
+
+ ;Remove the uninstaller itself.
+ Delete "$INSTDIR\Uninstall.exe"
+ DeleteRegKey SHCTX "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_NAME@"
+
+ ;Remove the installation directory if it is empty.
+ RMDir "$INSTDIR"
+
+ ; Remove the registry entries.
+ DeleteRegKey SHCTX "Software\@CPACK_PACKAGE_VENDOR@\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@"
+
+ ; Removes all optional components
+ !insertmacro SectionList "RemoveSection"
+
+ !insertmacro MUI_STARTMENU_GETFOLDER Application $MUI_TEMP
+
+ Delete "$SMPROGRAMS\$MUI_TEMP\Uninstall.lnk"
+@CPACK_NSIS_DELETE_ICONS@
+@CPACK_NSIS_DELETE_ICONS_EXTRA@
+
+ ;Delete empty start menu parent diretories
+ StrCpy $MUI_TEMP "$SMPROGRAMS\$MUI_TEMP"
+
+ startMenuDeleteLoop:
+ ClearErrors
+ RMDir $MUI_TEMP
+ GetFullPathName $MUI_TEMP "$MUI_TEMP\.."
+
+ IfErrors startMenuDeleteLoopDone
+
+ StrCmp "$MUI_TEMP" "$SMPROGRAMS" startMenuDeleteLoopDone startMenuDeleteLoop
+ startMenuDeleteLoopDone:
+
+ ; If the user changed the shortcut, then untinstall may not work. This should
+ ; try to fix it.
+ StrCpy $MUI_TEMP "$START_MENU"
+ Delete "$SMPROGRAMS\$MUI_TEMP\Uninstall.lnk"
+@CPACK_NSIS_DELETE_ICONS_EXTRA@
+
+ ;Delete empty start menu parent diretories
+ StrCpy $MUI_TEMP "$SMPROGRAMS\$MUI_TEMP"
+
+ secondStartMenuDeleteLoop:
+ ClearErrors
+ RMDir $MUI_TEMP
+ GetFullPathName $MUI_TEMP "$MUI_TEMP\.."
+
+ IfErrors secondStartMenuDeleteLoopDone
+
+ StrCmp "$MUI_TEMP" "$SMPROGRAMS" secondStartMenuDeleteLoopDone secondStartMenuDeleteLoop
+ secondStartMenuDeleteLoopDone:
+
+ DeleteRegKey /ifempty SHCTX "Software\@CPACK_PACKAGE_VENDOR@\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@"
+
+ Push $INSTDIR\bin
+ StrCmp $DO_NOT_ADD_TO_PATH_ "1" doNotRemoveFromPath 0
+ Call un.RemoveFromPath
+ doNotRemoveFromPath:
+SectionEnd
+
+;--------------------------------
+; determine admin versus local install
+; Is install for "AllUsers" or "JustMe"?
+; Default to "JustMe" - set to "AllUsers" if admin or on Win9x
+; This function is used for the very first "custom page" of the installer.
+; This custom page does not show up visibly, but it executes prior to the
+; first visible page and sets up $INSTDIR properly...
+; Choose different default installation folder based on SV_ALLUSERS...
+; "Program Files" for AllUsers, "My Documents" for JustMe...
+
+Function .onInit
+ !insertmacro MUI_LANGDLL_DISPLAY
+ ; Reads components status for registry
+ !insertmacro SectionList "InitSection"
+
+ StrCpy $SV_ALLUSERS "JustMe"
+ StrCpy $INSTDIR "$DOCUMENTS\@CPACK_PACKAGE_INSTALL_DIRECTORY@"
+
+ ClearErrors
+ UserInfo::GetName
+ IfErrors noLM
+ Pop $0
+ UserInfo::GetAccountType
+ Pop $1
+ StrCmp $1 "Admin" 0 +3
+ SetShellVarContext all
+ ;MessageBox MB_OK 'User "$0" is in the Admin group'
+ StrCpy $SV_ALLUSERS "AllUsers"
+ Goto done
+ StrCmp $1 "Power" 0 +3
+ SetShellVarContext all
+ ;MessageBox MB_OK 'User "$0" is in the Power Users group'
+ StrCpy $SV_ALLUSERS "AllUsers"
+ Goto done
+
+ noLM:
+ StrCpy $SV_ALLUSERS "AllUsers"
+ ;Get installation folder from registry if available
+
+ done:
+ StrCmp $SV_ALLUSERS "AllUsers" 0 +2
+ StrCpy $INSTDIR "$PROGRAMFILES\@CPACK_PACKAGE_INSTALL_DIRECTORY@"
+
+FunctionEnd
diff --git a/cmake/ReadFile.cmake b/cmake/ReadFile.cmake
new file mode 100644
index 000000000..be60f1fa7
--- /dev/null
+++ b/cmake/ReadFile.cmake
@@ -0,0 +1,5 @@
+# This file is external to the read_from_file macro in Anope.cmake in order to
+# get around a possible memory leak in older versions of CMake.
+
+file(READ "${FILE}" RESULT)
+message("${RESULT}")