Generate automatic dependencies.

svn path=/branches/xmlbuildsystem/; revision=13371
This commit is contained in:
Casper Hornstrup 2005-01-31 18:25:55 +00:00
parent adeb8563b5
commit 6052ab4bd7
11 changed files with 325 additions and 83 deletions

View file

@ -1,5 +1,6 @@
<module name="freeldr_base" type="objectlibrary">
<include base="freeldr_base">include</include>
<include base="freeldr_base">cache</include>
<compilerflag>-nostdlib</compilerflag>
<compilerflag>-nostdinc</compilerflag>
<compilerflag>-ffreestanding</compilerflag>

View file

@ -13,20 +13,42 @@
/* Read at most this amount of bytes from each file and assume that all #includes are located within this block */
#define MAX_BYTES_TO_READ 4096
using std::string;
using std::vector;
using std::map;
SourceFile::SourceFile ( AutomaticDependency* automaticDependency,
Module& module,
const string& filename )
const string& filename,
SourceFile* parent,
bool isNonAutomaticDependency )
: automaticDependency ( automaticDependency ),
module ( module ),
filename ( filename )
filename ( filename ),
isNonAutomaticDependency ( isNonAutomaticDependency )
{
if ( parent != NULL )
parents.push_back ( parent );
GetDirectoryAndFilenameParts ();
}
void
SourceFile::GetDirectoryAndFilenameParts ()
{
size_t index = filename.find_last_of ( CSEP );
if ( index != string::npos )
{
directoryPart = filename.substr ( 0, index );
filenamePart = filename.substr ( index + 1, filename.length () - index );
}
else
{
directoryPart = "";
filenamePart = filename;
}
}
void
SourceFile::Close ()
{
@ -87,14 +109,65 @@ SourceFile::ReadInclude ( string& filename )
return false;
}
bool
SourceFile::IsParentOf ( const SourceFile* parent,
const SourceFile* child )
{
size_t i;
for ( i = 0; i < child->parents.size (); i++ )
{
if ( child->parents[i] != NULL )
{
if ( child->parents[i] == parent )
return true;
}
}
for ( i = 0; i < child->parents.size (); i++ )
{
if ( child->parents[i] != NULL )
{
if ( IsParentOf ( parent,
child->parents[i] ) )
return true;
}
}
return false;
}
bool
SourceFile::IsIncludedFrom ( const string& normalizedFilename )
{
if ( normalizedFilename == filename )
return true;
SourceFile* sourceFile = automaticDependency->RetrieveFromCache ( normalizedFilename );
if ( sourceFile == NULL )
return false;
return IsParentOf ( sourceFile,
this );
}
SourceFile*
SourceFile::GetParentSourceFile ()
{
if ( isNonAutomaticDependency )
return NULL;
return this;
}
SourceFile*
SourceFile::ParseFile ( const string& normalizedFilename )
{
string extension = GetExtension ( normalizedFilename );
if ( extension == ".c" || extension == ".C" || extension == ".h" || extension == ".H")
if ( extension == ".c" || extension == ".C" || extension == ".h" || extension == ".H" )
{
if ( IsIncludedFrom ( normalizedFilename ) )
return NULL;
SourceFile* sourceFile = automaticDependency->RetrieveFromCacheOrParse ( module,
normalizedFilename );
normalizedFilename,
GetParentSourceFile () );
return sourceFile;
}
return NULL;
@ -118,7 +191,8 @@ SourceFile::Parse ()
if ( locatedFile )
{
SourceFile* sourceFile = ParseFile ( resolvedFilename );
files.push_back ( sourceFile );
if ( sourceFile != NULL )
files.push_back ( sourceFile );
}
}
p++;
@ -173,10 +247,9 @@ AutomaticDependency::ProcessFile ( Module& module,
const File& file )
{
string normalizedFilename = NormalizeFilename ( file.name );
SourceFile sourceFile = SourceFile ( this,
module,
normalizedFilename );
sourceFile.Parse ();
RetrieveFromCacheOrParse ( module,
normalizedFilename,
NULL );
}
bool
@ -201,40 +274,54 @@ AutomaticDependency::LocateIncludedFile ( Module& module,
const string& includedFilename,
string& resolvedFilename )
{
for ( size_t i = 0; i < module.includes.size (); i++ )
size_t i;
for ( i = 0; i < module.includes.size (); i++ )
{
Include* include = module.includes[0];
Include* include = module.includes[i];
if ( LocateIncludedFile ( include->directory,
includedFilename,
resolvedFilename ) )
return true;
}
/* FIXME: Ifs */
for ( i = 0; i < module.project.includes.size (); i++ )
{
Include* include = module.project.includes[i];
if ( LocateIncludedFile ( include->directory,
includedFilename,
resolvedFilename ) )
return true;
}
resolvedFilename = "";
return false;
}
SourceFile*
AutomaticDependency::RetrieveFromCacheOrParse ( Module& module,
const string& filename )
const string& filename,
SourceFile* parentSourceFile )
{
SourceFile* sourceFile = sourcefile_map[filename];
if ( sourceFile == NULL )
{
sourceFile = new SourceFile ( this,
module,
filename );
sourceFile->Parse ();
filename,
parentSourceFile,
false );
sourcefile_map[filename] = sourceFile;
sourceFile->Parse ();
}
else if ( parentSourceFile != NULL )
sourceFile->parents.push_back ( parentSourceFile );
return sourceFile;
}
SourceFile*
AutomaticDependency::RetrieveFromCache ( Module& module,
const string& filename )
AutomaticDependency::RetrieveFromCache ( const string& filename )
{
return sourcefile_map[filename];
}

View file

@ -19,7 +19,8 @@ public:
MingwBackend::MingwBackend ( Project& project )
: Backend ( project )
: Backend ( project ),
automaticDependencyUniqueIdCounter ( 0 )
{
}
@ -240,12 +241,19 @@ MingwBackend::GenerateAllTarget () const
fprintf ( fMakefile, "\n\t\n\n" );
}
string*
MingwBackend::GenerateAutomaticDependencyUniqueId ()
{
automaticDependencyUniqueIdCounter++;
return new string ( ssprintf ( "d%d",
automaticDependencyUniqueIdCounter ) );
}
void
MingwBackend::GenerateAutomaticDependencies () const
MingwBackend::GenerateAutomaticDependencies ()
{
AutomaticDependency automaticDependency ( ProjectNode );
automaticDependency.Process ();
for ( size_t mi = 0; mi < ProjectNode.modules.size (); mi++ )
{
Module& module = *ProjectNode.modules[mi];
@ -253,34 +261,110 @@ MingwBackend::GenerateAutomaticDependencies () const
{
File& file = *module.files[fi];
string normalizedFilename = NormalizeFilename ( file.name );
SourceFile* sourceFile = automaticDependency.RetrieveFromCache ( module,
normalizedFilename );
SourceFile* sourceFile = automaticDependency.RetrieveFromCache ( normalizedFilename );
if ( sourceFile != NULL )
{
string dependencies ( "" );
GenerateAutomaticDependenciesForFile ( sourceFile,
dependencies );
fprintf ( fMakefile,
"%s:: %s",
normalizedFilename.c_str (),
dependencies.c_str () );
GenerateAutomaticDependenciesForFileCached ( sourceFile,
dependencies );
if ( dependencies.size () > 0 )
{
const string& objectFilename = MingwModuleHandler::GetObjectFilename ( normalizedFilename );
string* uniqueId = automaticDependencyMap[dependencies];
if ( uniqueId == NULL )
{
uniqueId = GenerateAutomaticDependencyUniqueId ();
automaticDependencyMap[dependencies] = uniqueId;
fprintf ( fMakefile,
"%s = %s\n",
uniqueId->c_str (),
dependencies.c_str () );
}
fprintf ( fMakefile,
"%s: $(%s)\n",
objectFilename.c_str (),
uniqueId->c_str () );
}
}
}
}
}
void
MingwBackend::GenerateAutomaticDependenciesForFile ( SourceFile* sourceFile,
string& dependencies ) const
string
MingwBackend::GetFilename ( const string& filename ) const
{
if ( dependencies.size () > 0 )
dependencies += " ";
dependencies += sourceFile->filename;
size_t index = filename.find_last_of ( CSEP );
if ( index == string::npos )
return filename;
else
return filename.substr ( index + 1, filename.length () - index );
}
void
MingwBackend::GenerateAutomaticDependenciesForFileCached ( SourceFile* sourceFile,
string& dependencies )
{
for ( size_t i = 0; i < sourceFile->files.size (); i++)
{
SourceFile* childSourceFile = sourceFile->files[0];
SourceFile* childSourceFile = sourceFile->files[i];
string* uniqueId = automaticDependencyDirectoryMap[childSourceFile->directoryPart];
if ( uniqueId == NULL )
{
uniqueId = GenerateAutomaticDependencyUniqueId ();
automaticDependencyDirectoryMap[childSourceFile->directoryPart] = uniqueId;
fprintf ( fMakefile,
"%s = %s\n",
uniqueId->c_str (),
childSourceFile->directoryPart.c_str () );
}
dependencies += ssprintf ( "${%s}%s%s",
uniqueId->c_str (),
SSEP,
childSourceFile->filenamePart.c_str () );
string childDependencies;
if ( childSourceFile->cachedDependencies.length () > 0 )
childDependencies = childSourceFile->cachedDependencies;
else
{
GenerateAutomaticDependenciesForFile ( childSourceFile,
childDependencies );
if ( childDependencies.length () > 200 )
{
childSourceFile->cachedDependencies = childDependencies;
}
}
dependencies += " " + childDependencies;
}
}
void
MingwBackend::GenerateAutomaticDependenciesForFile ( SourceFile* sourceFile,
string& dependencies )
{
for ( size_t i = 0; i < sourceFile->files.size (); i++ )
{
SourceFile* childSourceFile = sourceFile->files[i];
if ( dependencies.length () > 0 )
dependencies += " ";
string* uniqueId = automaticDependencyDirectoryMap[childSourceFile->directoryPart];
if ( uniqueId == NULL )
{
uniqueId = GenerateAutomaticDependencyUniqueId ();
automaticDependencyDirectoryMap[childSourceFile->directoryPart] = uniqueId;
fprintf ( fMakefile,
"%s = %s\n",
uniqueId->c_str (),
childSourceFile->directoryPart.c_str () );
}
dependencies += ssprintf ( "${%s}%s%s",
uniqueId->c_str (),
SSEP,
childSourceFile->filenamePart.c_str () );
GenerateAutomaticDependenciesForFile ( childSourceFile,
dependencies );
}

View file

@ -8,6 +8,7 @@ class MingwBackend : public Backend
{
public:
MingwBackend ( Project& project );
virtual ~MingwBackend () { };
virtual void Process ();
private:
void ProcessModule ( Module& module ) const;
@ -27,10 +28,19 @@ private:
void GenerateGlobalVariables () const;
bool IncludeInAllTarget ( const Module& module ) const;
void GenerateAllTarget () const;
void GenerateAutomaticDependencies () const;
std::string* GenerateAutomaticDependencyUniqueId ();
void GenerateAutomaticDependencies ();
bool IsAutomaticDependencyGenerated ( SourceFile* sourceFile );
void OutputAutomaticDependenciesForFile ( SourceFile* sourceFile );
std::string GetFilename ( const std::string& filename ) const;
void GenerateAutomaticDependenciesForFileCached ( SourceFile* sourceFile,
std::string& dependencies );
void GenerateAutomaticDependenciesForFile ( SourceFile* sourceFile,
std::string& dependencies ) const;
std::string& dependencies );
FILE* fMakefile;
int automaticDependencyUniqueIdCounter;
std::map<std::string, std::string*> automaticDependencyMap;
std::map<std::string, std::string*> automaticDependencyDirectoryMap;
};
std::string FixupTargetFilename ( const std::string& targetFilename );

View file

@ -22,6 +22,20 @@ MingwModuleHandler::ref = 0;
FILE*
MingwModuleHandler::fMakefile = NULL;
string
ReplaceExtension ( const string& filename,
const string& newExtension )
{
size_t index = filename.find_last_of ( '/' );
if (index == string::npos) index = 0;
string tmp = filename.substr( index, filename.size() - index );
size_t ext_index = tmp.find_last_of( '.' );
if (ext_index != string::npos)
return filename.substr ( 0, index + ext_index ) + newExtension;
return filename + newExtension;
}
MingwModuleHandler::MingwModuleHandler ( ModuleType moduletype )
{
if ( !ref++ )
@ -72,10 +86,10 @@ MingwModuleHandler::GetWorkingDirectory () const
return ".";
}
string
MingwModuleHandler::GetDirectory ( const string& filename ) const
string
MingwModuleHandler::GetDirectory ( const string& filename )
{
size_t index = filename.find_last_of ( '/' );
size_t index = filename.find_last_of ( CSEP );
if (index == string::npos)
return ".";
else
@ -91,19 +105,6 @@ MingwModuleHandler::GetBasename ( const string& filename ) const
return "";
}
string
MingwModuleHandler::ReplaceExtension ( const string& filename,
const string& newExtension ) const
{
size_t index = filename.find_last_of ( '/' );
if (index == string::npos) index = 0;
string tmp = filename.substr( index, filename.size() - index );
size_t ext_index = tmp.find_last_of( '.' );
if (ext_index != string::npos)
return filename.substr ( 0, index + ext_index ) + newExtension;
return filename + newExtension;
}
string
MingwModuleHandler::GetActualSourceFilename ( const string& filename ) const
{
@ -237,7 +238,7 @@ MingwModuleHandler::GetSourceFilenamesWithoutGeneratedFiles ( const Module& modu
}
string
MingwModuleHandler::GetObjectFilename ( const string& sourceFilename ) const
MingwModuleHandler::GetObjectFilename ( const string& sourceFilename )
{
string newExtension;
string extension = GetExtension ( sourceFilename );
@ -247,9 +248,8 @@ MingwModuleHandler::GetObjectFilename ( const string& sourceFilename ) const
newExtension = ".stubs.o";
else
newExtension = ".o";
return PassThruCacheDirectory (
FixupTargetFilename (
ReplaceExtension ( sourceFilename, newExtension ) ) );
return FixupTargetFilename (
ReplaceExtension ( sourceFilename, newExtension ) );
}
string
@ -263,7 +263,7 @@ MingwModuleHandler::GetObjectFilenames ( const Module& module ) const
{
if ( objectFilenames.size () > 0 )
objectFilenames += " ";
objectFilenames += GetObjectFilename ( module.files[i]->name );
objectFilenames += PassThruCacheDirectory ( MingwModuleHandler::GetObjectFilename ( module.files[i]->name ) );
}
return objectFilenames;
}
@ -510,7 +510,7 @@ MingwModuleHandler::GenerateMacros (
fprintf ( fMakefile,
"%s := %s $(%s)\n",
objs_macro.c_str(),
GetObjectFilename(files[i]->name).c_str(),
PassThruCacheDirectory ( MingwModuleHandler::GetObjectFilename ( files[i]->name ) ).c_str (),
objs_macro.c_str() );
}
}
@ -530,7 +530,7 @@ MingwModuleHandler::GenerateMacros (
fMakefile,
"%s%s",
( i%10 == 9 ? "\\\n\t" : " " ),
GetObjectFilename(files[i]->name).c_str() );
PassThruCacheDirectory ( MingwModuleHandler::GetObjectFilename ( files[i]->name ) ).c_str () );
}
}
fprintf ( fMakefile, "\n" );
@ -612,7 +612,7 @@ MingwModuleHandler::GenerateGccCommand ( const Module& module,
const string& cc,
const string& cflagsMacro ) const
{
string objectFilename = GetObjectFilename ( sourceFilename );
string objectFilename = PassThruCacheDirectory ( MingwModuleHandler::GetObjectFilename ( sourceFilename ) );
fprintf ( fMakefile,
"%s: %s\n",
objectFilename.c_str (),
@ -631,7 +631,7 @@ MingwModuleHandler::GenerateGccAssemblerCommand ( const Module& module,
const string& cc,
const string& cflagsMacro ) const
{
string objectFilename = GetObjectFilename ( sourceFilename );
string objectFilename = PassThruCacheDirectory ( MingwModuleHandler::GetObjectFilename ( sourceFilename ) );
fprintf ( fMakefile,
"%s: %s\n",
objectFilename.c_str (),
@ -649,7 +649,7 @@ MingwModuleHandler::GenerateNasmCommand ( const Module& module,
const string& sourceFilename,
const string& nasmflagsMacro ) const
{
string objectFilename = GetObjectFilename ( sourceFilename );
string objectFilename = PassThruCacheDirectory ( MingwModuleHandler::GetObjectFilename ( sourceFilename ) );
fprintf ( fMakefile,
"%s: %s\n",
objectFilename.c_str (),
@ -667,7 +667,7 @@ MingwModuleHandler::GenerateWindresCommand ( const Module& module,
const string& sourceFilename,
const string& windresflagsMacro ) const
{
string objectFilename = GetObjectFilename ( sourceFilename );
string objectFilename = PassThruCacheDirectory ( MingwModuleHandler::GetObjectFilename ( sourceFilename ) );
fprintf ( fMakefile,
"%s: %s\n",
objectFilename.c_str (),
@ -908,7 +908,7 @@ MingwModuleHandler::GetCleanTargets ( vector<string>& out,
size_t i;
for ( i = 0; i < files.size(); i++ )
out.push_back ( GetObjectFilename(files[i]->name) );
out.push_back ( PassThruCacheDirectory ( MingwModuleHandler::GetObjectFilename ( files[i]->name ) ) );
for ( i = 0; i < ifs.size(); i++ )
GetCleanTargets ( out, ifs[i]->files, ifs[i]->ifs );

View file

@ -3,6 +3,11 @@
#include "../backend.h"
extern std::string
ReplaceExtension ( const std::string& filename,
const std::string& newExtension );
class MingwModuleHandler
{
public:
@ -16,15 +21,13 @@ public:
static MingwModuleHandler* LookupHandler ( const std::string& location,
ModuleType moduletype_ );
virtual void Process ( const Module& module ) = 0;
void GenerateDirectoryTargets () const;
void GenerateDirectoryTargets () const;
static std::string GetObjectFilename ( const std::string& sourceFilename );
static std::string GetDirectory ( const std::string& filename );
protected:
const std::string &PassThruCacheDirectory ( const std::string &f ) const;
std::string GetWorkingDirectory () const;
std::string GetDirectory (const std::string& filename ) const;
std::string GetBasename ( const std::string& filename ) const;
std::string ReplaceExtension ( const std::string& filename,
const std::string& newExtension ) const;
std::string GetActualSourceFilename ( const std::string& filename ) const;
std::string GetModuleArchiveFilename ( const Module& module ) const;
bool IsGeneratedFile ( const File& file ) const;
@ -37,7 +40,6 @@ protected:
std::string GetSourceFilenames ( const Module& module ) const;
std::string GetSourceFilenamesWithoutGeneratedFiles ( const Module& module ) const;
std::string GetObjectFilename ( const std::string& sourceFilename ) const;
std::string GetObjectFilenames ( const Module& module ) const;
void GenerateMacrosAndTargetsHost ( const Module& module ) const;
void GenerateMacrosAndTargetsTarget ( const Module& module ) const;
@ -47,6 +49,8 @@ protected:
std::string GetInvocationDependencies ( const Module& module ) const;
std::string GetInvocationParameters ( const Invoke& invoke ) const;
void GenerateInvocations ( const Module& module ) const;
std::string GetPreconditionDependenciesName ( const Module& module ) const;
void GeneratePreconditionDependencies ( const Module& module ) const;
std::string GetCFlagsMacro ( const Module& module ) const;
std::string GetObjectsMacro ( const Module& module ) const;
@ -144,7 +148,6 @@ private:
const std::string& ar,
const std::string* clags,
const std::string* nasmflags ) const;
std::string GetPreconditionDependenciesName ( const Module& module ) const;
std::string GetSpecObjectDependencies ( const std::string& filename ) const;
};

View file

@ -352,7 +352,9 @@ class SourceFile
public:
SourceFile ( AutomaticDependency* automaticDependency,
Module& module,
const std::string& filename );
const std::string& filename,
SourceFile* parent,
bool isNonAutomaticDependency );
SourceFile* ParseFile ( const std::string& normalizedFilename );
void Parse ();
std::string Location () const;
@ -360,11 +362,21 @@ public:
AutomaticDependency* automaticDependency;
Module& module;
std::string filename;
std::string filenamePart;
std::string directoryPart;
std::vector<SourceFile*> parents; /* List of files, this file is included from */
bool isNonAutomaticDependency;
std::string cachedDependencies;
private:
void GetDirectoryAndFilenameParts ();
void Close ();
void Open ();
void SkipWhitespace ();
bool ReadInclude ( std::string& filename );
bool IsIncludedFrom ( const std::string& normalizedFilename );
SourceFile* GetParentSourceFile ();
bool IsParentOf ( const SourceFile* parent,
const SourceFile* child );
std::string buf;
const char *p;
const char *end;
@ -387,9 +399,9 @@ public:
const std::string& includedFilename,
std::string& resolvedFilename );
SourceFile* RetrieveFromCacheOrParse ( Module& module,
const std::string& filename );
SourceFile* RetrieveFromCache ( Module& module,
const std::string& filename );
const std::string& filename,
SourceFile* parentSourceFile );
SourceFile* RetrieveFromCache ( const std::string& filename );
private:
void ProcessModule ( Module& module );
void ProcessFile ( Module& module,

View file

@ -108,6 +108,10 @@ class SourceFileTest : public BaseTest
{
public:
void Run();
private:
bool IsParentOf ( const SourceFile* parent,
const SourceFile* child );
};
#endif /* __TEST_H */

View file

@ -1,2 +1,3 @@
#include <sourcefile1/sourcefile1_header3.h>
#include "sourcefile1/sourcefile1_header3.h"
#include <sourcefile2/sourcefile1_dontexist.h>
#include <sourcefile1_recurse.h>

View file

@ -0,0 +1,2 @@
#include <sourcefile1_recurse.h>
#include <sourcefile1_header1.h>

View file

@ -2,10 +2,48 @@
using std::string;
void SourceFileTest::Run()
bool
SourceFileTest::IsParentOf ( const SourceFile* parent,
const SourceFile* child )
{
size_t i;
for ( i = 0; i < child->parents.size (); i++ )
{
if ( child->parents[i] != NULL )
{
if ( child->parents[i] == parent )
{
return true;
}
}
}
for ( i = 0; i < child->parents.size (); i++ )
{
if ( child->parents[i] != NULL )
{
if ( IsParentOf ( parent,
child->parents[i] ) )
{
return true;
}
}
}
return false;
}
void
SourceFileTest::Run ()
{
const Project project ( "tests/data/automaticdependency.xml" );
AutomaticDependency automaticDependency ( project );
automaticDependency.Process ();
ARE_EQUAL(3, automaticDependency.sourcefile_map.size());
ARE_EQUAL( 5, automaticDependency.sourcefile_map.size () );
const SourceFile* header1 = automaticDependency.RetrieveFromCache ( "tests" SSEP "data" SSEP "sourcefile1_header1.h" );
IS_NOT_NULL( header1 );
const SourceFile* recurse = automaticDependency.RetrieveFromCache ( "tests" SSEP "data" SSEP "sourcefile1_recurse.h" );
IS_NOT_NULL( recurse );
IS_TRUE( IsParentOf ( header1,
recurse ) );
IS_FALSE( IsParentOf ( recurse,
header1 ) );
}