Files
CMake/Source/cmLocalUnixMakefileGenerator.cxx
Brad King 4df215a268 Removing automatic addition of a -I path for the current source directory.
This is not consistent with the Visual Studio generators which do not
provide this path.  It should not be added anyway because it is adding
an include path not requested by the CMakeLists.txt code.  The code I'm
removing was originally added in revision 1.17 of cmUnixMakefileGenerator.cxx
as a part of several other changes and has a commit log entry of

  "some bug fixes"

It was propagated from their to cmLocalUnixMakefileGenerator.cxx.
Since all our projects build in the VS IDE without this include path, it should not be needed.  Users can easily fix problems caused by this by adding

  INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR})

to their CMakeLists.txt code.  This was often necessary previously when a
project was originally written on a Unix system and then built with
Visual Studio.
2004-06-15 11:52:58 -04:00

3300 lines
108 KiB
C++

/*=========================================================================
Program: CMake - Cross-Platform Makefile Generator
Module: $RCSfile$
Language: C++
Date: $Date$
Version: $Revision$
Copyright (c) 2002 Kitware, Inc., Insight Consortium. All rights reserved.
See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.
This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE. See the above copyright notices for more information.
=========================================================================*/
#include "cmGlobalGenerator.h"
#include "cmLocalUnixMakefileGenerator.h"
#include "cmMakefile.h"
#include "cmSystemTools.h"
#include "cmSourceFile.h"
#include "cmMakeDepend.h"
#include "cmCacheManager.h"
#include "cmGeneratedFileStream.h"
#include <cmsys/RegularExpression.hxx>
cmLocalUnixMakefileGenerator::cmLocalUnixMakefileGenerator()
{
m_WindowsShell = false;
m_IncludeDirective = "include";
m_MakefileVariableSize = 0;
m_IgnoreLibPrefix = false;
m_PassMakeflags = false;
m_UseRelativePaths = false;
}
cmLocalUnixMakefileGenerator::~cmLocalUnixMakefileGenerator()
{
}
void cmLocalUnixMakefileGenerator::Generate(bool fromTheTop)
{
m_UseRelativePaths = m_Makefile->IsOn("CMAKE_USE_RELATIVE_PATHS");
// suppoirt override in output directories
if (m_Makefile->GetDefinition("LIBRARY_OUTPUT_PATH"))
{
m_LibraryOutputPath = m_Makefile->GetDefinition("LIBRARY_OUTPUT_PATH");
if(m_LibraryOutputPath.size())
{
if(m_LibraryOutputPath[m_LibraryOutputPath.size() -1] != '/')
{
m_LibraryOutputPath += "/";
}
if(!cmSystemTools::MakeDirectory(m_LibraryOutputPath.c_str()))
{
cmSystemTools::Error("Error failed create "
"LIBRARY_OUTPUT_PATH directory:",
m_LibraryOutputPath.c_str());
}
m_Makefile->AddLinkDirectory(m_LibraryOutputPath.c_str());
}
}
if (m_Makefile->GetDefinition("EXECUTABLE_OUTPUT_PATH"))
{
m_ExecutableOutputPath =
m_Makefile->GetDefinition("EXECUTABLE_OUTPUT_PATH");
if(m_ExecutableOutputPath.size())
{
if(m_ExecutableOutputPath[m_ExecutableOutputPath.size() -1] != '/')
{
m_ExecutableOutputPath += "/";
}
if(!cmSystemTools::MakeDirectory(m_ExecutableOutputPath.c_str()))
{
cmSystemTools::Error("Error failed to create "
"EXECUTABLE_OUTPUT_PATH directory:",
m_ExecutableOutputPath.c_str());
}
m_Makefile->AddLinkDirectory(m_ExecutableOutputPath.c_str());
}
}
if (!fromTheTop)
{
// Generate depends
cmMakeDepend md;
md.SetMakefile(m_Makefile);
md.GenerateMakefileDependencies();
this->ProcessDepends(md);
}
// output the makefile fragment
std::string dest = m_Makefile->GetStartOutputDirectory();
dest += "/Makefile";
this->OutputMakefile(dest.c_str(), !fromTheTop);
}
void
cmLocalUnixMakefileGenerator::AddDependenciesToSourceFile(cmDependInformation const *info,
cmSourceFile *i,
std::set<cmDependInformation const*> *visited)
{
// add info to the visited set
visited->insert(info);
// add this dependency and the recurse
// now recurse with info's dependencies
for(cmDependInformation::DependencySet::const_iterator d =
info->m_DependencySet.begin();
d != info->m_DependencySet.end(); ++d)
{
if (visited->find(*d) == visited->end())
{
if((*d)->m_FullPath != "")
{
i->GetDepends().push_back((*d)->m_FullPath.c_str());
}
this->AddDependenciesToSourceFile(*d,i,visited);
}
}
}
void cmLocalUnixMakefileGenerator::ProcessDepends(const cmMakeDepend &md)
{
// Now create cmDependInformation objects for files in the directory
cmTargets &tgts = m_Makefile->GetTargets();
for(cmTargets::iterator l = tgts.begin(); l != tgts.end(); l++)
{
std::vector<cmSourceFile*> &classes = l->second.GetSourceFiles();
for(std::vector<cmSourceFile*>::iterator i = classes.begin();
i != classes.end(); ++i)
{
if(!(*i)->GetPropertyAsBool("HEADER_FILE_ONLY"))
{
// get the depends
const cmDependInformation *info =
md.GetDependInformationForSourceFile(*(*i));
// Delete any hints from the source file's dependencies.
(*i)->GetDepends().erase((*i)->GetDepends().begin(), (*i)->GetDepends().end());
// Now add the real dependencies for the file.
if (info)
{
// create visited set
std::set<cmDependInformation const*> visited;
this->AddDependenciesToSourceFile(info,*i, &visited);
}
}
}
}
}
// This is where CMakeTargets.make is generated
void cmLocalUnixMakefileGenerator::OutputMakefile(const char* file,
bool withDepends)
{
// Create sub directories fro aux source directories
std::vector<std::string>& auxSourceDirs =
m_Makefile->GetAuxSourceDirectories();
if( auxSourceDirs.size() )
{
// For the case when this is running as a remote build
// on unix, make the directory
for(std::vector<std::string>::iterator i = auxSourceDirs.begin();
i != auxSourceDirs.end(); ++i)
{
if(i->c_str()[0] != '/')
{
std::string dir = m_Makefile->GetCurrentOutputDirectory();
if(dir.size() && dir[dir.size()-1] != '/')
{
dir += "/";
}
dir += *i;
cmSystemTools::MakeDirectory(dir.c_str());
}
else
{
cmSystemTools::MakeDirectory(i->c_str());
}
}
}
// Create a stream that writes to a temporary file
// then does a copy at the end. This is to allow users
// to hit control-c during the make of the makefile
cmGeneratedFileStream tempFile(file);
tempFile.SetAlwaysCopy(true);
std::ostream& fout = tempFile.GetStream();
if(!fout)
{
cmSystemTools::Error("Error can not open for write: ", file);
return;
}
fout << "# CMAKE generated Makefile, DO NOT EDIT!\n"
<< "# Generated by \"" << m_GlobalGenerator->GetName() << "\""
<< " Generator, CMake Version "
<< cmMakefile::GetMajorVersion() << "."
<< cmMakefile::GetMinorVersion() << "\n"
<< "# Generated from the following files:\n# "
<< m_Makefile->GetHomeOutputDirectory() << "/CMakeCache.txt\n";
std::vector<std::string> lfiles = m_Makefile->GetListFiles();
// sort the array
std::sort(lfiles.begin(), lfiles.end(), std::less<std::string>());
// remove duplicates
std::vector<std::string>::iterator new_end =
std::unique(lfiles.begin(), lfiles.end());
lfiles.erase(new_end, lfiles.end());
for(std::vector<std::string>::const_iterator i = lfiles.begin();
i != lfiles.end(); ++i)
{
fout << "# " << i->c_str() << "\n";
}
fout << "\n\n";
fout << "# disable some common implicit rules to speed things up\n";
fout << ".SUFFIXES:\n";
fout << ".SUFFIXES:.hpuxmakemusthaverule\n";
// create a make variable with all of the sources for this Makefile
// for depend purposes.
fout << "CMAKE_MAKEFILE_SOURCES = ";
for(std::vector<std::string>::const_iterator i = lfiles.begin();
i != lfiles.end(); ++i)
{
fout << " " << this->ConvertToRelativeOutputPath(i->c_str());
}
// Add the cache to the list
std::string cacheFile = m_Makefile->GetHomeOutputDirectory();
cacheFile += "/CMakeCache.txt";
fout << " " << this->ConvertToRelativeOutputPath(cacheFile.c_str());
fout << "\n\n\n";
this->OutputMakeVariables(fout);
std::string checkCache = m_Makefile->GetHomeOutputDirectory();
checkCache += "/cmake.check_cache";
checkCache = this->ConvertToRelativeOutputPath(checkCache.c_str());
// most unix makes will pass the command line flags to make down
// to sub invoked makes via an environment variable. However, some
// makes do not support that, so you have to pass the flags explicitly
const char* allRule = "$(MAKE) $(MAKESILENT) all";
if(m_PassMakeflags)
{
allRule = "$(MAKE) $(MAKESILENT) -$(MAKEFLAGS) all";
}
// Set up the default target as the VERY first target, so that make with no arguments will run it
this->
OutputMakeRule(fout,
"Default target executed when no arguments are given to make, first make sure cmake.depends exists, cmake.check_depends is up-to-date, check the sources, then build the all target",
"default_target",
checkCache.c_str(),
"$(MAKE) $(MAKESILENT) cmake.depends",
"$(MAKE) $(MAKESILENT) cmake.check_depends",
"$(MAKE) $(MAKESILENT) -f cmake.check_depends",
allRule);
// Generation of SILENT target must be after default_target.
if(!m_Makefile->IsOn("CMAKE_VERBOSE_MAKEFILE"))
{
fout << "# Suppresses display of executed commands\n";
fout << "$(VERBOSE).SILENT:\n\n";
}
this->OutputTargetRules(fout);
this->OutputDependLibs(fout);
this->OutputTargets(fout);
this->OutputSubDirectoryRules(fout);
std::string dependName = m_Makefile->GetStartOutputDirectory();
dependName += "/cmake.depends";
if(withDepends)
{
std::ofstream dependout(dependName.c_str());
if(!dependout)
{
cmSystemTools::Error("Error can not open for write: ", dependName.c_str());
return;
}
dependout << "# .o dependencies in this directory." << std::endl;
std::string checkDepend = m_Makefile->GetStartOutputDirectory();
checkDepend += "/cmake.check_depends";
std::ofstream checkdependout(checkDepend.c_str());
if(!checkdependout)
{
cmSystemTools::Error("Error can not open for write: ", checkDepend.c_str());
return;
}
checkdependout << "# This file is used as a tag file, that all sources depend on. If a source changes, then the rule to rebuild this file will cause cmake.depends to be rebuilt." << std::endl;
// if there were any depends output, then output the check depends
// information inot checkdependout
if(this->OutputObjectDepends(dependout))
{
this->OutputCheckDepends(checkdependout);
}
else
{
checkdependout << "all:\n\t@echo cmake.depends is up-to-date\n";
}
}
this->OutputCustomRules(fout);
this->OutputMakeRules(fout);
// only add the depend include if the depend file exists
if(cmSystemTools::FileExists(dependName.c_str()))
{
fout << m_IncludeDirective << " cmake.depends\n";
}
}
std::string cmLocalUnixMakefileGenerator::GetOutputExtension(const char* s)
{
if(m_Makefile->IsOn("WIN32") && !(m_Makefile->IsOn("CYGWIN") || m_Makefile->IsOn("MINGW")))
{
std::string sourceExtension = s;
if(sourceExtension == "def")
{
return "";
}
if(sourceExtension == "ico" || sourceExtension == "rc2")
{
return "";
}
if(sourceExtension == "rc")
{
return ".res";
}
return ".obj";
}
else
{
return ".o";
}
}
std::string cmLocalUnixMakefileGenerator::GetBaseTargetName(const char* n,
const cmTarget& t)
{
const char* targetPrefix = t.GetProperty("PREFIX");
const char* prefixVar = 0;
switch(t.GetType())
{
case cmTarget::STATIC_LIBRARY:
prefixVar = "CMAKE_STATIC_LIBRARY_PREFIX";
break;
case cmTarget::SHARED_LIBRARY:
prefixVar = "CMAKE_SHARED_LIBRARY_PREFIX";
break;
case cmTarget::MODULE_LIBRARY:
prefixVar = "CMAKE_SHARED_MODULE_PREFIX";
break;
case cmTarget::EXECUTABLE:
case cmTarget::UTILITY:
case cmTarget::INSTALL_FILES:
case cmTarget::INSTALL_PROGRAMS:
break;
}
// if there is no prefix on the target use the cmake definition
if(!targetPrefix && prefixVar)
{
targetPrefix = m_Makefile->GetSafeDefinition(prefixVar);
}
std::string name = targetPrefix?targetPrefix:"";
name += n;
return name;
}
std::string cmLocalUnixMakefileGenerator::GetFullTargetName(const char* n,
const cmTarget& t)
{
const char* targetSuffix = t.GetProperty("SUFFIX");
const char* suffixVar = 0;
switch(t.GetType())
{
case cmTarget::STATIC_LIBRARY:
suffixVar = "CMAKE_STATIC_LIBRARY_SUFFIX";
break;
case cmTarget::SHARED_LIBRARY:
suffixVar = "CMAKE_SHARED_LIBRARY_SUFFIX";
break;
case cmTarget::MODULE_LIBRARY:
suffixVar = "CMAKE_SHARED_MODULE_SUFFIX";
break;
case cmTarget::EXECUTABLE:
targetSuffix = cmSystemTools::GetExecutableExtension();
case cmTarget::UTILITY:
case cmTarget::INSTALL_FILES:
case cmTarget::INSTALL_PROGRAMS:
break;
}
// if there is no suffix on the target use the cmake definition
if(!targetSuffix && suffixVar)
{
targetSuffix = m_Makefile->GetSafeDefinition(suffixVar);
}
std::string name = this->GetBaseTargetName(n, t);
name += targetSuffix?targetSuffix:"";
return name;
}
// Output the rules for any targets
void cmLocalUnixMakefileGenerator::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";
}
}
// Output the rules for any targets
void cmLocalUnixMakefileGenerator::OutputTargetRules(std::ostream& fout)
{
const cmTargets &tgts = m_Makefile->GetTargets();
// add the help target
fout << "help:\n";
this->OutputEcho(fout,"The following are some of the valid targets for this Makefile:");
this->OutputEcho(fout,"... all (the default if no target is provided)");
this->OutputEcho(fout,"... clean");
this->OutputEcho(fout,"... depend");
this->OutputEcho(fout,"... install");
this->OutputEcho(fout,"... rebuild_cache");
// libraries
std::string path;
for(cmTargets::const_iterator l = tgts.begin();
l != tgts.end(); l++)
{
if((l->second.GetType() == cmTarget::STATIC_LIBRARY) ||
(l->second.GetType() == cmTarget::SHARED_LIBRARY) ||
(l->second.GetType() == cmTarget::MODULE_LIBRARY))
{
std::string path2 = m_LibraryOutputPath;
path2 += this->GetFullTargetName(l->first.c_str(), l->second);
path = "... ";
path += this->ConvertToRelativeOutputPath(path2.c_str());
this->OutputEcho(fout,path.c_str());
}
}
// executables
for(cmTargets::const_iterator l = tgts.begin();
l != tgts.end(); l++)
{
if ( l->second.GetType() == cmTarget::EXECUTABLE )
{
path = "... ";
path += l->first + cmSystemTools::GetExecutableExtension();
this->OutputEcho(fout,path.c_str());
}
}
// list utilities last
for(cmTargets::const_iterator l = tgts.begin();
l != tgts.end(); l++)
{
if (l->second.GetType() == cmTarget::UTILITY)
{
path = "... ";
path += l->first;
this->OutputEcho(fout,path.c_str());
}
}
fout << "\n\n";
// for each target add to the list of targets
fout << "TARGETS = ";
// list libraries first
for(cmTargets::const_iterator l = tgts.begin();
l != tgts.end(); l++)
{
if (l->second.IsInAll())
{
if((l->second.GetType() == cmTarget::STATIC_LIBRARY) ||
(l->second.GetType() == cmTarget::SHARED_LIBRARY) ||
(l->second.GetType() == cmTarget::MODULE_LIBRARY))
{
path = m_LibraryOutputPath;
path += this->GetFullTargetName(l->first.c_str(), l->second);
fout << " \\\n"
<< this->ConvertToMakeTarget(this->ConvertToRelativeOutputPath(path.c_str()).c_str());
}
}
}
// executables
for(cmTargets::const_iterator l = tgts.begin();
l != tgts.end(); l++)
{
if (l->second.GetType() == cmTarget::EXECUTABLE &&
l->second.IsInAll())
{
path = m_ExecutableOutputPath;
path += this->GetFullTargetName(l->first.c_str(), l->second);
fout << " \\\n" << this->ConvertToMakeTarget(this->ConvertToRelativeOutputPath(path.c_str()).c_str());
}
}
// list utilities last
for(cmTargets::const_iterator l = tgts.begin();
l != tgts.end(); l++)
{
if (l->second.GetType() == cmTarget::UTILITY &&
l->second.IsInAll())
{
fout << " \\\n" << l->first.c_str();
}
}
fout << "\n\n";
// get the classes from the source lists then add them to the groups
for(cmTargets::const_iterator l = tgts.begin();
l != tgts.end(); l++)
{
std::vector<cmSourceFile*> classes = l->second.GetSourceFiles();
if (classes.begin() != classes.end())
{
fout << this->CreateMakeVariable(l->first.c_str(), "_SRC_OBJS") << " = ";
for(std::vector<cmSourceFile*>::iterator i = classes.begin();
i != classes.end(); i++)
{
if(!(*i)->GetPropertyAsBool("HEADER_FILE_ONLY") &&
!(*i)->GetCustomCommand())
{
std::string outExt(
this->GetOutputExtension((*i)->GetSourceExtension().c_str()));
if(outExt.size() && !(*i)->GetPropertyAsBool("EXTERNAL_OBJECT") )
{
fout << "\\\n";
std::string ofname = (*i)->GetSourceName() + outExt;
ofname = this->CreateSafeUniqueObjectFileName(ofname.c_str());
fout << this->ConvertToMakeTarget(this->ConvertToRelativeOutputPath(ofname.c_str()).c_str());
}
}
}
fout << "\n\n";
fout << this->CreateMakeVariable(l->first.c_str(), "_EXTERNAL_OBJS") << " = ";
for(std::vector<cmSourceFile*>::iterator i = classes.begin();
i != classes.end(); i++)
{
if(!(*i)->GetPropertyAsBool("HEADER_FILE_ONLY") &&
!(*i)->GetCustomCommand())
{
std::string outExt(
this->GetOutputExtension((*i)->GetSourceExtension().c_str()));
if(outExt.size() && (*i)->GetPropertyAsBool("EXTERNAL_OBJECT") )
{
fout << "\\\n";
fout << this->ConvertToMakeTarget(this->ConvertToRelativeOutputPath((*i)->GetFullPath().c_str()).c_str()) << " ";
}
}
}
fout << "\n\n";
fout << this->CreateMakeVariable(l->first.c_str(), "_SRC_OBJS_QUOTED") << " = ";
for(std::vector<cmSourceFile*>::iterator i = classes.begin();
i != classes.end(); i++)
{
if(!(*i)->GetPropertyAsBool("HEADER_FILE_ONLY") &&
!(*i)->GetCustomCommand())
{
std::string outExt(this->GetOutputExtension((*i)->GetSourceExtension().c_str()));
if(outExt.size() && !(*i)->GetPropertyAsBool("EXTERNAL_OBJECT") )
{
std::string ofname = (*i)->GetSourceName() + outExt;
ofname = this->CreateSafeUniqueObjectFileName(ofname.c_str());
fout << "\\\n\"" << this->ConvertToMakeTarget(ConvertToRelativeOutputPath(ofname.c_str()).c_str()) << "\" ";
}
}
}
fout << "\n\n";
fout << this->CreateMakeVariable(l->first.c_str(), "_EXTERNAL_OBJS_QUOTED") << " = ";
for(std::vector<cmSourceFile*>::iterator i = classes.begin();
i != classes.end(); i++)
{
if(!(*i)->GetPropertyAsBool("HEADER_FILE_ONLY") &&
!(*i)->GetCustomCommand())
{
std::string outExt(this->GetOutputExtension((*i)->GetSourceExtension().c_str()));
if(outExt.size() && (*i)->GetPropertyAsBool("EXTERNAL_OBJECT") )
{
fout << "\\\n\"" << this->ConvertToMakeTarget(ConvertToRelativeOutputPath((*i)->GetFullPath().c_str()).c_str()) << "\" ";
}
}
}
fout << "\n\n";
}
}
// This list contains extra files created for a target. It includes
// the extra names associated with a versioned shared library.
fout << "TARGET_EXTRAS = ";
for(cmTargets::const_iterator l = tgts.begin();
l != tgts.end(); l++)
{
if (l->second.IsInAll())
{
if(l->second.GetType() == cmTarget::SHARED_LIBRARY ||
l->second.GetType() == cmTarget::MODULE_LIBRARY)
{
std::string targetName;
std::string targetNameSO;
std::string targetNameReal;
std::string targetNameBase;
this->GetLibraryNames(l->first.c_str(), l->second,
targetName, targetNameSO,
targetNameReal, targetNameBase);
if(targetNameSO != targetName)
{
path = m_LibraryOutputPath;
path += targetNameSO;
fout << " \\\n"
<< this->ConvertToRelativeOutputPath(path.c_str());
}
if(targetNameReal != targetName &&
targetNameReal != targetNameSO)
{
path = m_LibraryOutputPath;
path += targetNameReal;
fout << " \\\n"
<< this->ConvertToRelativeOutputPath(path.c_str());
}
}
}
}
fout << "\n\n";
fout << "CLEAN_OBJECT_FILES = ";
for(cmTargets::const_iterator l = tgts.begin();
l != tgts.end(); l++)
{
std::vector<cmSourceFile*> classes = l->second.GetSourceFiles();
if (classes.begin() != classes.end())
{
fout << "$(" << this->CreateMakeVariable(l->first.c_str(), "_SRC_OBJS")
<< ") ";
}
}
fout << "\n\n";
const char * additional_clean_files =
m_Makefile->GetProperty("ADDITIONAL_MAKE_CLEAN_FILES");
if ( additional_clean_files && strlen(additional_clean_files) > 0 )
{
std::string arg = additional_clean_files;
std::vector<std::string> args;
cmSystemTools::ExpandListArgument(arg, args);
fout << "ADDITIONAL_MAKE_CLEAN_FILES = ";
for(std::vector<std::string>::iterator i = args.begin(); i != args.end(); ++i)
{
fout << this->ConvertToRelativeOutputPath(i->c_str()) << " ";
}
fout << "\n\n";
}
const char * qt_files = m_Makefile->GetDefinition("GENERATED_QT_FILES");
if (qt_files != NULL &&
strlen(m_Makefile->GetDefinition("GENERATED_QT_FILES"))>0)
{
fout << "GENERATED_QT_FILES = ";
fout << qt_files;
fout << "\n\n";
}
}
/**
* Output the linking rules on a command line. For executables,
* targetLibrary should be a NULL pointer. For libraries, it should point
* to the name of the library. This will not link a library against itself.
*/
void cmLocalUnixMakefileGenerator::OutputLinkLibraries(std::ostream& fout,
const char* targetLibrary,
const cmTarget &tgt)
{
// Try to emit each search path once
std::set<std::string> emitted;
// Embed runtime search paths if possible and if required.
bool outputRuntime = true;
std::string runtimeFlag;
std::string runtimeSep;
std::vector<std::string> runtimeDirs;
std::string buildType = m_Makefile->GetSafeDefinition("CMAKE_BUILD_TYPE");
buildType = cmSystemTools::UpperCase(buildType);
bool cxx = tgt.HasCxx();
if(!cxx )
{
// if linking a c executable use the C runtime flag as cc
// may not be the same program that creates shared libaries
// and may have different flags
runtimeFlag = m_Makefile->GetSafeDefinition("CMAKE_SHARED_LIBRARY_RUNTIME_FLAG");
runtimeSep = m_Makefile->GetSafeDefinition("CMAKE_SHARED_LIBRARY_RUNTIME_FLAG_SEP");
}
else
{
runtimeFlag = m_Makefile->GetSafeDefinition("CMAKE_SHARED_LIBRARY_RUNTIME_CXX_FLAG");
runtimeSep = m_Makefile->GetSafeDefinition("CMAKE_SHARED_LIBRARY_RUNTIME_CXX_FLAG_SEP");
}
// concatenate all paths or no?
bool runtimeConcatenate = ( runtimeSep!="" );
if(runtimeFlag == "" || m_Makefile->IsOn("CMAKE_SKIP_RPATH") )
{
outputRuntime = false;
}
// Some search paths should never be emitted
emitted.insert("");
emitted.insert("/usr/lib");
std::string libPathFlag = m_Makefile->GetDefinition("CMAKE_LIBRARY_PATH_FLAG");
std::string libLinkFlag = m_Makefile->GetSafeDefinition("CMAKE_LINK_LIBRARY_FLAG");
// collect all the flags needed for linking libraries
std::string linkLibs;
// Flags to link an executable to shared libraries.
if( tgt.GetType() == cmTarget::EXECUTABLE )
{
if(cxx)
{
linkLibs = m_Makefile->GetSafeDefinition("CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS");
}
else
{
linkLibs = m_Makefile->GetSafeDefinition("CMAKE_SHARED_LIBRARY_LINK_FLAGS");
}
linkLibs += " ";
}
const std::vector<std::string>& libdirs = tgt.GetLinkDirectories();
for(std::vector<std::string>::const_iterator libDir = libdirs.begin();
libDir != libdirs.end(); ++libDir)
{
std::string libpath = this->ConvertToOutputForExisting(libDir->c_str());
if(emitted.insert(libpath).second)
{
std::string fullLibPath;
if(!m_WindowsShell && m_UseRelativePaths)
{
fullLibPath = "\"`cd ";
}
fullLibPath += libpath;
if(!m_WindowsShell && m_UseRelativePaths)
{
fullLibPath += ";pwd`\"";
}
std::string::size_type pos = libDir->find(libPathFlag.c_str());
if((pos == std::string::npos || pos > 0)
&& libDir->find("${") == std::string::npos)
{
linkLibs += libPathFlag;
if(outputRuntime)
{
runtimeDirs.push_back( fullLibPath );
}
}
linkLibs += fullLibPath;
linkLibs += " ";
}
}
std::string linkSuffix = m_Makefile->GetSafeDefinition("CMAKE_LINK_LIBRARY_SUFFIX");
std::string regexp = ".*\\";
regexp += linkSuffix;
regexp += "$";
cmsys::RegularExpression hasSuffix(regexp.c_str());
std::string librariesLinked;
const cmTarget::LinkLibraries& libs = tgt.GetLinkLibraries();
for(cmTarget::LinkLibraries::const_iterator lib = libs.begin();
lib != libs.end(); ++lib)
{
// Don't link the library against itself!
if(targetLibrary && (lib->first == targetLibrary)) continue;
// use the correct lib for the current configuration
if (lib->second == cmTarget::DEBUG && buildType != "DEBUG")
{
continue;
}
if (lib->second == cmTarget::OPTIMIZED && buildType == "DEBUG")
{
continue;
}
// skip zero size library entries, this may happen
// if a variable expands to nothing.
if (lib->first.size() == 0) continue;
// if it is a full path break it into -L and -l
cmsys::RegularExpression reg("^([ \t]*\\-[lWRB])|([ \t]*\\-framework)|(\\${)|([ \t]*\\-pthread)|([ \t]*`)");
if(lib->first.find('/') != std::string::npos
&& !reg.find(lib->first))
{
std::string dir, file;
cmSystemTools::SplitProgramPath(lib->first.c_str(),
dir, file);
std::string libpath = this->ConvertToOutputForExisting(dir.c_str());
if(emitted.insert(libpath).second)
{
linkLibs += libPathFlag;
linkLibs += libpath;
linkLibs += " ";
if(outputRuntime)
{
runtimeDirs.push_back( libpath );
}
}
cmsys::RegularExpression libname("^lib([^/]*)(\\.so|\\.lib|\\.dll|\\.sl|\\.a|\\.dylib).*");
cmsys::RegularExpression libname_noprefix("([^/]*)(\\.so|\\.lib|\\.dll|\\.sl|\\.a|\\.dylib).*");
if(libname.find(file))
{
// Library had "lib" prefix.
librariesLinked += libLinkFlag;
file = libname.match(1);
// if ignore libprefix is on,
// then add the lib prefix back into the name
if(m_IgnoreLibPrefix)
{
std::cout << "m_IgnoreLibPrefix\n";
file = "lib" + file;
}
librariesLinked += file;
if(linkSuffix.size() && !hasSuffix.find(file))
{
librariesLinked += linkSuffix;
}
librariesLinked += " ";
}
else if(libname_noprefix.find(file))
{
// Library had no "lib" prefix.
librariesLinked += libLinkFlag;
file = libname_noprefix.match(1);
librariesLinked += file;
if(linkSuffix.size() && !hasSuffix.find(file))
{
librariesLinked += linkSuffix;
}
librariesLinked += " ";
}
else
{
// Error parsing the library name. Just use the full path.
// The linker will give an error if it is invalid.
librariesLinked += lib->first;
librariesLinked += " ";
}
}
// not a full path, so add -l name
else
{
if(!reg.find(lib->first))
{
librariesLinked += libLinkFlag;
}
librariesLinked += lib->first;
if(linkSuffix.size() && !hasSuffix.find(lib->first))
{
librariesLinked += linkSuffix;
}
librariesLinked += " ";
}
}
linkLibs += librariesLinked;
fout << linkLibs;
if(outputRuntime && runtimeDirs.size()>0)
{
// For the runtime search directories, do a "-Wl,-rpath,a:b:c" or
// a "-R a -R b -R c" type link line
fout << runtimeFlag;
std::vector<std::string>::iterator itr = runtimeDirs.begin();
fout << *itr;
++itr;
for( ; itr != runtimeDirs.end(); ++itr )
{
if(runtimeConcatenate)
{
fout << runtimeSep << *itr;
}
else
{
fout << " " << runtimeFlag << *itr;
}
}
fout << " ";
}
if(m_Makefile->GetDefinition("CMAKE_STANDARD_LIBRARIES"))
{
fout << m_Makefile->GetDefinition("CMAKE_STANDARD_LIBRARIES") << " ";
}
}
std::string cmLocalUnixMakefileGenerator::CreatePreBuildRules(
const cmTarget &target, const char* /* targetName */)
{
std::string customRuleCode = "";
bool initNext = false;
for (std::vector<cmCustomCommand>::const_iterator cr =
target.GetPreBuildCommands().begin();
cr != target.GetPreBuildCommands().end(); ++cr)
{
cmCustomCommand cc(*cr);
cc.ExpandVariables(*m_Makefile);
if(initNext)
{
customRuleCode += "\n\t";
}
else
{
initNext = true;
}
std::string command = this->ConvertToRelativeOutputPath(cc.GetCommand().c_str());
customRuleCode += command + " " + cc.GetArguments();
}
return customRuleCode;
}
std::string cmLocalUnixMakefileGenerator::CreatePreLinkRules(
const cmTarget &target, const char* /* targetName */)
{
std::string customRuleCode = "";
bool initNext = false;
for (std::vector<cmCustomCommand>::const_iterator cr =
target.GetPreLinkCommands().begin();
cr != target.GetPreLinkCommands().end(); ++cr)
{
cmCustomCommand cc(*cr);
cc.ExpandVariables(*m_Makefile);
if(initNext)
{
customRuleCode += "\n\t";
}
else
{
initNext = true;
}
std::string command = this->ConvertToRelativeOutputPath(cc.GetCommand().c_str());
customRuleCode += command + " " + cc.GetArguments();
}
return customRuleCode;
}
std::string cmLocalUnixMakefileGenerator::CreatePostBuildRules(
const cmTarget &target, const char* /* targetName */)
{
std::string customRuleCode = "";
bool initNext = false;
for (std::vector<cmCustomCommand>::const_iterator cr =
target.GetPostBuildCommands().begin();
cr != target.GetPostBuildCommands().end(); ++cr)
{
cmCustomCommand cc(*cr);
cc.ExpandVariables(*m_Makefile);
if(initNext)
{
customRuleCode += "\n\t";
}
else
{
initNext = true;
}
std::string command = this->ConvertToRelativeOutputPath(cc.GetCommand().c_str());
customRuleCode += command + " " + cc.GetArguments();
}
return customRuleCode;
}
struct RuleVariables
{
const char* replace;
const char* lookup;
};
static RuleVariables ruleReplaceVars[] =
{
{"<CMAKE_SHARED_LIBRARY_CREATE_CXX_FLAGS>", "CMAKE_SHARED_LIBRARY_CREATE_CXX_FLAGS"},
{"<CMAKE_SHARED_MODULE_CREATE_CXX_FLAGS>", "CMAKE_SHARED_MODULE_CREATE_CXX_FLAGS"},
{"<CMAKE_SHARED_MODULE_C_FLAGS>", "CMAKE_SHARED_MODULE_C_FLAGS"},
{"<CMAKE_SHARED_MODULE_CXX_FLAGS>", "CMAKE_SHARED_MODULE_CXX_FLAGS"},
{"<CMAKE_SHARED_LIBRARY_C_FLAGS>", "CMAKE_SHARED_LIBRARY_C_FLAGS"},
{"<CMAKE_SHARED_LIBRARY_CXX_FLAGS>", "CMAKE_SHARED_LIBRARY_CXX_FLAGS"},
{"<CMAKE_CXX_LINK_FLAGS>", "CMAKE_CXX_LINK_FLAGS"},
{"<CMAKE_SHARED_LIBRARY_CREATE_C_FLAGS>", "CMAKE_SHARED_LIBRARY_CREATE_C_FLAGS"},
{"<CMAKE_SHARED_MODULE_CREATE_C_FLAGS>", "CMAKE_SHARED_MODULE_CREATE_C_FLAGS"},
{"<CMAKE_SHARED_LIBRARY_SONAME_C_FLAG>", "CMAKE_SHARED_LIBRARY_SONAME_C_FLAG"},
{"<CMAKE_SHARED_LIBRARY_SONAME_CXX_FLAG>", "CMAKE_SHARED_LIBRARY_SONAME_CXX_FLAG"},
{"<CMAKE_C_LINK_FLAGS>", "CMAKE_C_LINK_FLAGS"},
{"<CMAKE_AR>", "CMAKE_AR"},
{"<CMAKE_RANLIB>", "CMAKE_RANLIB"},
{0, 0}
};
void
cmLocalUnixMakefileGenerator::ExpandRuleVariables(std::string& s,
const char* objects,
const char* target,
const char* linkLibs,
const char* source,
const char* object,
const char* flags,
const char* objectsquoted,
const char* targetBase,
const char* targetSOName,
const char* linkFlags)
{
std::string cxxcompiler = this->ConvertToOutputForExisting(
m_Makefile->GetSafeDefinition("CMAKE_CXX_COMPILER"));
std::string ccompiler = this->ConvertToOutputForExisting(
m_Makefile->GetSafeDefinition("CMAKE_C_COMPILER"));
cmSystemTools::ReplaceString(s, "<CMAKE_CXX_COMPILER>", cxxcompiler.c_str());
cmSystemTools::ReplaceString(s, "<CMAKE_C_COMPILER>", ccompiler.c_str());
if(linkFlags)
{
cmSystemTools::ReplaceString(s, "<LINK_FLAGS>", linkFlags);
}
if(flags)
{
cmSystemTools::ReplaceString(s, "<FLAGS>", flags);
}
if(source)
{
cmSystemTools::ReplaceString(s, "<SOURCE>", source);
}
if(object)
{
cmSystemTools::ReplaceString(s, "<OBJECT>", object);
}
if(objects)
{
cmSystemTools::ReplaceString(s, "<OBJECTS>", objects);
}
if(objectsquoted)
{
cmSystemTools::ReplaceString(s, "<OBJECTS_QUOTED>", objectsquoted);
}
if(target)
{
std::string targetQuoted = target;
if(targetQuoted.size() && targetQuoted[0] != '\"')
{
targetQuoted = '\"';
targetQuoted += target;
targetQuoted += '\"';
}
cmSystemTools::ReplaceString(s, "<TARGET_QUOTED>", targetQuoted.c_str());
cmSystemTools::ReplaceString(s, "<TARGET>", target);
}
if(targetBase)
{
// special case for quoted paths with spaces
// if you see <TARGET_BASE>.lib then put the .lib inside
// the quotes, same for .dll
if((strlen(targetBase) > 1) && targetBase[0] == '\"')
{
std::string base = targetBase;
base[base.size()-1] = '.';
std::string baseLib = base + "lib\"";
std::string baseDll = base + "dll\"";
cmSystemTools::ReplaceString(s, "<TARGET_BASE>.lib", baseLib.c_str());
cmSystemTools::ReplaceString(s, "<TARGET_BASE>.dll", baseDll.c_str());
}
cmSystemTools::ReplaceString(s, "<TARGET_BASE>", targetBase);
}
if(targetSOName)
{
if(m_Makefile->GetDefinition("CMAKE_SHARED_LIBRARY_SONAME_C_FLAG"))
{
cmSystemTools::ReplaceString(s, "<TARGET_SONAME>", targetSOName);
}
else
{
cmSystemTools::ReplaceString(s, "<TARGET_SONAME>", "");
}
}
if(linkLibs)
{
cmSystemTools::ReplaceString(s, "<LINK_LIBRARIES>", linkLibs);
}
RuleVariables* rv = ruleReplaceVars;
while(rv->replace)
{
cmSystemTools::ReplaceString(s, rv->replace,
m_Makefile->GetSafeDefinition(rv->lookup));
rv++;
}
}
void cmLocalUnixMakefileGenerator::OutputLibraryRule(std::ostream& fout,
const char* name,
const cmTarget &t,
const char* createVariable,
const char* comment,
const char* linkFlags
)
{
std::string targetName;
std::string targetNameSO;
std::string targetNameReal;
std::string targetNameBase;
this->GetLibraryNames(name, t,
targetName, targetNameSO,
targetNameReal, targetNameBase);
std::string outpath;
std::string outdir;
if(m_UseRelativePaths)
{
outdir = this->ConvertToRelativeOutputPath(m_LibraryOutputPath.c_str());
}
else
{
outdir = m_LibraryOutputPath;
}
if(!m_WindowsShell && m_UseRelativePaths && outdir.size())
{
outpath = "\"`cd ";
}
outpath += outdir;
if(!m_WindowsShell && m_UseRelativePaths && outdir.size())
{
outpath += ";pwd`\"/";
}
if(outdir.size() == 0 && m_UseRelativePaths && !m_WindowsShell)
{
outpath = "\"`pwd`\"/";
}
// The full path versions of the names.
std::string targetFullPath = outpath + targetName;
std::string targetFullPathSO = outpath + targetNameSO;
std::string targetFullPathReal = outpath + targetNameReal;
std::string targetFullPathBase = outpath + targetNameBase;
// If not using relative paths then the output path needs to be
// converted here
if(!m_UseRelativePaths)
{
targetFullPath = this->ConvertToRelativeOutputPath(targetFullPath.c_str());
targetFullPathSO = this->ConvertToRelativeOutputPath(targetFullPathSO.c_str());
targetFullPathReal = this->ConvertToRelativeOutputPath(targetFullPathReal.c_str());
targetFullPathBase = this->ConvertToRelativeOutputPath(targetFullPathBase.c_str());
}
// get the objects that are used to link this library
std::string objs = "$(" + this->CreateMakeVariable(name, "_SRC_OBJS") + ") $(" + this->CreateMakeVariable(name, "_EXTERNAL_OBJS") + ") ";
std::string objsQuoted = "$(" + this->CreateMakeVariable(name, "_SRC_OBJS_QUOTED") + ") $(" + this->CreateMakeVariable(name, "_EXTERNAL_OBJS_QUOTED") + ") ";
// create a variable with the objects that this library depends on
std::string depend =
objs + " $(" + this->CreateMakeVariable(name, "_DEPEND_LIBS") + ")";
std::vector<std::string> commands;
std::string cmakecommand = this->ConvertToOutputForExisting(
m_Makefile->GetDefinition("CMAKE_COMMAND"));
// Remove any existing files for this library.
std::string remove = cmakecommand;
remove += " -E remove -f ";
remove += targetFullPathReal;
if(targetFullPathSO != targetFullPathReal)
{
remove += " ";
remove += targetFullPathSO;
}
if(targetFullPath != targetFullPathSO &&
targetFullPath != targetFullPathReal)
{
remove += " ";
remove += targetFullPath;
}
commands.push_back(remove);
// collect custom commands for this target and add them to the list
std::string customCommands = this->CreatePreBuildRules(t, name);
if(customCommands.size() > 0)
{
commands.push_back(customCommands);
}
// collect custom commands for this target and add them to the list
customCommands = this->CreatePreLinkRules(t, name);
if(customCommands.size() > 0)
{
commands.push_back(customCommands);
}
// collect up the build rules
std::vector<std::string> rules;
rules.push_back(m_Makefile->GetDefinition(createVariable));
// expand multi-command semi-colon separated lists
// of commands into separate commands
cmSystemTools::ExpandList(rules, commands);
// Create necessary symlinks for library.
if(targetFullPath != targetFullPathReal)
{
std::string symlink = cmakecommand;
symlink += " -E cmake_symlink_library ";
symlink += targetFullPathReal;
symlink += " ";
symlink += targetFullPathSO;
symlink += " ";
symlink += targetFullPath;
commands.push_back(symlink);
}
// collect custom commands for this target and add them to the list
customCommands = this->CreatePostBuildRules(t, name);
if(customCommands.size() > 0)
{
commands.push_back(customCommands);
}
// collect up the link libraries
cmOStringStream linklibs;
this->OutputLinkLibraries(linklibs, name, t);
for(std::vector<std::string>::iterator i = commands.begin();
i != commands.end(); ++i)
{
this->ExpandRuleVariables(*i,
objs.c_str(),
targetFullPathReal.c_str(),
linklibs.str().c_str(),
0, 0, 0, objsQuoted.c_str(),
targetFullPathBase.c_str(),
targetNameSO.c_str(),
linkFlags);
}
targetFullPath = m_LibraryOutputPath + targetName;
this->OutputMakeRule(fout, comment,
targetFullPath.c_str(),
depend.c_str(),
commands);
depend = targetFullPath;
std::string tgt = this->ConvertToRelativeOutputPath(targetFullPath.c_str());
tgt = this->ConvertToMakeTarget(tgt.c_str());
cmSystemTools::ConvertToUnixSlashes(tgt);
if(tgt.find('/', 0) != tgt.npos)
{
// we need a local target
depend = this->ConvertToRelativeOutputPath(depend.c_str());
std::string target = targetName;
commands.resize(0);
this->OutputMakeRule(fout,
comment,
target.c_str(),
depend.c_str(),
commands);
}
}
void cmLocalUnixMakefileGenerator::OutputSharedLibraryRule(std::ostream& fout,
const char* name,
const cmTarget &t)
{
const char* createRule;
if(t.HasCxx())
{
createRule = "CMAKE_CXX_CREATE_SHARED_LIBRARY";
}
else
{
createRule = "CMAKE_C_CREATE_SHARED_LIBRARY";
}
std::string buildType = m_Makefile->GetSafeDefinition("CMAKE_BUILD_TYPE");
buildType = cmSystemTools::UpperCase(buildType);
std::string linkFlags = m_Makefile->GetSafeDefinition("CMAKE_SHARED_LINKER_FLAGS");
linkFlags += " ";
if(buildType.size())
{
std::string build = "CMAKE_SHARED_LINKER_FLAGS_";
build += buildType;
linkFlags += m_Makefile->GetSafeDefinition(build.c_str());
linkFlags += " ";
}
if(m_Makefile->IsOn("WIN32") && !(m_Makefile->IsOn("CYGWIN") || m_Makefile->IsOn("MINGW")))
{
const std::vector<cmSourceFile*>& sources = t.GetSourceFiles();
for(std::vector<cmSourceFile*>::const_iterator i = sources.begin();
i != sources.end(); ++i)
{
if((*i)->GetSourceExtension() == "def")
{
linkFlags += m_Makefile->GetSafeDefinition("CMAKE_LINK_DEF_FILE_FLAG");
linkFlags += this->ConvertToRelativeOutputPath((*i)->GetFullPath().c_str());
linkFlags += " ";
}
}
}
const char* targetLinkFlags = t.GetProperty("LINK_FLAGS");
if(targetLinkFlags)
{
linkFlags += targetLinkFlags;
linkFlags += " ";
}
this->OutputLibraryRule(fout, name, t,
createRule,
"shared library",
linkFlags.c_str());
}
void cmLocalUnixMakefileGenerator::OutputModuleLibraryRule(std::ostream& fout,
const char* name,
const cmTarget &t)
{
const char* createRule;
if(t.HasCxx())
{
createRule = "CMAKE_CXX_CREATE_SHARED_MODULE";
}
else
{
createRule = "CMAKE_C_CREATE_SHARED_MODULE";
}
std::string buildType = m_Makefile->GetSafeDefinition("CMAKE_BUILD_TYPE");
buildType = cmSystemTools::UpperCase(buildType);
std::string linkFlags = m_Makefile->GetSafeDefinition("CMAKE_MODULE_LINKER_FLAGS");
linkFlags += " ";
if(buildType.size())
{
std::string build = "CMAKE_MODULE_LINKER_FLAGS_";
build += buildType;
linkFlags += m_Makefile->GetSafeDefinition(build.c_str());
linkFlags += " ";
}
const char* targetLinkFlags = t.GetProperty("LINK_FLAGS");
if(targetLinkFlags)
{
linkFlags += targetLinkFlags;
linkFlags += " ";
}
this->OutputLibraryRule(fout, name, t,
createRule,
"shared module",
linkFlags.c_str());
}
void cmLocalUnixMakefileGenerator::OutputStaticLibraryRule(std::ostream& fout,
const char* name,
const cmTarget &t)
{
const char* createRule;
if(t.HasCxx())
{
createRule = "CMAKE_CXX_CREATE_STATIC_LIBRARY";
}
else
{
createRule = "CMAKE_C_CREATE_STATIC_LIBRARY";
}
std::string linkFlags;
const char* targetLinkFlags = t.GetProperty("STATIC_LIBRARY_FLAGS");
if(targetLinkFlags)
{
linkFlags += targetLinkFlags;
linkFlags += " ";
}
this->OutputLibraryRule(fout, name, t,
createRule,
"static library",
linkFlags.c_str());
}
void cmLocalUnixMakefileGenerator::OutputExecutableRule(std::ostream& fout,
const char* name,
const cmTarget &t)
{
std::string linkFlags;
std::string buildType = m_Makefile->GetSafeDefinition("CMAKE_BUILD_TYPE");
buildType = cmSystemTools::UpperCase(buildType);
std::string flags;
// Construct the full path to the executable that will be generated.
std::string target = m_ExecutableOutputPath;
if(target.length() == 0)
{
target = m_Makefile->GetCurrentOutputDirectory();
if(target.size() && target[target.size()-1] != '/')
{
target += "/";
}
}
#ifdef __APPLE__
if ( t.GetPropertyAsBool("MACOSX_BUNDLE") )
{
// Make bundle directories
target += name;
target += ".app/Contents/MacOS/";
}
#endif
target += name;
target += cmSystemTools::GetExecutableExtension();
target = this->ConvertToRelativeOutputPath(target.c_str());
bool needsLocalTarget = false;
if(m_UseRelativePaths)
{
cmSystemTools::ConvertToUnixSlashes(target);
std::string tgt = this->ConvertToMakeTarget(target.c_str());
if(tgt.find('/', 0) != tgt.npos)
{
needsLocalTarget = true;
}
target = cmSystemTools::ConvertToOutputPath(target.c_str());
}
else
{
needsLocalTarget = true;
}
std::string objs = "$(" + this->CreateMakeVariable(name, "_SRC_OBJS") + ") $(" + this->CreateMakeVariable(name, "_EXTERNAL_OBJS") + ") ";
std::string depend = "$(";
depend += this->CreateMakeVariable(name, "_SRC_OBJS")
+ ") $(" + this->CreateMakeVariable(name, "_EXTERNAL_OBJS")
+ ") $(" + this->CreateMakeVariable(name, "_DEPEND_LIBS") + ")";
std::vector<std::string> rules;
linkFlags += m_Makefile->GetSafeDefinition("CMAKE_EXE_LINKER_FLAGS");
linkFlags += " ";
if(buildType.size())
{
std::string build = "CMAKE_EXE_LINKER_FLAGS_";
build += buildType;
linkFlags += m_Makefile->GetSafeDefinition(build.c_str());
linkFlags += " ";
}
if(t.HasCxx())
{
rules.push_back(m_Makefile->GetDefinition("CMAKE_CXX_LINK_EXECUTABLE"));
flags += m_Makefile->GetSafeDefinition("CMAKE_CXX_FLAGS");
flags += " ";
flags += m_Makefile->GetSafeDefinition("CMAKE_SHARED_LIBRARY_CXX_FLAGS");
flags += " ";
}
else
{
rules.push_back(m_Makefile->GetDefinition("CMAKE_C_LINK_EXECUTABLE"));
flags += m_Makefile->GetSafeDefinition("CMAKE_C_FLAGS");
flags += " ";
flags += m_Makefile->GetSafeDefinition("CMAKE_SHARED_LIBRARY_C_FLAGS");
flags += " ";
}
cmOStringStream linklibs;
this->OutputLinkLibraries(linklibs, 0, t);
std::string comment = "executable";
std::vector<std::string> commands;
std::string customCommands = this->CreatePreBuildRules(t, name);
if(customCommands.size() > 0)
{
commands.push_back(customCommands.c_str());
}
customCommands = this->CreatePreLinkRules(t, name);
if(customCommands.size() > 0)
{
commands.push_back(customCommands.c_str());
}
cmSystemTools::ExpandList(rules, commands);
customCommands = this->CreatePostBuildRules(t, name);
if(customCommands.size() > 0)
{
commands.push_back(customCommands.c_str());
}
if(cmSystemTools::IsOn(m_Makefile->GetDefinition("BUILD_SHARED_LIBS")))
{
linkFlags += m_Makefile->GetSafeDefinition("CMAKE_SHARED_BUILD_CXX_FLAGS");
linkFlags += " ";
}
if ( t.GetPropertyAsBool("WIN32_EXECUTABLE") )
{
linkFlags += m_Makefile->GetSafeDefinition("CMAKE_CREATE_WIN32_EXE");
linkFlags += " ";
}
else
{
linkFlags += m_Makefile->GetSafeDefinition("CMAKE_CREATE_CONSOLE_EXE");
linkFlags += " ";
}
const char* targetLinkFlags = t.GetProperty("LINK_FLAGS");
if(targetLinkFlags)
{
linkFlags += targetLinkFlags;
linkFlags += " ";
}
for(std::vector<std::string>::iterator i = commands.begin();
i != commands.end(); ++i)
{
this->ExpandRuleVariables(*i,
objs.c_str(),
target.c_str(),
linklibs.str().c_str(),
0,
0,
flags.c_str(),
0,
0,
0,
linkFlags.c_str());
}
this->OutputMakeRule(fout,
comment.c_str(),
target.c_str(),
depend.c_str(),
commands);
// If there is no executable output path, add a rule with the
// relative path to the executable. This is necessary for
// try-compile to work in this case.
if(needsLocalTarget)
{
depend = target;
target = name;
target += cmSystemTools::GetExecutableExtension();
target = this->ConvertToRelativeOutputPath(target.c_str());
commands.resize(0);
this->OutputMakeRule(fout,
comment.c_str(),
target.c_str(),
depend.c_str(),
commands);
}
}
void cmLocalUnixMakefileGenerator::OutputUtilityRule(std::ostream& fout,
const char* name,
const cmTarget &t)
{
const char* cc = 0;
std::string customCommands = this->CreatePreBuildRules(t, name);
std::string customCommands2 = this->CreatePreLinkRules(t, name);
if(customCommands2.size() > 0)
{
customCommands += customCommands2;
}
customCommands2 = this->CreatePostBuildRules(t, name);
if(customCommands2.size() > 0)
{
customCommands += customCommands2;
}
if(customCommands.size() > 0)
{
cc = customCommands.c_str();
}
std::string comment = "Utility";
std::string depends;
depends = "$(" + this->CreateMakeVariable(name, "_DEPEND_LIBS") + ")";
std::string replaceVars;
const std::vector<cmCustomCommand> &ccs = t.GetPostBuildCommands();
for(std::vector<cmCustomCommand>::const_iterator i = ccs.begin();
i != ccs.end(); ++i)
{
const std::vector<std::string> & dep = i->GetDepends();
for(std::vector<std::string>::const_iterator d = dep.begin();
d != dep.end(); ++d)
{
depends += " \\\n";
replaceVars = *d;
m_Makefile->ExpandVariablesInString(replaceVars);
depends += this->ConvertToMakeTarget(this->ConvertToRelativeOutputPath(replaceVars.c_str()).c_str());
}
}
this->OutputMakeRule(fout, comment.c_str(), name,
depends.c_str(), cc);
}
void cmLocalUnixMakefileGenerator::OutputTargets(std::ostream& fout)
{
// for each target
const cmTargets &tgts = m_Makefile->GetTargets();
for(cmTargets::const_iterator l = tgts.begin();
l != tgts.end(); l++)
{
switch(l->second.GetType())
{
case cmTarget::STATIC_LIBRARY:
this->OutputStaticLibraryRule(fout, l->first.c_str(), l->second);
break;
case cmTarget::SHARED_LIBRARY:
this->OutputSharedLibraryRule(fout, l->first.c_str(), l->second);
break;
case cmTarget::MODULE_LIBRARY:
this->OutputModuleLibraryRule(fout, l->first.c_str(), l->second);
break;
case cmTarget::EXECUTABLE:
this->OutputExecutableRule(fout, l->first.c_str(), l->second);
break;
case cmTarget::UTILITY:
this->OutputUtilityRule(fout, l->first.c_str(), l->second);
break;
// This is handled by the OutputCustomRules method
case cmTarget::INSTALL_FILES:
// This is handled by the OutputInstallRules method
case cmTarget::INSTALL_PROGRAMS:
// This is handled by the OutputInstallRules method
break;
}
}
}
// For each target that is an executable or shared library, generate
// the "<name>_DEPEND_LIBS" variable listing its library dependencies.
void cmLocalUnixMakefileGenerator::OutputDependLibs(std::ostream& fout)
{
// Build a set of libraries that will be linked into any target in
// this directory.
std::set<std::string> used;
// for each target
const cmTargets &tgts = m_Makefile->GetTargets();
for(cmTargets::const_iterator l = tgts.begin();
l != tgts.end(); l++)
{
// Each dependency should only be emitted once per target.
std::set<std::string> emitted;
if ((l->second.GetType() == cmTarget::SHARED_LIBRARY)
|| (l->second.GetType() == cmTarget::MODULE_LIBRARY)
|| (l->second.GetType() == cmTarget::STATIC_LIBRARY)
|| (l->second.GetType() == cmTarget::EXECUTABLE)
|| (l->second.GetType() == cmTarget::UTILITY))
{
fout << this->CreateMakeVariable(l->first.c_str(), "_DEPEND_LIBS") << " = ";
// A library should not depend on itself!
emitted.insert(l->first);
// for static libraries do not depend on other libraries
if(l->second.GetType() != cmTarget::STATIC_LIBRARY)
{
// Now, look at all link libraries specific to this target.
const cmTarget::LinkLibraries& tlibs = l->second.GetLinkLibraries();
for(cmTarget::LinkLibraries::const_iterator lib = tlibs.begin();
lib != tlibs.end(); ++lib)
{
// Record that this library was used.
used.insert(lib->first);
// Don't emit the same library twice for this target.
if(emitted.insert(lib->first).second)
{
// Output this dependency.
this->OutputLibDepend(fout, lib->first.c_str());
}
}
}
// for all targets depend on utilities
// Now, look at all utilities specific to this target.
const std::set<cmStdString>& tutils = l->second.GetUtilities();
for(std::set<cmStdString>::const_iterator util = tutils.begin();
util != tutils.end(); ++util)
{
// Record that this utility was used.
used.insert(*util);
// Don't emit the same utility twice for this target.
if(emitted.insert(*util).second)
{
// Output this dependency.
std::string utilType = *util + "_LIBRARY_TYPE";
const char* libType = m_Makefile->GetDefinition(utilType.c_str());
if ( libType )
{
this->OutputLibDepend(fout, util->c_str());
}
else
{
this->OutputExeDepend(fout, util->c_str());
}
}
}
fout << "\n";
}
}
fout << "\n";
// Loop over the libraries used and make sure there is a rule to
// build them in this makefile. If the library is in another
// directory, add a rule to jump to that directory and make sure it
// exists.
for(std::set<std::string>::const_iterator lib = used.begin();
lib != used.end(); ++lib)
{
// loop over the list of directories that the libraries might
// be in, looking for an ADD_LIBRARY(lib...) line. This would
// be stored in the cache
std::string libPath = *lib + "_CMAKE_PATH";
const char* cacheValue = m_Makefile->GetDefinition(libPath.c_str());
// if cache and not the current directory add a rule, to
// jump into the directory and build for the first time
if(cacheValue && *cacheValue &&
(!this->SamePath(m_Makefile->GetCurrentOutputDirectory(), cacheValue)))
{
// add the correct extension
std::string ltname = *lib+"_LIBRARY_TYPE";
const char* libType
= m_Makefile->GetDefinition(ltname.c_str());
// if it was a library..
if (libType)
{
std::string library;
std::string libpath = cacheValue;
if(libType && std::string(libType) == "SHARED")
{
library = m_Makefile->GetSafeDefinition("CMAKE_SHARED_LIBRARY_PREFIX");
library += *lib;
library += m_Makefile->GetSafeDefinition("CMAKE_SHARED_LIBRARY_SUFFIX");
}
else if(libType && std::string(libType) == "MODULE")
{
library = m_Makefile->GetSafeDefinition("CMAKE_SHARED_MODULE_PREFIX");
library += *lib;
library += m_Makefile->GetSafeDefinition("CMAKE_SHARED_MODULE_SUFFIX");
}
else if(libType && std::string(libType) == "STATIC")
{
library = m_Makefile->GetSafeDefinition("CMAKE_STATIC_LIBRARY_PREFIX");
library += *lib;
library += m_Makefile->GetSafeDefinition("CMAKE_STATIC_LIBRARY_SUFFIX");
}
else
{
cmSystemTools::Error("Unknown library type!");
return;
}
if(m_LibraryOutputPath.size())
{
libpath = m_LibraryOutputPath;
}
else
{
libpath += "/";
}
libpath += library;
// put out a rule to build the library if it does not exist
this->OutputBuildTargetInDir(fout,
cacheValue,
library.c_str(),
libpath.c_str());
}
// something other than a library...
else
{
std::string exepath = cacheValue;
if(m_ExecutableOutputPath.size())
{
exepath = m_ExecutableOutputPath;
}
else
{
exepath += "/";
}
std::string fullName = lib->c_str();
fullName += cmSystemTools::GetExecutableExtension();
exepath += fullName;
this->OutputBuildTargetInDir(fout,
cacheValue,
fullName.c_str(),
exepath.c_str());
}
}
}
}
void cmLocalUnixMakefileGenerator::OutputBuildTargetInDirWindows(std::ostream& fout,
const char* path,
const char* library,
const char* fullpath)
{
std::string jumpBack;
if(m_UseRelativePaths)
{
cmSystemTools::Message("using relative paths??");
jumpBack = cmSystemTools::RelativePath(cmSystemTools::GetProgramPath(path).c_str(),
m_Makefile->GetCurrentOutputDirectory());
}
else
{
jumpBack = m_Makefile->GetCurrentOutputDirectory();
}
jumpBack = this->ConvertToOutputForExisting(jumpBack.c_str());
std::string wpath = this->ConvertToOutputForExisting(path);
std::string wfullpath = this->ConvertToRelativeOutputPath(fullpath);
fout << wfullpath
<< ":\n\tcd " << wpath << "\n"
<< "\t$(MAKE) -$(MAKEFLAGS) $(MAKESILENT) cmake.depends\n"
<< "\t$(MAKE) -$(MAKEFLAGS) $(MAKESILENT) cmake.check_depends\n"
<< "\t$(MAKE) -$(MAKEFLAGS) $(MAKESILENT) -f cmake.check_depends\n"
<< "\t$(MAKE) $(MAKESILENT) " << library
<< "\n\tcd " << jumpBack << "\n";
}
void cmLocalUnixMakefileGenerator::OutputBuildTargetInDir(std::ostream& fout,
const char* path,
const char* library,
const char* fullpath)
{
if(m_WindowsShell)
{
this->OutputBuildTargetInDirWindows(fout, path, library, fullpath);
return;
}
fout << this->ConvertToOutputForExisting(fullpath)
<< ":\n\tcd " << this->ConvertToOutputForExisting(path)
<< "; $(MAKE) $(MAKESILENT) cmake.depends"
<< "; $(MAKE) $(MAKESILENT) cmake.check_depends"
<< "; $(MAKE) $(MAKESILENT) -f cmake.check_depends"
<< "; $(MAKE) $(MAKESILENT) "
<< library << "\n\n";
}
bool cmLocalUnixMakefileGenerator::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
}
void cmLocalUnixMakefileGenerator::OutputLibDepend(std::ostream& fout,
const char* name)
{
std::string libPath = name;
libPath += "_CMAKE_PATH";
const char* cacheValue = m_Makefile->GetDefinition(libPath.c_str());
if( cacheValue && *cacheValue )
{
// if there is a cache value, then this is a library that cmake
// knows how to build, so we can depend on it
std::string libpath;
if (!this->SamePath(m_Makefile->GetCurrentOutputDirectory(), cacheValue))
{
// if the library is not in the current directory, then get the full
// path to it
if(m_LibraryOutputPath.size())
{
libpath = m_LibraryOutputPath;
}
else
{
libpath = cacheValue;
libpath += "/";
}
}
else
{
// library is in current Makefile so use lib as a prefix
libpath = m_LibraryOutputPath;
}
// add the correct extension
std::string ltname = name;
ltname += "_LIBRARY_TYPE";
const char* libType = m_Makefile->GetDefinition(ltname.c_str());
if(libType && std::string(libType) == "SHARED")
{
libpath += m_Makefile->GetSafeDefinition("CMAKE_SHARED_LIBRARY_PREFIX");
libpath += name;
libpath += m_Makefile->GetSafeDefinition("CMAKE_SHARED_LIBRARY_SUFFIX");
}
else if (libType && std::string(libType) == "MODULE")
{
libpath += m_Makefile->GetSafeDefinition("CMAKE_SHARED_MODULE_PREFIX");
libpath += name;
libpath += m_Makefile->GetSafeDefinition("CMAKE_SHARED_MODULE_SUFFIX");
}
else if (libType && std::string(libType) == "STATIC")
{
libpath += m_Makefile->GetSafeDefinition("CMAKE_STATIC_LIBRARY_PREFIX");
libpath += name;
libpath += m_Makefile->GetSafeDefinition("CMAKE_STATIC_LIBRARY_SUFFIX");
}
fout << this->ConvertToRelativeOutputPath(libpath.c_str()) << " ";
}
else
{
if(cmSystemTools::FileExists(name))
{
std::string nameStr = name;
// if it starts with / or \ or ?:/ or ?:\ then it must be a full path
if( (nameStr.size() && (nameStr[0] == '/' || nameStr[0] == '\\')) ||
((nameStr.size() > 3) && (nameStr[1] == ':') && (nameStr[2] == '/' || nameStr[2] == '\\')))
{
fout << this->ConvertToRelativeOutputPath(name) << " ";
}
}
}
}
void cmLocalUnixMakefileGenerator::OutputExeDepend(std::ostream& fout,
const char* name)
{
std::string exePath = name;
exePath += "_CMAKE_PATH";
const char* cacheValue = m_Makefile->GetDefinition(exePath.c_str());
if( cacheValue && *cacheValue )
{
// if there is a cache value, then this is a executable/utility that cmake
// knows how to build, so we can depend on it
std::string exepath;
if (!this->SamePath(m_Makefile->GetCurrentOutputDirectory(), cacheValue))
{
// if the exe/utility is not in the current directory, then get the full
// path to it
if(m_ExecutableOutputPath.size())
{
exepath = m_ExecutableOutputPath;
}
else
{
exepath = cacheValue;
exepath += "/";
}
}
else
{
// library is in current Makefile
exepath = m_ExecutableOutputPath;
}
// add the library name
exepath += name;
// add the correct extension
exepath += cmSystemTools::GetExecutableExtension();
fout << this->ConvertToRelativeOutputPath(exepath.c_str()) << " ";
}
// if it isn't in the cache, it might still be a utility target
// so check for that
else
{
std::map<cmStdString, cmTarget>& targets = m_Makefile->GetTargets();
if (targets.find(name) != targets.end())
{
fout << name << " ";
}
}
}
// fix up names of directories so they can be used
// as targets in makefiles.
inline std::string FixDirectoryName(const char* dir)
{
std::string s = dir;
// replace ../ with 3 under bars
size_t pos = s.find("../");
if(pos != std::string::npos)
{
s.replace(pos, 3, "___");
}
// replace / directory separators with a single under bar
pos = s.find("/");
while(pos != std::string::npos)
{
s.replace(pos, 1, "_");
pos = s.find("/");
}
return s;
}
void cmLocalUnixMakefileGenerator::
BuildInSubDirectoryWindows(std::ostream& fout,
const char* directory,
const char* target1,
const char* target2,
bool silent)
{
std::string dir;
if(target1)
{
dir = this->ConvertToOutputForExisting(directory);
if(dir[0] == '\"')
{
dir = dir.substr(1, dir.size()-2);
}
fout << "\tif not exist \"" << dir << "\\$(NULL)\""
<< " "
<< "$(MAKE) $(MAKESILENT) rebuild_cache\n";
if (!silent)
{
fout << "\t@echo " << directory << ": building " << target1 << "\n";
}
fout << "\tcd " << dir << "\n"
<< "\t$(MAKE) -$(MAKEFLAGS) $(MAKESILENT) " << target1 << "\n";
}
if(target2)
{
if (!silent)
{
fout << "\t@echo " << directory << ": building " << target2 << "\n";
}
fout << "\t$(MAKE) -$(MAKEFLAGS) $(MAKESILENT) " << target2 << "\n";
}
std::string currentDir;
if(m_UseRelativePaths)
{
currentDir = dir;
cmSystemTools::ConvertToUnixSlashes(currentDir);
std::string cdback = "..";
unsigned int i = 0;
if(currentDir.size() > 2 && currentDir[0] == '.' && currentDir[1] == '/')
{
// start past ./ if it starts with ./
i = 2;
}
for(; i < currentDir.size(); ++i)
{
if(currentDir[i] == '/')
{
cdback += "/..";
}
}
fout << "\tcd " << this->ConvertToOutputForExisting(cdback.c_str()) << "\n\n";
}
else
{
currentDir = m_Makefile->GetCurrentOutputDirectory();
fout << "\tcd " << this->ConvertToOutputForExisting(currentDir.c_str()) << "\n\n";
}
}
void cmLocalUnixMakefileGenerator::BuildInSubDirectory(std::ostream& fout,
const char* dir,
const char* target1,
const char* target2,
bool silent)
{
if(m_WindowsShell)
{
this->BuildInSubDirectoryWindows(fout, dir, target1, target2, silent);
return;
}
std::string directory = this->ConvertToRelativeOutputPath(dir);
if(target1)
{
fout << "\t@if test ! -d " << directory
<< "; then $(MAKE) rebuild_cache; fi\n";
if (!silent)
{
fout << "\t@echo " << directory << ": building " << target1 << "\n";
}
fout << "\t@cd " << directory
<< "; $(MAKE) " << target1 << "\n";
}
if(target2)
{
if (!silent)
{
fout << "\t@echo " << directory << ": building " << target2 << "\n";
}
fout << "\t@cd " << directory
<< "; $(MAKE) " << target2 << "\n";
}
fout << "\n";
}
void
cmLocalUnixMakefileGenerator::
OutputSubDirectoryVars(std::ostream& fout,
const char* var,
const char* target,
const char* target1,
const char* target2,
const char* depend,
const std::vector<std::pair<cmStdString, bool> >& SubDirectories,
bool silent, int order)
{
if(!depend)
{
depend = "";
}
if( SubDirectories.size() == 0)
{
return;
}
fout << "# Variable for making " << target << " in subdirectories.\n";
fout << var << " = ";
unsigned int ii;
// make sure all the pre-order subdirectories are fist
// other than that keep the same order that the user specified
std::vector<std::pair<cmStdString, bool> > orderedDirs;
// collect pre-order first
for(ii =0; ii < SubDirectories.size(); ii++)
{
if(m_Makefile->IsDirectoryPreOrder(SubDirectories[ii].first.c_str()))
{
orderedDirs.push_back(SubDirectories[ii]);
}
}
// now collect post order dirs
for(ii =0; ii < SubDirectories.size(); ii++)
{
if(!m_Makefile->IsDirectoryPreOrder(SubDirectories[ii].first.c_str()))
{
orderedDirs.push_back(SubDirectories[ii]);
}
}
for(ii =0; ii < orderedDirs.size(); ii++)
{
if(!orderedDirs[ii].second)
{
continue;
}
if(order == 1 && m_Makefile->IsDirectoryPreOrder(orderedDirs[ii].first.c_str()))
{
continue;
}
if(order == 2 && !m_Makefile->IsDirectoryPreOrder(orderedDirs[ii].first.c_str()))
{
continue;
}
fout << " \\\n";
std::string subdir = FixDirectoryName(orderedDirs[ii].first.c_str());
fout << target << "_" << subdir.c_str();
}
fout << " \n\n";
fout << "# Targets for making " << target << " in subdirectories.\n";
std::string last = "";
for(unsigned int cc =0; cc < orderedDirs.size(); cc++)
{
if(!orderedDirs[cc].second)
{
continue;
}
std::string subdir = FixDirectoryName(orderedDirs[cc].first.c_str());
if(order == 1 && m_Makefile->IsDirectoryPreOrder(orderedDirs[cc].first.c_str()))
{
last = subdir;
continue;
}
if(order == 2 && !m_Makefile->IsDirectoryPreOrder(orderedDirs[cc].first.c_str()))
{
last = subdir;
continue;
}
fout << target << "_" << subdir.c_str() << ": " << depend;
// Make each subdirectory depend on previous one. This forces
// parallel builds (make -j 2) to build in same order as a single
// threaded build to avoid dependency problems.
if(cc > 0)
{
fout << " " << target << "_" << last.c_str();
}
fout << "\n";
last = subdir;
std::string dir = m_Makefile->GetCurrentOutputDirectory();
dir += "/";
dir += orderedDirs[cc].first;
this->BuildInSubDirectory(fout, dir.c_str(),
target1, target2, silent);
}
fout << "\n\n";
}
// output rules for decending into sub directories
void cmLocalUnixMakefileGenerator::OutputSubDirectoryRules(std::ostream& fout)
{
// Output Sub directory build rules
const std::vector<std::pair<cmStdString, bool> >& SubDirectories
= m_Makefile->GetSubDirectories();
if( SubDirectories.size() == 0)
{
return;
}
this->OutputSubDirectoryVars(fout,
"SUBDIR_BUILD",
"default_target",
"default_target",
0, "$(TARGETS)",
SubDirectories,
false, 1);
this->OutputSubDirectoryVars(fout,
"SUBDIR_PREORDER_BUILD",
"default_target",
"default_target",
0, 0,
SubDirectories,
false, 2);
this->OutputSubDirectoryVars(fout, "SUBDIR_CLEAN", "clean",
"clean",
0, 0,
SubDirectories);
this->OutputSubDirectoryVars(fout, "SUBDIR_DEPEND", "depend",
"depend",
0, 0,
SubDirectories);
}
// Output the depend information for all the classes
// in the makefile. These would have been generated
// by the class cmMakeDepend GenerateMakefile
bool cmLocalUnixMakefileGenerator::OutputObjectDepends(std::ostream& fout)
{
bool ret = false;
// Iterate over every target.
std::map<cmStdString, cmTarget>& targets = m_Makefile->GetTargets();
for(std::map<cmStdString, cmTarget>::const_iterator target = targets.begin();
target != targets.end(); ++target)
{
// Iterate over every source for this target.
const std::vector<cmSourceFile*>& sources = target->second.GetSourceFiles();
for(std::vector<cmSourceFile*>::const_iterator source = sources.begin();
source != sources.end(); ++source)
{
if(!(*source)->GetPropertyAsBool("HEADER_FILE_ONLY"))
{
if(!(*source)->GetDepends().empty())
{
// Iterate through all the dependencies for this source.
for(std::vector<std::string>::const_iterator dep =
(*source)->GetDepends().begin();
dep != (*source)->GetDepends().end(); ++dep)
{
std::string s = (*source)->GetSourceName();
s += this->GetOutputExtension((*source)->GetSourceExtension().c_str());
fout << this->ConvertToRelativeOutputPath(s.c_str()) << " : "
<< this->ConvertToRelativeOutputPath(dep->c_str()) << "\n";
ret = true;
}
fout << "\n\n";
}
}
}
}
return ret;
}
// Output the depend information for all the classes
// in the makefile. These would have been generated
// by the class cmMakeDepend GenerateMakefile
void cmLocalUnixMakefileGenerator::OutputCheckDepends(std::ostream& fout)
{
std::set<std::string> emittedLowerPath;
std::set<std::string> emitted;
// Iterate over every target.
std::map<cmStdString, cmTarget>& targets = m_Makefile->GetTargets();
fout << "# Suppresses display of executed commands\n";
fout << ".SILENT:\n";
fout << "# disable some common implicit rules to speed things up\n";
fout << ".SUFFIXES:\n";
fout << ".SUFFIXES:.hpuxmakemusthaverule\n";
this->OutputMakeVariables(fout);
fout << "default:\n";
fout << "\t$(MAKE) $(MAKESILENT) -f cmake.check_depends all\n"
<< "\t$(MAKE) $(MAKESILENT) -f cmake.check_depends cmake.depends\n\n";
for(std::map<cmStdString, cmTarget>::const_iterator target = targets.begin();
target != targets.end(); ++target)
{
// Iterate over every source for this target.
const std::vector<cmSourceFile*>& sources = target->second.GetSourceFiles();
for(std::vector<cmSourceFile*>::const_iterator source = sources.begin();
source != sources.end(); ++source)
{
if(!(*source)->GetPropertyAsBool("HEADER_FILE_ONLY"))
{
if(!(*source)->GetDepends().empty())
{
for(std::vector<std::string>::const_iterator dep =
(*source)->GetDepends().begin();
dep != (*source)->GetDepends().end(); ++dep)
{
// do not call CollapseFullPath on dep here, because it already
// has been done because m_FullPath on cmDependInformation
// always is it called. If it is called here, network builds are
// very slow because of the number of stats
std::string dependfile = this->ConvertToRelativeOutputPath(dep->c_str());
// use the lower path function to create uniqe names
std::string lowerpath = this->LowerCasePath(dependfile.c_str());
if(emittedLowerPath.insert(lowerpath).second)
{
emitted.insert(dependfile);
fout << "all: " << dependfile << "\n";
}
}
}
}
}
}
fout << "\n\n# if any of these files changes run make dependlocal\n";
std::set<std::string>::iterator i;
for(i = emitted.begin(); i != emitted.end(); ++i)
{
fout << "cmake.depends: " << *i << "\n";
}
fout << "cmake.depends: \n"
<< "\t$(MAKE) $(MAKESILENT) dependlocal\n\n";
fout << "\n\n";
fout << "# if a .h file is removed then run make dependlocal\n\n";
for(std::set<std::string>::iterator it = emitted.begin();
it != emitted.end(); ++it)
{
fout << *it << ":\n"
<< "\t$(MAKE) $(MAKESILENT) dependlocal\n\n";
}
}
// Output each custom rule in the following format:
// output: source depends...
// (tab) command...
void cmLocalUnixMakefileGenerator::OutputCustomRules(std::ostream& fout)
{
// we cannot provide multiple rules for a single output
// so we will keep track of outputs to make sure we don't write
// two rules. First found wins
std::set<std::string> processedOutputs;
// first output all custom rules
const std::vector<cmSourceFile*>& sources = m_Makefile->GetSourceFiles();
for(std::vector<cmSourceFile*>::const_iterator i = sources.begin();
i != sources.end(); ++i)
{
if ((*i)->GetCustomCommand())
{
cmCustomCommand *c = (*i)->GetCustomCommand();
// escape spaces and convert to native slashes path for
// the command
std::string comment = c->GetComment();
std::string command = c->GetCommand();
cmSystemTools::ReplaceString(command, "/./", "/");
command = this->ConvertToRelativeOutputPath(command.c_str());
command += " ";
// now add the arguments
command += c->GetArguments();
std::vector<std::string> depends;
// Collect out all the dependencies for this rule.
for(std::vector<std::string>::const_iterator d =
c->GetDepends().begin();
d != c->GetDepends().end(); ++d)
{
std::string dep = *d;
m_Makefile->ExpandVariablesInString(dep);
// watch for target dependencies,
std::string libPath = dep + "_CMAKE_PATH";
const char* cacheValue = m_Makefile->GetDefinition(libPath.c_str());
if ( cacheValue && *cacheValue )
{
libPath = cacheValue;
if (m_Makefile->GetDefinition("EXECUTABLE_OUTPUT_PATH") &&
m_Makefile->GetDefinition("EXECUTABLE_OUTPUT_PATH")[0] != '\0')
{
libPath = m_Makefile->GetDefinition("EXECUTABLE_OUTPUT_PATH");
}
libPath += "/";
libPath += dep;
libPath += cmSystemTools::GetExecutableExtension();
dep = libPath;
}
cmSystemTools::ReplaceString(dep, "/./", "/");
cmSystemTools::ReplaceString(dep, "/$(IntDir)/", "/");
dep = this->ConvertToRelativeOutputPath(dep.c_str());
depends.push_back(dep.c_str());
}
// output rule
if (processedOutputs.find(c->GetOutput()) == processedOutputs.end())
{
this->OutputMakeRule(fout,
(comment.size()?comment.c_str():"Custom command"),
c->GetOutput().c_str(),
depends,
command.c_str());
processedOutputs.insert(c->GetOutput());
}
else
{
cmSystemTools::Error("An output was found with multiple rules on how to build it for output: ",
c->GetOutput().c_str());
}
}
}
}
std::string
cmLocalUnixMakefileGenerator::ConvertToOutputForExisting(const char* p)
{
std::string ret = this->ConvertToRelativeOutputPath(p);
// if there are spaces in the path, then get the short path version
// if there is one
if(ret.find(' ') != std::string::npos)
{
if(cmSystemTools::FileExists(p))
{
if(!cmSystemTools::GetShortPath(ret.c_str(), ret))
{
ret = this->ConvertToRelativeOutputPath(p);
}
}
}
return ret;
}
void cmLocalUnixMakefileGenerator::OutputMakeVariables(std::ostream& fout)
{
const char* variables =
"# the standard shell for make\n"
"SHELL = /bin/sh\n"
"\n";
if(!m_WindowsShell)
{
fout << variables;
}
else
{
fout <<
"!IF \"$(OS)\" == \"Windows_NT\"\n"
"NULL=\n"
"!ELSE \n"
"NULL=nul\n"
"!ENDIF \n";
}
if(m_MakeSilentFlag.size())
{
fout << "MAKESILENT = " << m_MakeSilentFlag << "\n";
}
std::string cmakecommand = this->ConvertToOutputForExisting(
m_Makefile->GetDefinition("CMAKE_COMMAND"));
fout << "CMAKE_COMMAND = "
<< cmakecommand
<< "\n";
fout << "RM = " << cmakecommand.c_str() << " -E remove -f\n";
if(m_Makefile->GetDefinition("CMAKE_EDIT_COMMAND"))
{
fout << "CMAKE_EDIT_COMMAND = "
<< this->ConvertToOutputForExisting(m_Makefile->GetDefinition("CMAKE_EDIT_COMMAND"))
<< "\n";
}
fout << "CMAKE_CURRENT_SOURCE = " <<
this->ConvertToRelativeOutputPath(m_Makefile->GetStartDirectory())
<< "\n";
fout << "CMAKE_CURRENT_BINARY = " <<
this->ConvertToRelativeOutputPath(m_Makefile->GetStartOutputDirectory())
<< "\n";
fout << "CMAKE_SOURCE_DIR = " <<
this->ConvertToRelativeOutputPath(m_Makefile->GetHomeDirectory())
<< "\n";
fout << "CMAKE_BINARY_DIR = " <<
this->ConvertToRelativeOutputPath(m_Makefile->GetHomeOutputDirectory())
<< "\n";
// Output Include paths
fout << "INCLUDE_FLAGS = ";
std::vector<std::string>& includes = m_Makefile->GetIncludeDirectories();
std::vector<std::string>::iterator i;
std::map<cmStdString, cmStdString> implicitIncludes;
implicitIncludes["/usr/include"] = "/usr/include";
if(m_Makefile->GetDefinition("CMAKE_PLATFORM_IMPLICIT_INCLUDE_DIRECTORIES"))
{
std::string arg = m_Makefile->GetDefinition("CMAKE_PLATFORM_IMPLICIT_INCLUDE_DIRECTORIES");
std::vector<std::string> implicitIncludeVec;
cmSystemTools::ExpandListArgument(arg, implicitIncludeVec);
for(unsigned int k =0; k < implicitIncludeVec.size(); k++)
{
implicitIncludes[implicitIncludeVec[k]] = implicitIncludeVec[k];
}
}
for(i = includes.begin(); i != includes.end(); ++i)
{
std::string include = *i;
// Don't output a -I for the standard include path "/usr/include".
// This can cause problems with certain standard library
// implementations because the wrong headers may be found first.
if(implicitIncludes.find(include) == implicitIncludes.end())
{
fout << "-I" << this->ConvertToOutputForExisting(i->c_str()) << " ";
}
}
fout << m_Makefile->GetDefineFlags();
fout << "\n\n";
}
void cmLocalUnixMakefileGenerator::OutputMakeRules(std::ostream& fout)
{
this->OutputMakeRule(fout,
"default build rule",
"all",
"cmake.depends $(SUBDIR_PREORDER_BUILD) $(TARGETS) $(SUBDIR_BUILD)",
0);
this->OutputMakeRule(fout,
"clean generated files",
"clean",
"$(SUBDIR_CLEAN)",
"-@ $(RM) $(CLEAN_OBJECT_FILES) "
" $(TARGETS) $(TARGET_EXTRAS) $(GENERATED_QT_FILES) $(GENERATED_FLTK_FILES) $(ADDITIONAL_MAKE_CLEAN_FILES)");
// collect up all the sources
std::vector<std::string> allsources;
std::map<cmStdString, cmTarget>& targets = m_Makefile->GetTargets();
for(std::map<cmStdString,cmTarget>::const_iterator target = targets.begin();
target != targets.end(); ++target)
{
// Iterate over every source for this target.
const std::vector<cmSourceFile*>& sources = target->second.GetSourceFiles();
for(std::vector<cmSourceFile*>::const_iterator source = sources.begin();
source != sources.end(); ++source)
{
if(!(*source)->GetPropertyAsBool("HEADER_FILE_ONLY"))
{
allsources.push_back(this->ConvertToRelativeOutputPath((*source)->GetFullPath().c_str()));
}
}
}
std::string checkCache = m_Makefile->GetHomeOutputDirectory();
checkCache += "/cmake.check_cache";
checkCache = this->ConvertToRelativeOutputPath(checkCache.c_str());
std::vector<std::string> cmake_depends;
cmake_depends.push_back("$(CMAKE_MAKEFILE_SOURCES)");
this->OutputMakeRule(fout,
"dependencies.",
"cmake.depends",
cmake_depends,
"$(CMAKE_COMMAND) "
"-S$(CMAKE_CURRENT_SOURCE) -O$(CMAKE_CURRENT_BINARY) "
"-H$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR)");
this->OutputMakeRule(fout,
"dependencies",
"cmake.check_depends",
allsources,
"$(CMAKE_COMMAND) "
"-S$(CMAKE_CURRENT_SOURCE) -O$(CMAKE_CURRENT_BINARY) "
"-H$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR)");
this->OutputMakeRule(fout,
"dependencies",
"depend",
"$(SUBDIR_DEPEND)",
"$(CMAKE_COMMAND) "
"-S$(CMAKE_CURRENT_SOURCE) -O$(CMAKE_CURRENT_BINARY) "
"-H$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR)");
this->OutputMakeRule(fout,
"dependencies",
"dependlocal",
0,
"$(CMAKE_COMMAND) "
"-S$(CMAKE_CURRENT_SOURCE) -O$(CMAKE_CURRENT_BINARY) "
"-H$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR)");
this->OutputMakeRule(fout,
"CMakeCache.txt",
"rebuild_cache",
0,
"$(CMAKE_COMMAND) "
"-H$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR)");
std::vector<std::string> check_cache_depends;
std::string CMakeCache = m_Makefile->GetHomeOutputDirectory();
CMakeCache += "/CMakeCache.txt";
CMakeCache = this->ConvertToRelativeOutputPath(CMakeCache.c_str());
check_cache_depends.push_back("$(CMAKE_MAKEFILE_SOURCES)");
this->OutputMakeRule(fout,
"CMakeCache.txt because out-of-date:",
checkCache.c_str(),
check_cache_depends,
"$(CMAKE_COMMAND) "
"-H$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR)");
// if CMAKE_EDIT_COMMAND is defined then add a rule to run it
// called edit_cache
if(m_Makefile->GetDefinition("CMAKE_EDIT_COMMAND"))
{
this->OutputMakeRule(fout,
"edit CMakeCache.txt",
"edit_cache",
0,
"$(CMAKE_EDIT_COMMAND) "
"-H$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR)");
}
else
{
this->OutputMakeRule(fout,
"edit CMakeCache.txt",
"edit_cache",
0,
"$(CMAKE_COMMAND) "
"-H$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) -i");
}
std::string cacheFile = m_Makefile->GetHomeOutputDirectory();
cacheFile += "/CMakeCache.txt";
cacheFile = this->ConvertToRelativeOutputPath(cacheFile.c_str());
this->OutputMakeRule(fout,
"CMakeCache.txt",
cacheFile.c_str(),
0,
"$(CMAKE_COMMAND) "
"-H$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR)");
this->OutputMakeRule(fout,
"Rule to keep make from removing Makefiles "
"if control-C is hit during a run of cmake.",
".PRECIOUS",
"Makefile cmake.depends",
0);
this->OutputSourceObjectBuildRules(fout);
// find ctest
std::string ctest = m_Makefile->GetDefinition("CMAKE_COMMAND");
ctest = cmSystemTools::GetFilenamePath(ctest.c_str());
ctest += "/";
ctest += "ctest";
ctest += cmSystemTools::GetExecutableExtension();
if(!cmSystemTools::FileExists(ctest.c_str()))
{
ctest = m_Makefile->GetDefinition("CMAKE_COMMAND");
ctest = cmSystemTools::GetFilenamePath(ctest.c_str());
ctest += "/Debug/";
ctest += "ctest";
ctest += cmSystemTools::GetExecutableExtension();
}
if(!cmSystemTools::FileExists(ctest.c_str()))
{
ctest = m_Makefile->GetDefinition("CMAKE_COMMAND");
ctest = cmSystemTools::GetFilenamePath(ctest.c_str());
ctest += "/Release/";
ctest += "ctest";
ctest += cmSystemTools::GetExecutableExtension();
}
if (!cmSystemTools::FileExists(ctest.c_str()))
{
if ( !m_Makefile->GetDefinition("PROJECT_NAME") ||
strcmp(m_Makefile->GetDefinition("PROJECT_NAME"), "CMake") )
{
return;
}
ctest = m_Makefile->GetDefinition("EXECUTABLE_OUTPUT_PATH");
ctest += "/ctest";
}
if (m_Makefile->IsOn("CMAKE_TESTING_ENABLED"))
{
fout << "ARGS=\n";
std::string cmd = this->ConvertToOutputForExisting(ctest.c_str());
cmd += " $(ARGS)";
this->OutputMakeRule(fout,
"tests",
"test",
"",
cmd.c_str());
}
if(m_Makefile->GetDefinition("CMake_BINARY_DIR"))
{
// We are building CMake itself. We cannot use the original
// executable to install over itself.
std::string rule = m_Makefile->GetDefinition("EXECUTABLE_OUTPUT_PATH");
rule += "/cmake";
rule = cmSystemTools::ConvertToOutputPath(rule.c_str());
rule += " -P cmake_install.cmake";
this->OutputMakeRule(fout, "installation", "install", "", rule.c_str());
}
else
{
this->OutputMakeRule(fout, "installation", "install", "",
"$(CMAKE_COMMAND) -P cmake_install.cmake");
}
}
void
cmLocalUnixMakefileGenerator::
OutputBuildObjectFromSource(std::ostream& fout,
const char* shortName,
const cmSourceFile& source,
const char* extraCompileFlags,
bool shared)
{
// Header files shouldn't have build rules.
if(source.GetPropertyAsBool("HEADER_FILE_ONLY"))
{
return;
}
std::string comment = "object file";
std::string objectFile = std::string(shortName) +
this->GetOutputExtension(source.GetSourceExtension().c_str());
objectFile = this->CreateSafeUniqueObjectFileName(objectFile.c_str());
objectFile = this->ConvertToRelativeOutputPath(objectFile.c_str());
cmSystemTools::FileFormat format =
cmSystemTools::GetFileFormat(source.GetSourceExtension().c_str());
std::vector<std::string> rules;
std::string flags;
if(extraCompileFlags)
{
flags += extraCompileFlags;
}
std::string sourceFile =
this->ConvertToRelativeOutputPath(source.GetFullPath().c_str());
std::string buildType = m_Makefile->GetSafeDefinition("CMAKE_BUILD_TYPE");
buildType = cmSystemTools::UpperCase(buildType);
switch(format)
{
case cmSystemTools::C_FILE_FORMAT:
{
rules.push_back(m_Makefile->GetDefinition("CMAKE_C_COMPILE_OBJECT"));
flags += m_Makefile->GetSafeDefinition("CMAKE_C_FLAGS");
flags += " ";
if(buildType.size())
{
std::string build = "CMAKE_C_FLAGS_";
build += buildType;
flags += m_Makefile->GetSafeDefinition(build.c_str());
flags += " ";
}
if(shared)
{
flags += m_Makefile->GetSafeDefinition("CMAKE_SHARED_LIBRARY_C_FLAGS");
flags += " ";
}
if(cmSystemTools::IsOn(m_Makefile->GetDefinition("BUILD_SHARED_LIBS")))
{
flags += m_Makefile->GetSafeDefinition("CMAKE_SHARED_BUILD_C_FLAGS");
flags += " ";
}
break;
}
case cmSystemTools::CXX_FILE_FORMAT:
{
rules.push_back(m_Makefile->GetDefinition("CMAKE_CXX_COMPILE_OBJECT"));
flags += m_Makefile->GetSafeDefinition("CMAKE_CXX_FLAGS");
flags += " ";
if(buildType.size())
{
std::string build = "CMAKE_CXX_FLAGS_";
build += buildType;
flags += m_Makefile->GetSafeDefinition(build.c_str());
flags += " ";
}
if(shared)
{
flags += m_Makefile->GetSafeDefinition("CMAKE_SHARED_LIBRARY_CXX_FLAGS");
flags += " ";
}
if(cmSystemTools::IsOn(m_Makefile->GetDefinition("BUILD_SHARED_LIBS")))
{
flags += m_Makefile->GetSafeDefinition("CMAKE_SHARED_BUILD_CXX_FLAGS");
flags += " ";
}
break;
}
case cmSystemTools::HEADER_FILE_FORMAT:
return;
case cmSystemTools::DEFINITION_FILE_FORMAT:
return;
case cmSystemTools::OBJECT_FILE_FORMAT:
return;
case cmSystemTools::RESOURCE_FILE_FORMAT:
{
flags = " $(INCLUDE_FLAGS) ";
// use rc rule here if it is defined
const char* rule = m_Makefile->GetDefinition("CMAKE_COMPILE_RESOURCE");
if(rule)
{
rules.push_back(rule);
}
}
break;
case cmSystemTools::NO_FILE_FORMAT:
case cmSystemTools::JAVA_FILE_FORMAT:
case cmSystemTools::STATIC_LIBRARY_FILE_FORMAT:
case cmSystemTools::SHARED_LIBRARY_FILE_FORMAT:
case cmSystemTools::MODULE_FILE_FORMAT:
case cmSystemTools::UNKNOWN_FILE_FORMAT:
cmSystemTools::Error("Unexpected file type ",
sourceFile.c_str());
break;
}
flags += "$(INCLUDE_FLAGS) ";
// expand multi-command semi-colon separated lists
// of commands into separate commands
std::vector<std::string> commands;
cmSystemTools::ExpandList(rules, commands);
for(std::vector<std::string>::iterator i = commands.begin();
i != commands.end(); ++i)
{
this->ExpandRuleVariables(*i,
0, // no objects
0, // no target
0, // no link libs
sourceFile.c_str(),
objectFile.c_str(),
flags.c_str());
}
std::vector<std::string> sourceAndDeps;
sourceAndDeps.push_back(sourceFile);
// Check for extra object-file dependencies.
std::vector<std::string> depends;
const char* additionalDeps = source.GetProperty("OBJECT_DEPENDS");
if(additionalDeps)
{
cmSystemTools::ExpandListArgument(additionalDeps, depends);
for(std::vector<std::string>::iterator i = depends.begin();
i != depends.end(); ++i)
{
sourceAndDeps.push_back(this->ConvertToRelativeOutputPath(i->c_str()));
}
}
this->OutputMakeRule(fout,
comment.c_str(),
objectFile.c_str(),
sourceAndDeps,
commands);
}
void cmLocalUnixMakefileGenerator::OutputSourceObjectBuildRules(std::ostream& fout)
{
fout << "# Rules to build " << this->GetOutputExtension("")
<< " files from their sources:\n";
std::set<std::string> rules;
// Iterate over every target.
std::map<cmStdString, cmTarget>& targets = m_Makefile->GetTargets();
for(std::map<cmStdString, cmTarget>::const_iterator target = targets.begin();
target != targets.end(); ++target)
{
bool shared = ((target->second.GetType() == cmTarget::SHARED_LIBRARY) ||
(target->second.GetType() == cmTarget::MODULE_LIBRARY));
std::string exportsDef = "";
if(shared)
{
std::string export_symbol;
if (const char* custom_export_name = target->second.GetProperty("DEFINE_SYMBOL"))
{
export_symbol = custom_export_name;
}
else
{
std::string in = target->first + "_EXPORTS";
export_symbol = cmSystemTools::MakeCindentifier(in.c_str());
}
exportsDef = "-D"+ export_symbol;
}
// Iterate over every source for this target.
const std::vector<cmSourceFile*>& sources =
target->second.GetSourceFiles();
for(std::vector<cmSourceFile*>::const_iterator source = sources.begin();
source != sources.end(); ++source)
{
if(!(*source)->GetPropertyAsBool("HEADER_FILE_ONLY") &&
!(*source)->GetCustomCommand())
{
std::string shortName;
std::string sourceName;
// If the full path to the source file includes this
// directory, we want to use the relative path for the
// filename of the object file. Otherwise, we will use just
// the filename portion.
if((cmSystemTools::GetFilenamePath(
(*source)->GetFullPath()).find(
m_Makefile->GetCurrentDirectory()) == 0)
|| (cmSystemTools::GetFilenamePath(
(*source)->GetFullPath()).find(
m_Makefile->GetCurrentOutputDirectory()) == 0))
{
sourceName = (*source)->GetSourceName()+"."+
(*source)->GetSourceExtension();
shortName = (*source)->GetSourceName();
// The path may be relative. See if a directory needs to be
// created for the output file. This is a ugly, and perhaps
// should be moved elsewhere.
std::string relPath =
cmSystemTools::GetFilenamePath((*source)->GetSourceName());
if(relPath != "")
{
std::string outPath = m_Makefile->GetCurrentOutputDirectory();
outPath += "/"+relPath;
cmSystemTools::MakeDirectory(outPath.c_str());
}
}
else
{
sourceName = (*source)->GetFullPath();
shortName = cmSystemTools::GetFilenameName((*source)->GetSourceName());
}
std::string shortNameWithExt = shortName +
(*source)->GetSourceExtension();
// Only output a rule for each .o once.
std::string compileFlags = exportsDef;
compileFlags += " ";
if(rules.find(shortNameWithExt) == rules.end())
{
if((*source)->GetProperty("COMPILE_FLAGS"))
{
compileFlags += (*source)->GetProperty("COMPILE_FLAGS");
compileFlags += " ";
}
this->OutputBuildObjectFromSource(fout,
shortName.c_str(),
*(*source),
compileFlags.c_str(),
shared);
rules.insert(shortNameWithExt);
}
}
}
}
}
void cmLocalUnixMakefileGenerator::OutputMakeRule(std::ostream& fout,
const char* comment,
const char* target,
const char* depends,
const char* command,
const char* command2,
const char* command3,
const char* command4)
{
std::vector<std::string> commands;
if(command)
{
commands.push_back(command);
}
if(command2)
{
commands.push_back(command2);
}
if(command3)
{
commands.push_back(command3);
}
if(command4)
{
commands.push_back(command4);
}
this->OutputMakeRule(fout, comment, target, depends, commands);
}
void cmLocalUnixMakefileGenerator::OutputMakeRule(std::ostream& fout,
const char* comment,
const char* target,
const char* depends,
const std::vector<std::string>& commands)
{
std::vector<std::string> depend;
if(depends)
{
depend.push_back(depends);
}
this->OutputMakeRule(fout, comment, target, depend, commands);
}
void cmLocalUnixMakefileGenerator::OutputMakeRule(std::ostream& fout,
const char* comment,
const char* target,
const std::vector<std::string>& depends,
const char* command)
{
std::vector<std::string> commands;
if(command)
{
commands.push_back(command);
}
this->OutputMakeRule(fout, comment, target, depends, commands);
}
void cmLocalUnixMakefileGenerator::OutputMakeRule(std::ostream& fout,
const char* comment,
const char* target,
const std::vector<std::string>& depends,
const std::vector<std::string>& commands)
{
if(!target)
{
cmSystemTools::Error("no target for OutputMakeRule");
return;
}
std::string replace;
if(comment)
{
replace = comment;
m_Makefile->ExpandVariablesInString(replace);
fout << "#---------------------------------------------------------\n";
fout << "# " << replace;
fout << "\n#\n";
}
fout << "\n";
replace = target;
m_Makefile->ExpandVariablesInString(replace);
std::string tgt = this->ConvertToRelativeOutputPath(replace.c_str());
tgt = this->ConvertToMakeTarget(tgt.c_str());
if(depends.empty())
{
fout << tgt.c_str() << ":\n";
}
else
{
// Split dependencies into multiple rule lines. This allows for
// very long dependency lists.
for(std::vector<std::string>::const_iterator dep = depends.begin();
dep != depends.end(); ++dep)
{
replace = *dep;
m_Makefile->ExpandVariablesInString(replace);
replace = this->ConvertToMakeTarget(replace.c_str());
fout << tgt.c_str() << ": " << replace.c_str() << "\n";
}
}
int count = 0;
for (std::vector<std::string>::const_iterator i = commands.begin();
i != commands.end(); ++i)
{
replace = *i;
m_Makefile->ExpandVariablesInString(replace);
if(count == 0 && replace.find_first_not_of(" \t\n\r") != std::string::npos &&
replace[0] != '-' && replace.find("echo") != 0
&& replace.find("$(MAKE)") != 0)
{
std::string echostring = "Building ";
echostring += comment;
echostring += " ";
echostring += target;
echostring += "...";
this->OutputEcho(fout,echostring.c_str());
}
fout << "\t" << replace.c_str() << "\n";
count++;
}
fout << "\n";
}
std::string cmLocalUnixMakefileGenerator::LowerCasePath(const char* path)
{
#ifdef _WIN32
return cmSystemTools::LowerCase(path);
#else
return std::string(path);
#endif
}
std::string&
cmLocalUnixMakefileGenerator::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
cmLocalUnixMakefileGenerator::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;
}
void cmLocalUnixMakefileGenerator::GetLibraryNames(const char* n,
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(n, 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(n, t);
}
std::string cmLocalUnixMakefileGenerator::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;
}