Kaynağa Gözat

Merge 'remove-CTestTest3' into ctest-file-checksum

Conflicts:
	Tests/CMakeLists.txt
Brad King 15 yıl önce
ebeveyn
işleme
38c762c728
62 değiştirilmiş dosya ile 1638 ekleme ve 401 silme
  1. 1 0
      CTestCustom.cmake.in
  2. 10 0
      ChangeLog.manual
  3. 3 0
      Modules/CMakeCCompilerId.c.in
  4. 3 0
      Modules/CMakeCXXCompilerId.cpp.in
  5. 1 0
      Modules/Compiler/Clang-C.cmake
  6. 1 0
      Modules/Compiler/Clang-CXX.cmake
  7. 237 32
      Modules/ExternalProject.cmake
  8. 46 0
      Modules/FindGit.cmake
  9. 1 0
      Modules/Platform/CYGWIN-GNU.cmake
  10. 1 0
      Modules/Platform/Linux-Clang-C.cmake
  11. 1 0
      Modules/Platform/Linux-Clang-CXX.cmake
  12. 8 1
      Modules/Platform/Linux-SunPro-CXX.cmake
  13. 3 3
      Modules/Platform/Windows-wcl386.cmake
  14. 1 1
      Source/CMakeLists.txt
  15. 2 2
      Source/CPack/cmCPackGenerator.cxx
  16. 19 15
      Source/CTest/cmCTestCoverageHandler.cxx
  17. 14 46
      Source/CTest/cmCTestCoverageHandler.h
  18. 1 1
      Source/CTest/cmCTestGIT.cxx
  19. 15 6
      Source/CTest/cmCTestMultiProcessHandler.cxx
  20. 252 0
      Source/CTest/cmParsePHPCoverage.cxx
  21. 48 0
      Source/CTest/cmParsePHPCoverage.h
  22. 1 1
      Source/QtDialog/CMakeSetup.cxx
  23. 260 29
      Source/cmFileCommand.cxx
  24. 8 2
      Source/cmFileCommand.h
  25. 9 3
      Source/cmGlobalXCodeGenerator.cxx
  26. 22 0
      Source/cmLocalUnixMakefileGenerator3.cxx
  27. 85 29
      Source/cmLocalVisualStudio6Generator.cxx
  28. 14 1
      Source/cmLocalVisualStudio7Generator.cxx
  29. 4 0
      Source/cmMakefileLibraryTargetGenerator.cxx
  30. 15 0
      Source/cmSystemTools.cxx
  31. 3 0
      Source/cmSystemTools.h
  32. 5 0
      Source/cmTarget.cxx
  33. 24 5
      Source/cmVisualStudio10TargetGenerator.cxx
  34. 9 12
      Source/cmWriteFileCommand.cxx
  35. 8 0
      Source/kwsys/CMakeLists.txt
  36. 0 84
      Source/kwsys/DynamicLoader.cxx
  37. 4 4
      Source/kwsys/DynamicLoader.hxx.in
  38. 11 0
      Source/kwsys/ProcessUNIX.c
  39. 8 0
      Source/kwsys/ProcessWin32.c
  40. 12 29
      Source/kwsys/SystemTools.cxx
  41. 7 16
      Source/kwsys/SystemTools.hxx.in
  42. 1 1
      Source/kwsys/kwsysDateStamp.cmake
  43. 4 4
      Templates/staticLibHeader.dsptemplate
  44. 34 14
      Tests/CMakeLists.txt
  45. 8 2
      Tests/CMakeTests/CMakeLists.txt
  46. 173 51
      Tests/CMakeTests/CheckSourceTreeTest.cmake.in
  47. BIN
      Tests/CMakeTests/FileDownloadInput.png
  48. 41 0
      Tests/CMakeTests/FileDownloadTest.cmake.in
  49. 1 0
      Tests/CTestSubmitLargeOutput/test.cmake.in
  50. 145 5
      Tests/ExternalProject/CMakeLists.txt
  51. 11 0
      Tests/ExternalProject/Example/CMakeLists.txt
  52. BIN
      Tests/ExternalProject/Step1.tar.bz2
  53. BIN
      Tests/ExternalProject/Step1.zip
  54. BIN
      Tests/ExternalProject/Step1NoDir.tar.bz2
  55. BIN
      Tests/ExternalProject/Step1NoDir.zip
  56. BIN
      Tests/ExternalProject/gitrepo.tgz
  57. 28 0
      Tests/LinkFlags/CMakeLists.txt
  58. 1 0
      Tests/LinkFlags/LinkFlags.c
  59. 6 0
      Tests/LinkFlags/LinkFlagsExe.c
  60. 6 0
      Tests/LinkFlags/LinkFlagsLib.c
  61. 1 1
      Utilities/Release/dash2win64_release.cmake
  62. 1 1
      Utilities/Release/release_cmake.sh.in

+ 1 - 0
CTestCustom.cmake.in

@@ -39,6 +39,7 @@ SET(CTEST_CUSTOM_WARNING_EXCEPTION
   "warning:.*is.*very unsafe.*consider using.*"
   "warning:.*is.*misused, please use.*"
   "CMakeSetupManifest.xml.*manifest authoring warning.*Unrecognized Element"
+  "cc-3968 CC: WARNING File.*" # "implicit" truncation by static_cast
   )
 
 IF(NOT "@CMAKE_GENERATOR@" MATCHES "Xcode")

+ 10 - 0
ChangeLog.manual

@@ -4,15 +4,18 @@ Changes since CMake 2.8.1
 - Build on old Sun (#10550, #10543)
 - CPack: Add native BZip2 support
 - CPack: Set compression type in RPM spec (#10363)
+- CPack: Try harder to initialize staging directory (#10793)
 - CTest: Add --stop-time argument
 - CTest: Cost data with '-j'
 - CTest: Fix memory report
 - CTest: Glob for uncovered files during coverage tests
 - CTest: Option to specify cdash server
+- CTest: PHP Coverage support
 - CTest: Process tree kill for OpenBSD, FreeBSD, kFreeBSD, GNU/Hurd
 - CTest: Report failure in Update.xml
 - CTest: Submit author email in Update.xml
 - CTest: Teach ctest_update about Git submodules
+- Cygwin: Export all symbols with ENABLE_EXPORTS (#10122)
 - Do not list file names during 'cmake -E tar xz'
 - Documentation: Comply with "XHTML 1.0 Strict"
 - Documentation: Fix typo in CMAKE_LIBRARY_PATH (#10291)
@@ -20,6 +23,9 @@ Changes since CMake 2.8.1
 - Documentation: More consistent command signatures
 - Eclipse: Do not add INCLUDE to environment twice
 - Enable extra CodeBlocks generator on Cygwin
+- ExternalProject: Support .zip and .bz2 archives, MD5 verification
+- ExternalProject: Reconfigure when args change (#10258)
+- ExternalProject: Support Git, SVN username/password
 - FindCurses: Fix for cygwin ncurses package
 - FindHSPELL: Version support
 - FindJava: Error if version is not found only when REQUIRED
@@ -37,6 +43,7 @@ Changes since CMake 2.8.1
 - Fix cross-compiling from Linux to iPhone (#10526)
 - Fix documentation typos
 - Fix g95 Fortran compiler support
+- Fix uname masking in file(WRITE) and write_file (#10789)
 - GetPrerequisites: Provide an override hook
 - Handle non-ASCII terminators in file(STRINGS)
 - Module fixes: FindPythonLibs, FindQt4, FindX11, FindwxWidgets
@@ -44,11 +51,14 @@ Changes since CMake 2.8.1
 - Qt4 OpenGL framework fix
 - Qt4ConfigDependentSettings.cmake Qt4Macros.cmake UseQt4.cmake
 - Recognize ARM ABI/EABI with GNU compilers
+- Recognize Clang compiler
 - Search basic directories on "Generic" platform
 - Set MSVC* variables consistently on all generators, and test
+- Support SunPro C++ 5.11 on Linux (new compiler)
 - Support VS 10 Express (related to #10670)
 - Support compression with 'cmake -E tar'
 - Support multiple arguments in CC,CXX,FC environment variables
+- Support per-configuration librarian flags (#10768)
 - Support per-platform initial ASM language flags (#10577)
 - Use Fortran ABI detection results conservatively
 - Use libarchive to replace the unmaintained libtar

+ 3 - 0
Modules/CMakeCCompilerId.c.in

@@ -9,6 +9,9 @@
 #if defined(__INTEL_COMPILER) || defined(__ICC)
 # define COMPILER_ID "Intel"
 
+#elif defined(__clang__)
+# define COMPILER_ID "Clang"
+
 #elif defined(__BORLANDC__)
 # define COMPILER_ID "Borland"
 

+ 3 - 0
Modules/CMakeCXXCompilerId.cpp.in

@@ -11,6 +11,9 @@
 #elif defined(__INTEL_COMPILER) || defined(__ICC)
 # define COMPILER_ID "Intel"
 
+#elif defined(__clang__)
+# define COMPILER_ID "Clang"
+
 #elif defined(__BORLANDC__)
 # define COMPILER_ID "Borland"
 

+ 1 - 0
Modules/Compiler/Clang-C.cmake

@@ -0,0 +1 @@
+include(Compiler/GNU-C)

+ 1 - 0
Modules/Compiler/Clang-CXX.cmake

@@ -0,0 +1 @@
+include(Compiler/GNU-CXX)

+ 237 - 32
Modules/ExternalProject.cmake

@@ -16,7 +16,12 @@
 #    [CVS_TAG tag]               # Tag to checkout from CVS repo
 #    [SVN_REPOSITORY url]        # URL of Subversion repo
 #    [SVN_REVISION rev]          # Revision to checkout from Subversion repo
+#    [SVN_USERNAME john ]        # Username for Subversion checkout and update
+#    [SVN_PASSWORD doe ]         # Password for Subversion checkout and update
+#    [GIT_REPOSITORY url]        # URL of git repo
+#    [GIT_TAG tag]               # Git branch name, commit id or tag
 #    [URL /.../src.tgz]          # Full path or URL of source
+#    [URL_MD5 md5]               # MD5 checksum of file at URL
 #    [TIMEOUT seconds]           # Time allowed for file download operations
 #   #--Update/Patch step----------
 #    [UPDATE_COMMAND cmd...]     # Source work-tree update command
@@ -111,19 +116,19 @@
 #  License text for the above reference.)
 
 # Pre-compute a regex to match documented keywords for each command.
-file(STRINGS "${CMAKE_CURRENT_LIST_FILE}" lines LIMIT_COUNT 100
-     REGEX "^#  (  \\[[A-Z_]+ [^]]*\\] +#.*$|[A-Za-z_]+\\()")
+file(STRINGS "${CMAKE_CURRENT_LIST_FILE}" lines LIMIT_COUNT 103
+     REGEX "^#  (  \\[[A-Z0-9_]+ [^]]*\\] +#.*$|[A-Za-z0-9_]+\\()")
 foreach(line IN LISTS lines)
-  if("${line}" MATCHES "^#  [A-Za-z_]+\\(")
+  if("${line}" MATCHES "^#  [A-Za-z0-9_]+\\(")
     if(_ep_func)
       set(_ep_keywords_${_ep_func} "${_ep_keywords_${_ep_func}})$")
     endif()
-    string(REGEX REPLACE "^#  ([A-Za-z_]+)\\(.*" "\\1" _ep_func "${line}")
+    string(REGEX REPLACE "^#  ([A-Za-z0-9_]+)\\(.*" "\\1" _ep_func "${line}")
     #message("function [${_ep_func}]")
     set(_ep_keywords_${_ep_func} "^(")
     set(_ep_keyword_sep)
   else()
-    string(REGEX REPLACE "^#    \\[([A-Z_]+) .*" "\\1" _ep_key "${line}")
+    string(REGEX REPLACE "^#    \\[([A-Z0-9_]+) .*" "\\1" _ep_key "${line}")
     #message("  keyword [${_ep_key}]")
     set(_ep_keywords_${_ep_func}
       "${_ep_keywords_${_ep_func}}${_ep_keyword_sep}${_ep_key}")
@@ -148,7 +153,7 @@ function(_ep_parse_arguments f name ns args)
   foreach(arg IN LISTS args)
     set(is_value 1)
 
-    if(arg MATCHES "^[A-Z][A-Z_][A-Z_]+$" AND
+    if(arg MATCHES "^[A-Z][A-Z0-9_][A-Z0-9_]+$" AND
         NOT ((arg STREQUAL "${key}") AND (key STREQUAL "COMMAND")) AND
         NOT arg MATCHES "^(TRUE|FALSE)$")
       if(_ep_keywords_${f} AND arg MATCHES "${_ep_keywords_${f}}")
@@ -157,6 +162,7 @@ function(_ep_parse_arguments f name ns args)
         if(NOT (key STREQUAL "COMMAND")
           AND NOT (key STREQUAL "CVS_MODULE")
           AND NOT (key STREQUAL "DEPENDS")
+          AND NOT (key STREQUAL "DOWNLOAD_COMMAND")
           )
           message(AUTHOR_WARNING "unknown ${f} keyword: ${arg}")
         endif()
@@ -203,7 +209,63 @@ define_property(DIRECTORY PROPERTY "EP_PREFIX" INHERITED
   )
 
 
-function(_ep_write_downloadfile_script script_filename remote local timeout)
+function(_ep_write_gitclone_script script_filename source_dir git_EXECUTABLE git_repository git_tag src_name work_dir)
+  file(WRITE ${script_filename}
+"if(\"${git_tag}\" STREQUAL \"\")
+  message(FATAL_ERROR \"Tag for git checkout should not be empty.\")
+endif()
+
+execute_process(
+  COMMAND \${CMAKE_COMMAND} -E remove_directory \"${source_dir}\"
+  RESULT_VARIABLE error_code
+  )
+if(error_code)
+  message(FATAL_ERROR \"Failed to remove directory: '${source_dir}'\")
+endif()
+
+execute_process(
+  COMMAND \"${git_EXECUTABLE}\" clone \"${git_repository}\" \"${src_name}\"
+  WORKING_DIRECTORY \"${work_dir}\"
+  RESULT_VARIABLE error_code
+  )
+if(error_code)
+  message(FATAL_ERROR \"Failed to clone repository: '${git_repository}'\")
+endif()
+
+execute_process(
+  COMMAND \"${git_EXECUTABLE}\" checkout ${git_tag}
+  WORKING_DIRECTORY \"${work_dir}/${src_name}\"
+  RESULT_VARIABLE error_code
+  )
+if(error_code)
+  message(FATAL_ERROR \"Failed to checkout tag: '${git_tag}'\")
+endif()
+
+execute_process(
+  COMMAND \"${git_EXECUTABLE}\" submodule init
+  WORKING_DIRECTORY \"${work_dir}/${src_name}\"
+  RESULT_VARIABLE error_code
+  )
+if(error_code)
+  message(FATAL_ERROR \"Failed to init submodules in: '${work_dir}/${src_name}'\")
+endif()
+
+execute_process(
+  COMMAND \"${git_EXECUTABLE}\" submodule update --recursive
+  WORKING_DIRECTORY \"${work_dir}/${src_name}\"
+  RESULT_VARIABLE error_code
+  )
+if(error_code)
+  message(FATAL_ERROR \"Failed to update submodules in: '${work_dir}/${src_name}'\")
+endif()
+
+"
+)
+
+endfunction(_ep_write_gitclone_script)
+
+
+function(_ep_write_downloadfile_script script_filename remote local timeout md5)
   if(timeout)
     set(timeout_args TIMEOUT ${timeout})
     set(timeout_msg "${timeout} seconds")
@@ -212,6 +274,12 @@ function(_ep_write_downloadfile_script script_filename remote local timeout)
     set(timeout_msg "none")
   endif()
 
+  if(md5)
+    set(md5_args EXPECTED_MD5 ${md5})
+  else()
+    set(md5_args "# no EXPECTED_MD5")
+  endif()
+
   file(WRITE ${script_filename}
 "message(STATUS \"downloading...
      src='${remote}'
@@ -221,6 +289,8 @@ function(_ep_write_downloadfile_script script_filename remote local timeout)
 file(DOWNLOAD
   \"${remote}\"
   \"${local}\"
+  SHOW_PROGRESS
+  ${md5_args}
   ${timeout_args}
   STATUS status
   LOG log)
@@ -243,23 +313,64 @@ message(STATUS \"downloading... done\")
 endfunction(_ep_write_downloadfile_script)
 
 
-function(_ep_write_extractfile_script script_filename filename tmp directory)
-  set(args "")
+function(_ep_write_verifyfile_script script_filename local md5)
+  file(WRITE ${script_filename}
+"message(STATUS \"verifying file...
+     file='${local}'\")
 
-  if(filename MATCHES ".tar$")
-    set(args xf)
+set(verified 0)
+
+# If an expected md5 checksum exists, compare against it:
+#
+if(NOT \"${md5}\" STREQUAL \"\")
+  execute_process(COMMAND \${CMAKE_COMMAND} -E md5sum \"${local}\"
+    OUTPUT_VARIABLE ov
+    OUTPUT_STRIP_TRAILING_WHITESPACE
+    RESULT_VARIABLE rv)
+
+  if(NOT rv EQUAL 0)
+    message(FATAL_ERROR \"error: computing md5sum of '${local}' failed\")
   endif()
 
-  if(filename MATCHES ".tgz$")
-    set(args xfz)
+  string(REGEX MATCH \"^([0-9A-Fa-f]+)\" md5_actual \"\${ov}\")
+
+  string(TOLOWER \"\${md5_actual}\" md5_actual)
+  string(TOLOWER \"${md5}\" md5)
+
+  if(NOT \"\${md5}\" STREQUAL \"\${md5_actual}\")
+    message(FATAL_ERROR \"error: md5sum of '${local}' does not match expected value
+  md5_expected: \${md5}
+    md5_actual: \${md5_actual}
+\")
   endif()
 
-  if(filename MATCHES ".tar.gz$")
+  set(verified 1)
+endif()
+
+if(verified)
+  message(STATUS \"verifying file... done\")
+else()
+  message(STATUS \"verifying file... warning: did not verify file - no URL_MD5 checksum argument? corrupt file?\")
+endif()
+"
+)
+
+endfunction(_ep_write_verifyfile_script)
+
+
+function(_ep_write_extractfile_script script_filename filename directory)
+  set(args "")
+
+  if(filename MATCHES "(\\.bz2|\\.tar\\.gz|\\.tgz|\\.zip)$")
     set(args xfz)
   endif()
 
+  if(filename MATCHES "\\.tar$")
+    set(args xf)
+  endif()
+
   if(args STREQUAL "")
-    message(SEND_ERROR "error: do not know how to extract '${filename}' -- known types are .tar, .tgz and .tar.gz")
+    message(SEND_ERROR "error: do not know how to extract '${filename}' -- known types are .bz2, .tar, .tar.gz, .tgz and .zip")
     return()
   endif()
 
@@ -267,20 +378,23 @@ function(_ep_write_extractfile_script script_filename filename tmp directory)
 "# Make file names absolute:
 #
 get_filename_component(filename \"${filename}\" ABSOLUTE)
-get_filename_component(tmp \"${tmp}\" ABSOLUTE)
 get_filename_component(directory \"${directory}\" ABSOLUTE)
 
 message(STATUS \"extracting...
      src='\${filename}'
      dst='\${directory}'\")
 
+if(NOT EXISTS \"\${filename}\")
+  message(FATAL_ERROR \"error: file to extract does not exist: '\${filename}'\")
+endif()
+
 # Prepare a space for extracting:
 #
-set(i 1)
-while(EXISTS \"\${tmp}/extract\${i}\")
+set(i 1234)
+while(EXISTS \"\${directory}/../ex\${i}\")
   math(EXPR i \"\${i} + 1\")
 endwhile()
-set(ut_dir \"\${tmp}/extract\${i}\")
+set(ut_dir \"\${directory}/../ex\${i}\")
 file(MAKE_DIRECTORY \"\${ut_dir}\")
 
 # Extract it:
@@ -305,10 +419,12 @@ if(NOT n EQUAL 1 OR NOT IS_DIRECTORY \"\${contents}\")
   set(contents \"\${ut_dir}\")
 endif()
 
-# Copy \"the one\" directory to the final directory:
+# Move \"the one\" directory to the final directory:
 #
-message(STATUS \"extracting... [copy]\")
-file(COPY \"\${contents}/\" DESTINATION \${directory})
+message(STATUS \"extracting... [rename]\")
+file(REMOVE_RECURSE \${directory})
+get_filename_component(contents \${contents} ABSOLUTE)
+file(RENAME \${contents} \${directory})
 
 # Clean up:
 #
@@ -609,6 +725,19 @@ function(_ep_add_mkdir_command name)
 endfunction(_ep_add_mkdir_command)
 
 
+function(_ep_get_git_version git_EXECUTABLE git_version_var)
+  if(git_EXECUTABLE)
+    execute_process(
+      COMMAND "${git_EXECUTABLE}" --version
+      OUTPUT_VARIABLE ov
+      OUTPUT_STRIP_TRAILING_WHITESPACE
+      )
+    string(REGEX REPLACE "^git version (.+)$" "\\1" version "${ov}")
+    set(${git_version_var} "${version}" PARENT_SCOPE)
+  endif()
+endfunction()
+
+
 function(_ep_add_download_command name)
   ExternalProject_Get_Property(${name} source_dir stamp_dir download_dir tmp_dir)
 
@@ -616,6 +745,7 @@ function(_ep_add_download_command name)
   get_property(cmd TARGET ${name} PROPERTY _EP_DOWNLOAD_COMMAND)
   get_property(cvs_repository TARGET ${name} PROPERTY _EP_CVS_REPOSITORY)
   get_property(svn_repository TARGET ${name} PROPERTY _EP_SVN_REPOSITORY)
+  get_property(git_repository TARGET ${name} PROPERTY _EP_GIT_REPOSITORY)
   get_property(url TARGET ${name} PROPERTY _EP_URL)
 
   # TODO: Perhaps file:// should be copied to download dir before extraction.
@@ -661,8 +791,10 @@ function(_ep_add_download_command name)
     endif()
 
     get_property(svn_revision TARGET ${name} PROPERTY _EP_SVN_REVISION)
+    get_property(svn_username TARGET ${name} PROPERTY _EP_SVN_USERNAME)
+    get_property(svn_password TARGET ${name} PROPERTY _EP_SVN_PASSWORD)
 
-    set(repository ${svn_repository})
+    set(repository "${svn_repository} user=${svn_username} password=${svn_password}")
     set(module)
     set(tag ${svn_revision})
     configure_file(
@@ -674,13 +806,55 @@ function(_ep_add_download_command name)
     get_filename_component(src_name "${source_dir}" NAME)
     get_filename_component(work_dir "${source_dir}" PATH)
     set(comment "Performing download step (SVN checkout) for '${name}'")
-    set(cmd ${Subversion_SVN_EXECUTABLE} co ${svn_repository} ${svn_revision} ${src_name})
+    set(cmd ${Subversion_SVN_EXECUTABLE} co ${svn_repository} ${svn_revision}
+      --username=${svn_username} --password=${svn_password} ${src_name})
     list(APPEND depends ${stamp_dir}/${name}-svninfo.txt)
+  elseif(git_repository)
+    find_package(Git)
+    if(NOT GIT_EXECUTABLE)
+      message(FATAL_ERROR "error: could not find git for clone of ${name}")
+    endif()
+
+    # The git submodule update '--recursive' flag requires git >= v1.6.5
+    #
+    _ep_get_git_version("${GIT_EXECUTABLE}" git_version)
+    if(git_version VERSION_LESS 1.6.5)
+      message(FATAL_ERROR "error: git version 1.6.5 or later required for 'git submodule update --recursive': git_version='${git_version}'")
+    endif()
+
+    get_property(git_tag TARGET ${name} PROPERTY _EP_GIT_TAG)
+    if(NOT git_tag)
+      set(git_tag "master")
+    endif()
+
+    set(repository ${git_repository})
+    set(module)
+    set(tag ${git_tag})
+    configure_file(
+      "${CMAKE_ROOT}/Modules/RepositoryInfo.txt.in"
+      "${stamp_dir}/${name}-gitinfo.txt"
+      @ONLY
+      )
+
+    get_filename_component(src_name "${source_dir}" NAME)
+    get_filename_component(work_dir "${source_dir}" PATH)
+
+    # Since git clone doesn't succeed if the non-empty source_dir exists,
+    # create a cmake script to invoke as download command.
+    # The script will delete the source directory and then call git clone.
+    #
+    _ep_write_gitclone_script(${tmp_dir}/${name}-gitclone.cmake ${source_dir}
+      ${GIT_EXECUTABLE} ${git_repository} ${git_tag} ${src_name} ${work_dir}
+      )
+    set(comment "Performing download step (git clone) for '${name}'")
+    set(cmd ${CMAKE_COMMAND} -P ${tmp_dir}/${name}-gitclone.cmake)
+    list(APPEND depends ${stamp_dir}/${name}-gitinfo.txt)
   elseif(url)
     get_filename_component(work_dir "${source_dir}" PATH)
+    get_property(md5 TARGET ${name} PROPERTY _EP_URL_MD5)
     set(repository "external project URL")
     set(module "${url}")
-    set(tag "")
+    set(tag "${md5}")
     configure_file(
       "${CMAKE_ROOT}/Modules/RepositoryInfo.txt.in"
       "${stamp_dir}/${name}-urlinfo.txt"
@@ -696,21 +870,23 @@ function(_ep_add_download_command name)
       if("${url}" MATCHES "^[a-z]+://")
         # TODO: Should download and extraction be different steps?
         string(REGEX MATCH "[^/]*$" fname "${url}")
-        if(NOT "${fname}" MATCHES "\\.(tar|tgz|tar\\.gz)$")
+        if(NOT "${fname}" MATCHES "\\.(bz2|tar|tgz|tar\\.gz|zip)$")
           message(FATAL_ERROR "Could not extract tarball filename from url:\n  ${url}")
         endif()
         set(file ${download_dir}/${fname})
         get_property(timeout TARGET ${name} PROPERTY _EP_TIMEOUT)
-        _ep_write_downloadfile_script("${stamp_dir}/download-${name}.cmake" "${url}" "${file}" "${timeout}")
+        _ep_write_downloadfile_script("${stamp_dir}/download-${name}.cmake" "${url}" "${file}" "${timeout}" "${md5}")
         set(cmd ${CMAKE_COMMAND} -P ${stamp_dir}/download-${name}.cmake
           COMMAND)
-        set(comment "Performing download step (download and extract) for '${name}'")
+        set(comment "Performing download step (download, verify and extract) for '${name}'")
       else()
         set(file "${url}")
-        set(comment "Performing download step (extract) for '${name}'")
+        set(comment "Performing download step (verify and extract) for '${name}'")
       endif()
+      _ep_write_verifyfile_script("${stamp_dir}/verify-${name}.cmake" "${file}" "${md5}")
+      list(APPEND cmd ${CMAKE_COMMAND} -P ${stamp_dir}/verify-${name}.cmake)
       # TODO: Support other archive formats.
-      _ep_write_extractfile_script("${stamp_dir}/extract-${name}.cmake" "${file}" "${tmp_dir}" "${source_dir}")
+      _ep_write_extractfile_script("${stamp_dir}/extract-${name}.cmake" "${file}" "${source_dir}")
       list(APPEND cmd ${CMAKE_COMMAND} -P ${stamp_dir}/extract-${name}.cmake)
     endif()
   else()
@@ -734,6 +910,7 @@ function(_ep_add_update_command name)
   get_property(cmd TARGET ${name} PROPERTY _EP_UPDATE_COMMAND)
   get_property(cvs_repository TARGET ${name} PROPERTY _EP_CVS_REPOSITORY)
   get_property(svn_repository TARGET ${name} PROPERTY _EP_SVN_REPOSITORY)
+  get_property(git_repository TARGET ${name} PROPERTY _EP_GIT_REPOSITORY)
 
   set(work_dir)
   set(comment)
@@ -757,7 +934,25 @@ function(_ep_add_update_command name)
     set(work_dir ${source_dir})
     set(comment "Performing update step (SVN update) for '${name}'")
     get_property(svn_revision TARGET ${name} PROPERTY _EP_SVN_REVISION)
-    set(cmd ${Subversion_SVN_EXECUTABLE} up ${svn_revision})
+    get_property(svn_username TARGET ${name} PROPERTY _EP_SVN_USERNAME)
+    get_property(svn_password TARGET ${name} PROPERTY _EP_SVN_PASSWORD)
+    set(cmd ${Subversion_SVN_EXECUTABLE} up ${svn_revision}
+      --username=${svn_username} --password=${svn_password})
+    set(always 1)
+  elseif(git_repository)
+    if(NOT GIT_EXECUTABLE)
+      message(FATAL_ERROR "error: could not find git for fetch of ${name}")
+    endif()
+    set(work_dir ${source_dir})
+    set(comment "Performing update step (git fetch) for '${name}'")
+    get_property(git_tag TARGET ${name} PROPERTY _EP_GIT_TAG)
+    if(NOT git_tag)
+      set(git_tag "master")
+    endif()
+    set(cmd ${GIT_EXECUTABLE} fetch
+      COMMAND ${GIT_EXECUTABLE} checkout ${git_tag}
+      COMMAND ${GIT_EXECUTABLE} submodule update --recursive
+      )
     set(always 1)
   endif()
 
@@ -793,7 +988,7 @@ endfunction(_ep_add_patch_command)
 
 # TODO: Make sure external projects use the proper compiler
 function(_ep_add_configure_command name)
-  ExternalProject_Get_Property(${name} source_dir binary_dir)
+  ExternalProject_Get_Property(${name} source_dir binary_dir tmp_dir)
 
   _ep_get_configuration_subdir_suffix(cfgdir)
 
@@ -827,6 +1022,16 @@ function(_ep_add_configure_command name)
     endif()
   endif()
 
+  # If anything about the configure command changes, (command itself, cmake
+  # used, cmake args or cmake generator) then re-run the configure step.
+  # Fixes issue http://public.kitware.com/Bug/view.php?id=10258
+  #
+  if(NOT EXISTS ${tmp_dir}/${name}-cfgcmd.txt.in)
+    file(WRITE ${tmp_dir}/${name}-cfgcmd.txt.in "cmd='@cmd@'\n")
+  endif()
+  configure_file(${tmp_dir}/${name}-cfgcmd.txt.in ${tmp_dir}/${name}-cfgcmd.txt)
+  list(APPEND file_deps ${tmp_dir}/${name}-cfgcmd.txt)
+
   ExternalProject_Add_Step(${name} configure
     COMMAND ${cmd}
     WORKING_DIRECTORY ${binary_dir}

+ 46 - 0
Modules/FindGit.cmake

@@ -0,0 +1,46 @@
+# The module defines the following variables:
+#   GIT_EXECUTABLE - path to git command line client
+#   GIT_FOUND - true if the command line client was found
+# Example usage:
+#   find_package(Git)
+#   if(GIT_FOUND)
+#     message("git found: ${GIT_EXECUTABLE}")
+#   endif()
+
+#=============================================================================
+# Copyright 2010 Kitware, Inc.
+#
+# Distributed under the OSI-approved BSD License (the "License");
+# see accompanying file Copyright.txt for details.
+#
+# This software is distributed WITHOUT ANY WARRANTY; without even the
+# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the License for more information.
+#=============================================================================
+# (To distributed this file outside of CMake, substitute the full
+#  License text for the above reference.)
+
+# Look for 'git' or 'eg' (easy git)
+#
+set(git_names git eg)
+
+# Prefer .cmd variants on Windows unless running in a Makefile
+# in the MSYS shell.
+#
+if(WIN32)
+  if(NOT CMAKE_GENERATOR MATCHES "MSYS")
+    set(git_names git.cmd git eg.cmd eg)
+  endif()
+endif()
+
+find_program(GIT_EXECUTABLE
+  NAMES ${git_names}
+  DOC "git command line client"
+  )
+mark_as_advanced(GIT_EXECUTABLE)
+
+# Handle the QUIETLY and REQUIRED arguments and set GIT_FOUND to TRUE if
+# all listed variables are TRUE
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(Git DEFAULT_MSG GIT_EXECUTABLE)

+ 1 - 0
Modules/Platform/CYGWIN-GNU.cmake

@@ -45,6 +45,7 @@ macro(__cygwin_compiler_gnu lang)
     SET(CMAKE_${type}_LINK_DYNAMIC_${lang}_FLAGS "-Wl,-Bdynamic")
   ENDFOREACH(type)
 
+  set(CMAKE_EXE_EXPORTS_${lang}_FLAG "-Wl,--export-all-symbols")
   # TODO: Is -Wl,--enable-auto-import now always default?
   set(CMAKE_SHARED_LIBRARY_CREATE_${lang}_FLAGS "${CMAKE_SHARED_LIBRARY_CREATE_${lang}_FLAGS} -Wl,--enable-auto-import")
   set(CMAKE_SHARED_MODULE_CREATE_${lang}_FLAGS "${CMAKE_SHARED_LIBRARY_CREATE_${lang}_FLAGS}")

+ 1 - 0
Modules/Platform/Linux-Clang-C.cmake

@@ -0,0 +1 @@
+INCLUDE(Platform/Linux-GNU-C)

+ 1 - 0
Modules/Platform/Linux-Clang-CXX.cmake

@@ -0,0 +1 @@
+INCLUDE(Platform/Linux-GNU-CXX)

+ 8 - 1
Modules/Platform/Linux-SunPro-CXX.cmake

@@ -1,2 +1,9 @@
-SET(CMAKE_SHARED_LIBRARY_RPATH_LINK_CXX_FLAG "-rpath-link ")
+# Sun C++ 5.9 does not support -Wl, but Sun C++ 5.11 does not work without it.
+# Query the compiler flags to detect whether to use -Wl.
+execute_process(COMMAND ${CMAKE_CXX_COMPILER} -flags OUTPUT_VARIABLE _cxx_flags ERROR_VARIABLE _cxx_error)
+if("${_cxx_flags}" MATCHES "\n-W[^\n]*component")
+  set(CMAKE_SHARED_LIBRARY_RPATH_LINK_CXX_FLAG "-Wl,-rpath-link,")
+else()
+  set(CMAKE_SHARED_LIBRARY_RPATH_LINK_CXX_FLAG "-rpath-link ")
+endif()
 SET(CMAKE_EXE_EXPORTS_CXX_FLAG "--export-dynamic")

+ 3 - 3
Modules/Platform/Windows-wcl386.cmake

@@ -31,7 +31,7 @@ SET(CMAKE_C_CREATE_IMPORT_LIBRARY
 SET(CMAKE_CXX_CREATE_IMPORT_LIBRARY ${CMAKE_C_CREATE_IMPORT_LIBRARY})
 
 SET(CMAKE_C_LINK_EXECUTABLE
-    "wlink ${CMAKE_START_TEMP_FILE} ${CMAKE_WLINK_QUIET} name '<TARGET_UNQUOTED>' option caseexact file {<OBJECTS>} <LINK_LIBRARIES> ${CMAKE_END_TEMP_FILE}")
+    "wlink ${CMAKE_START_TEMP_FILE} ${CMAKE_WLINK_QUIET} name '<TARGET_UNQUOTED>' <LINK_FLAGS> option caseexact file {<OBJECTS>} <LINK_LIBRARIES> ${CMAKE_END_TEMP_FILE}")
 
 SET(CMAKE_CXX_LINK_EXECUTABLE ${CMAKE_C_LINK_EXECUTABLE})
 
@@ -52,7 +52,7 @@ SET(CMAKE_CXX_CREATE_PREPROCESSED_SOURCE
     "<CMAKE_CXX_COMPILER> ${CMAKE_START_TEMP_FILE} ${CMAKE_WCL_QUIET} <FLAGS> -dWIN32 -d+ <DEFINES> -fo<PREPROCESSED_SOURCE> -pl -cc++ <SOURCE>${CMAKE_END_TEMP_FILE}")
 
 SET(CMAKE_CXX_CREATE_SHARED_MODULE
- "wlink ${CMAKE_START_TEMP_FILE} system nt_dll  ${CMAKE_WLINK_QUIET} name '<TARGET_UNQUOTED>' option caseexact  file {<OBJECTS>} <LINK_LIBRARIES> ${CMAKE_END_TEMP_FILE}")
+ "wlink ${CMAKE_START_TEMP_FILE} system nt_dll  ${CMAKE_WLINK_QUIET} name '<TARGET_UNQUOTED>' <LINK_FLAGS> option caseexact  file {<OBJECTS>} <LINK_LIBRARIES> ${CMAKE_END_TEMP_FILE}")
 SET(CMAKE_CXX_CREATE_SHARED_LIBRARY
   ${CMAKE_CXX_CREATE_SHARED_MODULE}
   ${CMAKE_CXX_CREATE_IMPORT_LIBRARY})
@@ -64,7 +64,7 @@ SET(CMAKE_C_CREATE_SHARED_LIBRARY ${CMAKE_CXX_CREATE_SHARED_LIBRARY})
 SET(CMAKE_C_CREATE_SHARED_MODULE ${CMAKE_CXX_CREATE_SHARED_MODULE})
 
 # create a C++ static library
-SET(CMAKE_CXX_CREATE_STATIC_LIBRARY  "wlib ${CMAKE_LIB_QUIET} -n -b '<TARGET_UNQUOTED>' <OBJECTS> ")
+SET(CMAKE_CXX_CREATE_STATIC_LIBRARY  "wlib ${CMAKE_LIB_QUIET} -n -b '<TARGET_UNQUOTED>' <LINK_FLAGS> <OBJECTS> ")
 
 # create a C static library
 SET(CMAKE_C_CREATE_STATIC_LIBRARY ${CMAKE_CXX_CREATE_STATIC_LIBRARY})

+ 1 - 1
Source/CMakeLists.txt

@@ -366,6 +366,7 @@ SET(CTEST_SRCS cmCTest.cxx
   CTest/cmCTestConfigureHandler.cxx
   CTest/cmCTestCoverageCommand.cxx
   CTest/cmCTestCoverageHandler.cxx
+  CTest/cmParsePHPCoverage.cxx
   CTest/cmCTestEmptyBinaryDirectoryCommand.cxx
   CTest/cmCTestGenericHandler.cxx
   CTest/cmCTestHandlerCommand.cxx
@@ -502,4 +503,3 @@ IF(APPLE)
 ENDIF(APPLE)
 
 INSTALL_FILES(${CMAKE_DATA_DIR}/include cmCPluginAPI.h)
-

+ 2 - 2
Source/CPack/cmCPackGenerator.cxx

@@ -789,7 +789,7 @@ int cmCPackGenerator::DoPackage()
       cmCPackLogger(cmCPackLog::LOG_VERBOSE, 
                     "Remove toplevel directory: "
         << toplevelDirectory << std::endl);
-      if ( !cmSystemTools::RemoveADirectory(toplevelDirectory) )
+      if ( !cmSystemTools::RepeatedRemoveDirectory(toplevelDirectory) )
         {
         cmCPackLogger(cmCPackLog::LOG_ERROR,
           "Problem removing toplevel directory: "
@@ -1084,7 +1084,7 @@ int cmCPackGenerator::CleanTemporaryDirectory()
     cmCPackLogger(cmCPackLog::LOG_OUTPUT,
                   "- Clean temporary : "
                   << tempInstallDirectory << std::endl);
-    if(!cmsys::SystemTools::RemoveADirectory(tempInstallDirectory))
+    if(!cmSystemTools::RepeatedRemoveDirectory(tempInstallDirectory))
       {
       cmCPackLogger(cmCPackLog::LOG_ERROR,
                     "Problem removing temporary directory: " <<

+ 19 - 15
Source/CTest/cmCTestCoverageHandler.cxx

@@ -10,6 +10,7 @@
   See the License for more information.
 ============================================================================*/
 #include "cmCTestCoverageHandler.h"
+#include "cmParsePHPCoverage.h"
 #include "cmCTest.h"
 #include "cmake.h"
 #include "cmMakefile.h"
@@ -125,20 +126,6 @@ private:
 };
 
 
-//----------------------------------------------------------------------
-//**********************************************************************
-class cmCTestCoverageHandlerContainer
-{
-public:
-  int Error;
-  std::string SourceDir;
-  std::string BinaryDir;
-  typedef std::vector<int> SingleFileCoverageVector;
-  typedef std::map<std::string, SingleFileCoverageVector> TotalCoverageMap;
-  TotalCoverageMap TotalCoverage;
-  std::ostream* OFS;
-};
-//**********************************************************************
 //----------------------------------------------------------------------
 
 //----------------------------------------------------------------------
@@ -391,6 +378,11 @@ int cmCTestCoverageHandler::ProcessHandler()
     return error;
     }
   file_count += this->HandleTracePyCoverage(&cont);
+  if ( file_count < 0 )
+    {
+    return error;
+    }
+  file_count += this->HandlePHPCoverage(&cont);
   if ( file_count < 0 )
     {
     return error;
@@ -524,7 +516,7 @@ int cmCTestCoverageHandler::ProcessHandler()
         {
         cmOStringStream ostr;
         ostr << "Problem reading source file: " << fullFileName.c_str()
-          << " line:" << cc;
+             << " line:" << cc << "  out total: " << fcov.size()-1;
         errorsWhileAccumulating.push_back(ostr.str());
         error ++;
         break;
@@ -747,6 +739,18 @@ bool IsFileInDir(const std::string &infile, const std::string &indir)
   return false;
 }
 
+//----------------------------------------------------------------------
+int cmCTestCoverageHandler::HandlePHPCoverage(
+  cmCTestCoverageHandlerContainer* cont)
+{
+  cmParsePHPCoverage cov(*cont, this->CTest);
+  std::string coverageDir = this->CTest->GetBinaryDir() + "/xdebugCoverage";
+  if(cmSystemTools::FileIsDirectory(coverageDir.c_str()))
+    {
+    cov.ReadPHPCoverageDirectory(coverageDir.c_str());
+    }
+  return static_cast<int>(cont->TotalCoverage.size());
+}
 //----------------------------------------------------------------------
 int cmCTestCoverageHandler::HandleGCovCoverage(
   cmCTestCoverageHandlerContainer* cont)

+ 14 - 46
Source/CTest/cmCTestCoverageHandler.h

@@ -20,8 +20,17 @@
 #include <cmsys/RegularExpression.hxx>
 
 class cmGeneratedFileStream;
-class cmCTestCoverageHandlerContainer;
-
+class cmCTestCoverageHandlerContainer
+{
+public:
+  int Error;
+  std::string SourceDir;
+  std::string BinaryDir;
+  typedef std::vector<int> SingleFileCoverageVector;
+  typedef std::map<std::string, SingleFileCoverageVector> TotalCoverageMap;
+  TotalCoverageMap TotalCoverage;
+  std::ostream* OFS;
+};
 /** \class cmCTestCoverageHandler
  * \brief A class that handles coverage computaiton for ctest
  *
@@ -59,6 +68,9 @@ private:
   int HandleGCovCoverage(cmCTestCoverageHandlerContainer* cont);
   void FindGCovFiles(std::vector<std::string>& files);
 
+  //! Handle coverage using xdebug php coverage
+  int HandlePHPCoverage(cmCTestCoverageHandlerContainer* cont);
+
   //! Handle coverage using Bullseye
   int HandleBullseyeCoverage(cmCTestCoverageHandlerContainer* cont);
   int RunBullseyeSourceSummary(cmCTestCoverageHandlerContainer* cont);
@@ -94,54 +106,10 @@ private:
 
   std::set<std::string> FindUncoveredFiles(
     cmCTestCoverageHandlerContainer* cont);
-
-  struct cmCTestCoverage
-    {
-    cmCTestCoverage()
-      {
-      this->AbsolutePath = "";
-      this->FullPath = "";
-      this->Covered = false;
-      this->Tested = 0;
-      this->UnTested = 0;
-      this->Lines.clear();
-      this->Show = false;
-      }
-    cmCTestCoverage(const cmCTestCoverage& rhs) :
-      AbsolutePath(rhs.AbsolutePath),
-      FullPath(rhs.FullPath),
-      Covered(rhs.Covered),
-      Tested(rhs.Tested),
-      UnTested(rhs.UnTested),
-      Lines(rhs.Lines),
-      Show(rhs.Show)
-      {
-      }
-    cmCTestCoverage& operator=(const cmCTestCoverage& rhs)
-      {
-      this->AbsolutePath = rhs.AbsolutePath;
-      this->FullPath = rhs.FullPath;
-      this->Covered = rhs.Covered;
-      this->Tested = rhs.Tested;
-      this->UnTested = rhs.UnTested;
-      this->Lines = rhs.Lines;
-      this->Show = rhs.Show;
-      return *this;
-      }
-    std::string      AbsolutePath;
-    std::string      FullPath;
-    bool             Covered;
-    int              Tested;
-    int              UnTested;
-    std::vector<int> Lines;
-    bool             Show;
-    };
-
   std::vector<cmStdString> CustomCoverageExclude;
   std::vector<cmsys::RegularExpression> CustomCoverageExcludeRegex;
   std::vector<cmStdString> ExtraCoverageGlobs;
 
-  typedef std::map<std::string, cmCTestCoverage> CoverageMap;
 
   // Map from source file to label ids.
   class LabelSet: public std::set<int> {};

+ 1 - 1
Source/CTest/cmCTestGIT.cxx

@@ -119,7 +119,7 @@ bool cmCTestGIT::UpdateImpl()
     char const* git_submodule[] = {git, "submodule", "update", 0};
     OutputLogger out2(this->Log, "submodule-out> ");
     OutputLogger err2(this->Log, "submodule-err> ");
-    return this->RunChild(git_submodule, &out, &err);
+    return this->RunChild(git_submodule, &out2, &err2);
     }
   return false;
 }

+ 15 - 6
Source/CTest/cmCTestMultiProcessHandler.cxx

@@ -453,15 +453,24 @@ void cmCTestMultiProcessHandler::CreateTestCostList()
   for(TestMap::iterator i = this->Tests.begin();
       i != this->Tests.end(); ++i)
     {
-    std::string name = this->Properties[i->first]->Name;
-    if(std::find(this->LastTestsFailed.begin(), this->LastTestsFailed.end(),
-       name) != this->LastTestsFailed.end())
+    //We only want to schedule them by cost in a parallel situation
+    if(this->ParallelLevel > 1)
       {
-      this->TestCosts[FLT_MAX].insert(i->first);
+      std::string name = this->Properties[i->first]->Name;
+      if(std::find(this->LastTestsFailed.begin(), this->LastTestsFailed.end(),
+         name) != this->LastTestsFailed.end())
+        {
+        this->TestCosts[FLT_MAX].insert(i->first);
+        }
+      else
+        {
+        this->TestCosts[this->Properties[i->first]->Cost].insert(i->first);
+        }
       }
-    else
+    else //we ignore their cost
       {
-      this->TestCosts[this->Properties[i->first]->Cost].insert(i->first);
+      this->TestCosts[this->Tests.size()
+        - this->Properties[i->first]->Index].insert(i->first);
       }
     }
 }

+ 252 - 0
Source/CTest/cmParsePHPCoverage.cxx

@@ -0,0 +1,252 @@
+#include "cmStandardIncludes.h"
+#include "cmSystemTools.h"
+#include "cmParsePHPCoverage.h"
+#include <cmsys/Directory.hxx>
+
+/*
+  To setup coverage for php.
+
+  - edit php.ini to add auto prepend and append php files from phpunit
+  auto_prepend_file =
+  auto_append_file =
+  - run the tests
+  - run this program on all the files in c:/tmp
+
+*/
+
+cmParsePHPCoverage::cmParsePHPCoverage(cmCTestCoverageHandlerContainer& cont,
+    cmCTest* ctest)
+    :Coverage(cont), CTest(ctest)
+{
+}
+
+bool cmParsePHPCoverage::ReadUntil(std::ifstream& in, char until)
+{
+  char c = 0;
+  while(in.get(c) && c != until)
+    {
+    }
+  if(c != until)
+    {
+    return false;
+    }
+  return true;
+}
+bool cmParsePHPCoverage::ReadCoverageArray(std::ifstream& in,
+                                           cmStdString const& fileName)
+{
+  cmCTestCoverageHandlerContainer::SingleFileCoverageVector& coverageVector
+    = this->Coverage.TotalCoverage[fileName];
+
+  char c;
+  char buf[4];
+  in.read(buf, 3);
+  buf[3] = 0;
+  if(strcmp(buf, ";a:") != 0)
+    {
+    cmCTestLog(this->CTest, ERROR_MESSAGE,
+               "failed to read start of coverage array, found : "
+               << buf << "\n");
+    return false;
+    }
+  int size = 0;
+  if(!this->ReadInt(in, size))
+    {
+    cmCTestLog(this->CTest, ERROR_MESSAGE,
+               "failed to read size ");
+    return false;
+    }
+  if(!in.get(c) && c == '{')
+    {
+    cmCTestLog(this->CTest, ERROR_MESSAGE,
+               "failed to read open {\n");
+    return false;
+    }
+  for(int i =0; i < size; i++)
+    {
+    this->ReadUntil(in, ':');
+    int line = 0;
+    this->ReadInt(in, line);
+    // ok xdebug may have a bug here
+    // it seems to be 1 based but often times
+    // seems to have a 0'th line.
+    line--;
+    if(line < 0)
+      {
+      line = 0;
+      }
+    this->ReadUntil(in, ':');
+    int value = 0;
+    this->ReadInt(in, value);
+    // make sure the vector is the right size and is
+    // initialized with -1 for each line
+    while(coverageVector.size() <= static_cast<size_t>(line) )
+      {
+      coverageVector.push_back(-1);
+      }
+    // if value is less than 0, set it to zero
+    // TODO figure out the difference between
+    // -1 and -2 in xdebug coverage??  For now
+    // assume less than 0 is just not covered
+    // CDash expects -1 for non executable code (like comments)
+    // and 0 for uncovered code, and a positive value
+    // for number of times a line was executed
+    if(value < 0)
+      {
+      value = 0;
+      }
+    // if unset then set it to value
+    if(coverageVector[line] == -1)
+      {
+      coverageVector[line] = value;
+      }
+    // otherwise increment by value
+    else
+      {
+      coverageVector[line] += value;
+      }
+    }
+  return true;
+}
+
+bool cmParsePHPCoverage::ReadInt(std::ifstream& in, int& v)
+{
+  std::string s;
+  char c = 0;
+  while(in.get(c) && c != ':' && c != ';')
+    {
+    s += c;
+    }
+  v = atoi(s.c_str());
+  return true;
+}
+
+bool cmParsePHPCoverage::ReadArraySize(std::ifstream& in, int& size)
+{
+  char c = 0;
+  in.get(c);
+  if(c != 'a')
+    {
+    return false;
+    }
+  if(in.get(c) && c == ':')
+    {
+    if(this->ReadInt(in, size))
+      {
+      return true;
+      }
+    }
+  return false;
+}
+
+bool cmParsePHPCoverage::ReadFileInformation(std::ifstream& in)
+{
+  char buf[4];
+  in.read(buf, 2);
+  buf[2] = 0;
+  if(strcmp(buf, "s:") != 0)
+    {
+    cmCTestLog(this->CTest, ERROR_MESSAGE,
+               "failed to read start of file info found: [" << buf << "]\n");
+    return false;
+    }
+  char c;
+  int size = 0;
+  if(this->ReadInt(in, size))
+    {
+    size++; // add one for null termination
+    char* s = new char[size+1];
+    // read open quote
+    if(in.get(c) && c != '"')
+      {
+      return false;
+      }
+    // read the string data
+    in.read(s, size-1);
+    s[size-1] = 0;
+    cmStdString fileName = s;
+    delete [] s;
+    // read close quote
+    if(in.get(c) && c != '"')
+      {
+      cmCTestLog(this->CTest, ERROR_MESSAGE,
+                 "failed to read close quote\n"
+                 << "read [" << c << "]\n");
+      return false;
+      }
+    if(!this->ReadCoverageArray(in, fileName) )
+      {
+      cmCTestLog(this->CTest, ERROR_MESSAGE,
+                 "failed to read coverage array for file: "
+                 << fileName << "\n");
+      return false;
+      }
+    return true;
+    }
+  return false;
+}
+
+
+bool cmParsePHPCoverage::ReadPHPData(const char* file)
+{
+  std::ifstream in(file);
+  if(!in)
+    {
+    return false;
+    }
+  int size = 0;
+  this->ReadArraySize(in, size);
+  char c = 0;
+  in.get(c);
+  if(c != '{')
+    {
+    cmCTestLog(this->CTest, ERROR_MESSAGE,
+               "failed to read open array\n");
+    return false;
+    }
+  for(int i =0; i < size; i++)
+    {
+    if(!this->ReadFileInformation(in))
+      {
+      cmCTestLog(this->CTest, ERROR_MESSAGE,
+                 "Failed to read file #" << i << "\n");
+      return false;
+      }
+    in.get(c);
+    if(c != '}')
+      {
+      cmCTestLog(this->CTest, ERROR_MESSAGE,
+                 "failed to read close array\n");
+      return false;
+      }
+    }
+  return true;
+}
+
+bool cmParsePHPCoverage::ReadPHPCoverageDirectory(const char* d)
+{
+  cmsys::Directory dir;
+  if(!dir.Load(d))
+    {
+    return false;
+    }
+  size_t numf;
+  unsigned int i;
+  numf = dir.GetNumberOfFiles();
+  for (i = 0; i < numf; i++)
+    {
+    std::string file = dir.GetFile(i);
+    if(file != "." && file != ".."
+       && !cmSystemTools::FileIsDirectory(file.c_str()))
+      {
+      std::string path = d;
+      path += "/";
+      path += file;
+      if(!this->ReadPHPData(path.c_str()))
+        {
+        return false;
+        }
+      }
+    }
+  return true;
+}

+ 48 - 0
Source/CTest/cmParsePHPCoverage.h

@@ -0,0 +1,48 @@
+/*============================================================================
+  CMake - Cross Platform Makefile Generator
+  Copyright 2000-2009 Kitware, Inc.
+
+  Distributed under the OSI-approved BSD License (the "License");
+  see accompanying file Copyright.txt for details.
+
+  This software is distributed WITHOUT ANY WARRANTY; without even the
+  implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+  See the License for more information.
+============================================================================*/
+
+#ifndef cmParsePHPCoverage_h
+#define cmParsePHPCoverage_h
+
+#include "cmStandardIncludes.h"
+#include "cmCTestCoverageHandler.h"
+
+/** \class cmParsePHPCoverage
+ * \brief Parse xdebug PHP coverage information
+ *
+ * This class is used to parse php coverage information produced
+ * by xdebug.  The data is stored as a php dump of the array
+ * return by xdebug coverage.  It is an array of arrays.
+ */
+class cmParsePHPCoverage
+{
+public:
+  cmParsePHPCoverage(cmCTestCoverageHandlerContainer& cont,
+    cmCTest* ctest);
+  bool ReadPHPCoverageDirectory(const char* dir);
+  void PrintCoverage();
+private:
+  bool ReadPHPData(const char* file);
+  bool ReadArraySize(std::ifstream& in, int& size);
+  bool ReadFileInformation(std::ifstream& in);
+  bool ReadInt(std::ifstream& in, int& v);
+  bool ReadCoverageArray(std::ifstream& in, cmStdString const&);
+  bool ReadUntil(std::ifstream& in, char until);
+  typedef std::map<int, int> FileLineCoverage;
+  std::map<cmStdString, FileLineCoverage> FileToCoverage;
+  std::map<int, int> FileCoverage;
+  cmCTestCoverageHandlerContainer& Coverage;
+  cmCTest* CTest;
+};
+
+
+#endif

+ 1 - 1
Source/QtDialog/CMakeSetup.cxx

@@ -164,7 +164,7 @@ int main(int argc, char** argv)
     QStringList args = app.arguments();
     if(args.count() == 2)
       {
-      cmsys_stl::string filePath = cmSystemTools::CollapseFullPath("..");
+      cmsys_stl::string filePath = cmSystemTools::CollapseFullPath(args[1].toAscii().data());
       cmsys_stl::string buildFilePath =
         cmSystemTools::CollapseFullPath("CMakeCache.txt", filePath.c_str());
       cmsys_stl::string srcFilePath =

+ 260 - 29
Source/cmFileCommand.cxx

@@ -183,24 +183,18 @@ bool cmFileCommand::HandleWriteCommand(std::vector<std::string> const& args,
   std::string dir = cmSystemTools::GetFilenamePath(fileName);
   cmSystemTools::MakeDirectory(dir.c_str());
 
-  mode_t mode =
-#if defined( _MSC_VER ) || defined( __MINGW32__ )
-    S_IREAD | S_IWRITE
-#elif defined( __BORLANDC__ )
-    S_IRUSR | S_IWUSR
-#else
-    0666
-#endif
-    ;
+  mode_t mode = 0;
 
   // Set permissions to writable
   if ( cmSystemTools::GetPermissions(fileName.c_str(), mode) )
     {
     cmSystemTools::SetPermissions(fileName.c_str(),
 #if defined( _MSC_VER ) || defined( __MINGW32__ )
-      S_IREAD | S_IWRITE
+      mode | S_IWRITE
+#elif defined( __BORLANDC__ )
+      mode | S_IWUSR
 #else
-      0666
+      mode | S_IWUSR | S_IWGRP
 #endif
     );
     }
@@ -217,7 +211,10 @@ bool cmFileCommand::HandleWriteCommand(std::vector<std::string> const& args,
     }
   file << message;
   file.close();
-  cmSystemTools::SetPermissions(fileName.c_str(), mode);
+  if(mode)
+    {
+    cmSystemTools::SetPermissions(fileName.c_str(), mode);
+    }
   return true;
 }
 
@@ -1507,7 +1504,7 @@ bool cmFileCopier::InstallFile(const char* fromFile, const char* toFile,
   this->ReportCopy(toFile, TypeFile, copy);
 
   // Copy the file.
-  if(copy && !cmSystemTools::CopyAFile(fromFile, toFile, true, false))
+  if(copy && !cmSystemTools::CopyAFile(fromFile, toFile, true))
     {
     cmOStringStream e;
     e << this->Name << " cannot copy file \"" << fromFile
@@ -1519,6 +1516,13 @@ bool cmFileCopier::InstallFile(const char* fromFile, const char* toFile,
   // Set the file modification time of the destination file.
   if(copy && !this->Always)
     {
+    // Add write permission so we can set the file time.
+    // Permissions are set unconditionally below anyway.
+    mode_t perm = 0;
+    if(cmSystemTools::GetPermissions(toFile, perm))
+      {
+      cmSystemTools::SetPermissions(toFile, perm | mode_owner_write);
+      }
     if (!cmSystemTools::CopyFileTime(fromFile, toFile))
       {
       cmOStringStream e;
@@ -2443,7 +2447,8 @@ namespace{
     fout->write(chPtr, realsize);
     return realsize;
   }
-  
+
+
   static size_t
   cmFileCommandCurlDebugCallback(CURL *, curl_infotype, char *chPtr,
                                         size_t size, void *data)
@@ -2456,6 +2461,72 @@ namespace{
   }
 
 
+  class cURLProgressHelper
+  {
+  public:
+    cURLProgressHelper(cmFileCommand *fc)
+      {
+      this->CurrentPercentage = -1;
+      this->FileCommand = fc;
+      }
+
+    bool UpdatePercentage(double value, double total, std::string &status)
+      {
+      int OldPercentage = this->CurrentPercentage;
+
+      if (0.0 == total)
+        {
+        this->CurrentPercentage = 100;
+        }
+      else
+        {
+        this->CurrentPercentage = static_cast<int>(value/total*100.0 + 0.5);
+        }
+
+      bool updated = (OldPercentage != this->CurrentPercentage);
+
+      if (updated)
+        {
+        cmOStringStream oss;
+        oss << "[download " << this->CurrentPercentage << "% complete]";
+        status = oss.str();
+        }
+
+      return updated;
+      }
+
+    cmFileCommand *GetFileCommand()
+      {
+      return this->FileCommand;
+      }
+
+  private:
+    int CurrentPercentage;
+    cmFileCommand *FileCommand;
+  };
+
+
+  static int
+  cmFileCommandCurlProgressCallback(void *clientp,
+                                    double dltotal, double dlnow,
+                                    double ultotal, double ulnow)
+  {
+    cURLProgressHelper *helper =
+      reinterpret_cast<cURLProgressHelper *>(clientp);
+
+    static_cast<void>(ultotal);
+    static_cast<void>(ulnow);
+
+    std::string status;
+    if (helper->UpdatePercentage(dlnow, dltotal, status))
+      {
+      cmFileCommand *fc = helper->GetFileCommand();
+      cmMakefile *mf = fc->GetMakefile();
+      mf->DisplayStatus(status.c_str(), -1);
+      }
+
+    return 0;
+  }
 }
 
 #endif
@@ -2469,8 +2540,8 @@ namespace {
     cURLEasyGuard(CURL * easy)
       : Easy(easy)
       {}
-    
-    ~cURLEasyGuard(void) 
+
+    ~cURLEasyGuard(void)
       {
         if (this->Easy)
           {
@@ -2491,6 +2562,7 @@ namespace {
 }
 #endif
 
+
 bool
 cmFileCommand::HandleDownloadCommand(std::vector<std::string>
                                      const& args)
@@ -2508,9 +2580,13 @@ cmFileCommand::HandleDownloadCommand(std::vector<std::string>
   ++i;
   std::string file = *i;
   ++i;
+
   long timeout = 0;
   std::string verboseLog;
   std::string statusVar;
+  std::string expectedMD5sum;
+  bool showProgress = false;
+
   while(i != args.end())
     {
     if(*i == "TIMEOUT")
@@ -2549,9 +2625,65 @@ cmFileCommand::HandleDownloadCommand(std::vector<std::string>
         }
       statusVar = *i;
       }
+    else if(*i == "EXPECTED_MD5")
+      {
+      ++i;
+      if( i == args.end())
+        {
+        this->SetError("FILE(DOWNLOAD url file EXPECTED_MD5 sum) missing "
+                       "sum value for EXPECTED_MD5.");
+        return false;
+        }
+      expectedMD5sum = cmSystemTools::LowerCase(*i);
+      }
+    else if(*i == "SHOW_PROGRESS")
+      {
+      showProgress = true;
+      }
     ++i;
     }
 
+  // If file exists already, and caller specified an expected md5 sum,
+  // and the existing file already has the expected md5 sum, then simply
+  // return.
+  //
+  if(cmSystemTools::FileExists(file.c_str()) &&
+    !expectedMD5sum.empty())
+    {
+    char computedMD5[32];
+
+    if (!cmSystemTools::ComputeFileMD5(file.c_str(), computedMD5))
+      {
+      this->SetError("FILE(DOWNLOAD ) error; cannot compute MD5 sum on "
+        "pre-existing file");
+      return false;
+      }
+
+    std::string actualMD5sum = cmSystemTools::LowerCase(
+      std::string(computedMD5, 32));
+
+    if (expectedMD5sum == actualMD5sum)
+      {
+      this->Makefile->DisplayStatus(
+        "FILE(DOWNLOAD ) returning early: file already exists with "
+        "expected MD5 sum", -1);
+
+      if(statusVar.size())
+        {
+        cmOStringStream result;
+        result << (int)0 << ";\""
+          "returning early: file already exists with expected MD5 sum\"";
+        this->Makefile->AddDefinition(statusVar.c_str(),
+                                      result.str().c_str());
+        }
+
+      return true;
+      }
+    }
+
+  // Make sure parent directory exists so we can write to the file
+  // as we receive downloaded bits from curl...
+  //
   std::string dir = cmSystemTools::GetFilenamePath(file.c_str());
   if(!cmSystemTools::FileExists(dir.c_str()) &&
      !cmSystemTools::MakeDirectory(dir.c_str()))
@@ -2570,6 +2702,7 @@ cmFileCommand::HandleDownloadCommand(std::vector<std::string>
                        "file for write.");
     return false;
     }
+
   ::CURL *curl;
   ::curl_global_init(CURL_GLOBAL_DEFAULT);
   curl = ::curl_easy_init();
@@ -2585,28 +2718,31 @@ cmFileCommand::HandleDownloadCommand(std::vector<std::string>
   ::CURLcode res = ::curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
   if (res != CURLE_OK)
     {
-      std::string errstring = "FILE(DOWNLOAD ) error; cannot set url: ";
-      errstring += ::curl_easy_strerror(res);
+    std::string errstring = "FILE(DOWNLOAD ) error; cannot set url: ";
+    errstring += ::curl_easy_strerror(res);
+    this->SetError(errstring.c_str());
     return false;
     }
 
   res = ::curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION,
-                             cmFileCommandWriteMemoryCallback);
+                           cmFileCommandWriteMemoryCallback);
   if (res != CURLE_OK)
-      {
-      std::string errstring =
-        "FILE(DOWNLOAD ) error; cannot set write function: ";
-      errstring += ::curl_easy_strerror(res);
+    {
+    std::string errstring =
+      "FILE(DOWNLOAD ) error; cannot set write function: ";
+    errstring += ::curl_easy_strerror(res);
+    this->SetError(errstring.c_str());
     return false;
     }
 
   res = ::curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION,
-                             cmFileCommandCurlDebugCallback);
+                           cmFileCommandCurlDebugCallback);
   if (res != CURLE_OK)
     {
-     std::string errstring =
-       "FILE(DOWNLOAD ) error; cannot set debug function: ";
-     errstring += ::curl_easy_strerror(res);
+    std::string errstring =
+      "FILE(DOWNLOAD ) error; cannot set debug function: ";
+    errstring += ::curl_easy_strerror(res);
+    this->SetError(errstring.c_str());
     return false;
     }
 
@@ -2618,14 +2754,25 @@ cmFileCommand::HandleDownloadCommand(std::vector<std::string>
     {
     std::string errstring = "FILE(DOWNLOAD ) error; cannot set write data: ";
     errstring += ::curl_easy_strerror(res);
+    this->SetError(errstring.c_str());
     return false;
     }
 
   res = ::curl_easy_setopt(curl, CURLOPT_DEBUGDATA, (void *)&chunkDebug);
   if (res != CURLE_OK)
     {
-    std::string errstring = "FILE(DOWNLOAD ) error; cannot set write data: ";
+    std::string errstring = "FILE(DOWNLOAD ) error; cannot set debug data: ";
     errstring += ::curl_easy_strerror(res);
+    this->SetError(errstring.c_str());
+    return false;
+    }
+
+  res = ::curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
+  if (res != CURLE_OK)
+    {
+    std::string errstring = "FILE(DOWNLOAD ) error; cannot set follow-redirect option: ";
+    errstring += ::curl_easy_strerror(res);
+    this->SetError(errstring.c_str());
     return false;
     }
 
@@ -2637,24 +2784,70 @@ cmFileCommand::HandleDownloadCommand(std::vector<std::string>
       {
       std::string errstring = "FILE(DOWNLOAD ) error; cannot set verbose: ";
       errstring += ::curl_easy_strerror(res);
+      this->SetError(errstring.c_str());
       return false;
       }
     }
+
   if(timeout > 0)
     {
     res = ::curl_easy_setopt(curl, CURLOPT_TIMEOUT, timeout );
 
     if (res != CURLE_OK)
       {
-      std::string errstring = "FILE(DOWNLOAD ) error; cannot set verbose: ";
+      std::string errstring = "FILE(DOWNLOAD ) error; cannot set timeout: ";
       errstring += ::curl_easy_strerror(res);
+      this->SetError(errstring.c_str());
       return false;
       }
     }
+
+  // Need the progress helper's scope to last through the duration of
+  // the curl_easy_perform call... so this object is declared at function
+  // scope intentionally, rather than inside the "if(showProgress)"
+  // block...
+  //
+  cURLProgressHelper helper(this);
+
+  if(showProgress)
+    {
+    res = ::curl_easy_setopt(curl,
+      CURLOPT_NOPROGRESS, 0);
+    if (res != CURLE_OK)
+      {
+      std::string errstring = "FILE(DOWNLOAD ) error; cannot set noprogress value: ";
+      errstring += ::curl_easy_strerror(res);
+      this->SetError(errstring.c_str());
+      return false;
+      }
+
+    res = ::curl_easy_setopt(curl,
+      CURLOPT_PROGRESSFUNCTION, cmFileCommandCurlProgressCallback);
+    if (res != CURLE_OK)
+      {
+      std::string errstring = "FILE(DOWNLOAD ) error; cannot set progress function: ";
+      errstring += ::curl_easy_strerror(res);
+      this->SetError(errstring.c_str());
+      return false;
+      }
+
+    res = ::curl_easy_setopt(curl,
+      CURLOPT_PROGRESSDATA, reinterpret_cast<void*>(&helper));
+    if (res != CURLE_OK)
+      {
+      std::string errstring = "FILE(DOWNLOAD ) error; cannot set progress data: ";
+      errstring += ::curl_easy_strerror(res);
+      this->SetError(errstring.c_str());
+      return false;
+      }
+    }
+
   res = ::curl_easy_perform(curl);
+
   /* always cleanup */
   g_curl.release();
   ::curl_easy_cleanup(curl);
+
   if(statusVar.size())
     {
     cmOStringStream result;
@@ -2662,7 +2855,44 @@ cmFileCommand::HandleDownloadCommand(std::vector<std::string>
     this->Makefile->AddDefinition(statusVar.c_str(),
                                   result.str().c_str());
     }
+
   ::curl_global_cleanup();
+
+  // Explicitly flush/close so we can measure the md5 accurately.
+  //
+  fout.flush();
+  fout.close();
+
+  // Verify MD5 sum if requested:
+  //
+  if (!expectedMD5sum.empty())
+    {
+    char computedMD5[32];
+
+    if (!cmSystemTools::ComputeFileMD5(file.c_str(), computedMD5))
+      {
+      this->SetError("FILE(DOWNLOAD ) error; cannot compute MD5 sum on "
+        "downloaded file");
+      return false;
+      }
+
+    std::string actualMD5sum = cmSystemTools::LowerCase(
+      std::string(computedMD5, 32));
+
+    if (expectedMD5sum != actualMD5sum)
+      {
+      cmOStringStream oss;
+      oss << "FILE(DOWNLOAD ) error; expected and actual MD5 sums differ"
+        << std::endl
+        << "  for file: [" << file << "]" << std::endl
+        << "    expected MD5 sum: [" << expectedMD5sum << "]" << std::endl
+        << "      actual MD5 sum: [" << actualMD5sum << "]" << std::endl
+        ;
+      this->SetError(oss.str().c_str());
+      return false;
+      }
+    }
+
   if(chunkDebug.size())
     {
     chunkDebug.push_back(0);
@@ -2680,6 +2910,7 @@ cmFileCommand::HandleDownloadCommand(std::vector<std::string>
     this->Makefile->AddDefinition(verboseLog.c_str(),
                                   &*chunkDebug.begin());
     }
+
   return true;
 #else
   this->SetError("FILE(DOWNLOAD ) "

+ 8 - 2
Source/cmFileCommand.h

@@ -80,7 +80,8 @@ public:
       "  file(RELATIVE_PATH variable directory file)\n"
       "  file(TO_CMAKE_PATH path result)\n"
       "  file(TO_NATIVE_PATH path result)\n"
-      "  file(DOWNLOAD url file [TIMEOUT timeout] [STATUS status] [LOG log])\n"
+      "  file(DOWNLOAD url file [TIMEOUT timeout] [STATUS status] [LOG log]\n"
+      "       [EXPECTED_MD5 sum] [SHOW_PROGRESS])\n"
       "WRITE will write a message into a file called 'filename'. It "
       "overwrites the file if it already exists, and creates the file "
       "if it does not exist.\n"
@@ -152,7 +153,12 @@ public:
       "and the second element is a string value for the error. A 0 "
       "numeric error means no error in the operation. "
       "If TIMEOUT time is specified, the operation will "
-      "timeout after time seconds, time should be specified as an integer."
+      "timeout after time seconds, time should be specified as an integer. "
+      "If EXPECTED_MD5 sum is specified, the operation will verify that the "
+      "downloaded file's actual md5 sum matches the expected value. If it "
+      "does not match, the operation fails with an error. "
+      "If SHOW_PROGRESS is specified, progress information will be printed "
+      "as status messages until the operation is complete."
       "\n"
       "The file() command also provides COPY and INSTALL signatures:\n"
       "  file(<COPY|INSTALL> files... DESTINATION <dir>\n"

+ 9 - 3
Source/cmGlobalXCodeGenerator.cxx

@@ -1514,8 +1514,13 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmTarget& target,
     extraLinkOptions = this->CurrentMakefile->
       GetRequiredDefinition("CMAKE_MODULE_LINKER_FLAGS");
     }
-  
-  const char* targetLinkFlags = target.GetProperty("LINK_FLAGS");
+
+  const char* linkFlagsProp = "LINK_FLAGS";
+  if(target.GetType() == cmTarget::STATIC_LIBRARY)
+    {
+    linkFlagsProp = "STATIC_LIBRARY_FLAGS";
+    }
+  const char* targetLinkFlags = target.GetProperty(linkFlagsProp);
   if(targetLinkFlags)
     {
     extraLinkOptions += " ";
@@ -1523,7 +1528,8 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmTarget& target,
     }
   if(configName && *configName)
     {
-    std::string linkFlagsVar = "LINK_FLAGS_";
+    std::string linkFlagsVar = linkFlagsProp;
+    linkFlagsVar += "_";
     linkFlagsVar += cmSystemTools::UpperCase(configName);
     if(const char* linkFlags = target.GetProperty(linkFlagsVar.c_str()))
       {

+ 22 - 0
Source/cmLocalUnixMakefileGenerator3.cxx

@@ -973,6 +973,24 @@ cmLocalUnixMakefileGenerator3
                                       this->ConfigurationName.c_str());
     if (cmd.size())
       {
+      // Use "call " before any invocations of .bat or .cmd files
+      // invoked as custom commands in the WindowsShell.
+      //
+      bool useCall = false;
+
+      if (this->WindowsShell)
+        {
+        std::string suffix;
+        if (cmd.size() > 4)
+          {
+          suffix = cmSystemTools::LowerCase(cmd.substr(cmd.size()-4));
+          if (suffix == ".bat" || suffix == ".cmd")
+            {
+            useCall = true;
+            }
+          }
+        }
+
       cmSystemTools::ReplaceString(cmd, "/./", "/");
       // Convert the command to a relative path only if the current
       // working directory will be the start-output directory.
@@ -1044,6 +1062,10 @@ cmLocalUnixMakefileGenerator3
             }
           }
         }
+      if (useCall && launcher.empty())
+        {
+        cmd = "call " + cmd;
+        }
       commands1.push_back(cmd);
       }
     }

+ 85 - 29
Source/cmLocalVisualStudio6Generator.cxx

@@ -1142,6 +1142,10 @@ void cmLocalVisualStudio6Generator
 
   // Get extra linker options for this target type.
   std::string extraLinkOptions;
+  std::string extraLinkOptionsDebug;
+  std::string extraLinkOptionsRelease;
+  std::string extraLinkOptionsMinSizeRel;
+  std::string extraLinkOptionsRelWithDebInfo;
   if(target.GetType() == cmTarget::EXECUTABLE)
     {
     extraLinkOptions = 
@@ -1165,6 +1169,33 @@ void cmLocalVisualStudio6Generator
     extraLinkOptions += targetLinkFlags;
     }
 
+  if(const char* targetLinkFlags = target.GetProperty("LINK_FLAGS_DEBUG"))
+    {
+    extraLinkOptionsDebug += " ";
+    extraLinkOptionsDebug += targetLinkFlags;
+    }
+
+  if(const char* targetLinkFlags = target.GetProperty("LINK_FLAGS_RELEASE"))
+    {
+    extraLinkOptionsRelease += " ";
+    extraLinkOptionsRelease += targetLinkFlags;
+    }
+
+  if(const char* targetLinkFlags = target.GetProperty("LINK_FLAGS_MINSIZEREL"))
+    {
+    extraLinkOptionsMinSizeRel += " ";
+    extraLinkOptionsMinSizeRel += targetLinkFlags;
+    }
+
+  if(const char* targetLinkFlags = target.GetProperty("LINK_FLAGS_RELWITHDEBINFO"))
+    {
+    extraLinkOptionsRelWithDebInfo += " ";
+    extraLinkOptionsRelWithDebInfo += targetLinkFlags;
+    }
+
+
+
+
   // Get standard libraries for this language.
   if(targetBuilds)
     {
@@ -1259,13 +1290,21 @@ void cmLocalVisualStudio6Generator
      target.GetType() == cmTarget::SHARED_LIBRARY ||
      target.GetType() == cmTarget::MODULE_LIBRARY)
     {
-    this->ComputeLinkOptions(target, "Debug", extraLinkOptions,
+    extraLinkOptionsDebug =
+      extraLinkOptions + " " + extraLinkOptionsDebug;
+    extraLinkOptionsRelease =
+      extraLinkOptions + " " + extraLinkOptionsRelease;
+    extraLinkOptionsMinSizeRel =
+      extraLinkOptions + " " + extraLinkOptionsMinSizeRel;
+    extraLinkOptionsRelWithDebInfo =
+      extraLinkOptions + " " + extraLinkOptionsRelWithDebInfo;
+    this->ComputeLinkOptions(target, "Debug", extraLinkOptionsDebug,
                              optionsDebug);
-    this->ComputeLinkOptions(target, "Release", extraLinkOptions,
+    this->ComputeLinkOptions(target, "Release", extraLinkOptionsRelease,
                              optionsRelease);
-    this->ComputeLinkOptions(target, "MinSizeRel", extraLinkOptions,
+    this->ComputeLinkOptions(target, "MinSizeRel", extraLinkOptionsMinSizeRel,
                              optionsMinSizeRel);
-    this->ComputeLinkOptions(target, "RelWithDebInfo", extraLinkOptions,
+    this->ComputeLinkOptions(target, "RelWithDebInfo", extraLinkOptionsRelWithDebInfo,
                              optionsRelWithDebInfo);
     }
 
@@ -1342,11 +1381,43 @@ void cmLocalVisualStudio6Generator
     cmSystemTools::Error("Error Reading ", this->DSPHeaderTemplate.c_str());
     }
   std::string staticLibOptions;
+  std::string staticLibOptionsDebug;
+  std::string staticLibOptionsRelease;
+  std::string staticLibOptionsMinSizeRel;
+  std::string staticLibOptionsRelWithDebInfo;
   if(target.GetType() == cmTarget::STATIC_LIBRARY )
     { 
     if(const char* libflags = target.GetProperty("STATIC_LIBRARY_FLAGS"))
       {
       staticLibOptions = libflags;
+      staticLibOptionsDebug = libflags;
+      staticLibOptionsRelease = libflags;
+      staticLibOptionsMinSizeRel = libflags;
+      staticLibOptionsRelWithDebInfo = libflags;
+      }
+    if(const char* libflagsDebug =
+       target.GetProperty("STATIC_LIBRARY_FLAGS_DEBUG"))
+      {
+      staticLibOptionsDebug += " ";
+      staticLibOptionsDebug = libflagsDebug;
+      }
+    if(const char* libflagsRelease =
+       target.GetProperty("STATIC_LIBRARY_FLAGS_RELEASE"))
+      {
+      staticLibOptionsRelease += " ";
+      staticLibOptionsRelease = libflagsRelease;
+      }
+    if(const char* libflagsMinSizeRel =
+       target.GetProperty("STATIC_LIBRARY_FLAGS_MINSIZEREL"))
+      {
+      staticLibOptionsMinSizeRel += " ";
+      staticLibOptionsMinSizeRel = libflagsMinSizeRel;
+      }
+    if(const char* libflagsRelWithDebInfo =
+       target.GetProperty("STATIC_LIBRARY_FLAGS_RELWITHDEBINFO"))
+      {
+      staticLibOptionsRelWithDebInfo += " ";
+      staticLibOptionsRelWithDebInfo = libflagsRelWithDebInfo;
       }
     }
 
@@ -1378,6 +1449,14 @@ void cmLocalVisualStudio6Generator
                                  mfcFlag);
     if(target.GetType() == cmTarget::STATIC_LIBRARY )
       {
+      cmSystemTools::ReplaceString(line, "CM_STATIC_LIB_ARGS_DEBUG",
+                                   staticLibOptionsDebug.c_str());
+      cmSystemTools::ReplaceString(line, "CM_STATIC_LIB_ARGS_RELEASE",
+                                   staticLibOptionsRelease.c_str());
+      cmSystemTools::ReplaceString(line, "CM_STATIC_LIB_ARGS_MINSIZEREL",
+                                   staticLibOptionsMinSizeRel.c_str());
+      cmSystemTools::ReplaceString(line, "CM_STATIC_LIB_ARGS_RELWITHDEBINFO",
+                                   staticLibOptionsRelWithDebInfo.c_str());
       cmSystemTools::ReplaceString(line, "CM_STATIC_LIB_ARGS",
                                    staticLibOptions.c_str());
       } 
@@ -1519,41 +1598,18 @@ void cmLocalVisualStudio6Generator
       std::string flagVar = baseFlagVar + "_RELEASE";
       flagsRelease = this->Makefile->GetSafeDefinition(flagVar.c_str());
       flagsRelease += " -DCMAKE_INTDIR=\\\"Release\\\" ";
-      if(const char* targetLinkFlags = 
-         target.GetProperty("LINK_FLAGS_RELEASE"))
-        {
-        flagsRelease += targetLinkFlags;
-        flagsRelease += " ";
-        }
+
       flagVar = baseFlagVar + "_MINSIZEREL";
       flagsMinSize = this->Makefile->GetSafeDefinition(flagVar.c_str());
       flagsMinSize += " -DCMAKE_INTDIR=\\\"MinSizeRel\\\" ";
-      if(const char* targetLinkFlags = 
-         target.GetProperty("LINK_FLAGS_MINSIZEREL"))
-        {
-        flagsMinSize += targetLinkFlags;
-        flagsMinSize += " ";
-        }
-      
+
       flagVar = baseFlagVar + "_DEBUG";
       flagsDebug = this->Makefile->GetSafeDefinition(flagVar.c_str());
       flagsDebug += " -DCMAKE_INTDIR=\\\"Debug\\\" ";
-      if(const char* targetLinkFlags = target.GetProperty("LINK_FLAGS_DEBUG"))
-        {
-        flagsDebug += targetLinkFlags;
-        flagsDebug += " ";
-        }
 
       flagVar = baseFlagVar + "_RELWITHDEBINFO";
       flagsDebugRel = this->Makefile->GetSafeDefinition(flagVar.c_str());
       flagsDebugRel += " -DCMAKE_INTDIR=\\\"RelWithDebInfo\\\" ";
-      if(const char* targetLinkFlags = 
-         target.GetProperty("LINK_FLAGS_RELWITHDEBINFO"))
-        {
-        flagsDebugRel += targetLinkFlags;
-        flagsDebugRel += " ";
-        }
-
       }
     
     // if unicode is not found, then add -D_MBCS

+ 14 - 1
Source/cmLocalVisualStudio7Generator.cxx

@@ -915,7 +915,20 @@ void cmLocalVisualStudio7Generator::OutputBuildTool(std::ostream& fout,
       }
     fout << "\t\t\t<Tool\n"
          << "\t\t\t\tName=\"" << tool << "\"\n";
-    if(const char* libflags = target.GetProperty("STATIC_LIBRARY_FLAGS"))
+
+    std::string libflags;
+    if(const char* flags = target.GetProperty("STATIC_LIBRARY_FLAGS"))
+      {
+      libflags += flags;
+      }
+    std::string libFlagsConfig = "STATIC_LIBRARY_FLAGS_";
+    libFlagsConfig += configTypeUpper;
+    if(const char* flagsConfig = target.GetProperty(libFlagsConfig.c_str()))
+      {
+      libflags += " ";
+      libflags += flagsConfig;
+      }
+    if(!libflags.empty())
       {
       fout << "\t\t\t\tAdditionalOptions=\"" << libflags << "\"\n";
       }

+ 4 - 0
Source/cmMakefileLibraryTargetGenerator.cxx

@@ -122,6 +122,10 @@ void cmMakefileLibraryTargetGenerator::WriteStaticLibraryRules()
   std::string extraFlags;
   this->LocalGenerator->AppendFlags
     (extraFlags,this->Target->GetProperty("STATIC_LIBRARY_FLAGS"));
+  std::string staticLibraryFlagsConfig = "STATIC_LIBRARY_FLAGS_";
+  staticLibraryFlagsConfig += cmSystemTools::UpperCase(this->ConfigName);
+  this->LocalGenerator->AppendFlags
+    (extraFlags, this->Target->GetProperty(staticLibraryFlagsConfig.c_str()));
   this->WriteLibraryRules(linkRuleVar.c_str(), extraFlags.c_str(), false);
 }
 

+ 15 - 0
Source/cmSystemTools.cxx

@@ -2938,3 +2938,18 @@ bool cmSystemTools::CheckRPath(std::string const& file,
   return false;
 #endif
 }
+
+//----------------------------------------------------------------------------
+bool cmSystemTools::RepeatedRemoveDirectory(const char* dir)
+{
+  // Windows sometimes locks files temporarily so try a few times.
+  for(int i = 0; i < 10; ++i)
+    {
+    if(cmSystemTools::RemoveADirectory(dir))
+      {
+      return true;
+      }
+    cmSystemTools::Delay(100);
+    }
+  return false;
+}

+ 3 - 0
Source/cmSystemTools.h

@@ -436,6 +436,9 @@ public:
   static bool CheckRPath(std::string const& file,
                          std::string const& newRPath);
 
+  /** Remove a directory; repeat a few times in case of locked files.  */
+  static bool RepeatedRemoveDirectory(const char* dir);
+
 private:
   static bool s_ForceUnixPaths;
   static bool s_RunCommandHideConsole;

+ 5 - 0
Source/cmTarget.cxx

@@ -707,6 +707,11 @@ void cmTarget::DefineProperties(cmake *cm)
      "Extra flags to use when linking static libraries.",
      "Extra flags to use when linking a static library.");
 
+  cm->DefineProperty
+    ("STATIC_LIBRARY_FLAGS_<CONFIG>", cmProperty::TARGET,
+     "Per-configuration flags for creating a static library.",
+     "This is the configuration-specific version of STATIC_LIBRARY_FLAGS.");
+
   cm->DefineProperty
     ("SUFFIX", cmProperty::TARGET,
      "What comes after the library name.",

+ 24 - 5
Source/cmVisualStudio10TargetGenerator.cxx

@@ -860,6 +860,13 @@ OutputLinkIncremental(std::string const& configName)
     flags += " ";
     flags += targetLinkFlags;
     }
+  std::string flagsProp = "LINK_FLAGS_";
+  flagsProp += CONFIG;
+  if(const char* flagsConfig = this->Target->GetProperty(flagsProp.c_str()))
+    {
+    flags += " ";
+    flags += flagsConfig;
+    }
   if(flags.find("INCREMENTAL:NO") != flags.npos)
     {
     incremental = "false";
@@ -1016,22 +1023,27 @@ WriteRCOptions(std::string const& ,
 }
 
 
-void cmVisualStudio10TargetGenerator::WriteLibOptions(std::string const&
-                                                      )
+void
+cmVisualStudio10TargetGenerator::WriteLibOptions(std::string const& config)
 {
   if(this->Target->GetType() != cmTarget::STATIC_LIBRARY)
     {
     return;
     }
-  if(const char* libflags = this->Target
-     ->GetProperty("STATIC_LIBRARY_FLAGS"))
+  const char* libflags = this->Target->GetProperty("STATIC_LIBRARY_FLAGS");
+  std::string flagsConfigVar = "STATIC_LIBRARY_FLAGS_";
+  flagsConfigVar += cmSystemTools::UpperCase(config);
+  const char* libflagsConfig =
+    this->Target->GetProperty(flagsConfigVar.c_str());
+  if(libflags || libflagsConfig)
     {
     this->WriteString("<Lib>\n", 2);
     cmVisualStudioGeneratorOptions
       libOptions(this->LocalGenerator, 10,
                  cmVisualStudioGeneratorOptions::Linker,
                  cmVS10LibFlagTable, 0, this);
-    libOptions.Parse(libflags);  
+    libOptions.Parse(libflags?libflags:"");
+    libOptions.Parse(libflagsConfig?libflagsConfig:"");
     libOptions.OutputAdditionalOptions(*this->BuildFileStream, "      ", "");
     libOptions.OutputFlagMap(*this->BuildFileStream, "      "); 
     this->WriteString("</Lib>\n", 2);
@@ -1099,6 +1111,13 @@ void cmVisualStudio10TargetGenerator::WriteLinkOptions(std::string const&
     flags += " ";
     flags += targetLinkFlags;
     }
+  std::string flagsProp = "LINK_FLAGS_";
+  flagsProp += CONFIG;
+  if(const char* flagsConfig = this->Target->GetProperty(flagsProp.c_str()))
+    {
+    flags += " ";
+    flags += flagsConfig;
+    }
   cmVisualStudioGeneratorOptions
     linkOptions(this->LocalGenerator, 10,
                 cmVisualStudioGeneratorOptions::Linker,

+ 9 - 12
Source/cmWriteFileCommand.cxx

@@ -54,24 +54,18 @@ bool cmWriteFileCommand
   std::string dir = cmSystemTools::GetFilenamePath(fileName);
   cmSystemTools::MakeDirectory(dir.c_str());
 
-  mode_t mode =
-#if defined( _MSC_VER ) || defined( __MINGW32__ )
-    S_IREAD | S_IWRITE
-#elif defined( __BORLANDC__ )
-    S_IRUSR | S_IWUSR
-#else
-    0666
-#endif
-    ;
+  mode_t mode = 0;
 
   // Set permissions to writable
   if ( cmSystemTools::GetPermissions(fileName.c_str(), mode) )
     {
     cmSystemTools::SetPermissions(fileName.c_str(),
 #if defined( _MSC_VER ) || defined( __MINGW32__ )
-      S_IREAD | S_IWRITE
+      mode | S_IWRITE
+#elif defined( __BORLANDC__ )
+      mode | S_IWUSR
 #else
-      0666
+      mode | S_IWUSR | S_IWGRP
 #endif
     );
     }
@@ -89,7 +83,10 @@ bool cmWriteFileCommand
     }
   file << message << std::endl;
   file.close();
-  cmSystemTools::SetPermissions(fileName.c_str(), mode);
+  if(mode)
+    {
+    cmSystemTools::SetPermissions(fileName.c_str(), mode);
+    }
 
   return true;
 }

+ 8 - 0
Source/kwsys/CMakeLists.txt

@@ -309,6 +309,14 @@ IF(NOT KWSYS_IN_SOURCE_BUILD)
     ${PROJECT_BINARY_DIR}/kwsysPrivate.h COPY_ONLY IMMEDIATE)
 ENDIF(NOT KWSYS_IN_SOURCE_BUILD)
 
+# Select plugin module file name convention.
+IF(NOT KWSYS_DynamicLoader_PREFIX)
+  SET(KWSYS_DynamicLoader_PREFIX ${CMAKE_SHARED_MODULE_PREFIX})
+ENDIF()
+IF(NOT KWSYS_DynamicLoader_SUFFIX)
+  SET(KWSYS_DynamicLoader_SUFFIX ${CMAKE_SHARED_MODULE_SUFFIX})
+ENDIF()
+
 #-----------------------------------------------------------------------------
 # We require ANSI support from the C compiler.  Add any needed flags.
 IF(CMAKE_ANSI_CFLAGS)

+ 0 - 84
Source/kwsys/DynamicLoader.cxx

@@ -69,19 +69,6 @@ DynamicLoader::GetSymbolAddress(DynamicLoader::LibraryHandle lib, const char* sy
   return *reinterpret_cast<DynamicLoader::SymbolPointer*>(&result);
 }
 
-//----------------------------------------------------------------------------
-const char* DynamicLoader::LibPrefix()
-{
-  return "lib";
-}
-
-//----------------------------------------------------------------------------
-const char* DynamicLoader::LibExtension()
-{
-  return ".sl";
-}
-
-//----------------------------------------------------------------------------
 const char* DynamicLoader::LastError()
 {
   // TODO: Need implementation with errno/strerror
@@ -175,21 +162,6 @@ DynamicLoader::SymbolPointer DynamicLoader::GetSymbolAddress(
   return *reinterpret_cast<DynamicLoader::SymbolPointer*>(&result);
 }
 
-//----------------------------------------------------------------------------
-const char* DynamicLoader::LibPrefix()
-{
-  return "lib";
-}
-
-//----------------------------------------------------------------------------
-const char* DynamicLoader::LibExtension()
-{
-  // NSCreateObjectFileImageFromFile fail when dealing with dylib image
-  // it returns NSObjectFileImageInappropriateFile
-  //return ".dylib";
-  return ".so";
-}
-
 //----------------------------------------------------------------------------
 const char* DynamicLoader::LastError()
 {
@@ -284,22 +256,6 @@ DynamicLoader::SymbolPointer DynamicLoader::GetSymbolAddress(
 #endif
 }
 
-//----------------------------------------------------------------------------
-const char* DynamicLoader::LibPrefix()
-{
-#ifdef __MINGW32__
-  return "lib";
-#else
-  return "";
-#endif
-}
-
-//----------------------------------------------------------------------------
-const char* DynamicLoader::LibExtension()
-{
-  return ".dll";
-}
-
 //----------------------------------------------------------------------------
 const char* DynamicLoader::LastError()
 {
@@ -417,18 +373,6 @@ DynamicLoader::SymbolPointer DynamicLoader::GetSymbolAddress(
   return result.psym;
 }
 
-//----------------------------------------------------------------------------
-const char* DynamicLoader::LibPrefix()
-{
-  return "lib";
-}
-
-//----------------------------------------------------------------------------
-const char* DynamicLoader::LibExtension()
-{
-  return ".so";
-}
-
 //----------------------------------------------------------------------------
 const char* DynamicLoader::LastError()
 {
@@ -475,18 +419,6 @@ DynamicLoader::SymbolPointer DynamicLoader::GetSymbolAddress(
   return 0;
 }
 
-//----------------------------------------------------------------------------
-const char* DynamicLoader::LibPrefix()
-  {
-  return "lib";
-  }
-
-//----------------------------------------------------------------------------
-const char* DynamicLoader::LibExtension()
-  {
-  return ".a";
-  }
-
 //----------------------------------------------------------------------------
 const char* DynamicLoader::LastError()
   {
@@ -539,22 +471,6 @@ DynamicLoader::SymbolPointer DynamicLoader::GetSymbolAddress(
   return result.psym;
 }
 
-//----------------------------------------------------------------------------
-const char* DynamicLoader::LibPrefix()
-{
-  return "lib";
-}
-
-//----------------------------------------------------------------------------
-const char* DynamicLoader::LibExtension()
-{
-#ifdef __CYGWIN__
-  return ".dll";
-#else
-  return ".so";
-#endif
-}
-
 //----------------------------------------------------------------------------
 const char* DynamicLoader::LastError()
 {

+ 4 - 4
Source/kwsys/DynamicLoader.hxx.in

@@ -86,11 +86,11 @@ public:
   /** Find the address of the symbol in the given library. */
   static SymbolPointer GetSymbolAddress(LibraryHandle, const char*);
 
-  /** Return the library prefix for the given architecture */
-  static const char* LibPrefix();
+  /** Return the default module prefix for the current platform.  */
+  static const char* LibPrefix() { return "@KWSYS_DynamicLoader_PREFIX@"; }
 
-  /** Return the library extension for the given architecture. */
-  static const char* LibExtension();
+  /** Return the default module suffix for the current platform.  */
+  static const char* LibExtension() { return "@KWSYS_DynamicLoader_SUFFIX@"; }
 
   /** Return the last error produced from a calls made on this class. */
   static const char* LastError();

+ 11 - 0
Source/kwsys/ProcessUNIX.c

@@ -720,6 +720,14 @@ void kwsysProcess_Execute(kwsysProcess* cp)
     return;
     }
 
+  /* Make sure we have something to run.  */
+  if(cp->NumberOfCommands < 1)
+    {
+    strcpy(cp->ErrorMessage, "No command");
+    cp->State = kwsysProcess_State_Error;
+    return;
+    }
+
   /* Initialize the control structure for a new process.  */
   if(!kwsysProcessInitialize(cp))
     {
@@ -2377,6 +2385,9 @@ static pid_t kwsysProcessFork(kwsysProcess* cp,
    || defined(__OpenBSD__) || defined(__GLIBC__) || defined(__GNU__)
 # define KWSYSPE_PS_COMMAND "ps axo pid,ppid"
 # define KWSYSPE_PS_FORMAT  "%d %d\n"
+#elif defined(__sun) && (defined(__SVR4) || defined(__svr4__)) /* Solaris */
+# define KWSYSPE_PS_COMMAND "ps -e -o pid,ppid"
+# define KWSYSPE_PS_FORMAT  "%d %d\n"
 #elif defined(__hpux) || defined(__sun__) || defined(__sgi) || defined(_AIX) \
    || defined(__sparc)
 # define KWSYSPE_PS_COMMAND "ps -ef"

+ 8 - 0
Source/kwsys/ProcessWin32.c

@@ -987,6 +987,14 @@ void kwsysProcess_Execute(kwsysProcess* cp)
     return;
     }
 
+  /* Make sure we have something to run.  */
+  if(cp->NumberOfCommands < 1)
+    {
+    strcpy(cp->ErrorMessage, "No command");
+    cp->State = kwsysProcess_State_Error;
+    return;
+    }
+
   /* Initialize the control structure for a new process.  */
   if(!kwsysProcessInitialize(cp))
     {

+ 12 - 29
Source/kwsys/SystemTools.cxx

@@ -1722,8 +1722,7 @@ kwsys_stl::string SystemTools::ConvertToWindowsOutputPath(const char* path)
 }
 
 bool SystemTools::CopyFileIfDifferent(const char* source,
-                                      const char* destination,
-                                      bool copyPermissions)
+                                      const char* destination)
 {
   // special check for a destination that is a directory
   // FilesDiffer does not handle file to directory compare
@@ -1736,8 +1735,7 @@ bool SystemTools::CopyFileIfDifferent(const char* source,
     new_destination += SystemTools::GetFilenameName(source_name);
     if(SystemTools::FilesDiffer(source, new_destination.c_str()))
       {
-      return SystemTools::CopyFileAlways(source, destination,
-                                         copyPermissions);
+      return SystemTools::CopyFileAlways(source, destination);
       }
     else
       {
@@ -1750,7 +1748,7 @@ bool SystemTools::CopyFileIfDifferent(const char* source,
   // are different
   if(SystemTools::FilesDiffer(source, destination))
     {
-    return SystemTools::CopyFileAlways(source, destination, copyPermissions);
+    return SystemTools::CopyFileAlways(source, destination);
     }
   // at this point the files must be the same so return true
   return true;
@@ -1836,8 +1834,7 @@ bool SystemTools::FilesDiffer(const char* source,
 /**
  * Copy a file named by "source" to the file named by "destination".
  */
-bool SystemTools::CopyFileAlways(const char* source, const char* destination,
-                                 bool copyPermissions)
+bool SystemTools::CopyFileAlways(const char* source, const char* destination)
 {
   // If files are the same do not copy
   if ( SystemTools::SameFile(source, destination) )
@@ -1924,23 +1921,11 @@ bool SystemTools::CopyFileAlways(const char* source, const char* destination,
   fin.close();
   fout.close();
 
-  // More checks.
-  struct stat statSource, statDestination;
-  statSource.st_size = 12345;
-  statDestination.st_size = 12345;
-  if(stat(source, &statSource) != 0)
-    {
-    return false;
-    }
-  else if(stat(destination, &statDestination) != 0)
+  if(!fout)
     {
     return false;
     }
-  else if(statSource.st_size != statDestination.st_size)
-    {
-   return false;
-    }
-  if ( copyPermissions && perms )
+  if ( perms )
     {
     if ( !SystemTools::SetPermissions(destination, perm) )
       {
@@ -1952,15 +1937,15 @@ bool SystemTools::CopyFileAlways(const char* source, const char* destination,
 
 //----------------------------------------------------------------------------
 bool SystemTools::CopyAFile(const char* source, const char* destination,
-                            bool always, bool copyPermissions)
+                            bool always)
 {
   if(always)
     {
-    return SystemTools::CopyFileAlways(source, destination, copyPermissions);
+    return SystemTools::CopyFileAlways(source, destination);
     }
   else
     {
-    return SystemTools::CopyFileIfDifferent(source, destination, copyPermissions);
+    return SystemTools::CopyFileIfDifferent(source, destination);
     }
 }
 
@@ -1969,7 +1954,7 @@ bool SystemTools::CopyAFile(const char* source, const char* destination,
  * "destination".
  */
 bool SystemTools::CopyADirectory(const char* source, const char* destination,
-                                 bool always, bool copyPermissions)
+                                 bool always)
 {
   Directory dir;
   dir.Load(source);
@@ -1993,16 +1978,14 @@ bool SystemTools::CopyADirectory(const char* source, const char* destination,
         fullDestPath += dir.GetFile(static_cast<unsigned long>(fileNum));
         if (!SystemTools::CopyADirectory(fullPath.c_str(),
                                          fullDestPath.c_str(),
-                                         always,
-                                         copyPermissions))
+                                         always))
           {
           return false;
           }
         }
       else
         {
-        if(!SystemTools::CopyAFile(fullPath.c_str(), destination, always,
-                                   copyPermissions))
+        if(!SystemTools::CopyAFile(fullPath.c_str(), destination, always))
           {
           return false;
           }

+ 7 - 16
Source/kwsys/SystemTools.hxx.in

@@ -500,14 +500,10 @@ public:
 
   /**
    * Copy the source file to the destination file only
-   * if the two files differ. If the "copyPermissions"
-   * argument is true, the permissions of the copy are
-   * set to be the same as the permissions of the
-   * original.
+   * if the two files differ.
    */
   static bool CopyFileIfDifferent(const char* source,
-                                  const char* destination,
-                                  bool copyPermissions = true);
+                                  const char* destination);
 
   /**
    * Compare the contents of two files.  Return true if different
@@ -520,22 +516,17 @@ public:
   static bool SameFile(const char* file1, const char* file2);
 
   /**
-   * Copy a file. If the "copyPermissions" argument is true, the
-   * permissions of the copy are set to be the same as the permissions
-   * of the original.
+   * Copy a file.
    */
-  static bool CopyFileAlways(const char* source, const char* destination,
-                             bool copyPermissions = true);
+  static bool CopyFileAlways(const char* source, const char* destination);
 
   /**
    * Copy a file.  If the "always" argument is true the file is always
    * copied.  If it is false, the file is copied only if it is new or
-   * has changed. If the "copyPermissions" argument is true, the
-   * permissions of the copy are set to be the same as the permissions
-   * of the original.
+   * has changed.
    */
   static bool CopyAFile(const char* source, const char* destination,
-                        bool always = true, bool copyPermissions = true);
+                        bool always = true);
 
   /**
    * Copy content directory to another directory with all files and
@@ -544,7 +535,7 @@ public:
    * are new are copied.
    */
   static bool CopyADirectory(const char* source, const char* destination,
-                             bool always = true, bool copyPermissions = true);
+                             bool always = true);
   
   /**
    * Remove a file

+ 1 - 1
Source/kwsys/kwsysDateStamp.cmake

@@ -18,4 +18,4 @@ SET(KWSYS_DATE_STAMP_YEAR  2010)
 SET(KWSYS_DATE_STAMP_MONTH 06)
 
 # KWSys version date day component.  Format is DD.
-SET(KWSYS_DATE_STAMP_DAY   01)
+SET(KWSYS_DATE_STAMP_DAY   13)

+ 4 - 4
Templates/staticLibHeader.dsptemplate

@@ -67,7 +67,7 @@ BSC32=bscmake.exe
 # ADD BSC32 /nologo
 LIB32=link.exe -lib
 # ADD BASE LIB32 /nologo
-# ADD LIB32 /nologo /out:"OUTPUT_DIRECTORY_RELEASE/OUTPUT_NAME_RELEASE" CM_STATIC_LIB_ARGS
+# ADD LIB32 /nologo /out:"OUTPUT_DIRECTORY_RELEASE/OUTPUT_NAME_RELEASE" CM_STATIC_LIB_ARGS_RELEASE
 
 CMAKE_CUSTOM_RULE_CODE_RELEASE
 
@@ -97,7 +97,7 @@ BSC32=bscmake.exe
 # ADD BSC32 /nologo
 LIB32=link.exe -lib
 # ADD BASE LIB32 /nologo
-# ADD LIB32 /nologo /out:"OUTPUT_DIRECTORY_DEBUG/OUTPUT_NAME_DEBUG" CM_STATIC_LIB_ARGS
+# ADD LIB32 /nologo /out:"OUTPUT_DIRECTORY_DEBUG/OUTPUT_NAME_DEBUG" CM_STATIC_LIB_ARGS_DEBUG
 
 CMAKE_CUSTOM_RULE_CODE_DEBUG
 
@@ -128,7 +128,7 @@ BSC32=bscmake.exe
 # ADD BSC32 /nologo
 LIB32=link.exe -lib
 # ADD BASE LIB32 /nologo
-# ADD LIB32 /nologo /out:"OUTPUT_DIRECTORY_MINSIZEREL/OUTPUT_NAME_MINSIZEREL" CM_STATIC_LIB_ARGS
+# ADD LIB32 /nologo /out:"OUTPUT_DIRECTORY_MINSIZEREL/OUTPUT_NAME_MINSIZEREL" CM_STATIC_LIB_ARGS_MINSIZEREL
 
 CMAKE_CUSTOM_RULE_CODE_MINSIZEREL
 
@@ -158,7 +158,7 @@ BSC32=bscmake.exe
 # ADD BSC32 /nologo
 LIB32=link.exe -lib
 # ADD BASE LIB32 /nologo
-# ADD LIB32 /nologo /out:"OUTPUT_DIRECTORY_RELWITHDEBINFO/OUTPUT_NAME_RELWITHDEBINFO" CM_STATIC_LIB_ARGS
+# ADD LIB32 /nologo /out:"OUTPUT_DIRECTORY_RELWITHDEBINFO/OUTPUT_NAME_RELWITHDEBINFO" CM_STATIC_LIB_ARGS_RELWITHDEBINFO
 
 CMAKE_CUSTOM_RULE_CODE_RELWITHDEBINFO
 

+ 34 - 14
Tests/CMakeLists.txt

@@ -174,6 +174,34 @@ IF(BUILD_TESTING)
 
   ADD_TEST_MACRO(Module.CheckTypeSize CheckTypeSize)
 
+  ADD_TEST(LinkFlags-prepare
+    ${CMAKE_CTEST_COMMAND} -C \${CTEST_CONFIGURATION_TYPE}
+    --build-and-test
+    "${CMake_SOURCE_DIR}/Tests/LinkFlags"
+    "${CMake_BINARY_DIR}/Tests/LinkFlags"
+    --build-generator ${CMAKE_TEST_GENERATOR}
+    --build-makeprogram ${CMAKE_TEST_MAKEPROGRAM}
+    --build-project LinkFlags
+    --build-target LinkFlags
+    --build-options -DTEST_CONFIG=\${CTEST_CONFIGURATION_TYPE}
+    )
+  LIST(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/LinkFlags")
+
+  MACRO(ADD_LINK_FLAGS_TEST name depends)
+    ADD_TEST(LinkFlags-${name}
+      ${CMAKE_CMAKE_COMMAND} --build "${CMake_BINARY_DIR}/Tests/LinkFlags"
+      --target LinkFlags_${name} --config \${CTEST_CONFIGURATION_TYPE}
+      )
+    SET_TESTS_PROPERTIES(LinkFlags-${name} PROPERTIES
+      PASS_REGULAR_EXPRESSION "BADFLAG" DEPENDS LinkFlags-${depends})
+  ENDMACRO()
+  ADD_LINK_FLAGS_TEST(lib prepare)
+  ADD_LINK_FLAGS_TEST(dll lib)
+  ADD_LINK_FLAGS_TEST(exe dll)
+  ADD_LINK_FLAGS_TEST(lib_config exe)
+  ADD_LINK_FLAGS_TEST(dll_config lib_config)
+  ADD_LINK_FLAGS_TEST(exe_config dll_config)
+
   # If we are running right now with a UnixMakefiles based generator,
   # build the "Simple" test with the ExtraGenerators, if available
   # This doesn't test whether the generated project files work (unfortunately), 
@@ -270,7 +298,7 @@ IF(BUILD_TESTING)
     FILE(MAKE_DIRECTORY "${_TEST_DIR}")
     FILE(WRITE "${_TEST_DIR}/nightly-cmake.sh"
       "cd ${_TEST_DIR}
-${CMake_BINARY_DIR}/bin/cmake -DCMAKE_CREATE_VERSION=master -P ${CMake_SOURCE_DIR}/Utilities/Release/${script}
+${CMake_BINARY_DIR}/bin/cmake -DCMAKE_CREATE_VERSION=next -P ${CMake_SOURCE_DIR}/Utilities/Release/${script}
 ${CMake_BINARY_DIR}/bin/cmake -DVERSION=master -P ${CMake_SOURCE_DIR}/Utilities/Release/upload_release.cmake
     ")
     ADD_TEST(${name} /bin/sh ${_TEST_DIR}/nightly-cmake.sh)
@@ -1442,13 +1470,6 @@ ${CMake_BINARY_DIR}/bin/cmake -DVERSION=master -P ${CMake_SOURCE_DIR}/Utilities/
       --output-log "${CMake_BINARY_DIR}/Tests/CTestTest2/testOutput.log"
       )
 
-    CONFIGURE_FILE("${CMake_SOURCE_DIR}/Tests/CTestTest3/test.cmake.in"
-      "${CMake_BINARY_DIR}/Tests/CTestTest3/test.cmake" @ONLY ESCAPE_QUOTES)
-    ADD_TEST(CTestTest3 ${CMAKE_CTEST_COMMAND}
-      -S "${CMake_BINARY_DIR}/Tests/CTestTest3/test.cmake" -V
-      --output-log "${CMake_BINARY_DIR}/Tests/CTestTest3/testOutput.log"
-      )
-
     CONFIGURE_FILE("${CMake_SOURCE_DIR}/Tests/CTestTestChecksum/test.cmake.in"
       "${CMake_BINARY_DIR}/Tests/CTestTestChecksum/test.cmake" @ONLY
       ESCAPE_QUOTES)
@@ -1473,12 +1494,6 @@ ${CMake_BINARY_DIR}/bin/cmake -DVERSION=master -P ${CMake_SOURCE_DIR}/Utilities/
       SET_TESTS_PROPERTIES ( CTestTest2
         PROPERTIES TIMEOUT ${CMAKE_LONG_TEST_TIMEOUT})
     ENDIF ("${PREVIOUS_TIMEOUT}" MATCHES NOTFOUND)
-
-    GET_TEST_PROPERTY(CTestTest3 TIMEOUT PREVIOUS_TIMEOUT)
-    IF ("${PREVIOUS_TIMEOUT}" MATCHES NOTFOUND)
-      SET_TESTS_PROPERTIES ( CTestTest3
-        PROPERTIES TIMEOUT ${CMAKE_LONG_TEST_TIMEOUT})
-    ENDIF ("${PREVIOUS_TIMEOUT}" MATCHES NOTFOUND)
   ENDIF (CTEST_TEST_CTEST AND CMAKE_RUN_LONG_TESTS AND CMAKE_TESTS_CDASH_SERVER)
 
   IF(NOT DEFINED CTEST_RUN_CTestSubmitLargeOutput)
@@ -1504,6 +1519,11 @@ ${CMake_BINARY_DIR}/bin/cmake -DVERSION=master -P ${CMake_SOURCE_DIR}/Utilities/
     #
     SET_TESTS_PROPERTIES(CTestSubmitLargeOutput PROPERTIES
       PASS_REGULAR_EXPRESSION "Errors occurred during submission")
+
+    # Give this test plenty of time to run on slower machines:
+    #
+    SET_TESTS_PROPERTIES(CTestSubmitLargeOutput PROPERTIES
+      TIMEOUT ${CMAKE_LONG_TEST_TIMEOUT})
   ENDIF(CTEST_RUN_CTestSubmitLargeOutput)
 
   IF (CMAKE_RUN_LONG_TESTS AND TEST_KDE4_STABLE_BRANCH)

+ 8 - 2
Tests/CMakeTests/CMakeLists.txt

@@ -28,6 +28,11 @@ AddCMakeTest(Math "")
 AddCMakeTest(CMakeMinimumRequired "")
 AddCMakeTest(CompilerIdVendor "")
 
+AddCMakeTest(FileDownload "")
+set_property(TEST CMake.FileDownload PROPERTY
+  PASS_REGULAR_EXPRESSION "file already exists with expected MD5 sum"
+  )
+
 if(HAVE_ELF_H)
   AddCMakeTest(ELF "")
 endif()
@@ -46,13 +51,14 @@ AddCMakeTest(GetPrerequisites "${GetPrerequisites_PreArgs}")
 # suite. It detects if any changes have been made to the CMake source tree
 # by any previous configure, build or test steps.
 #
-if(do_cvs_tests)
+if(do_cvs_tests OR GIT_EXECUTABLE)
   string(REPLACE "\\" "/" ENV_HOME "$ENV{HOME}")
   set(CheckSourceTree_PreArgs
     "-DCMake_BINARY_DIR:PATH=${CMake_BINARY_DIR}"
     "-DCMake_SOURCE_DIR:PATH=${CMake_SOURCE_DIR}"
     "-DCVS_EXECUTABLE:STRING=${CVS_EXECUTABLE}"
+    "-DGIT_EXECUTABLE:STRING=${GIT_EXECUTABLE}"
     "-DHOME:STRING=${ENV_HOME}"
     )
   AddCMakeTest(CheckSourceTree "${CheckSourceTree_PreArgs}")
-endif(do_cvs_tests)
+endif(do_cvs_tests OR GIT_EXECUTABLE)

+ 173 - 51
Tests/CMakeTests/CheckSourceTreeTest.cmake.in

@@ -6,6 +6,7 @@ message("")
 message("CMake_BINARY_DIR='${CMake_BINARY_DIR}'")
 message("CMake_SOURCE_DIR='${CMake_SOURCE_DIR}'")
 message("CVS_EXECUTABLE='${CVS_EXECUTABLE}'")
+message("GIT_EXECUTABLE='${GIT_EXECUTABLE}'")
 message("HOME='${HOME}'")
 message("ENV{DASHBOARD_TEST_FROM_CTEST}='$ENV{DASHBOARD_TEST_FROM_CTEST}'")
 message("")
@@ -42,55 +43,161 @@ message("in_source_build='${in_source_build}'")
 message("")
 
 
-# If this does not appear to be a CVS checkout, just pass the test here and now.
-# (Do not let the test fail if it is run in a tree *exported* from CVS or
-# unpacked from a .zip file source installer...)
+# If this does not appear to be a git or CVS checkout, just pass the test here
+# and now. (Do not let the test fail if it is run in a tree *exported* from a
+# repository or unpacked from a .zip file source installer...)
 #
-if(NOT EXISTS "${CMake_SOURCE_DIR}/CVS/Root")
-  message("source tree is not a CVS checkout... test passes by early return...")
-  return()
+set(is_git_checkout 0)
+if(EXISTS "${CMake_SOURCE_DIR}/.git")
+  set(is_git_checkout 1)
 endif()
 
+set(is_cvs_checkout 0)
+if(EXISTS "${CMake_SOURCE_DIR}/CVS/Root")
+  set(is_cvs_checkout 1)
+endif()
 
-# Check with "cvs -q -n up -dP" if there are any local modifications to the
-# CMake source tree:
-#
-message("=============================================================================")
-message("Copy/paste this command to reproduce:")
-message("cd \"${CMake_SOURCE_DIR}\" && \"${CVS_EXECUTABLE}\" -q -n up -dP")
+message("is_git_checkout='${is_git_checkout}'")
+message("is_cvs_checkout='${is_cvs_checkout}'")
 message("")
 
-# Use the HOME value passed in to the script for calling cvs so it can find
-# its .cvspass and other file(s)
-#
-set(original_ENV_HOME "$ENV{HOME}")
-set(ENV{HOME} "${HOME}")
-
-execute_process(COMMAND ${CVS_EXECUTABLE} -q -n up -dP
-  WORKING_DIRECTORY ${CMake_SOURCE_DIR}
-  OUTPUT_VARIABLE ov
-  ERROR_VARIABLE ev
-  RESULT_VARIABLE rv)
-
-set(ENV{HOME} "${original_ENV_HOME}")
-
-message("Results of running '${CVS_EXECUTABLE} -q -n up -dP'")
-message("rv='${rv}'")
-message("ov='${ov}'")
-message("ev='${ev}'")
-message("")
+if(NOT is_cvs_checkout)
+if(NOT is_git_checkout)
+  message("source tree is neither git nor CVS checkout... test passes by early return...")
+  return()
+endif()
+endif()
 
-if(NOT rv STREQUAL 0)
-  message(FATAL_ERROR "error: 'cvs -q -n up -dP' attempt failed... (see output above)")
+if(is_cvs_checkout)
+if(is_git_checkout)
+  message("warning: source tree has both git *and* CVS file system bits???")
+  # should this condition be a FATAL_ERROR test failure...?
 endif()
+endif()
+
 
-# Analyze cvs output:
+# This test looks for the following types of changes in the source tree:
 #
 set(additions 0)
 set(conflicts 0)
 set(modifications 0)
 set(nonadditions 0)
 
+# ov == output variable... conditionally filled in by either cvs or git below:
+#
+set(cmd "")
+set(ov "")
+set(ev "")
+set(rv "")
+
+
+if(is_cvs_checkout AND CVS_EXECUTABLE)
+  # Check with "cvs -q -n up -dP" if there are any local modifications to the
+  # CMake source tree:
+  #
+  message("=============================================================================")
+  message("This is a cvs checkout, using cvs to verify source tree....")
+  message("")
+
+  execute_process(COMMAND ${CVS_EXECUTABLE} --version
+    WORKING_DIRECTORY ${CMake_SOURCE_DIR}
+    OUTPUT_VARIABLE version_output
+    OUTPUT_STRIP_TRAILING_WHITESPACE)
+  message("=== output of 'cvs --version' ===")
+  message("${version_output}")
+  message("=== end output ===")
+  message("")
+
+  file(READ "${CMake_SOURCE_DIR}/CVS/Root" contents)
+  message("=== content of CVS/Root ===")
+  message("${contents}")
+  message("=== end content ===")
+  message("")
+
+  file(READ "${CMake_SOURCE_DIR}/CVS/Repository" contents)
+  message("=== content of CVS/Repository ===")
+  message("${contents}")
+  message("=== end content ===")
+  message("")
+
+  message("Copy/paste this command to reproduce:")
+  message("cd \"${CMake_SOURCE_DIR}\" && \"${CVS_EXECUTABLE}\" -q -n up -dP")
+  message("")
+
+  set(cmd ${CVS_EXECUTABLE} -q -n up -dP)
+endif()
+
+
+if(is_git_checkout AND GIT_EXECUTABLE)
+  # Check with "git status" if there are any local modifications to the
+  # CMake source tree:
+  #
+  message("=============================================================================")
+  message("This is a git checkout, using git to verify source tree....")
+  message("")
+
+  execute_process(COMMAND ${GIT_EXECUTABLE} --version
+    WORKING_DIRECTORY ${CMake_SOURCE_DIR}
+    OUTPUT_VARIABLE version_output
+    OUTPUT_STRIP_TRAILING_WHITESPACE)
+  message("=== output of 'git --version' ===")
+  message("${version_output}")
+  message("=== end output ===")
+  message("")
+
+  execute_process(COMMAND ${GIT_EXECUTABLE} branch -a
+    WORKING_DIRECTORY ${CMake_SOURCE_DIR}
+    OUTPUT_VARIABLE git_branch_output
+    OUTPUT_STRIP_TRAILING_WHITESPACE)
+  message("=== output of 'git branch -a' ===")
+  message("${git_branch_output}")
+  message("=== end output ===")
+  message("")
+
+  message("Copy/paste this command to reproduce:")
+  message("cd \"${CMake_SOURCE_DIR}\" && \"${GIT_EXECUTABLE}\" status")
+  message("")
+
+  set(cmd ${GIT_EXECUTABLE} status)
+endif()
+
+
+if(cmd)
+  # Use the HOME value passed in to the script for calling cvs/git so it can
+  # find its .cvspass or user/global config settings...
+  #
+  set(original_ENV_HOME "$ENV{HOME}")
+  set(ENV{HOME} "${HOME}")
+
+  execute_process(COMMAND ${cmd}
+    WORKING_DIRECTORY ${CMake_SOURCE_DIR}
+    OUTPUT_VARIABLE ov
+    ERROR_VARIABLE ev
+    RESULT_VARIABLE rv)
+
+  set(ENV{HOME} "${original_ENV_HOME}")
+
+  message("Results of running ${cmd}")
+  message("rv='${rv}'")
+  message("ov='${ov}'")
+  message("ev='${ev}'")
+  message("")
+
+  if(NOT rv STREQUAL 0)
+    if(is_git_checkout AND (rv STREQUAL "1"))
+      # Many builds of git return "1" from a "nothing is changed" git status call...
+      # Do not fail with an error for rv==1 with git...
+    else()
+      message(FATAL_ERROR "error: ${cmd} attempt failed... (see output above)")
+    endif()
+  endif()
+else()
+  message(FATAL_ERROR "error: no COMMAND to run to analyze source tree...")
+endif()
+
+
+# Analyze output:
+#
 if(NOT ov STREQUAL "")
   string(REPLACE ";" "\\\\;" lines "${ov}")
   string(REPLACE "\n" "E;" lines "${lines}")
@@ -110,29 +217,44 @@ if(NOT ov STREQUAL "")
     endif()
 
     if(consider)
-      if(line MATCHES "^A ")
-        message("   locally added file/directory detected...")
-        set(additions 1)
+      if(is_cvs_checkout)
+        if(line MATCHES "^A ")
+          message("   locally added file/directory detected...")
+          set(additions 1)
+        endif()
+
+        if(line MATCHES "^C ")
+          message("   conflict detected...")
+          set(conflicts 1)
+        endif()
+
+        if(line MATCHES "^M ")
+          message("   locally modified file detected...")
+          set(modifications 1)
+        endif()
+
+        if(line MATCHES "^\\? ")
+          message("   locally non-added file/directory detected...")
+          set(nonadditions 1)
+        endif()
       endif()
 
-      if(line MATCHES "^C ")
-        message("   conflict detected...")
-        set(conflicts 1)
-      endif()
+      if(is_git_checkout)
+        if(line MATCHES "^#[ \t]*modified:")
+          message("   locally modified file detected...")
+          set(modifications 1)
+        endif()
 
-      if(line MATCHES "^M ")
-        message("   locally modified file detected...")
-        set(modifications 1)
-      endif()
-
-      if(line MATCHES "^\\? ")
-        message("   locally non-added file/directory detected...")
-        set(nonadditions 1)
+        if(line MATCHES "^# Untracked")
+          message("   locally non-added file/directory detected...")
+          set(nonadditions 1)
+        endif()
       endif()
     endif()
   endforeach()
 endif()
 
+
 message("=============================================================================")
 message("additions='${additions}'")
 message("conflicts='${conflicts}'")
@@ -185,14 +307,14 @@ if(nonadditions)
     message("
 warning: test results confounded because this is an 'in-source' build - cannot
 distinguish between non-added files that are in-source build products and
-non-added source files that somebody forgot to 'cvs add'... - this is only ok
+non-added source files that somebody forgot to 'git add'... - this is only ok
 if this is intentionally an in-source dashboard build... Developers should
 use out-of-source builds to verify a clean source tree with this test...
 
 Allowing test to pass despite the warning message...
 ")
   else()
-    message(FATAL_ERROR "test fails: local source tree non-additions: use cvs add before committing, or remove the files from the source tree")
+    message(FATAL_ERROR "test fails: local source tree non-additions: use git add before committing, or remove the files from the source tree")
   endif()
 endif()
 

BIN
Tests/CMakeTests/FileDownloadInput.png


+ 41 - 0
Tests/CMakeTests/FileDownloadTest.cmake.in

@@ -0,0 +1,41 @@
+set(url "file://@CMAKE_CURRENT_SOURCE_DIR@/FileDownloadInput.png")
+set(dir "@CMAKE_CURRENT_BINARY_DIR@/downloads")
+
+message(STATUS "FileDownload:1")
+file(DOWNLOAD
+  ${url}
+  ${dir}/file1.png
+  TIMEOUT 2
+  )
+
+message(STATUS "FileDownload:2")
+file(DOWNLOAD
+  ${url}
+  ${dir}/file2.png
+  TIMEOUT 2
+  SHOW_PROGRESS
+  )
+
+# Two calls in a row, exactly the same arguments.
+# Since downloaded file should exist already for 2nd call,
+# the 2nd call will short-circuit and return early...
+#
+if(EXISTS ${dir}/file3.png)
+  file(REMOVE ${dir}/file3.png)
+endif()
+
+message(STATUS "FileDownload:3")
+file(DOWNLOAD
+  ${url}
+  ${dir}/file3.png
+  TIMEOUT 2
+  EXPECTED_MD5 d16778650db435bda3a8c3435c3ff5d1
+  )
+
+message(STATUS "FileDownload:4")
+file(DOWNLOAD
+  ${url}
+  ${dir}/file3.png
+  TIMEOUT 2
+  EXPECTED_MD5 d16778650db435bda3a8c3435c3ff5d1
+  )

+ 1 - 0
Tests/CTestSubmitLargeOutput/test.cmake.in

@@ -16,6 +16,7 @@ CTEST_BUILD(BUILD "${CTEST_BINARY_DIRECTORY}" RETURN_VALUE res)
 
 SET(CTEST_CUSTOM_MAXIMUM_FAILED_TEST_OUTPUT_SIZE 1000000000)
 SET(CTEST_CUSTOM_MAXIMUM_PASSED_TEST_OUTPUT_SIZE 1000000000)
+SET(CTEST_TEST_TIMEOUT @CMAKE_LONG_TEST_TIMEOUT@)
 
 CTEST_TEST(BUILD "${CTEST_BINARY_DIRECTORY}" RETURN_VALUE res)
 

+ 145 - 5
Tests/ExternalProject/CMakeLists.txt

@@ -1,10 +1,11 @@
-cmake_minimum_required(VERSION 2.6)
+cmake_minimum_required(VERSION 2.8)
 project(ExternalProjectTest NONE)
 
 include(ExternalProject)
 
 find_package(CVS)
 find_package(Subversion)
+find_package(Git)
 
 set(base "${CMAKE_BINARY_DIR}/CMakeExternals")
 set(binary_base "${base}/Build")
@@ -37,8 +38,6 @@ if(NOT DEFINED can_build_tutorial_step5)
   endif()
 endif()
 
-message(STATUS "can_build_tutorial_step5='${can_build_tutorial_step5}'")
-
 
 # Empty projects that test all the known ExternalProject_Add argument key words:
 #
@@ -65,7 +64,9 @@ ExternalProject_Add(${proj}
   SVN_REPOSITORY ""
   SVN_REVISION ""
   TEST_COMMAND ""
+  TIMEOUT ""
   URL ""
+  URL_MD5 ""
   UPDATE_COMMAND ""
 )
 
@@ -96,6 +97,7 @@ endif()
 set(proj TutorialStep1-LocalTAR)
 ExternalProject_Add(${proj}
   URL "${CMAKE_CURRENT_SOURCE_DIR}/Step1.tar"
+  URL_MD5 a87c5b47c0201c09ddfe1d5738fdb1e3
   LIST_SEPARATOR ::
   PATCH_COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_SOURCE_DIR}/Step1Patch.cmake
   CMAKE_GENERATOR "${CMAKE_GENERATOR}"
@@ -107,6 +109,7 @@ ExternalProject_Add(${proj}
 set(proj TutorialStep1-LocalNoDirTAR)
 ExternalProject_Add(${proj}
   URL "${CMAKE_CURRENT_SOURCE_DIR}/Step1NoDir.tar"
+  URL_MD5 d09e3d370c5c908fa035c30939ee438e
   LIST_SEPARATOR @@
   CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR> -G ${CMAKE_GENERATOR} <SOURCE_DIR>
              -DTEST_LIST:STRING=1@@2@@3
@@ -126,6 +129,7 @@ ExternalProject_Add_Step(${proj} mypatch
 set(proj TutorialStep1-LocalTGZ)
 ExternalProject_Add(${proj}
   URL "${CMAKE_CURRENT_SOURCE_DIR}/Step1.tgz"
+  URL_MD5 38c648e817339c356f6be00eeed79bd0
   CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR> -G ${CMAKE_GENERATOR} <SOURCE_DIR>
   INSTALL_COMMAND ""
 )
@@ -133,12 +137,63 @@ ExternalProject_Add(${proj}
 set(proj TutorialStep1-LocalNoDirTGZ)
 ExternalProject_Add(${proj}
   URL "${CMAKE_CURRENT_SOURCE_DIR}/Step1NoDir.tgz"
+  URL_MD5 0b8182edcecdf40bf1c9d71d7d259f78
   CMAKE_GENERATOR "${CMAKE_GENERATOR}"
   CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>
   INSTALL_COMMAND ""
 )
 
 
+# Local BZ2:
+#
+# (The bz2 tests are here just to verify that the bz2 decompression is executed
+#  during a test suite run... The configure and build commands are set to
+#  nothing to make the test quicker. To make this more complete, I should add
+#  a diff between this and the TGZ source tree since that one does build...)
+#
+set(proj TutorialStep1-LocalBZ2)
+ExternalProject_Add(${proj}
+  URL "${CMAKE_CURRENT_SOURCE_DIR}/Step1.tar.bz2"
+  CONFIGURE_COMMAND ""
+  BUILD_COMMAND ""
+  INSTALL_COMMAND ""
+)
+
+set(proj TutorialStep1-LocalNoDirBZ2)
+ExternalProject_Add(${proj}
+  URL "${CMAKE_CURRENT_SOURCE_DIR}/Step1NoDir.tar.bz2"
+  CONFIGURE_COMMAND ""
+  BUILD_COMMAND ""
+  INSTALL_COMMAND ""
+)
+
+
+# Local ZIP:
+#
+# (The zip tests are here just to verify that the zip decompression is executed
+#  during a test suite run... The configure and build commands are set to
+#  nothing to make the test quicker. To make this more complete, I should add
+#  a diff between this and the TGZ source tree since that one does build...)
+#
+set(proj TutorialStep1-LocalZIP)
+ExternalProject_Add(${proj}
+  URL "${CMAKE_CURRENT_SOURCE_DIR}/Step1.zip"
+  CONFIGURE_COMMAND ""
+  BUILD_COMMAND ""
+  INSTALL_COMMAND ""
+)
+
+set(proj TutorialStep1-LocalNoDirZIP)
+ExternalProject_Add(${proj}
+  URL "${CMAKE_CURRENT_SOURCE_DIR}/Step1NoDir.zip"
+  CONFIGURE_COMMAND ""
+  BUILD_COMMAND ""
+  INSTALL_COMMAND ""
+)
+
+
+# CVS-based tests:
+#
 set(do_cvs_tests 0)
 
 if(CVS_EXECUTABLE)
@@ -161,8 +216,9 @@ if(do_cvs_tests)
   ExternalProject_Add(${proj}
     SOURCE_DIR ${local_cvs_repo}
     URL ${CMAKE_CURRENT_SOURCE_DIR}/cvsrepo.tgz
+    URL_MD5 55fc85825ffdd9ed2597123c68b79f7e
     BUILD_COMMAND ""
-    CONFIGURE_COMMAND ${CVS_EXECUTABLE} --version
+    CONFIGURE_COMMAND "${CVS_EXECUTABLE}" --version
     INSTALL_COMMAND ""
   )
 
@@ -215,6 +271,8 @@ if(do_cvs_tests)
 endif()
 
 
+# SVN-based tests:
+#
 set(do_svn_tests 0)
 
 if(Subversion_SVN_EXECUTABLE)
@@ -257,8 +315,9 @@ if(do_svn_tests)
   ExternalProject_Add(${proj}
     SOURCE_DIR ${local_svn_repo}
     URL ${CMAKE_CURRENT_SOURCE_DIR}/svnrepo.tgz
+    URL_MD5 2f468be4ed1fa96377fca0cc830819c4
     BUILD_COMMAND ""
-    CONFIGURE_COMMAND ${Subversion_SVN_EXECUTABLE} --version
+    CONFIGURE_COMMAND "${Subversion_SVN_EXECUTABLE}" --version
     INSTALL_COMMAND ""
   )
 
@@ -301,6 +360,80 @@ if(do_svn_tests)
 endif()
 
 
+set(do_git_tests 0)
+
+if(GIT_EXECUTABLE)
+  set(do_git_tests 1)
+
+  execute_process(
+    COMMAND "${GIT_EXECUTABLE}" --version
+    OUTPUT_VARIABLE ov
+    OUTPUT_STRIP_TRAILING_WHITESPACE
+    )
+  string(REGEX REPLACE "^git version (.+)$" "\\1" git_version "${ov}")
+  message(STATUS "git_version='${git_version}'")
+
+  if(git_version VERSION_LESS 1.6.5)
+    message(STATUS "No ExternalProject git tests with git client less than version 1.6.5")
+    set(do_git_tests 0)
+  endif()
+endif()
+
+
+if(do_git_tests)
+  set(local_git_repo "../../LocalRepositories/GIT")
+
+  # Unzip/untar the git repository in our source folder so that other
+  # projects below may use it to test git args of ExternalProject_Add
+  #
+  set(proj SetupLocalGITRepository)
+  ExternalProject_Add(${proj}
+    SOURCE_DIR ${CMAKE_CURRENT_BINARY_DIR}/LocalRepositories/GIT
+    URL ${CMAKE_CURRENT_SOURCE_DIR}/gitrepo.tgz
+    BUILD_COMMAND ""
+    CONFIGURE_COMMAND "${GIT_EXECUTABLE}" --version
+    INSTALL_COMMAND ""
+  )
+
+  # git by commit id:
+  #
+  set(proj TutorialStep1-GIT-byhash)
+  ExternalProject_Add(${proj}
+    GIT_REPOSITORY "${local_git_repo}"
+    GIT_TAG d1970730310fe8bc07e73f15dc570071f9f9654a
+    UPDATE_COMMAND ""
+    CMAKE_GENERATOR "${CMAKE_GENERATOR}"
+    CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>
+    INSTALL_COMMAND ""
+    DEPENDS "SetupLocalGITRepository"
+  )
+
+  # git by explicit branch/tag name:
+  #
+  set(proj TutorialStep1-GIT-bytag)
+  ExternalProject_Add(${proj}
+    GIT_REPOSITORY "${local_git_repo}"
+    GIT_TAG "origin/master"
+    UPDATE_COMMAND ""
+    CMAKE_GENERATOR "${CMAKE_GENERATOR}"
+    CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>
+    INSTALL_COMMAND ""
+    DEPENDS "SetupLocalGITRepository"
+  )
+
+  # Live git / master (no GIT_TAG):
+  #
+  set(proj TutorialStep1-GIT-master)
+  ExternalProject_Add(${proj}
+    GIT_REPOSITORY "${local_git_repo}"
+    CMAKE_GENERATOR "${CMAKE_GENERATOR}"
+    CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>
+    INSTALL_COMMAND ""
+    DEPENDS "SetupLocalGITRepository"
+  )
+endif()
+
+
 # Test the testable built/installed products:
 #
 enable_testing()
@@ -365,3 +498,10 @@ if(can_build_tutorial_step5)
   set_property(TEST TutorialStep5-InstallTreeTest
     APPEND PROPERTY LABELS Step5 InstallTree)
 endif()
+
+
+message(STATUS "can_build_tutorial_step5='${can_build_tutorial_step5}'")
+message(STATUS "do_cvs_tests='${do_cvs_tests}'")
+message(STATUS "do_svn_tests='${do_svn_tests}'")
+message(STATUS "do_git_tests='${do_git_tests}'")
+message(STATUS "GIT_EXECUTABLE='${GIT_EXECUTABLE}'")

+ 11 - 0
Tests/ExternalProject/Example/CMakeLists.txt

@@ -0,0 +1,11 @@
+# This is the canonical simplest ExternalProject example CMakeLists.txt file:
+cmake_minimum_required(VERSION 2.8)
+project(ExternalProjectExample NONE)
+include(ExternalProject)
+
+ExternalProject_Add(
+  cmake281
+  URL http://www.cmake.org/files/v2.8/cmake-2.8.1.tar.gz
+  CMAKE_ARGS -D CMAKE_INSTALL_PREFIX=<INSTALL_DIR>
+  BUILD_COMMAND ""
+)

BIN
Tests/ExternalProject/Step1.tar.bz2


BIN
Tests/ExternalProject/Step1.zip


BIN
Tests/ExternalProject/Step1NoDir.tar.bz2


BIN
Tests/ExternalProject/Step1NoDir.zip


BIN
Tests/ExternalProject/gitrepo.tgz


+ 28 - 0
Tests/LinkFlags/CMakeLists.txt

@@ -0,0 +1,28 @@
+cmake_minimum_required(VERSION 2.8)
+project(LinkFlags C)
+
+string(TOUPPER "${TEST_CONFIG}" TEST_CONFIG_UPPER)
+set(obj "${CMAKE_C_OUTPUT_EXTENSION}")
+if(BORLAND)
+  set(pre -)
+endif()
+
+add_library(LinkFlags_lib STATIC LinkFlagsLib.c)
+set_property(TARGET LinkFlags_lib PROPERTY STATIC_LIBRARY_FLAGS ${pre}BADFLAG${obj})
+
+add_library(LinkFlags_dll SHARED LinkFlagsLib.c)
+set_property(TARGET LinkFlags_dll PROPERTY LINK_FLAGS ${pre}BADFLAG${obj})
+
+add_executable(LinkFlags_exe LinkFlagsExe.c)
+set_property(TARGET LinkFlags_exe PROPERTY LINK_FLAGS ${pre}BADFLAG${obj})
+
+add_library(LinkFlags_lib_config STATIC LinkFlagsLib.c)
+set_property(TARGET LinkFlags_lib_config PROPERTY STATIC_LIBRARY_FLAGS_${TEST_CONFIG_UPPER} ${pre}BADFLAG_${TEST_CONFIG}${obj})
+
+add_library(LinkFlags_dll_config SHARED LinkFlagsLib.c)
+set_property(TARGET LinkFlags_dll_config PROPERTY LINK_FLAGS_${TEST_CONFIG_UPPER} ${pre}BADFLAG_${TEST_CONFIG}${obj})
+
+add_executable(LinkFlags_exe_config LinkFlagsExe.c)
+set_property(TARGET LinkFlags_exe_config PROPERTY LINK_FLAGS_${TEST_CONFIG_UPPER} ${pre}BADFLAG_${TEST_CONFIG}${obj})
+
+add_executable(LinkFlags LinkFlags.c)

+ 1 - 0
Tests/LinkFlags/LinkFlags.c

@@ -0,0 +1 @@
+int main(void) { return 0; }

+ 6 - 0
Tests/LinkFlags/LinkFlagsExe.c

@@ -0,0 +1,6 @@
+int main(void) { return 0; }
+
+/* Intel compiler does not reject bad flags or objects!  */
+#if defined(__INTEL_COMPILER)
+# error BADFLAG
+#endif

+ 6 - 0
Tests/LinkFlags/LinkFlagsLib.c

@@ -0,0 +1,6 @@
+int flags_lib(void) { return 0; }
+
+/* Intel compiler does not reject bad flags or objects!  */
+#if defined(__INTEL_COMPILER)
+# error BADFLAG
+#endif

+ 1 - 1
Utilities/Release/dash2win64_release.cmake

@@ -12,7 +12,7 @@ CMAKE_SKIP_BOOTSTRAP_TEST:STRING=TRUE
 CMAKE_Fortran_COMPILER:FILEPATH=FALSE
 CMAKE_GENERATOR:INTERNAL=Unix Makefiles
 BUILD_QtDialog:BOOL:=TRUE
-QT_QMAKE_EXECUTABLE:FILEPATH=c:/Dashboards/Support/qt-4.5.3-static/bin/qmake.exe
+QT_QMAKE_EXECUTABLE:FILEPATH=c:/Dashboards/Support/qt-build/Qt/bin/qmake.exe
 ")
 get_filename_component(path "${CMAKE_CURRENT_LIST_FILE}" PATH)
 set(GIT_COMMAND git)

+ 1 - 1
Utilities/Release/release_cmake.sh.in

@@ -123,7 +123,7 @@ check_exit_value $? "Build cmake" || exit 1
 
 if [ -z "@SKIP_TESTS@" ]; then
     echo "Run cmake tests"
-    ./bin/ctest -j @PROCESSORS@ test
+    ./bin/ctest --output-on-failure -j @PROCESSORS@ test
     check_exit_value $? "Test cmake" || exit 1
 fi