summaryrefslogtreecommitdiff
path: root/cmake
diff options
context:
space:
mode:
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 a