ENH: Split cmLocalUnixMakefileGenerator2 away from cmLocalUnixMakefileGenerator to be a stand-alone generator.

This commit is contained in:
Brad King 2005-02-10 16:18:27 -05:00
parent 23276ca3a2
commit 6173dea153
2 changed files with 408 additions and 22 deletions

View File

@ -35,13 +35,8 @@
#include <assert.h>
// Quick-switch for generating old makefiles.
#if 1
# define CMLUMG_MAKEFILE_NAME "Makefile"
#else
# define CMLUMG_WRITE_OLD_MAKEFILE
# define CMLUMG_MAKEFILE_NAME "Makefile2"
#endif
// TODO: Convert makefile name to a runtime switch.
#define CMLUMG_MAKEFILE_NAME "Makefile"
// TODO: Add "help" target.
// TODO: Identify remaining relative path violations.
@ -50,6 +45,12 @@
//----------------------------------------------------------------------------
cmLocalUnixMakefileGenerator2::cmLocalUnixMakefileGenerator2()
{
m_WindowsShell = false;
m_IncludeDirective = "include";
m_MakefileVariableSize = 0;
m_IgnoreLibPrefix = false;
m_PassMakeflags = false;
m_UseRelativePaths = false;
}
//----------------------------------------------------------------------------
@ -70,10 +71,6 @@ void cmLocalUnixMakefileGenerator2::SetEmptyCommand(const char* cmd)
//----------------------------------------------------------------------------
void cmLocalUnixMakefileGenerator2::Generate(bool fromTheTop)
{
#ifdef CMLUMG_WRITE_OLD_MAKEFILE
// Generate old style for now.
this->cmLocalUnixMakefileGenerator::Generate(fromTheTop);
#else
// Make sure we never run a local generate.
if(!fromTheTop)
{
@ -82,10 +79,8 @@ void cmLocalUnixMakefileGenerator2::Generate(bool fromTheTop)
return;
}
// Handle EXECUTABLE_OUTPUT_PATH and LIBRARY_OUTPUT_PATH since
// superclass generator is not called.
// Setup our configuration variables for this directory.
this->ConfigureOutputPaths();
#endif
// Generate the rule files for each target.
const cmTargets& targets = m_Makefile->GetTargets();
@ -1797,7 +1792,7 @@ cmLocalUnixMakefileGenerator2
std::string targetNameSO;
std::string targetNameReal;
std::string targetNameBase;
this->GetLibraryNames(target.GetName(), target,
this->GetLibraryNames(target,
targetName, targetNameSO,
targetNameReal, targetNameBase);
@ -2379,11 +2374,22 @@ cmLocalUnixMakefileGenerator2::ConvertToRelativeOutputPath(const char* p)
}
//----------------------------------------------------------------------------
void
cmLocalUnixMakefileGenerator2::ConfigureOutputPaths()
void cmLocalUnixMakefileGenerator2::ConfigureOutputPaths()
{
// Call superclass version first.
this->cmLocalUnixMakefileGenerator::ConfigureOutputPaths();
// Save whether to use relative paths.
m_UseRelativePaths = m_Makefile->IsOn("CMAKE_USE_RELATIVE_PATHS");
// Format the library and executable output paths.
if(const char* libOut = m_Makefile->GetDefinition("LIBRARY_OUTPUT_PATH"))
{
m_LibraryOutputPath = libOut;
this->FormatOutputPath(m_LibraryOutputPath, "LIBRARY");
}
if(const char* exeOut = m_Makefile->GetDefinition("EXECUTABLE_OUTPUT_PATH"))
{
m_ExecutableOutputPath = exeOut;
this->FormatOutputPath(m_ExecutableOutputPath, "EXECUTABLE");
}
// Setup fully collapsed paths.
m_CurrentOutputDirectory =
@ -2432,6 +2438,37 @@ cmLocalUnixMakefileGenerator2::ConfigureOutputPaths()
}
}
//----------------------------------------------------------------------------
void cmLocalUnixMakefileGenerator2::FormatOutputPath(std::string& path,
const char* name)
{
if(!path.empty())
{
// Convert the output path to a full path in case it is
// specified as a relative path. Treat a relative path as
// relative to the current output directory for this makefile.
path =
cmSystemTools::CollapseFullPath(path.c_str(),
m_Makefile->GetStartOutputDirectory());
// Add a trailing slash for easy appending later.
if(path.empty() || path[path.size()-1] != '/')
{
path += "/";
}
// Make sure the output path exists on disk.
if(!cmSystemTools::MakeDirectory(path.c_str()))
{
cmSystemTools::Error("Error failed to create ",
name, "_OUTPUT_PATH directory:", path.c_str());
}
// Add this as a link directory automatically.
m_Makefile->AddLinkDirectory(path.c_str());
}
}
//----------------------------------------------------------------------------
bool cmLocalUnixMakefileGenerator2::ComparePath(const char* c1, const char* c2)
{
@ -2683,6 +2720,292 @@ cmLocalUnixMakefileGenerator2
}
}
//============================================================================
//----------------------------------------------------------------------------
void cmLocalUnixMakefileGenerator2::OutputEcho(std::ostream& fout,
const char* msg)
{
std::string echostring = msg;
// For UNIX we want to quote the output of echo.
// For NMake and Borland, the echo should not be quoted.
if(strcmp(m_GlobalGenerator->GetName(), "Unix Makefiles") == 0)
{
cmSystemTools::ReplaceString(echostring, "\\\n", " ");
cmSystemTools::ReplaceString(echostring, " \t", " ");
cmSystemTools::ReplaceString(echostring, "\n\t", "\"\n\t@echo \"");
fout << "\t@echo \"" << echostring.c_str() << "\"\n";
}
else
{
cmSystemTools::ReplaceString(echostring, "\n\t", "\n\t@echo ");
fout << "\t@echo " << echostring.c_str() << "\n";
}
}
//----------------------------------------------------------------------------
bool
cmLocalUnixMakefileGenerator2::SamePath(const char* path1, const char* path2)
{
if (strcmp(path1, path2) == 0)
{
return true;
}
#if defined(_WIN32) || defined(__APPLE__)
return
(cmSystemTools::LowerCase(this->ConvertToOutputForExisting(path1)) ==
cmSystemTools::LowerCase(this->ConvertToOutputForExisting(path2)));
#else
return false;
#endif
}
//----------------------------------------------------------------------------
std::string
cmLocalUnixMakefileGenerator2::GetBaseTargetName(const cmTarget& t)
{
std::string pathPrefix = "";
#ifdef __APPLE__
if ( t.GetPropertyAsBool("MACOSX_BUNDLE") )
{
pathPrefix = t.GetName();
pathPrefix += ".app/Contents/MacOS/";
}
#endif
const char* targetPrefix = t.GetProperty("PREFIX");
const char* prefixVar = t.GetPrefixVariable();
// if there is no prefix on the target use the cmake definition
if(!targetPrefix && prefixVar)
{
// first check for a language specific suffix var
const char* ll = t.GetLinkerLanguage(this->GetGlobalGenerator());
if(ll)
{
std::string langPrefix = prefixVar + std::string("_") + ll;
targetPrefix = m_Makefile->GetDefinition(langPrefix.c_str());
}
// if there not a language specific suffix then use the general one
if(!targetPrefix)
{
targetPrefix = m_Makefile->GetSafeDefinition(prefixVar);
}
}
std::string name = pathPrefix + (targetPrefix?targetPrefix:"");
name += t.GetName();
return name;
}
//----------------------------------------------------------------------------
void cmLocalUnixMakefileGenerator2::GetLibraryNames(const cmTarget& t,
std::string& name,
std::string& soName,
std::string& realName,
std::string& baseName)
{
// Check for library version properties.
const char* version = t.GetProperty("VERSION");
const char* soversion = t.GetProperty("SOVERSION");
if((t.GetType() != cmTarget::SHARED_LIBRARY &&
t.GetType() != cmTarget::MODULE_LIBRARY) ||
!m_Makefile->GetDefinition("CMAKE_SHARED_LIBRARY_SONAME_C_FLAG"))
{
// Versioning is supported only for shared libraries and modules,
// and then only when the platform supports an soname flag.
version = 0;
soversion = 0;
}
if(version && !soversion)
{
// The soversion must be set if the library version is set. Use
// the library version as the soversion.
soversion = version;
}
// The library name.
name = this->GetFullTargetName(t.GetName(), t);
// The library's soname.
soName = name;
if(soversion)
{
soName += ".";
soName += soversion;
}
// The library's real name on disk.
realName = name;
if(version)
{
realName += ".";
realName += version;
}
else if(soversion)
{
realName += ".";
realName += soversion;
}
// The library name without extension.
baseName = this->GetBaseTargetName(t);
}
//----------------------------------------------------------------------------
std::string
cmLocalUnixMakefileGenerator2
::ConvertToMakeTarget(const char* tgt)
{
// Make targets should not have a leading './' for a file in the
// directory containing the makefile.
std::string ret = tgt;
if(ret.size() > 2 &&
(ret[0] == '.') &&
( (ret[1] == '/') || ret[1] == '\\'))
{
std::string upath = ret;
cmSystemTools::ConvertToUnixSlashes(upath);
if(upath.find(2, '/') == upath.npos)
{
ret = ret.substr(2, ret.size()-2);
}
}
return ret;
}
//----------------------------------------------------------------------------
std::string&
cmLocalUnixMakefileGenerator2::CreateSafeUniqueObjectFileName(const char* sin)
{
if ( m_Makefile->IsOn("CMAKE_MANGLE_OBJECT_FILE_NAMES") )
{
std::map<cmStdString,cmStdString>::iterator it = m_UniqueObjectNamesMap.find(sin);
if ( it == m_UniqueObjectNamesMap.end() )
{
std::string ssin = sin;
bool done;
int cc = 0;
char rpstr[100];
sprintf(rpstr, "_p_");
cmSystemTools::ReplaceString(ssin, "+", rpstr);
std::string sssin = sin;
do
{
done = true;
for ( it = m_UniqueObjectNamesMap.begin();
it != m_UniqueObjectNamesMap.end();
++ it )
{
if ( it->second == ssin )
{
done = false;
}
}
if ( done )
{
break;
}
sssin = ssin;
cmSystemTools::ReplaceString(ssin, "_p_", rpstr);
sprintf(rpstr, "_p%d_", cc++);
}
while ( !done );
m_UniqueObjectNamesMap[sin] = ssin;
}
}
else
{
m_UniqueObjectNamesMap[sin] = sin;
}
return m_UniqueObjectNamesMap[sin];
}
//----------------------------------------------------------------------------
std::string
cmLocalUnixMakefileGenerator2
::CreateMakeVariable(const char* sin, const char* s2in)
{
std::string s = sin;
std::string s2 = s2in;
std::string unmodified = s;
unmodified += s2;
// if there is no restriction on the length of make variables
// and there are no "." charactors in the string, then return the
// unmodified combination.
if(!m_MakefileVariableSize && unmodified.find('.') == s.npos)
{
return unmodified;
}
// see if the variable has been defined before and return
// the modified version of the variable
std::map<cmStdString, cmStdString>::iterator i = m_MakeVariableMap.find(unmodified);
if(i != m_MakeVariableMap.end())
{
return i->second;
}
// start with the unmodified variable
std::string ret = unmodified;
// if this there is no value for m_MakefileVariableSize then
// the string must have bad characters in it
if(!m_MakefileVariableSize)
{
cmSystemTools::ReplaceString(ret, ".", "_");
int ni = 0;
char buffer[5];
// make sure the _ version is not already used, if
// it is used then add number to the end of the variable
while(m_ShortMakeVariableMap.count(ret) && ni < 1000)
{
++ni;
sprintf(buffer, "%04d", ni);
ret = unmodified + buffer;
}
m_ShortMakeVariableMap[ret] = "1";
m_MakeVariableMap[unmodified] = ret;
return ret;
}
// if the string is greater the 32 chars it is an invalid vairable name
// for borland make
if(static_cast<int>(ret.size()) > m_MakefileVariableSize)
{
int keep = m_MakefileVariableSize - 8;
int size = keep + 3;
std::string str1 = s;
std::string str2 = s2;
// we must shorten the combined string by 4 charactors
// keep no more than 24 charactors from the second string
if(static_cast<int>(str2.size()) > keep)
{
str2 = str2.substr(0, keep);
}
if(static_cast<int>(str1.size()) + static_cast<int>(str2.size()) > size)
{
str1 = str1.substr(0, size - str2.size());
}
char buffer[5];
int ni = 0;
sprintf(buffer, "%04d", ni);
ret = str1 + str2 + buffer;
while(m_ShortMakeVariableMap.count(ret) && ni < 1000)
{
++ni;
sprintf(buffer, "%04d", ni);
ret = str1 + str2 + buffer;
}
if(ni == 1000)
{
cmSystemTools::Error("Borland makefile variable length too long");
return unmodified;
}
// once an unused variable is found
m_ShortMakeVariableMap[ret] = "1";
}
// always make an entry into the unmodified to variable map
m_MakeVariableMap[unmodified] = ret;
return ret;
}
//============================================================================
//----------------------------------------------------------------------------
std::string
cmLocalUnixMakefileGenerator2

View File

@ -17,7 +17,7 @@
#ifndef cmLocalUnixMakefileGenerator2_h
#define cmLocalUnixMakefileGenerator2_h
#include "cmLocalUnixMakefileGenerator.h"
#include "cmLocalGenerator.h"
class cmCustomCommand;
class cmDependInformation;
@ -32,7 +32,7 @@ class cmSourceFile;
* cmLocalUnixMakefileGenerator2 produces a LocalUnix makefile from its
* member m_Makefile.
*/
class cmLocalUnixMakefileGenerator2 : public cmLocalUnixMakefileGenerator
class cmLocalUnixMakefileGenerator2 : public cmLocalGenerator
{
public:
///! Set cache only and recurse to false by default.
@ -45,6 +45,42 @@ public:
implementations. */
void SetEmptyCommand(const char* cmd);
/**
* Set to true if the shell being used is the windows shell.
* This controls if statements in the makefile and the SHELL variable.
* The default is false.
*/
void SetWindowsShell(bool v) {m_WindowsShell = v;}
/**
* Set the string used to include one makefile into another default
* is include.
*/
void SetIncludeDirective(const char* s) { m_IncludeDirective = s; }
/**
* Set the flag used to keep the make program silent.
*/
void SetMakeSilentFlag(const char* s) { m_MakeSilentFlag = s; }
/**
* Set max makefile variable size, default is 0 which means unlimited.
*/
void SetMakefileVariableSize(int s) { m_MakefileVariableSize = s; }
/**
* If ignore lib prefix is true, then do not strip lib from the name
* of a library.
*/
void SetIgnoreLibPrefix(bool s) { m_IgnoreLibPrefix = s; }
/**
* If true, then explicitly pass MAKEFLAGS on the make all target for makes
* that do not use environment variables.
*
*/
void SetPassMakeflags(bool s){m_PassMakeflags = s;}
/**
* Generate the makefile for this directory. fromTheTop indicates if this
* is being invoked as part of a global Generate or specific to this
@ -165,7 +201,8 @@ protected:
std::string ConvertToFullPath(const std::string& localPath);
std::string ConvertToRelativePath(const char* p);
std::string ConvertToRelativeOutputPath(const char* p);
virtual void ConfigureOutputPaths();
void ConfigureOutputPaths();
void FormatOutputPath(std::string& path, const char* name);
bool ComparePath(const char* c1, const char* c2);
void AppendTargetDepends(std::vector<std::string>& depends,
@ -181,6 +218,19 @@ protected:
const cmCustomCommand& cc);
void AppendCleanCommand(std::vector<std::string>& commands,
const std::vector<std::string>& files);
//==========================================================================
void OutputEcho(std::ostream& fout, const char* msg);
bool SamePath(const char* path1, const char* path2);
std::string GetBaseTargetName(const cmTarget& t);
void GetLibraryNames(const cmTarget& t,
std::string& name, std::string& soName,
std::string& realName, std::string& baseName);
std::string ConvertToMakeTarget(const char* tgt);
std::string& CreateSafeUniqueObjectFileName(const char* sin);
std::string CreateMakeVariable(const char* sin, const char* s2in);
//==========================================================================
std::string GetRecursiveMakeCall(const char* tgt);
void WriteJumpAndBuildRules(std::ostream& makefileStream);
@ -207,6 +257,19 @@ private:
// Command used when a rule has no dependencies or commands.
std::vector<std::string> m_EmptyCommands;
//==========================================================================
// Configuration settings.
int m_MakefileVariableSize;
std::map<cmStdString, cmStdString> m_MakeVariableMap;
std::map<cmStdString, cmStdString> m_ShortMakeVariableMap;
std::map<cmStdString, cmStdString> m_UniqueObjectNamesMap;
std::string m_IncludeDirective;
std::string m_MakeSilentFlag;
std::string m_ExecutableOutputPath;
std::string m_LibraryOutputPath;
bool m_PassMakeflags;
//==========================================================================
// List of make rule files that need to be included by the makefile.
std::vector<std::string> m_IncludeRuleFiles;