Verify MD5 sum for FFTW download
authorTeemu Murtola <teemu.murtola@gmail.com>
Sun, 3 Aug 2014 14:32:31 +0000 (17:32 +0300)
committerTeemu Murtola <teemu.murtola@gmail.com>
Mon, 4 Aug 2014 15:32:59 +0000 (18:32 +0300)
Since ExternalProject provides confusing error messages with MD5
checking enabled, add a custom download step that works as expected.
When passed a local file as the URL, ExternalProject does the MD5
verification just fine, so the code now downloads the tarball in a
custom step and then passes that local file to ExternalProject.

This allows removing the lengthy security warning that appeared there if
one was just following the quick-and-dirty installation instructions,
and likely only confused novice users.  While this change may not
improve overall security significantly, it hopefully allows everyone to
agree to remove that warning and thus improve the end-user experience.

Change-Id: I9ac5a30ae5858b7a6557ccb2d981cc909457d020

install-guide/install-guide.md
src/contrib/fftw/.gitattributes [new file with mode: 0644]
src/contrib/fftw/CMakeLists.txt
src/contrib/fftw/fftw-download.cmake.cmakein [new file with mode: 0644]

index 84481d005977e21e96c7354ae806ad4d9707ce3d..211f1af223d734c22ec7bcd29375e450aa90040a 100644 (file)
@@ -223,11 +223,6 @@ recommends either
   `cmake -DGMX_BUILD_OWN_FFTW=ON`), or
 * that you build FFTW from the source code.
 
-Note that the GROMACS-managed download of the FFTW tarball has a
-slight chance of posing a security risk. If you use this option, you
-will see a warning that advises how you can eliminate this risk
-(before the opportunity has arisen).
-
 If you build FFTW from source yourself, get the most recent version
 and follow its [installation
 guide](http://www.fftw.org/doc/Installation-and-Customization.html#Installation-and-Customization).
diff --git a/src/contrib/fftw/.gitattributes b/src/contrib/fftw/.gitattributes
new file mode 100644 (file)
index 0000000..9e8e962
--- /dev/null
@@ -0,0 +1 @@
+fftw-download.cmake.cmakein !filter
index b553c405899e650810ca23da118735b0d24a9bd4..c7d72989521fdc46130dbb3ae5e06bd1521b933f 100644 (file)
@@ -68,25 +68,54 @@ endif()
 # Machinery for running the external project
 set(EXTERNAL_FFTW_VERSION 3.3.3)
 # cmake make eats slashes //// -> //
-set(GMX_BUILD_OWN_FFTW_URL "http:////www.fftw.org/fftw-${EXTERNAL_FFTW_VERSION}.tar.gz" CACHE PATH "URL from where to download fftw, (use an absolute path when offline)")
-mark_as_advanced(GMX_BUILD_OWN_FFTW_URL)
-set(EXTERNAL_FFTW_MD5SUM 0a05ca9c7b3bfddc8278e7c40791a1c2)
-set (EXTERNAL_FFTW_BUILD_TARGET fftwBuild)
+set(GMX_BUILD_OWN_FFTW_URL
+    "http:////www.fftw.org/fftw-${EXTERNAL_FFTW_VERSION}.tar.gz" CACHE PATH
+    "URL from where to download fftw (use an absolute path when offline, adjust GMX_BUILD_OWN_FFTW_MD5 if downloading other version than ${EXTERNAL_FFTW_VERSION})")
+set(GMX_BUILD_OWN_FFTW_MD5 0a05ca9c7b3bfddc8278e7c40791a1c2 CACHE STRING
+    "Expected MD5 hash for the file at GMX_BUILD_OWN_FFTW_URL")
+mark_as_advanced(GMX_BUILD_OWN_FFTW_URL GMX_BUILD_OWN_FFTW_MD5)
+
+# ExternalProject at least up to CMake 3.0 prints a confusing error message if
+# download fails when MD5 verification is enabled.  So we manage the download
+# ourselves so that MD5 sum is not verified there, and then pass a local file
+# as the URL to ExternalProject.  This way, ExternalProject still verifies the
+# MD5 sum with a proper message if that fails.
+set(url "${GMX_BUILD_OWN_FFTW_URL}")
+# Determine whether we are actually downloading (this matches the conditions in
+# ExternalProject).  ExternalProject works as expected if passed a local file.
+set(is_download TRUE)
+if (IS_DIRECTORY "${url}" OR "${url}" MATCHES "^file://" OR NOT "${url}" MATCHES "^[a-z]+://")
+    set(is_download FALSE)
+endif()
+if (is_download)
+    # For simplicity, don't try to extract the file name from the URL, but use
+    # a hard-coded value.
+    set(remote_url "${GMX_BUILD_OWN_FFTW_URL}")
+    set(local_path "${CMAKE_CURRENT_BINARY_DIR}/fftw.tar.gz")
+    set(url ${local_path})
+    # Write a script to do our own download step (mimics what ExternalProject
+    # would do, but without MD5 sum verification at this step).
+    set(download_script ${CMAKE_CURRENT_BINARY_DIR}/fftw-download.cmake)
+    configure_file(fftw-download.cmake.cmakein ${download_script} @ONLY)
+endif()
+
+# The actual build target.
+set(EXTERNAL_FFTW_BUILD_TARGET fftwBuild)
 include(ExternalProject)
-# TODO in master branch - show this warning only on the first run
-# by using gmx_check_if_changed_result from I21b791ab8e4f3 when
-# that becomes available
-message(WARNING "The GROMACS build will download FFTW ${EXTERNAL_FFTW_VERSION} as requested, but it will not know the file it receives is correct. If you now use\nmake\n GROMACS will build and link to FFTW anyway, but there is a possible security risk if you execute a GROMACS tool that calls this library. Instead, you can use\nmake ${EXTERNAL_FFTW_BUILD_TARGET}\n to do just the download and build of FFTW, and then run\nmd5sum src/contrib/fftw/${EXTERNAL_FFTW_BUILD_TARGET}-prefix/src/fftw-${EXTERNAL_FFTW_VERSION}.tar.gz\nto see if it matches ${EXTERNAL_FFTW_MD5SUM}. If so, everything is OK and you should use \nmake\n to proceed with the rest of the GROMACS build. Alternatively, you could stop using GMX_BUILD_OWN_FFTW, and instead follow the GROMACS installation instructions to build FFTW yourself.")
-# TODO if/when CMake fixes http://www.cmake.org/Bug/view.php?id=14330
-# (ie. at least version > 2.8.11.2), consider reverting to using an
-# md5sum check to avoid needing the above warning
-    ExternalProject_add(${EXTERNAL_FFTW_BUILD_TARGET}
-        URL "${GMX_BUILD_OWN_FFTW_URL}"
+ExternalProject_add(${EXTERNAL_FFTW_BUILD_TARGET}
+        URL "${url}" URL_MD5 ${GMX_BUILD_OWN_FFTW_MD5}
         CONFIGURE_COMMAND <SOURCE_DIR>/configure --prefix=<INSTALL_DIR> --libdir=<INSTALL_DIR>/lib --disable-fortran
         ${GMX_BUILD_OWN_FFTW_SHARED_FLAG} ${GMX_BUILD_OWN_FFTW_OPTIMIZATION_CONFIGURATION}
         ${GMX_BUILD_OWN_FFTW_PREC}
         ${GMX_BUILD_OWN_FFTW_TARGET_HOST})
-externalproject_get_property(${EXTERNAL_FFTW_BUILD_TARGET} INSTALL_DIR)
+# Add a custom step to do our own download if that is necessary.
+if (is_download)
+    ExternalProject_add_step(${EXTERNAL_FFTW_BUILD_TARGET} pre-download
+            COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/fftw-download.cmake
+            DEPENDERS download)
+endif()
+
+ExternalProject_get_property(${EXTERNAL_FFTW_BUILD_TARGET} INSTALL_DIR)
 
 string(TOUPPER "${FFTW}" UPPERFFTW)
 string(TOLOWER "${FFTW}" LOWERFFTW)
diff --git a/src/contrib/fftw/fftw-download.cmake.cmakein b/src/contrib/fftw/fftw-download.cmake.cmakein
new file mode 100644 (file)
index 0000000..777fe3b
--- /dev/null
@@ -0,0 +1,19 @@
+# Custom download script for Gromacs external FFTW build.
+
+# Mimics a similar script generated by CMake ExternalProject package, but
+# does not verify the MD5 sum (which would give confusing error messages if the
+# download fails).
+message(STATUS "downloading...
+     src='@remote_url@'
+     dest='@local_path@'")
+file(DOWNLOAD "@remote_url@" "@local_path@"
+     SHOW_PROGRESS STATUS status LOG log)
+list(GET status 0 status_code)
+list(GET status 1 status_string)
+if (NOT status_code EQUAL 0)
+  message(FATAL_ERROR "error: downloading '@remote_url@' failed
+     status_code: ${status_code}
+     status_string: ${status_string}
+     log: ${log}")
+endif()
+message(STATUS "downloading... done")