Commit ce331bab authored by Brad King's avatar Brad King
Browse files

find_library: Fix repeat call after changing directory content (#15293)

We use cmGlobalGenerator::GetDirectoryContent to avoid repeating
directory listings.  However, GetDirectoryContent loads content from
disk at most once.  This breaks find_library calls that occur when disk
content has changed since preceding find_library calls.

Teach cmGlobalGenerator::GetDirectoryContent to save the directory
modification time when content is loaded and re-load content if it
changes.

Create a RunCMake.find_library test with a case covering this.
parent 09498b2e
......@@ -2725,7 +2725,9 @@ void cmGlobalGenerator::AddToManifest(const std::string& config,
// Add to the content listing for the file's directory.
std::string dir = cmSystemTools::GetFilenamePath(f);
std::string file = cmSystemTools::GetFilenameName(f);
this->DirectoryContentMap[dir].insert(file);
DirectoryContent& dc = this->DirectoryContentMap[dir];
dc.Generated.insert(file);
dc.All.insert(file);
}
//----------------------------------------------------------------------------
......@@ -2733,25 +2735,32 @@ std::set<std::string> const&
cmGlobalGenerator::GetDirectoryContent(std::string const& dir, bool needDisk)
{
DirectoryContent& dc = this->DirectoryContentMap[dir];
if(needDisk && !dc.LoadedFromDisk)
if(needDisk)
{
// Load the directory content from disk.
cmsys::Directory d;
if(d.Load(dir))
long mt = cmSystemTools::ModifiedTime(dir);
if (mt != dc.LastDiskTime)
{
unsigned long n = d.GetNumberOfFiles();
for(unsigned long i = 0; i < n; ++i)
// Reset to non-loaded directory content.
dc.All = dc.Generated;
// Load the directory content from disk.
cmsys::Directory d;
if(d.Load(dir))
{
const char* f = d.GetFile(i);
if(strcmp(f, ".") != 0 && strcmp(f, "..") != 0)
unsigned long n = d.GetNumberOfFiles();
for(unsigned long i = 0; i < n; ++i)
{
dc.insert(f);
const char* f = d.GetFile(i);
if(strcmp(f, ".") != 0 && strcmp(f, "..") != 0)
{
dc.All.insert(f);
}
}
}
dc.LastDiskTime = mt;
}
dc.LoadedFromDisk = true;
}
return dc;
return dc.All;
}
//----------------------------------------------------------------------------
......
......@@ -255,9 +255,9 @@ public:
cmTargetManifest const& GetTargetManifest() const
{ return this->TargetManifest; }
/** Get the content of a directory. Directory listings are loaded
from disk at most once and cached. During the generation step
the content will include the target files to be built even if
/** Get the content of a directory. Directory listings are cached
and re-loaded from disk only when modified. During the generation
step the content will include the target files to be built even if
they do not yet exist. */
std::set<std::string> const& GetDirectoryContent(std::string const& dir,
bool needDisk = true);
......@@ -486,13 +486,14 @@ private:
virtual const char* GetBuildIgnoreErrorsFlag() const { return 0; }
// Cache directory content and target files to be built.
struct DirectoryContent: public std::set<std::string>
struct DirectoryContent
{
typedef std::set<std::string> derived;
bool LoadedFromDisk;
DirectoryContent(): LoadedFromDisk(false) {}
long LastDiskTime;
std::set<std::string> All;
std::set<std::string> Generated;
DirectoryContent(): LastDiskTime(-1) {}
DirectoryContent(DirectoryContent const& dc):
derived(dc), LoadedFromDisk(dc.LoadedFromDisk) {}
LastDiskTime(dc.LastDiskTime), All(dc.All), Generated(dc.Generated) {}
};
std::map<std::string, DirectoryContent> DirectoryContentMap;
......
......@@ -104,6 +104,7 @@ add_RunCMake_test(export)
add_RunCMake_test(cmake_minimum_required)
add_RunCMake_test(continue)
add_RunCMake_test(file)
add_RunCMake_test(find_library)
add_RunCMake_test(find_package)
add_RunCMake_test(get_filename_component)
add_RunCMake_test(if)
......
cmake_minimum_required(VERSION 3.1)
project(${RunCMake_TEST} NONE)
include(${RunCMake_TEST}.cmake)
CREATED_LIBRARY='CREATED_LIBRARY-NOTFOUND'
CREATED_LIBRARY='[^']*/Tests/RunCMake/find_library/Created-build/lib/libcreated.a'
list(APPEND CMAKE_FIND_LIBRARY_PREFIXES lib)
list(APPEND CMAKE_FIND_LIBRARY_SUFFIXES .a)
find_library(CREATED_LIBRARY
NAMES created
PATHS ${CMAKE_CURRENT_BINARY_DIR}/lib
NO_DEFAULT_PATH
)
message("CREATED_LIBRARY='${CREATED_LIBRARY}'")
file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/lib)
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/lib/libcreated.a" "created")
find_library(CREATED_LIBRARY
NAMES created
PATHS ${CMAKE_CURRENT_BINARY_DIR}/lib
NO_DEFAULT_PATH
)
message("CREATED_LIBRARY='${CREATED_LIBRARY}'")
include(RunCMake)
run_cmake(Created)
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