Commit a2c068a7 authored by Domen Vrankar's avatar Domen Vrankar Committed by Brad King
Browse files

file: Teach GLOB to list directories optionally

GLOB lists directories by default and GLOB_RECURSE does not.
LIST_DIRECTORIES enables user to control the behavior explicitly for
consistently for both GLOB and GLOB_RECURSE.
parent a5cab2e7
......@@ -92,9 +92,12 @@ store it in a ``<variable>``.
::
file(GLOB <variable> [RELATIVE <path>] [<globbing-expressions>...])
file(GLOB_RECURSE <variable> [RELATIVE <path>]
[FOLLOW_SYMLINKS] [<globbing-expressions>...])
file(GLOB <variable>
[LIST_DIRECTORIES true|false] [RELATIVE <path>]
[<globbing-expressions>...])
file(GLOB_RECURSE <variable> [FOLLOW_SYMLINKS]
[LIST_DIRECTORIES true|false] [RELATIVE <path>]
[<globbing-expressions>...])
Generate a list of files that match the ``<globbing-expressions>`` and
store it into the ``<variable>``. Globbing expressions are similar to
......@@ -102,6 +105,9 @@ regular expressions, but much simpler. If ``RELATIVE`` flag is
specified, the results will be returned as relative paths to the given
path.
By default ``GLOB`` lists directories - directories are omited in result if
``LIST_DIRECTORIES`` is set to false.
.. note::
We do not recommend using GLOB to collect a list of source files from
your source tree. If no CMakeLists.txt file changes when a source is
......@@ -119,6 +125,11 @@ matched directory and match the files. Subdirectories that are symlinks
are only traversed if ``FOLLOW_SYMLINKS`` is given or policy
:policy:`CMP0009` is not set to ``NEW``.
By default ``GLOB_RECURSE`` omits directories from result list - setting
``LIST_DIRECTORIES`` to true adds directories to result list.
If ``FOLLOW_SYMLINKS`` is given or policy :policy:`CMP0009` is not set to
``OLD`` then ``LIST_DIRECTORIES`` treats symlinks as directories.
Examples of recursive globbing include::
/dir/*.py - match all python files in /dir and subdirectories
......
......@@ -920,6 +920,35 @@ bool cmFileCommand::HandleGlobCommand(std::vector<std::string> const& args,
bool first = true;
for ( ; i != args.end(); ++i )
{
if( *i == "LIST_DIRECTORIES" )
{
++i;
if(i != args.end())
{
if(cmSystemTools::IsOn(i->c_str()))
{
g.SetListDirs(true);
g.SetRecurseListDirs(true);
}
else if(cmSystemTools::IsOff(i->c_str()))
{
g.SetListDirs(false);
g.SetRecurseListDirs(false);
}
else
{
this->SetError("LIST_DIRECTORIES missing bool value.");
return false;
}
}
else
{
this->SetError("LIST_DIRECTORIES missing bool value.");
return false;
}
++i;
}
if ( recurse && (*i == "FOLLOW_SYMLINKS") )
{
explicitFollowSymlinks = true;
......@@ -950,6 +979,7 @@ bool cmFileCommand::HandleGlobCommand(std::vector<std::string> const& args,
}
}
cmsys::Glob::GlobMessages globMessages;
if ( !cmsys::SystemTools::FileIsFullPath(i->c_str()) )
{
std::string expr = this->Makefile->GetCurrentDirectory();
......@@ -957,16 +987,42 @@ bool cmFileCommand::HandleGlobCommand(std::vector<std::string> const& args,
if (!expr.empty())
{
expr += "/" + *i;
g.FindFiles(expr);
g.FindFiles(expr, &globMessages);
}
else
{
g.FindFiles(*i);
g.FindFiles(*i, &globMessages);
}
}
else
{
g.FindFiles(*i);
g.FindFiles(*i, &globMessages);
}
if(!globMessages.empty())
{
bool shouldExit = false;
for(cmsys::Glob::GlobMessagesIterator it=globMessages.begin();
it != globMessages.end(); ++it)
{
if(it->type == cmsys::Glob::cyclicRecursion)
{
this->Makefile->IssueMessage(cmake::AUTHOR_WARNING,
"Cyclic recursion detected while globbing for '"
+ *i + "':\n" + it->content);
}
else
{
this->Makefile->IssueMessage(cmake::FATAL_ERROR,
"Error has occured while globbing for '"
+ *i + "' - " + it->content);
shouldExit = true;
}
}
if(shouldExit)
{
return false;
}
}
std::vector<std::string>::size_type cc;
......
content: 6[ ]
.*/test/dir 1/dir 1 file;.*/test/dir 1/empty_dir;.*/test/dir 1/non_empty_dir;.*/test/dir 2/dir 2 file;.*/test/dir 2/empty_dir;.*/test/dir 2/non_empty_dir
content: 6[ ]
.*/test/dir 1/dir 1 file;.*/test/dir 1/empty_dir;.*/test/dir 1/non_empty_dir;.*/test/dir 2/dir 2 file;.*/test/dir 2/empty_dir;.*/test/dir 2/non_empty_dir
content: 2[ ]
.*/test/dir 1/dir 1 file;.*/test/dir 2/dir 2 file
file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/test/dir 1/empty_dir")
file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/test/dir 1/non_empty_dir")
file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/test/dir 2/empty_dir")
file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/test/dir 2/non_empty_dir")
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/test/dir 1/dir 1 file" "test file")
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/test/dir 1/non_empty_dir/dir 1 subdir file" "test file")
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/test/dir 2/dir 2 file" "test file")
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/test/dir 2/non_empty_dir/dir 2 subdir file" "test file")
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}")
.*Cyclic recursion detected while globbing for.*
.*/test/depth1/depth2/depth3.*
.*/test/depth1/depth2/depth3/recursion.*
content: 4[ ]
.*/test/abc;.*/test/depth1/depth2/depth3/file_symlink;.*/test/depth1/depth2/depth3/recursion/abc;.*/test/depth1/depth2/depth3/recursion/depth1/depth2/depth3/file_symlink
.*Cyclic recursion detected while globbing for.*
.*/test/depth1/depth2/depth3.*
.*/test/depth1/depth2/depth3/recursion.*
content: 4[ ]
.*/test/abc;.*/test/depth1/depth2/depth3/file_symlink;.*/test/depth1/depth2/depth3/recursion/abc;.*/test/depth1/depth2/depth3/recursion/depth1/depth2/depth3/file_symlink
.*Cyclic recursion detected while globbing for.*
.*/test/depth1/depth2/depth3.*
.*/test/depth1/depth2/depth3/recursion.*
content: 11[ ]
.*/test/abc;.*/test/depth1;.*/test/depth1/depth2;.*/test/depth1/depth2/depth3;.*/test/depth1/depth2/depth3/file_symlink;.*/test/depth1/depth2/depth3/recursion;.*/test/depth1/depth2/depth3/recursion/abc;.*/test/depth1/depth2/depth3/recursion/depth1;.*/test/depth1/depth2/depth3/recursion/depth1/depth2;.*/test/depth1/depth2/depth3/recursion/depth1/depth2/depth3;.*/test/depth1/depth2/depth3/recursion/depth1/depth2/depth3/file_symlink
file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/test/depth1/depth2/depth3")
execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink "${CMAKE_CURRENT_BINARY_DIR}/test" "${CMAKE_CURRENT_BINARY_DIR}/test/depth1/depth2/depth3/recursion")
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/test/abc" "message to write")
execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink "${CMAKE_CURRENT_BINARY_DIR}/test/abc" "${CMAKE_CURRENT_BINARY_DIR}/test/depth1/depth2/depth3/file_symlink")
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}")
content: 4[ ]
.*/test/dir 1/dir 1 file;.*/test/dir 1/non_empty_dir/dir 1 subdir file;.*/test/dir 2/dir 2 file;.*/test/dir 2/non_empty_dir/dir 2 subdir file
content: 4[ ]
.*/test/dir 1/dir 1 file;.*/test/dir 1/non_empty_dir/dir 1 subdir file;.*/test/dir 2/dir 2 file;.*/test/dir 2/non_empty_dir/dir 2 subdir file
content: 8[ ]
.*/test/dir 1/dir 1 file;.*/test/dir 1/empty_dir;.*/test/dir 1/non_empty_dir;.*/test/dir 1/non_empty_dir/dir 1 subdir file;.*/test/dir 2/dir 2 file;.*/test/dir 2/empty_dir;.*/test/dir 2/non_empty_dir;.*/test/dir 2/non_empty_dir/dir 2 subdir file
file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/test/dir 1/empty_dir")
file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/test/dir 1/non_empty_dir")
file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/test/dir 2/empty_dir")
file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/test/dir 2/non_empty_dir")
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/test/dir 1/dir 1 file" "test file")
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/test/dir 1/non_empty_dir/dir 1 subdir file" "test file")
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/test/dir 2/dir 2 file" "test file")
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/test/dir 2/non_empty_dir/dir 2 subdir file" "test file")
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}")
......@@ -17,3 +17,13 @@ run_cmake(LOCK-error-no-result-variable)
run_cmake(LOCK-error-no-timeout)
run_cmake(LOCK-error-timeout)
run_cmake(LOCK-error-unknown-option)
run_cmake(GLOB)
run_cmake(GLOB_RECURSE)
# test is valid both for GLOB and GLOB_RECURSE
run_cmake(GLOB-error-LIST_DIRECTORIES-not-boolean)
# test is valid both for GLOB and GLOB_RECURSE
run_cmake(GLOB-error-LIST_DIRECTORIES-no-arg)
if(NOT WIN32 OR CYGWIN)
run_cmake(GLOB_RECURSE-cyclic-recursion)
endif()
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment