Răsfoiți Sursa

file: Sort GLOB results to make it deterministic (#14491)

Even though the `file(GLOB)` documentation specifically warns against
using it to collect a list of source files, projects often do it anyway.
Since it uses `readdir()`, the list of files will be unsorted.
This list is often passed directly to add_executable / add_library.
Linking binaries with an unsorted list will make it unreproducible,
which means that the produced binary will differ depending on the
unpredictable `readdir()` order.

To solve those reproducibility issues in a lot of programs (which don't
explicitly `list(SORT)` the list manually), sort the resulting list of
the `file(GLOB)` command.

A more detailed rationale about reproducible builds is available
[here](https://reproducible-builds.org/).
Reiner Herrmann 9 ani în urmă
părinte
comite
edcccde7d6

+ 3 - 2
Help/command/file.rst

@@ -103,8 +103,9 @@ Generate a list of files that match the ``<globbing-expressions>`` and
 store it into the ``<variable>``.  Globbing expressions are similar to
 regular expressions, but much simpler.  If ``RELATIVE`` flag is
 specified, the results will be returned as relative paths to the given
-path.  No specific order of results is defined.  If order is important then
-sort the list explicitly (e.g. using the :command:`list(SORT)` command).
+path.  No specific order of results is defined other than that it is
+deterministic.  If order is important then sort the list explicitly
+(e.g. using the :command:`list(SORT)` command).
 
 By default ``GLOB`` lists directories - directories are omited in result if
 ``LIST_DIRECTORIES`` is set to false.

+ 1 - 0
Source/cmFileCommand.cxx

@@ -823,6 +823,7 @@ bool cmFileCommand::HandleGlobCommand(std::vector<std::string> const& args,
 
     std::vector<std::string>::size_type cc;
     std::vector<std::string>& files = g.GetFiles();
+    std::sort(files.begin(), files.end());
     for (cc = 0; cc < files.size(); cc++) {
       if (!first) {
         output += ";";

+ 0 - 3
Tests/RunCMake/file/GLOB.cmake

@@ -12,17 +12,14 @@ file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/test/dir 2/non_empty_dir/dir 2 subdir fi
 file(GLOB CONTENT_LIST "${CMAKE_CURRENT_BINARY_DIR}/test/*/*")
 list(LENGTH CONTENT_LIST CONTENT_COUNT)
 message("content: ${CONTENT_COUNT} ")
-list(SORT CONTENT_LIST)
 message("${CONTENT_LIST}")
 
 file(GLOB CONTENT_LIST LIST_DIRECTORIES true "${CMAKE_CURRENT_BINARY_DIR}/test/*/*")
 list(LENGTH CONTENT_LIST CONTENT_COUNT)
 message("content: ${CONTENT_COUNT} ")
-list(SORT CONTENT_LIST)
 message("${CONTENT_LIST}")
 
 file(GLOB CONTENT_LIST LIST_DIRECTORIES false "${CMAKE_CURRENT_BINARY_DIR}/test/*/*")
 list(LENGTH CONTENT_LIST CONTENT_COUNT)
 message("content: ${CONTENT_COUNT} ")
-list(SORT CONTENT_LIST)
 message("${CONTENT_LIST}")

+ 0 - 3
Tests/RunCMake/file/GLOB_RECURSE-cyclic-recursion.cmake

@@ -7,17 +7,14 @@ execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink "${CMAKE_CURRENT_BINA
 file(GLOB_RECURSE CONTENT_LIST FOLLOW_SYMLINKS "${CMAKE_CURRENT_BINARY_DIR}/test/*")
 list(LENGTH CONTENT_LIST CONTENT_COUNT)
 message("content: ${CONTENT_COUNT} ")
-list(SORT CONTENT_LIST)
 message("${CONTENT_LIST}")
 
 file(GLOB_RECURSE CONTENT_LIST LIST_DIRECTORIES false FOLLOW_SYMLINKS "${CMAKE_CURRENT_BINARY_DIR}/test/*")
 list(LENGTH CONTENT_LIST CONTENT_COUNT)
 message("content: ${CONTENT_COUNT} ")
-list(SORT CONTENT_LIST)
 message("${CONTENT_LIST}")
 
 file(GLOB_RECURSE CONTENT_LIST LIST_DIRECTORIES true FOLLOW_SYMLINKS "${CMAKE_CURRENT_BINARY_DIR}/test/*")
 list(LENGTH CONTENT_LIST CONTENT_COUNT)
 message("content: ${CONTENT_COUNT} ")
-list(SORT CONTENT_LIST)
 message("${CONTENT_LIST}")

+ 0 - 3
Tests/RunCMake/file/GLOB_RECURSE.cmake

@@ -12,17 +12,14 @@ file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/test/dir 2/non_empty_dir/dir 2 subdir fi
 file(GLOB_RECURSE CONTENT_LIST "${CMAKE_CURRENT_BINARY_DIR}/test/*/*")
 list(LENGTH CONTENT_LIST CONTENT_COUNT)
 message("content: ${CONTENT_COUNT} ")
-list(SORT CONTENT_LIST)
 message("${CONTENT_LIST}")
 
 file(GLOB_RECURSE CONTENT_LIST LIST_DIRECTORIES false "${CMAKE_CURRENT_BINARY_DIR}/test/*/*")
 list(LENGTH CONTENT_LIST CONTENT_COUNT)
 message("content: ${CONTENT_COUNT} ")
-list(SORT CONTENT_LIST)
 message("${CONTENT_LIST}")
 
 file(GLOB_RECURSE CONTENT_LIST LIST_DIRECTORIES true "${CMAKE_CURRENT_BINARY_DIR}/test/*/*")
 list(LENGTH CONTENT_LIST CONTENT_COUNT)
 message("content: ${CONTENT_COUNT} ")
-list(SORT CONTENT_LIST)
 message("${CONTENT_LIST}")