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.
This commit is contained in:
parent
09498b2ead
commit
ce331bab92
|
@ -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)
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
cmake_minimum_required(VERSION 3.1)
|
||||
project(${RunCMake_TEST} NONE)
|
||||
include(${RunCMake_TEST}.cmake)
|
|
@ -0,0 +1,2 @@
|
|||
CREATED_LIBRARY='CREATED_LIBRARY-NOTFOUND'
|
||||
CREATED_LIBRARY='[^']*/Tests/RunCMake/find_library/Created-build/lib/libcreated.a'
|
|
@ -0,0 +1,16 @@
|
|||
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}'")
|
|
@ -0,0 +1,3 @@
|
|||
include(RunCMake)
|
||||
|
||||
run_cmake(Created)
|
Loading…
Reference in New Issue