summaryrefslogtreecommitdiffstats
path: root/Source
diff options
context:
space:
mode:
Diffstat (limited to 'Source')
-rw-r--r--Source/CPack/cmCPackGenericGenerator.cxx53
-rw-r--r--Source/CPack/cmCPackGenericGenerator.h5
-rw-r--r--Source/CTest/cmCTestBuildAndTestHandler.cxx2
-rw-r--r--Source/CTest/cmCTestBuildCommand.cxx2
-rw-r--r--Source/CursesDialog/form/form.priv.h32
-rw-r--r--Source/MFCDialog/CMakeSetupDialog.cpp3
-rw-r--r--Source/cmAddCustomCommandCommand.h10
-rw-r--r--Source/cmAddCustomTargetCommand.h15
-rw-r--r--Source/cmAddSubDirectoryCommand.cxx16
-rw-r--r--Source/cmBuildCommand.cxx2
-rw-r--r--Source/cmCacheManager.cxx8
-rw-r--r--Source/cmDepends.cxx6
-rw-r--r--Source/cmDepends.h15
-rw-r--r--Source/cmDependsC.cxx19
-rw-r--r--Source/cmFileCommand.cxx38
-rw-r--r--Source/cmFileCommand.h1
-rw-r--r--Source/cmForEachCommand.cxx25
-rw-r--r--Source/cmForEachCommand.h4
-rw-r--r--Source/cmGlobalBorlandMakefileGenerator.cxx1
-rw-r--r--Source/cmGlobalGenerator.cxx35
-rw-r--r--Source/cmGlobalGenerator.h11
-rw-r--r--Source/cmGlobalKdevelopGenerator.cxx12
-rw-r--r--Source/cmGlobalMSYSMakefileGenerator.cxx1
-rw-r--r--Source/cmGlobalMinGWMakefileGenerator.cxx1
-rw-r--r--Source/cmGlobalNMakeMakefileGenerator.cxx1
-rw-r--r--Source/cmGlobalUnixMakefileGenerator3.cxx280
-rw-r--r--Source/cmGlobalUnixMakefileGenerator3.h17
-rw-r--r--Source/cmGlobalVisualStudio6Generator.cxx3
-rw-r--r--Source/cmGlobalVisualStudio6Generator.h3
-rw-r--r--Source/cmGlobalVisualStudio7Generator.cxx2
-rw-r--r--Source/cmGlobalVisualStudio7Generator.h3
-rw-r--r--Source/cmGlobalXCodeGenerator.cxx11
-rw-r--r--Source/cmGlobalXCodeGenerator.h3
-rw-r--r--Source/cmIfCommand.cxx41
-rw-r--r--Source/cmIfCommand.h8
-rw-r--r--Source/cmInstallTargetGenerator.cxx6
-rw-r--r--Source/cmLocalGenerator.cxx27
-rw-r--r--Source/cmLocalGenerator.h3
-rw-r--r--Source/cmLocalUnixMakefileGenerator3.cxx164
-rw-r--r--Source/cmLocalUnixMakefileGenerator3.h9
-rw-r--r--Source/cmLocalVisualStudio7Generator.cxx30
-rw-r--r--Source/cmMacroCommand.cxx23
-rw-r--r--Source/cmMacroCommand.h3
-rw-r--r--Source/cmMakefile.cxx106
-rw-r--r--Source/cmMakefile.h5
-rw-r--r--Source/cmMakefileExecutableTargetGenerator.cxx31
-rw-r--r--Source/cmMakefileLibraryTargetGenerator.cxx109
-rw-r--r--Source/cmMakefileTargetGenerator.cxx279
-rw-r--r--Source/cmMakefileTargetGenerator.h14
-rw-r--r--Source/cmMakefileUtilityTargetGenerator.cxx17
-rw-r--r--Source/cmMessageCommand.cxx7
-rw-r--r--Source/cmSetTargetPropertiesCommand.h6
-rw-r--r--Source/cmTarget.cxx28
-rw-r--r--Source/cmTarget.h2
-rw-r--r--Source/cmTryCompileCommand.cxx4
-rw-r--r--Source/cmTryRunCommand.cxx4
-rw-r--r--Source/cmWhileCommand.cxx23
-rw-r--r--Source/cmWhileCommand.h4
-rw-r--r--Source/cmake.cxx339
-rw-r--r--Source/cmake.h6
-rw-r--r--Source/cmakemain.cxx6
-rw-r--r--Source/kwsys/CommandLineArguments.cxx2
-rw-r--r--Source/kwsys/Directory.cxx59
-rw-r--r--Source/kwsys/Directory.hxx.in6
-rw-r--r--Source/kwsys/Process.h.in12
-rw-r--r--Source/kwsys/ProcessUNIX.c676
-rw-r--r--Source/kwsys/ProcessWin32.c407
-rw-r--r--Source/kwsys/Terminal.c3
-rw-r--r--Source/kwsys/kwsysPlatformCxxTests.cmake6
-rw-r--r--Source/kwsys/testProcess.c111
70 files changed, 2543 insertions, 683 deletions
diff --git a/Source/CPack/cmCPackGenericGenerator.cxx b/Source/CPack/cmCPackGenericGenerator.cxx
index 846226c..f4e51b3 100644
--- a/Source/CPack/cmCPackGenericGenerator.cxx
+++ b/Source/CPack/cmCPackGenericGenerator.cxx
@@ -43,6 +43,21 @@ cmCPackGenericGenerator::~cmCPackGenericGenerator()
}
//----------------------------------------------------------------------
+void cmCPackGenericGeneratorProgress(const char *msg, float prog, void* ptr)
+{
+ cmCPackGenericGenerator* self = static_cast<cmCPackGenericGenerator*>(ptr);
+ self->DisplayVerboseOutput(msg, prog);
+}
+
+//----------------------------------------------------------------------
+void cmCPackGenericGenerator::DisplayVerboseOutput(const char* msg,
+ float progress)
+{
+ (void)progress;
+ cmCPackLogger(cmCPackLog::LOG_VERBOSE, "" << msg << std::endl);
+}
+
+//----------------------------------------------------------------------
int cmCPackGenericGenerator::PrepareNames()
{
this->SetOption("CPACK_GENERATOR", this->Name.c_str());
@@ -152,6 +167,7 @@ int cmCPackGenericGenerator::InstallProject()
ignoreFilesRegex.push_back(it->c_str());
}
}
+ this->CleanTemporaryDirectory();
const char* tempInstallDirectory
= this->GetOption("CPACK_TEMPORARY_INSTALL_DIRECTORY");
int res = 1;
@@ -174,6 +190,9 @@ int cmCPackGenericGenerator::InstallProject()
destDir += tempInstallDirectory;
cmSystemTools::PutEnv(destDir.c_str());
}
+
+ // If the CPackConfig file sets CPACK_INSTALL_COMMANDS then run them
+ // as listed
const char* installCommands = this->GetOption("CPACK_INSTALL_COMMANDS");
if ( installCommands && *installCommands )
{
@@ -207,6 +226,10 @@ int cmCPackGenericGenerator::InstallProject()
}
}
}
+
+ // If the CPackConfig file sets CPACK_INSTALLED_DIRECTORIES
+ // then glob it and copy it to CPACK_TEMPORARY_DIRECTORY
+ // This is used in Source packageing
const char* installDirectories
= this->GetOption("CPACK_INSTALLED_DIRECTORIES");
if ( installDirectories && *installDirectories )
@@ -281,6 +304,9 @@ int cmCPackGenericGenerator::InstallProject()
}
}
}
+
+ // If the project is a CMAKE project then run pre-install
+ // and then read the cmake_install script to run it
const char* cmakeProjects
= this->GetOption("CPACK_INSTALL_CMAKE_PROJECTS");
const char* cmakeGenerator
@@ -346,7 +372,7 @@ int cmCPackGenericGenerator::InstallProject()
= globalGenerator->GenerateBuildCommand(cmakeMakeProgram,
installProjectName.c_str(), 0,
globalGenerator->GetPreinstallTargetName(),
- buildConfig, false);
+ buildConfig, false, false);
cmCPackLogger(cmCPackLog::LOG_DEBUG,
"- Install command: " << buildCommand << std::endl);
cmCPackLogger(cmCPackLog::LOG_OUTPUT,
@@ -381,6 +407,7 @@ int cmCPackGenericGenerator::InstallProject()
cmCPackLogger(cmCPackLog::LOG_OUTPUT,
"- Install project: " << installProjectName << std::endl);
cmake cm;
+ cm.SetProgressCallback(cmCPackGenericGeneratorProgress, this);
cmGlobalGenerator gg;
gg.SetCMakeInstance(&cm);
std::auto_ptr<cmLocalGenerator> lg(gg.CreateLocalGenerator());
@@ -414,6 +441,8 @@ int cmCPackGenericGenerator::InstallProject()
}
}
}
+
+ // ?????
const char* binaryDirectories = this->GetOption("CPACK_BINARY_DIR");
if ( binaryDirectories && !cmakeProjects )
{
@@ -846,3 +875,25 @@ bool cmCPackGenericGenerator::ConfigureFile(const char* inName,
return this->MakefileMap->ConfigureFile(inName, outName,
false, true, false) == 1;
}
+
+//----------------------------------------------------------------------
+int cmCPackGenericGenerator::CleanTemporaryDirectory()
+{
+ const char* tempInstallDirectory
+ = this->GetOption("CPACK_TEMPORARY_INSTALL_DIRECTORY");
+ if(cmsys::SystemTools::FileExists(tempInstallDirectory))
+ {
+ cmCPackLogger(cmCPackLog::LOG_OUTPUT,
+ "- Clean temporary : "
+ << tempInstallDirectory << std::endl);
+ if(!cmsys::SystemTools::RemoveADirectory(tempInstallDirectory))
+ {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Problem removing temporary directory: " <<
+ tempInstallDirectory
+ << std::endl);
+ return 0;
+ }
+ }
+ return 1;
+}
diff --git a/Source/CPack/cmCPackGenericGenerator.h b/Source/CPack/cmCPackGenericGenerator.h
index 6867613..87c486d 100644
--- a/Source/CPack/cmCPackGenericGenerator.h
+++ b/Source/CPack/cmCPackGenericGenerator.h
@@ -87,10 +87,13 @@ public:
//! Set the logger
void SetLogger(cmCPackLog* log) { this->Logger = log; }
+ //! Display verbose information via logger
+ void DisplayVerboseOutput(const char* msg, float progress);
+
protected:
int PrepareNames();
int InstallProject();
-
+ int CleanTemporaryDirectory();
virtual const char* GetOutputExtension() { return "cpack"; }
virtual const char* GetOutputPostfix() { return 0; }
virtual int CompressFiles(const char* outFileName, const char* toplevel,
diff --git a/Source/CTest/cmCTestBuildAndTestHandler.cxx b/Source/CTest/cmCTestBuildAndTestHandler.cxx
index b7a27d9..6948bc6 100644
--- a/Source/CTest/cmCTestBuildAndTestHandler.cxx
+++ b/Source/CTest/cmCTestBuildAndTestHandler.cxx
@@ -196,7 +196,7 @@ int cmCTestBuildAndTestHandler::RunCMakeAndTest(std::string* outstring)
this->SourceDir.c_str(), this->BinaryDir.c_str(),
this->BuildProject.c_str(), tarIt->c_str(),
&output, this->BuildMakeProgram.c_str(),
- this->CTest->GetConfigType().c_str(),!this->BuildNoClean);
+ this->CTest->GetConfigType().c_str(),!this->BuildNoClean, false);
out << output;
// if the build failed then return
diff --git a/Source/CTest/cmCTestBuildCommand.cxx b/Source/CTest/cmCTestBuildCommand.cxx
index 7838118..f6a196d 100644
--- a/Source/CTest/cmCTestBuildCommand.cxx
+++ b/Source/CTest/cmCTestBuildCommand.cxx
@@ -93,7 +93,7 @@ cmCTestGenericHandler* cmCTestBuildCommand::InitializeHandler()
std::string buildCommand
= this->GlobalGenerator->GenerateBuildCommand(cmakeMakeProgram,
cmakeProjectName,
- cmakeBuildAdditionalFlags, 0, cmakeBuildConfiguration, true);
+ cmakeBuildAdditionalFlags, 0, cmakeBuildConfiguration, true, false);
this->CTest->SetCTestConfiguration("MakeCommand", buildCommand.c_str());
}
else
diff --git a/Source/CursesDialog/form/form.priv.h b/Source/CursesDialog/form/form.priv.h
index 886121c..3691f2f 100644
--- a/Source/CursesDialog/form/form.priv.h
+++ b/Source/CursesDialog/form/form.priv.h
@@ -33,6 +33,12 @@
#include "mf_common.h"
#include "form.h"
+/* get around odd bug on aCC and itanium */
+#if defined(__hpux) && defined(__ia64)
+#define getmaxx __getmaxx
+#define getmaxy __getmaxy
+#endif
+
/* form status values */
#define _OVLMODE (0x04) /* Form is in overlay mode */
#define _WINDOW_MODIFIED (0x10) /* Current field window has been modified */
@@ -41,7 +47,7 @@
/* field status values */
#define _CHANGED (0x01) /* Field has been changed */
#define _NEWTOP (0x02) /* Vertical scrolling occured */
-#define _NEWPAGE (0x04) /* field begins new page of form */
+#define _NEWPAGE (0x04) /* field begins new page of form */
#define _MAY_GROW (0x08) /* dynamic field may still grow */
/* fieldtype status values */
@@ -91,20 +97,20 @@ typedef struct typearg {
#define FIRST_ACTIVE_MAGIC (-291056)
#define ALL_FORM_OPTS ( \
- O_NL_OVERLOAD |\
- O_BS_OVERLOAD )
+ O_NL_OVERLOAD |\
+ O_BS_OVERLOAD )
#define ALL_FIELD_OPTS ( \
- O_VISIBLE |\
- O_ACTIVE |\
- O_PUBLIC |\
- O_EDIT |\
- O_WRAP |\
- O_BLANK |\
- O_AUTOSKIP|\
- O_NULLOK |\
- O_PASSOK |\
- O_STATIC )
+ O_VISIBLE |\
+ O_ACTIVE |\
+ O_PUBLIC |\
+ O_EDIT |\
+ O_WRAP |\
+ O_BLANK |\
+ O_AUTOSKIP|\
+ O_NULLOK |\
+ O_PASSOK |\
+ O_STATIC )
#define C_BLANK ' '
diff --git a/Source/MFCDialog/CMakeSetupDialog.cpp b/Source/MFCDialog/CMakeSetupDialog.cpp
index 534f713..0a605f2 100644
--- a/Source/MFCDialog/CMakeSetupDialog.cpp
+++ b/Source/MFCDialog/CMakeSetupDialog.cpp
@@ -83,7 +83,7 @@ void MFCMessageCallback(const char* m, const char* title, bool& nomore, void*)
// CMakeSetupDialog dialog
void updateProgress(const char *msg, float prog, void *cd)
{
- char tmp[1024];
+ char* tmp = new char[strlen(msg) + 40];
if (prog >= 0)
{
sprintf(tmp,"%s %i%%",msg,(int)(100*prog));
@@ -120,6 +120,7 @@ void updateProgress(const char *msg, float prog, void *cd)
break;
}
}
+ delete [] tmp;
}
// Convert to Win32 path (slashes). This calls the system tools one and then
diff --git a/Source/cmAddCustomCommandCommand.h b/Source/cmAddCustomCommandCommand.h
index 7a40c47..bacce8f 100644
--- a/Source/cmAddCustomCommandCommand.h
+++ b/Source/cmAddCustomCommandCommand.h
@@ -74,7 +74,9 @@ public:
" [WORKING_DIRECTORY dir]\n"
" [COMMENT comment])\n"
"This defines a new command that can be executed during the build "
- "process. Note that MAIN_DEPENDENCY is completely optional and is "
+ "process. The outputs named should be listed as source files in the "
+ "target for which they are to be generated. "
+ "Note that MAIN_DEPENDENCY is completely optional and is "
"used as a suggestion to visual studio about where to hang the "
"custom command. In makefile terms this creates a new target in the "
"following form:\n"
@@ -100,9 +102,9 @@ public:
" POST_BUILD - run after the target has been built\n"
"Note that the PRE_BUILD option is only supported on Visual "
"Studio 7 or later. For all other generators PRE_BUILD "
- "will be treated as PRE_LINK."
- "If WORKING_DIRECTORY is specified the command a cd \"dir\" is "
- "done prior to running the command.";
+ "will be treated as PRE_LINK. "
+ "If WORKING_DIRECTORY is specified the command will be executed "
+ "in the directory given.";
}
cmTypeMacro(cmAddCustomCommandCommand, cmCommand);
diff --git a/Source/cmAddCustomTargetCommand.h b/Source/cmAddCustomTargetCommand.h
index 7bc8c5d..4a448b3 100644
--- a/Source/cmAddCustomTargetCommand.h
+++ b/Source/cmAddCustomTargetCommand.h
@@ -70,13 +70,16 @@ public:
"Adds a target with the given name that executes the given commands "
"every time the target is built. If the ALL option is specified "
"it indicates that this target should be added to the default build "
- "target so that it will be run every time. "
- "The command and arguments are optional. If not specified, "
- "it will create an empty target. The ADD_DEPENDENCIES command can be "
- "used in conjunction with this command to drive custom target "
- "generation. The command cannot be called ALL. "
+ "target so that it will be run every time "
+ "(the command cannot be called ALL). "
+ "The command and arguments are optional and if not specified an "
+ "empty target will be created. "
"If WORKING_DIRECTORY is set, then the command will be run in that "
- "directory.";
+ "directory. "
+ "Dependencies listed with the DEPENDS argument may reference files "
+ "and outputs of custom commands created with ADD_CUSTOM_COMMAND. "
+ "Dependencies on other targets may be added using the "
+ "ADD_DEPENDENCIES command.";
}
cmTypeMacro(cmAddCustomTargetCommand, cmCommand);
diff --git a/Source/cmAddSubDirectoryCommand.cxx b/Source/cmAddSubDirectoryCommand.cxx
index 5e13150..6591b44 100644
--- a/Source/cmAddSubDirectoryCommand.cxx
+++ b/Source/cmAddSubDirectoryCommand.cxx
@@ -54,14 +54,12 @@ bool cmAddSubDirectoryCommand::InitialPass
}
// check for relative arguments
- bool relativeSource = true;
std::string binPath = binArg;
std::string srcPath = std::string(this->Makefile->GetCurrentDirectory()) +
"/" + srcArg;
// if the path does not exist then the arg was relative
if (!cmSystemTools::FileIsDirectory(srcPath.c_str()))
{
- relativeSource = false;
srcPath = srcArg;
if (!cmSystemTools::FileIsDirectory(srcPath.c_str()))
{
@@ -74,6 +72,7 @@ bool cmAddSubDirectoryCommand::InitialPass
// at this point srcPath has the full path to the source directory
// now we need to compute the binPath if it was not provided
+ srcPath = cmSystemTools::CollapseFullPath(srcPath.c_str());
// if the argument was provided then use it
if (binArg.size())
@@ -87,21 +86,13 @@ bool cmAddSubDirectoryCommand::InitialPass
// otherwise compute the binPath from the srcPath
else
{
- // if the srcArg was relative then we just do the same for the binPath
- if (relativeSource)
- {
- binPath = std::string(this->Makefile->GetCurrentOutputDirectory()) +
- "/" + srcArg;
- }
- // otherwise we try to remove the CurrentDirectory from the srcPath and
+ // we try to remove the CurrentDirectory from the srcPath and
// replace it with the CurrentOutputDirectory. This may not really work
// because the source dir they provided may not be "in" the source
// tree. This is an error if this happens.
- else
- {
// try replacing the home dir with the home output dir
binPath = srcPath;
- if (!cmSystemTools::FindLastString(binPath.c_str(),
+ if(!cmSystemTools::FindLastString(binPath.c_str(),
this->Makefile->GetHomeDirectory()))
{
this->SetError("A full source directory was specified that is not "
@@ -114,7 +105,6 @@ bool cmAddSubDirectoryCommand::InitialPass
cmSystemTools::ReplaceString(binPath,
this->Makefile->GetHomeDirectory(),
this->Makefile->GetHomeOutputDirectory());
- }
}
// now we have all the arguments
diff --git a/Source/cmBuildCommand.cxx b/Source/cmBuildCommand.cxx
index 13443b0..405b463 100644
--- a/Source/cmBuildCommand.cxx
+++ b/Source/cmBuildCommand.cxx
@@ -34,7 +34,7 @@ bool cmBuildCommand::InitialPass(std::vector<std::string> const& args)
std::string makecommand = this->Makefile->GetLocalGenerator()
->GetGlobalGenerator()->GenerateBuildCommand
(makeprogram.c_str(), this->Makefile->GetProjectName(), 0,
- 0, "Release", true);
+ 0, "Release", true, false);
if(cacheValue)
{
diff --git a/Source/cmCacheManager.cxx b/Source/cmCacheManager.cxx
index a0a231f..5eecb1d 100644
--- a/Source/cmCacheManager.cxx
+++ b/Source/cmCacheManager.cxx
@@ -19,6 +19,7 @@
#include "cmSystemTools.h"
#include "cmCacheManager.h"
#include "cmMakefile.h"
+#include "cmake.h"
#include <cmsys/Directory.hxx>
#include <cmsys/Glob.hxx>
@@ -163,7 +164,8 @@ bool cmCacheManager::ParseEntry(const char* entry,
void cmCacheManager::CleanCMakeFiles(const char* path)
{
std::string glob = path;
- glob += "/CMakeFiles/*.cmake";
+ glob += cmake::GetCMakeFilesDirectory();
+ glob += "/*.cmake";
cmsys::Glob globIt;
globIt.FindFiles(glob);
std::vector<std::string> files = globIt.GetFiles();
@@ -601,7 +603,7 @@ bool cmCacheManager::SaveCache(const char* path)
cacheFile.c_str());
cmSystemTools::RemoveFile(tempFile.c_str());
std::string checkCacheFile = path;
- checkCacheFile += "/CMakeFiles";
+ checkCacheFile += cmake::GetCMakeFilesDirectory();
cmSystemTools::MakeDirectory(checkCacheFile.c_str());
checkCacheFile += "/cmake.check_cache";
std::ofstream checkCache(checkCacheFile.c_str());
@@ -626,7 +628,7 @@ bool cmCacheManager::DeleteCache(const char* path)
// now remove the files in the CMakeFiles directory
// this cleans up language cache files
cmsys::Directory dir;
- cmakeFiles += "/CMakeFiles";
+ cmakeFiles += cmake::GetCMakeFilesDirectory();
dir.Load(cmakeFiles.c_str());
for (unsigned long fileNum = 0;
fileNum < dir.GetNumberOfFiles();
diff --git a/Source/cmDepends.cxx b/Source/cmDepends.cxx
index f6d577c..37c177b 100644
--- a/Source/cmDepends.cxx
+++ b/Source/cmDepends.cxx
@@ -22,7 +22,11 @@
#include <string.h>
//----------------------------------------------------------------------------
-cmDepends::cmDepends(): Verbose(false), FileComparison(0),
+cmDepends::cmDepends():
+ CompileDirectory(),
+ LocalGenerator(0),
+ Verbose(false),
+ FileComparison(0),
MaxPath(cmSystemTools::GetMaximumFilePathLength()),
Dependee(new char[MaxPath]),
Depender(new char[MaxPath])
diff --git a/Source/cmDepends.h b/Source/cmDepends.h
index d6269af..b7a11de 100644
--- a/Source/cmDepends.h
+++ b/Source/cmDepends.h
@@ -20,6 +20,7 @@
#include "cmStandardIncludes.h"
class cmFileTimeComparison;
+class cmLocalGenerator;
/** \class cmDepends
* \brief Dependency scanner superclass.
@@ -38,11 +39,11 @@ public:
/** at what level will the compile be done from */
void SetCompileDirectory(const char *dir) {this->CompileDirectory = dir;};
- /** Set the full path to the top of the build tree. This is
- the base path from which dependencies are referenced as
- relative paths. */
- void SetHomeOutputDirectory(const char *dir) {
- this->HomeOutputDirectory = dir;};
+ /** Set the local generator for the directory in which we are
+ scanning dependencies. This is not a full local generator; it
+ has been setup to do relative path conversions for the current
+ directory. */
+ void SetLocalGenerator(cmLocalGenerator* lg) { this->LocalGenerator = lg; }
/** should this be verbose in its output */
void SetVerbose(bool verb) { this->Verbose = verb; }
@@ -79,8 +80,8 @@ protected:
// The directory in which the build rule for the target file is executed.
std::string CompileDirectory;
- // The full path to the top of the build tree.
- std::string HomeOutputDirectory;
+ // The local generator.
+ cmLocalGenerator* LocalGenerator;
// Flag for verbose output.
bool Verbose;
diff --git a/Source/cmDependsC.cxx b/Source/cmDependsC.cxx
index ad1d021..7806ab3 100644
--- a/Source/cmDependsC.cxx
+++ b/Source/cmDependsC.cxx
@@ -16,8 +16,9 @@
=========================================================================*/
#include "cmDependsC.h"
-#include "cmSystemTools.h"
#include "cmFileTimeComparison.h"
+#include "cmLocalGenerator.h"
+#include "cmSystemTools.h"
#include <ctype.h> // isspace
@@ -194,13 +195,18 @@ bool cmDependsC::WriteDependencies(const char *src, const char *obj,
first = false;
}
- // Write the dependencies to the output stream.
+ // Write the dependencies to the output stream. Makefile rules
+ // written by the original local generator for this directory
+ // convert the dependencies to paths relative to the home output
+ // directory. We must do the same here.
internalDepends << obj << std::endl;
for(std::set<cmStdString>::iterator i=dependencies.begin();
i != dependencies.end(); ++i)
{
- makeDepends << obj << ": "
- << cmSystemTools::ConvertToOutputPath(i->c_str()).c_str()
+ makeDepends << obj << ": " <<
+ this->LocalGenerator->Convert(i->c_str(),
+ cmLocalGenerator::HOME_OUTPUT,
+ cmLocalGenerator::MAKEFILE)
<< std::endl;
internalDepends << " " << i->c_str() << std::endl;
}
@@ -370,8 +376,9 @@ bool cmDependsC::FileExistsOrIsGenerated(const std::string& fname,
// Note that CMAKE_GENERATED_FILES is written with a conversion
// relative to the home output directory.
std::string rname =
- cmSystemTools::RelativePath(this->HomeOutputDirectory.c_str(),
- fname.c_str());
+ this->LocalGenerator->Convert(fname.c_str(),
+ cmLocalGenerator::HOME_OUTPUT,
+ cmLocalGenerator::UNCHANGED);
if(this->FileIsGenerated(rname, scanned, dependencies))
{
return true;
diff --git a/Source/cmFileCommand.cxx b/Source/cmFileCommand.cxx
index 27c5e58..bbf4265 100644
--- a/Source/cmFileCommand.cxx
+++ b/Source/cmFileCommand.cxx
@@ -233,6 +233,11 @@ bool cmFileCommand::HandleGlobCommand(std::vector<std::string> const& args,
}
g.SetRelative(i->c_str());
++i;
+ if(i == args.end())
+ {
+ this->SetError("GLOB requires a glob expression after the directory");
+ return false;
+ }
}
if ( !cmsys::SystemTools::FileIsFullPath(i->c_str()) )
{
@@ -775,15 +780,10 @@ bool cmFileCommand::HandleInstallCommand(
std::string libname = toFile;
std::string soname = toFile;
std::string soname_nopath = fromName;
- soname += ".";
- soname += lib_soversion;
- soname_nopath += ".";
- soname_nopath += lib_soversion;
-
- fromName += ".";
- fromName += lib_version;
- toFile += ".";
- toFile += lib_version;
+ this->ComputeVersionedName(soname, lib_soversion);
+ this->ComputeVersionedName(soname_nopath, lib_soversion);
+ this->ComputeVersionedName(fromName, lib_version);
+ this->ComputeVersionedName(toFile, lib_version);
cmSystemTools::RemoveFile(soname.c_str());
cmSystemTools::RemoveFile(libname.c_str());
@@ -946,6 +946,26 @@ bool cmFileCommand::HandleInstallCommand(
}
//----------------------------------------------------------------------------
+void cmFileCommand::ComputeVersionedName(std::string& name,
+ const char* version)
+{
+#if defined(__APPLE__)
+ std::string ext;
+ kwsys_stl::string::size_type dot_pos = name.rfind(".");
+ if(dot_pos != name.npos)
+ {
+ ext = name.substr(dot_pos, name.npos);
+ name = name.substr(0, dot_pos);
+ }
+#endif
+ name += ".";
+ name += version;
+#if defined(__APPLE__)
+ name += ext;
+#endif
+}
+
+//----------------------------------------------------------------------------
bool cmFileCommand::HandleRelativePathCommand(
std::vector<std::string> const& args)
{
diff --git a/Source/cmFileCommand.h b/Source/cmFileCommand.h
index 249cbb6..610fb7d 100644
--- a/Source/cmFileCommand.h
+++ b/Source/cmFileCommand.h
@@ -125,6 +125,7 @@ protected:
bool HandleRelativePathCommand(std::vector<std::string> const& args);
bool HandleCMakePathCommand(std::vector<std::string> const& args,
bool nativePath);
+ void ComputeVersionedName(std::string& name, const char* version);
};
diff --git a/Source/cmForEachCommand.cxx b/Source/cmForEachCommand.cxx
index fe53b12..b7f388b 100644
--- a/Source/cmForEachCommand.cxx
+++ b/Source/cmForEachCommand.cxx
@@ -26,13 +26,17 @@ IsFunctionBlocked(const cmListFileFunction& lff, cmMakefile &mf)
return false;
}
- // at end of for each execute recorded commands
- if (cmSystemTools::LowerCase(lff.Name) == "endforeach")
+ if (!cmSystemTools::Strucmp(lff.Name.c_str(),"foreach"))
{
- std::vector<std::string> expandedArguments;
- mf.ExpandArguments(lff.Arguments, expandedArguments);
- if(!expandedArguments.empty() && (expandedArguments[0] == this->Args[0]))
+ // record the number of nested foreach commands
+ this->Depth++;
+ }
+ else if (!cmSystemTools::Strucmp(lff.Name.c_str(),"endforeach"))
+ {
+ // if this is the endofreach for this statement
+ if (!this->Depth)
{
+ // at end of for each execute recorded commands
// store the old value
std::string oldDef;
if (mf.GetDefinition(this->Args[0].c_str()))
@@ -60,6 +64,11 @@ IsFunctionBlocked(const cmListFileFunction& lff, cmMakefile &mf)
mf.RemoveFunctionBlocker(lff);
return true;
}
+ else
+ {
+ // close out a nested foreach
+ this->Depth--;
+ }
}
// record the command
@@ -72,11 +81,13 @@ IsFunctionBlocked(const cmListFileFunction& lff, cmMakefile &mf)
bool cmForEachFunctionBlocker::
ShouldRemove(const cmListFileFunction& lff, cmMakefile& mf)
{
- if(cmSystemTools::LowerCase(lff.Name) == "endforeach")
+ if(!cmSystemTools::Strucmp(lff.Name.c_str(),"endforeach"))
{
std::vector<std::string> expandedArguments;
mf.ExpandArguments(lff.Arguments, expandedArguments);
- if(!expandedArguments.empty() && (expandedArguments[0] == this->Args[0]))
+ if ((!expandedArguments.empty() &&
+ (expandedArguments[0] == this->Args[0]))
+ || mf.IsOn("CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS"))
{
return true;
}
diff --git a/Source/cmForEachCommand.h b/Source/cmForEachCommand.h
index 5a30359..04843c4 100644
--- a/Source/cmForEachCommand.h
+++ b/Source/cmForEachCommand.h
@@ -29,7 +29,7 @@
class cmForEachFunctionBlocker : public cmFunctionBlocker
{
public:
- cmForEachFunctionBlocker() {this->Executing = false;}
+ cmForEachFunctionBlocker() {this->Executing = false; Depth = 0;}
virtual ~cmForEachFunctionBlocker() {}
virtual bool IsFunctionBlocked(const cmListFileFunction& lff,
cmMakefile &mf);
@@ -39,6 +39,8 @@ public:
std::vector<std::string> Args;
std::vector<cmListFileFunction> Functions;
bool Executing;
+private:
+ int Depth;
};
/** \class cmForEachCommand
diff --git a/Source/cmGlobalBorlandMakefileGenerator.cxx b/Source/cmGlobalBorlandMakefileGenerator.cxx
index 5018a8c..1ce506d 100644
--- a/Source/cmGlobalBorlandMakefileGenerator.cxx
+++ b/Source/cmGlobalBorlandMakefileGenerator.cxx
@@ -25,6 +25,7 @@ cmGlobalBorlandMakefileGenerator::cmGlobalBorlandMakefileGenerator()
this->FindMakeProgramFile = "CMakeBorlandFindMake.cmake";
this->ForceUnixPaths = false;
this->ToolSupportsColor = true;
+ this->UseLinkScript = false;
}
diff --git a/Source/cmGlobalGenerator.cxx b/Source/cmGlobalGenerator.cxx
index ca1c126..42e404f 100644
--- a/Source/cmGlobalGenerator.cxx
+++ b/Source/cmGlobalGenerator.cxx
@@ -36,6 +36,12 @@ cmGlobalGenerator::cmGlobalGenerator()
// By default do not try to support color.
this->ToolSupportsColor = false;
+
+ // By default do not use link scripts.
+ this->UseLinkScript = false;
+
+ // Relative paths are not configured in the constructor.
+ this->RelativePathsConfigured = false;
}
cmGlobalGenerator::~cmGlobalGenerator()
@@ -175,7 +181,7 @@ cmGlobalGenerator::EnableLanguage(std::vector<std::string>const& languages,
}
mf->AddDefinition("RUN_CONFIGURE", true);
std::string rootBin = mf->GetHomeOutputDirectory();
- rootBin += "/CMakeFiles";
+ rootBin += cmake::GetCMakeFilesDirectory();
// If the configuration files path has been set,
// then we are in a try compile and need to copy the enable language
@@ -589,8 +595,6 @@ void cmGlobalGenerator::Configure()
}
this->LocalGenerators.clear();
- // Setup relative path generation.
- this->ConfigureRelativePaths();
this->TotalTargets.clear();
// start with this directory
@@ -772,13 +776,13 @@ int cmGlobalGenerator::TryCompile(const char *srcdir, const char *bindir,
const char* config = mf->GetDefinition("CMAKE_TRY_COMPILE_CONFIGURATION");
return this->Build(srcdir,bindir,projectName,
newTarget.c_str(),
- output,makeCommand.c_str(),config,false);
+ output,makeCommand.c_str(),config,false,true);
}
std::string cmGlobalGenerator
::GenerateBuildCommand(const char* makeProgram, const char *projectName,
const char* additionalOptions, const char *targetName,
- const char* config, bool ignoreErrors)
+ const char* config, bool ignoreErrors, bool)
{
// Project name and config are not used yet.
(void)projectName;
@@ -816,7 +820,7 @@ int cmGlobalGenerator::Build(
std::string *output,
const char *makeCommandCSTR,
const char *config,
- bool clean)
+ bool clean, bool fast)
{
*output += "\nTesting TryCompileWithoutMakefile\n";
@@ -836,7 +840,7 @@ int cmGlobalGenerator::Build(
{
std::string cleanCommand =
this->GenerateBuildCommand(makeCommandCSTR, projectName,
- 0, "clean", config, false);
+ 0, "clean", config, false, fast);
if (!cmSystemTools::RunSingleCommand(cleanCommand.c_str(), output,
&retVal, 0, false, timeout))
{
@@ -856,7 +860,7 @@ int cmGlobalGenerator::Build(
// now build
std::string makeCommand =
this->GenerateBuildCommand(makeCommandCSTR, projectName,
- 0, target, config, false);
+ 0, target, config, false, fast);
if (!cmSystemTools::RunSingleCommand(makeCommand.c_str(), output,
&retVal, 0, false, timeout))
@@ -932,7 +936,7 @@ cmLocalGenerator *cmGlobalGenerator::CreateLocalGenerator()
void cmGlobalGenerator::EnableLanguagesFromGenerator(cmGlobalGenerator *gen )
{
std::string cfp = gen->GetCMakeInstance()->GetHomeOutputDirectory();
- cfp += "/CMakeFiles";
+ cfp += cmake::GetCMakeFilesDirectory();
this->SetConfiguredFilesPath(cfp.c_str());
const char* make =
gen->GetCMakeInstance()->GetCacheDefinition("CMAKE_MAKE_PROGRAM");
@@ -1097,6 +1101,13 @@ std::string cmGlobalGenerator
return in_remote;
}
+ // Make sure relative path conversion is configured.
+ if(!this->RelativePathsConfigured)
+ {
+ this->ConfigureRelativePaths();
+ this->RelativePathsConfigured = true;
+ }
+
std::string original = in_remote;
// Skip conversion if the path and local are not both in the source or both
@@ -1219,6 +1230,12 @@ inline std::string removeQuotes(const std::string& s)
return s;
}
+void cmGlobalGenerator::SetCMakeInstance(cmake* cm)
+{
+ // Store a pointer to the cmake object instance.
+ this->CMakeInstance = cm;
+}
+
void cmGlobalGenerator::SetupTests()
{
std::string ctest = this->LocalGenerators[0]->GetMakefile()->
diff --git a/Source/cmGlobalGenerator.h b/Source/cmGlobalGenerator.h
index 1134c2a..07ee8d8 100644
--- a/Source/cmGlobalGenerator.h
+++ b/Source/cmGlobalGenerator.h
@@ -100,16 +100,16 @@ public:
const char *projectName, const char *targetName,
std::string *output,
const char *makeProgram, const char *config,
- bool clean);
+ bool clean, bool fast);
virtual std::string GenerateBuildCommand
(const char* makeProgram,
const char *projectName, const char* additionalOptions,
const char *targetName,
- const char* config, bool ignoreErrors);
+ const char* config, bool ignoreErrors, bool fast);
///! Set the CMake instance
- void SetCMakeInstance(cmake *cm) { this->CMakeInstance = cm; };
+ void SetCMakeInstance(cmake *cm);
///! Get the CMake instance
cmake *GetCMakeInstance() { return this->CMakeInstance; };
@@ -152,6 +152,9 @@ public:
std::string ConvertToRelativePath(const std::vector<std::string>& local,
const char* remote);
+ /** Get whether the generator should use a script for link commands. */
+ bool GetUseLinkScript() { return this->UseLinkScript; }
+
/*
* Determine what program to use for building the project.
*/
@@ -197,6 +200,7 @@ protected:
bool IsExcluded(cmLocalGenerator* root, cmLocalGenerator* gen);
void ConfigureRelativePaths();
+ bool RelativePathsConfigured;
void SetupTests();
void CreateDefaultGlobalTargets(cmTargets* targets);
@@ -204,6 +208,7 @@ protected:
const cmCustomCommandLines* commandLines,
std::vector<std::string> depends, bool depends_on_all = false);
+ bool UseLinkScript;
bool ForceUnixPaths;
bool ToolSupportsColor;
cmStdString FindMakeProgramFile;
diff --git a/Source/cmGlobalKdevelopGenerator.cxx b/Source/cmGlobalKdevelopGenerator.cxx
index 244e031..ca90216 100644
--- a/Source/cmGlobalKdevelopGenerator.cxx
+++ b/Source/cmGlobalKdevelopGenerator.cxx
@@ -134,7 +134,9 @@ bool cmGlobalKdevelopGenerator
tmp=*lt;
cmSystemTools::ReplaceString(tmp, projectDir.c_str(), "");
// make sure the file is part of this source tree
- if ((tmp[0]!='/') && (strstr(tmp.c_str(), "CMakeFiles/")==0))
+ if ((tmp[0]!='/') &&
+ (strstr(tmp.c_str(),
+ cmake::GetCMakeFilesDirectoryPostSlash())==0))
{
files.insert(tmp);
tmp=cmSystemTools::GetFilenameName(tmp);
@@ -159,7 +161,9 @@ bool cmGlobalKdevelopGenerator
{
tmp=(*si)->GetFullPath();
cmSystemTools::ReplaceString(tmp, projectDir.c_str(), "");
- if ((tmp[0]!='/') && (strstr(tmp.c_str(), "CMakeFiles/")==0))
+ if ((tmp[0]!='/') &&
+ (strstr(tmp.c_str(),
+ cmake::GetCMakeFilesDirectoryPostSlash())==0))
{
files.insert(tmp);
}
@@ -169,7 +173,9 @@ bool cmGlobalKdevelopGenerator
{
tmp=*lt;
cmSystemTools::ReplaceString(tmp, projectDir.c_str(), "");
- if ((tmp[0]!='/') && (strstr(tmp.c_str(), "CMakeFiles/")==0))
+ if ((tmp[0]!='/') &&
+ (strstr(tmp.c_str(),
+ cmake::GetCMakeFilesDirectoryPostSlash())==0))
{
files.insert(tmp.c_str());
}
diff --git a/Source/cmGlobalMSYSMakefileGenerator.cxx b/Source/cmGlobalMSYSMakefileGenerator.cxx
index ca1a292..53ea649 100644
--- a/Source/cmGlobalMSYSMakefileGenerator.cxx
+++ b/Source/cmGlobalMSYSMakefileGenerator.cxx
@@ -24,6 +24,7 @@ cmGlobalMSYSMakefileGenerator::cmGlobalMSYSMakefileGenerator()
this->FindMakeProgramFile = "CMakeMSYSFindMake.cmake";
this->ForceUnixPaths = true;
this->ToolSupportsColor = true;
+ this->UseLinkScript = false;
}
std::string
diff --git a/Source/cmGlobalMinGWMakefileGenerator.cxx b/Source/cmGlobalMinGWMakefileGenerator.cxx
index 7e9ad82..f66134c 100644
--- a/Source/cmGlobalMinGWMakefileGenerator.cxx
+++ b/Source/cmGlobalMinGWMakefileGenerator.cxx
@@ -23,6 +23,7 @@ cmGlobalMinGWMakefileGenerator::cmGlobalMinGWMakefileGenerator()
this->FindMakeProgramFile = "CMakeMinGWFindMake.cmake";
this->ForceUnixPaths = true;
this->ToolSupportsColor = true;
+ this->UseLinkScript = true;
}
void cmGlobalMinGWMakefileGenerator
diff --git a/Source/cmGlobalNMakeMakefileGenerator.cxx b/Source/cmGlobalNMakeMakefileGenerator.cxx
index bfb09db..35a2a86 100644
--- a/Source/cmGlobalNMakeMakefileGenerator.cxx
+++ b/Source/cmGlobalNMakeMakefileGenerator.cxx
@@ -23,6 +23,7 @@ cmGlobalNMakeMakefileGenerator::cmGlobalNMakeMakefileGenerator()
this->FindMakeProgramFile = "CMakeNMakeFindMake.cmake";
this->ForceUnixPaths = false;
this->ToolSupportsColor = true;
+ this->UseLinkScript = false;
}
void cmGlobalNMakeMakefileGenerator
diff --git a/Source/cmGlobalUnixMakefileGenerator3.cxx b/Source/cmGlobalUnixMakefileGenerator3.cxx
index 7c506ea..df34fa3 100644
--- a/Source/cmGlobalUnixMakefileGenerator3.cxx
+++ b/Source/cmGlobalUnixMakefileGenerator3.cxx
@@ -20,6 +20,8 @@
#include "cmMakefile.h"
#include "cmake.h"
#include "cmGeneratedFileStream.h"
+#include "cmSourceFile.h"
+#include "cmTarget.h"
cmGlobalUnixMakefileGenerator3::cmGlobalUnixMakefileGenerator3()
{
@@ -27,6 +29,13 @@ cmGlobalUnixMakefileGenerator3::cmGlobalUnixMakefileGenerator3()
this->ForceUnixPaths = true;
this->FindMakeProgramFile = "CMakeUnixFindMake.cmake";
this->ToolSupportsColor = true;
+ this->NumberOfSourceFiles = 0;
+ this->NumberOfSourceFilesWritten = 0;
+#ifdef _WIN32
+ this->UseLinkScript = false;
+#else
+ this->UseLinkScript = true;
+#endif
}
void cmGlobalUnixMakefileGenerator3
@@ -110,8 +119,83 @@ cmGlobalUnixMakefileGenerator3
}
//----------------------------------------------------------------------------
+int cmGlobalUnixMakefileGenerator3::ShouldAddProgressRule()
+{
+ // add progress to 100 source files
+ if (this->NumberOfSourceFiles &&
+ (((this->NumberOfSourceFilesWritten + 1)*100)/this->NumberOfSourceFiles)
+ -(this->NumberOfSourceFilesWritten*100)/this->NumberOfSourceFiles)
+ {
+ this->NumberOfSourceFilesWritten++;
+ return (this->NumberOfSourceFilesWritten*100)/this->NumberOfSourceFiles;
+ }
+ this->NumberOfSourceFilesWritten++;
+ return 0;
+}
+
+int cmGlobalUnixMakefileGenerator3::
+GetNumberOfCompilableSourceFilesForTarget(cmTarget &tgt)
+{
+ std::map<cmStdString, int >::iterator tgtI =
+ this->TargetSourceFileCount.find(tgt.GetName());
+ if (tgtI != this->TargetSourceFileCount.end())
+ {
+ return tgtI->second;
+ }
+
+ int result = 0;
+
+ if((tgt.GetType() == cmTarget::EXECUTABLE) ||
+ (tgt.GetType() == cmTarget::STATIC_LIBRARY) ||
+ (tgt.GetType() == cmTarget::SHARED_LIBRARY) ||
+ (tgt.GetType() == cmTarget::MODULE_LIBRARY) )
+ {
+ std::vector<cmSourceFile*>& sources = tgt.GetSourceFiles();
+ for(std::vector<cmSourceFile*>::iterator source = sources.begin();
+ source != sources.end(); ++source)
+ {
+ if(!(*source)->GetPropertyAsBool("HEADER_FILE_ONLY") &&
+ !(*source)->GetCustomCommand())
+ {
+ if(!this->IgnoreFile((*source)->GetSourceExtension().c_str()))
+ {
+ const char* lang =
+ static_cast<cmLocalUnixMakefileGenerator3 *>
+ (tgt.GetMakefile()->GetLocalGenerator())
+ ->GetSourceFileLanguage(**source);
+ if(lang)
+ {
+ result++;
+ }
+ }
+ }
+ }
+ }
+ this->TargetSourceFileCount[tgt.GetName()] = result;
+ return result;
+}
+
+
+//----------------------------------------------------------------------------
void cmGlobalUnixMakefileGenerator3::Generate()
{
+ // initialize progress
+ this->NumberOfSourceFiles = 0;
+ unsigned int i;
+ for (i = 0; i < this->LocalGenerators.size(); ++i)
+ {
+ // for all of out targets
+ for (cmTargets::iterator l =
+ this->LocalGenerators[i]->GetMakefile()->GetTargets().begin();
+ l != this->LocalGenerators[i]->GetMakefile()->GetTargets().end();
+ l++)
+ {
+ this->NumberOfSourceFiles +=
+ this->GetNumberOfCompilableSourceFilesForTarget(l->second);
+ }
+ }
+ this->NumberOfSourceFilesWritten = 0;
+
// first do superclass method
this->cmGlobalGenerator::Generate();
@@ -127,7 +211,8 @@ void cmGlobalUnixMakefileGenerator3::WriteMainMakefile2()
// see if the build system must be regenerated.
std::string makefileName =
this->GetCMakeInstance()->GetHomeOutputDirectory();
- makefileName += "/CMakeFiles/Makefile2";
+ makefileName += cmake::GetCMakeFilesDirectory();
+ makefileName += "/Makefile2";
cmGeneratedFileStream makefileStream(makefileName.c_str());
if(!makefileStream)
{
@@ -214,7 +299,8 @@ void cmGlobalUnixMakefileGenerator3::WriteMainCMakefile()
// see if the build system must be regenerated.
std::string cmakefileName =
this->GetCMakeInstance()->GetHomeOutputDirectory();
- cmakefileName += "/CMakeFiles/Makefile.cmake";
+ cmakefileName += cmake::GetCMakeFilesDirectory();
+ cmakefileName += "/Makefile.cmake";
cmGeneratedFileStream cmakefileStream(cmakefileName.c_str());
if(!cmakefileStream)
{
@@ -281,7 +367,8 @@ void cmGlobalUnixMakefileGenerator3::WriteMainCMakefile()
// Build the path to the cache check file.
std::string check = this->GetCMakeInstance()->GetHomeOutputDirectory();
- check += "/CMakeFiles/cmake.check_cache";
+ check += cmake::GetCMakeFilesDirectory();
+ check += "/cmake.check_cache";
// Set the corresponding makefile in the cmake file.
cmakefileStream
@@ -301,7 +388,8 @@ void cmGlobalUnixMakefileGenerator3::WriteMainCMakefile()
lg =
static_cast<cmLocalUnixMakefileGenerator3 *>(this->LocalGenerators[i]);
tmpStr = lg->GetMakefile()->GetStartOutputDirectory();
- tmpStr += "/CMakeFiles/CMakeDirectoryInformation.cmake";
+ tmpStr += cmake::GetCMakeFilesDirectory();
+ tmpStr += "/CMakeDirectoryInformation.cmake";
cmakefileStream << " \"" <<
lg->Convert(tmpStr.c_str(),cmLocalGenerator::HOME_OUTPUT).c_str()
<< "\"\n";
@@ -518,7 +606,7 @@ cmGlobalUnixMakefileGenerator3
std::string cmGlobalUnixMakefileGenerator3
::GenerateBuildCommand(const char* makeProgram, const char *projectName,
const char* additionalOptions, const char *targetName,
- const char* config, bool ignoreErrors)
+ const char* config, bool ignoreErrors, bool fast)
{
// Project name and config are not used yet.
(void)projectName;
@@ -565,7 +653,10 @@ std::string cmGlobalUnixMakefileGenerator3
lg->SetupPathConversions();
makeCommand += " \"";
std::string tname = targetName;
+ if(fast)
+ {
tname += "/fast";
+ }
tname = lg->Convert(tname.c_str(),cmLocalGenerator::HOME_OUTPUT,
cmLocalGenerator::MAKEFILE);
tname = lg->ConvertToMakeTarget(tname.c_str());
@@ -601,18 +692,20 @@ cmGlobalUnixMakefileGenerator3
cmTargets& targets = lg->GetMakefile()->GetTargets();
for(cmTargets::iterator t = targets.begin(); t != targets.end(); ++t)
{
- if((t->second.GetType() == cmTarget::EXECUTABLE) ||
- (t->second.GetType() == cmTarget::STATIC_LIBRARY) ||
- (t->second.GetType() == cmTarget::SHARED_LIBRARY) ||
- (t->second.GetType() == cmTarget::MODULE_LIBRARY) ||
- (t->second.GetType() == cmTarget::UTILITY))
- {
// Don't emit the same rule twice (e.g. two targets with the same
// simple name)
if(t->second.GetName() &&
strlen(t->second.GetName()) &&
emitted.insert(t->second.GetName()).second)
{
+ // Handle user targets here. Global targets are handled in
+ // the local generator on a per-directory basis.
+ if((t->second.GetType() == cmTarget::EXECUTABLE) ||
+ (t->second.GetType() == cmTarget::STATIC_LIBRARY) ||
+ (t->second.GetType() == cmTarget::SHARED_LIBRARY) ||
+ (t->second.GetType() == cmTarget::MODULE_LIBRARY) ||
+ (t->second.GetType() == cmTarget::UTILITY))
+ {
// Add a rule to build the target by name.
lg->WriteDivider(ruleFileStream);
ruleFileStream
@@ -621,8 +714,10 @@ cmGlobalUnixMakefileGenerator3
// Write the rule.
commands.clear();
+ std::string tmp = cmake::GetCMakeFilesDirectoryPostSlash();
+ tmp += "Makefile2";
commands.push_back(lg->GetRecursiveMakeCall
- ("CMakeFiles/Makefile2",t->second.GetName()));
+ (tmp.c_str(),t->second.GetName()));
depends.clear();
depends.push_back("cmake_check_build_system");
lg->WriteMakeRule(ruleFileStream,
@@ -647,17 +742,6 @@ cmGlobalUnixMakefileGenerator3
localName.c_str(), depends, commands, true);
}
}
- else
- {
- // Add a fast rule to build the target
- depends.clear();
- commands.clear();
- std::string localName = t->second.GetName();
- depends.push_back(localName);
- localName += "/fast";
- lg->WriteMakeRule(ruleFileStream, "fast build rule for target.",
- localName.c_str(), depends, commands, true);
- }
}
}
}
@@ -675,6 +759,7 @@ cmGlobalUnixMakefileGenerator3
std::string localName;
std::string makeTargetName;
+
// write the directory level rules for this local gen
this->WriteDirectoryRules2(ruleFileStream,lg);
@@ -731,6 +816,30 @@ cmGlobalUnixMakefileGenerator3
// Write the rule.
localName += "/all";
depends.clear();
+
+ std::string progressDir =
+ lg->GetMakefile()->GetHomeOutputDirectory();
+ progressDir += cmake::GetCMakeFilesDirectory();
+ {
+ cmOStringStream progCmd;
+ progCmd << "$(CMAKE_COMMAND) -E cmake_progress_report ";
+ // all target counts
+ progCmd << lg->Convert(progressDir.c_str(),
+ cmLocalGenerator::FULL,
+ cmLocalGenerator::SHELL);
+ progCmd << " ";
+ std::vector<int> &progFiles = lg->ProgressFiles[t->first];
+ for (std::vector<int>::iterator i = progFiles.begin();
+ i != progFiles.end(); ++i)
+ {
+ progCmd << " " << *i;
+ }
+ commands.push_back(progCmd.str());
+ }
+ progressDir = "Building target ";
+ progressDir += t->first;
+ lg->AppendEcho(commands,progressDir.c_str());
+
this->AppendGlobalTargetDepends(depends,t->second);
lg->WriteMakeRule(ruleFileStream, "All Build rule for target.",
localName.c_str(), depends, commands, true);
@@ -747,8 +856,35 @@ cmGlobalUnixMakefileGenerator3
// Write the rule.
commands.clear();
+ progressDir = lg->GetMakefile()->GetHomeOutputDirectory();
+ progressDir += cmake::GetCMakeFilesDirectory();
+
+ {
+ // TODO: Convert the total progress count to a make variable.
+ cmOStringStream progCmd;
+ progCmd << "$(CMAKE_COMMAND) -E cmake_progress_start ";
+ // # in target
+ progCmd << lg->Convert(progressDir.c_str(),
+ cmLocalGenerator::FULL,
+ cmLocalGenerator::SHELL);
+ //
+ progCmd << " "
+ << this->GetTargetTotalNumberOfProgressFiles(t->second);
+ commands.push_back(progCmd.str());
+ }
+ std::string tmp = cmake::GetCMakeFilesDirectoryPostSlash();
+ tmp += "Makefile2";
commands.push_back(lg->GetRecursiveMakeCall
- ("CMakeFiles/Makefile2",localName.c_str()));
+ (tmp.c_str(),localName.c_str()));
+ {
+ cmOStringStream progCmd;
+ progCmd << "$(CMAKE_COMMAND) -E cmake_progress_start "; // # 0
+ progCmd << lg->Convert(progressDir.c_str(),
+ cmLocalGenerator::FULL,
+ cmLocalGenerator::SHELL);
+ progCmd << " 0";
+ commands.push_back(progCmd.str());
+ }
depends.clear();
depends.push_back("cmake_check_build_system");
localName = lg->GetRelativeTargetDirectory(t->second);
@@ -773,7 +909,6 @@ cmGlobalUnixMakefileGenerator3
commands.clear();
commands.push_back(lg->GetRecursiveMakeCall
(makefileName.c_str(), localName.c_str()));
- this->AppendGlobalTargetDepends(depends,t->second);
lg->WriteMakeRule(ruleFileStream,
"Pre-install relink rule for target.",
localName.c_str(), depends, commands, true);
@@ -803,6 +938,101 @@ cmGlobalUnixMakefileGenerator3
}
}
+//----------------------------------------------------------------------------
+int cmGlobalUnixMakefileGenerator3
+::GetTargetTotalNumberOfProgressFiles(cmTarget& target)
+{
+ cmLocalUnixMakefileGenerator3 *lg =
+ static_cast<cmLocalUnixMakefileGenerator3 *>
+ (target.GetMakefile()->GetLocalGenerator());
+ int result = static_cast<int>(lg->ProgressFiles[target.GetName()].size());
+ std::vector<cmTarget *>& depends = this->GetTargetDepends(target);
+
+ std::vector<cmTarget *>::iterator i;
+ for (i = depends.begin(); i != depends.end(); ++i)
+ {
+ result += this->GetTargetTotalNumberOfProgressFiles(**i);
+ }
+
+ return result;
+}
+
+
+//----------------------------------------------------------------------------
+std::vector<cmTarget *>& cmGlobalUnixMakefileGenerator3
+::GetTargetDepends(cmTarget& target)
+{
+ // if the depends are already in the map then return
+ std::map<cmStdString, std::vector<cmTarget *> >::iterator tgtI =
+ this->TargetDependencies.find(target.GetName());
+ if (tgtI != this->TargetDependencies.end())
+ {
+ return tgtI->second;
+ }
+
+ // A target should not depend on itself.
+ std::set<cmStdString> emitted;
+ emitted.insert(target.GetName());
+
+ // the vector of results
+ std::vector<cmTarget *>& result =
+ this->TargetDependencies[target.GetName()];
+
+ // Loop over all library dependencies but not for static libs
+ if (target.GetType() != cmTarget::STATIC_LIBRARY)
+ {
+ const cmTarget::LinkLibraryVectorType& tlibs = target.GetLinkLibraries();
+ for(cmTarget::LinkLibraryVectorType::const_iterator lib = tlibs.begin();
+ lib != tlibs.end(); ++lib)
+ {
+ // Don't emit the same library twice for this target.
+ if(emitted.insert(lib->first).second)
+ {
+ cmTarget *target2 =
+ target.GetMakefile()->FindTarget(lib->first.c_str());
+
+ // search each local generator until a match is found
+ if (!target2)
+ {
+ target2 = this->FindTarget(0,lib->first.c_str());
+ }
+
+ // if a match was found then ...
+ if (target2)
+ {
+ // Add this dependency.
+ result.push_back(target2);
+ }
+ }
+ }
+ }
+
+ // Loop over all utility dependencies.
+ const std::set<cmStdString>& tutils = target.GetUtilities();
+ for(std::set<cmStdString>::const_iterator util = tutils.begin();
+ util != tutils.end(); ++util)
+ {
+ // Don't emit the same utility twice for this target.
+ if(emitted.insert(*util).second)
+ {
+ cmTarget *target2 = target.GetMakefile()->FindTarget(util->c_str());
+
+ // search each local generator until a match is found
+ if (!target2)
+ {
+ target2 = this->FindTarget(0,util->c_str());
+ }
+
+ // if a match was found then ...
+ if (target2)
+ {
+ // Add this dependency.
+ result.push_back(target2);
+ }
+ }
+ }
+ return result;
+}
//----------------------------------------------------------------------------
void
diff --git a/Source/cmGlobalUnixMakefileGenerator3.h b/Source/cmGlobalUnixMakefileGenerator3.h
index 1b7733d..47557b9 100644
--- a/Source/cmGlobalUnixMakefileGenerator3.h
+++ b/Source/cmGlobalUnixMakefileGenerator3.h
@@ -121,7 +121,16 @@ public:
(const char* makeProgram,
const char *projectName, const char* additionalOptions,
const char *targetName,
- const char* config, bool ignoreErrors);
+ const char* config, bool ignoreErrors, bool fast);
+
+ // returns true if a progress rule should be added
+ int ShouldAddProgressRule();
+ int GetNumberOfCompilableSourceFilesForTarget(cmTarget &tgt);
+ int GetTargetTotalNumberOfProgressFiles(cmTarget& target);
+ int GetNumberOfSourceFiles() { return this->NumberOfSourceFiles; };
+
+ // what targets does the specified target depend on
+ std::vector<cmTarget *>& GetTargetDepends(cmTarget& target);
protected:
void WriteMainMakefile2();
@@ -173,6 +182,12 @@ protected:
typedef std::map<cmStdString, cmStdString> MultipleOutputPairsType;
MultipleOutputPairsType MultipleOutputPairs;
+
+ int NumberOfSourceFiles;
+ int NumberOfSourceFilesWritten;
+
+ std::map<cmStdString, std::vector<cmTarget *> > TargetDependencies;
+ std::map<cmStdString, int > TargetSourceFileCount;
};
#endif
diff --git a/Source/cmGlobalVisualStudio6Generator.cxx b/Source/cmGlobalVisualStudio6Generator.cxx
index f076efb..d2644d0 100644
--- a/Source/cmGlobalVisualStudio6Generator.cxx
+++ b/Source/cmGlobalVisualStudio6Generator.cxx
@@ -73,7 +73,8 @@ std::string cmGlobalVisualStudio6Generator
const char* additionalOptions,
const char *targetName,
const char* config,
- bool ignoreErrors)
+ bool ignoreErrors,
+ bool)
{
// Ingoring errors is not implemented in visual studio 6
(void) ignoreErrors;
diff --git a/Source/cmGlobalVisualStudio6Generator.h b/Source/cmGlobalVisualStudio6Generator.h
index 07456a2..792e7b1 100644
--- a/Source/cmGlobalVisualStudio6Generator.h
+++ b/Source/cmGlobalVisualStudio6Generator.h
@@ -60,7 +60,8 @@ public:
const char* additionalOptions,
const char *targetName,
const char* config,
- bool ignoreErrors);
+ bool ignoreErrors,
+ bool fast);
/**
* Generate the all required files for building this project/tree. This
diff --git a/Source/cmGlobalVisualStudio7Generator.cxx b/Source/cmGlobalVisualStudio7Generator.cxx
index 791daea..7bc0654 100644
--- a/Source/cmGlobalVisualStudio7Generator.cxx
+++ b/Source/cmGlobalVisualStudio7Generator.cxx
@@ -71,7 +71,7 @@ std::string cmGlobalVisualStudio7Generator
::GenerateBuildCommand(const char* makeProgram,
const char *projectName,
const char* additionalOptions, const char *targetName,
- const char* config, bool ignoreErrors)
+ const char* config, bool ignoreErrors, bool)
{
// Ingoring errors is not implemented in visual studio 6
(void) ignoreErrors;
diff --git a/Source/cmGlobalVisualStudio7Generator.h b/Source/cmGlobalVisualStudio7Generator.h
index 5b14449..9ff97da 100644
--- a/Source/cmGlobalVisualStudio7Generator.h
+++ b/Source/cmGlobalVisualStudio7Generator.h
@@ -60,7 +60,8 @@ public:
const char* additionalOptions,
const char *targetName,
const char* config,
- bool ignoreErrors);
+ bool ignoreErrors,
+ bool fast);
/**
* Generate the all required files for building this project/tree. This
diff --git a/Source/cmGlobalXCodeGenerator.cxx b/Source/cmGlobalXCodeGenerator.cxx
index d48723f..c7c50cd 100644
--- a/Source/cmGlobalXCodeGenerator.cxx
+++ b/Source/cmGlobalXCodeGenerator.cxx
@@ -133,7 +133,8 @@ std::string cmGlobalXCodeGenerator
const char* additionalOptions,
const char *targetName,
const char* config,
- bool ignoreErrors)
+ bool ignoreErrors,
+ bool)
{
// Config is not used yet
(void) ignoreErrors;
@@ -365,7 +366,8 @@ void cmGlobalXCodeGenerator::CreateReRunCMakeFile(cmLocalGenerator* root)
(this->CurrentReRunCMakeMakefile.c_str());
makefileStream.SetCopyIfDifferent(true);
makefileStream << "# Generated by CMake, DO NOT EDIT\n";
- makefileStream << "CMakeFiles/cmake.check_cache: ";
+ makefileStream << cmake::GetCMakeFilesDirectoryPostSlash();
+ makefileStream << "cmake.check_cache: ";
for(std::vector<std::string>::const_iterator i = lfiles.begin();
i != lfiles.end(); ++i)
{
@@ -946,8 +948,9 @@ cmGlobalXCodeGenerator::AddCommandsToBuildPhase(cmXCodeObject* buildphase,
}
else
{
- char c = '1' + count++;
- tname[&cc] = std::string(target.GetName()) + c;
+ cmOStringStream str;
+ str << "_buildpart_" << count++ ;
+ tname[&cc] = std::string(target.GetName()) + str.str();
makefileStream << "\\\n\t" << tname[&cc];
}
}
diff --git a/Source/cmGlobalXCodeGenerator.h b/Source/cmGlobalXCodeGenerator.h
index 326bfd0..991a223 100644
--- a/Source/cmGlobalXCodeGenerator.h
+++ b/Source/cmGlobalXCodeGenerator.h
@@ -63,7 +63,8 @@ public:
const char* additionalOptions,
const char *targetName,
const char* config,
- bool ignoreErrors);
+ bool ignoreErrors,
+ bool fast);
/**
* Generate the all required files for building this project/tree. This
diff --git a/Source/cmIfCommand.cxx b/Source/cmIfCommand.cxx
index 4e7c777..5ee5d90 100644
--- a/Source/cmIfCommand.cxx
+++ b/Source/cmIfCommand.cxx
@@ -22,23 +22,19 @@
bool cmIfFunctionBlocker::
IsFunctionBlocked(const cmListFileFunction& lff, cmMakefile &mf)
{
- const char* name = lff.Name.c_str();
- const std::vector<cmListFileArgument>& args = lff.Arguments;
// always let if statements through
- if (cmSystemTools::LowerCase(lff.Name) == "if")
+ if (!cmSystemTools::Strucmp(lff.Name.c_str(),"if"))
{
return false;
}
// watch for our ELSE or ENDIF
- if (cmSystemTools::LowerCase(lff.Name) == "else" ||
- cmSystemTools::LowerCase(lff.Name) == "endif")
- {
- if (args == this->Args)
+ if (!cmSystemTools::Strucmp(lff.Name.c_str(),"else") ||
+ !cmSystemTools::Strucmp(lff.Name.c_str(),"endif"))
{
// if it was an else statement then we should change state
// and block this Else Command
- if (cmSystemTools::LowerCase(lff.Name) == "else")
+ if (!cmSystemTools::Strucmp(lff.Name.c_str(),"else"))
{
this->IsBlocking = !this->IsBlocking;
return true;
@@ -48,39 +44,22 @@ IsFunctionBlocked(const cmListFileFunction& lff, cmMakefile &mf)
mf.RemoveFunctionBlocker(lff);
return true;
}
- else if(args.empty())
- {
- std::string err = "Empty arguments for ";
- err += name;
- err += ". Did you mean ";
- err += name;
- err += "( ";
- for(std::vector<cmListFileArgument>::const_iterator a =
- this->Args.begin();
- a != this->Args.end();++a)
- {
- err += (a->Quoted?"\"":"");
- err += a->Value;
- err += (a->Quoted?"\"":"");
- err += " ";
- }
- err += ")?";
- cmSystemTools::Error(err.c_str());
- }
- }
+
return this->IsBlocking;
}
bool cmIfFunctionBlocker::ShouldRemove(const cmListFileFunction& lff,
- cmMakefile&)
+ cmMakefile& mf)
{
- if (cmSystemTools::LowerCase(lff.Name) == "endif")
+ if (!cmSystemTools::Strucmp(lff.Name.c_str(),"endif"))
{
- if (lff.Arguments == this->Args)
+ if (mf.IsOn("CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS")
+ || lff.Arguments == this->Args)
{
return true;
}
}
+
return false;
}
diff --git a/Source/cmIfCommand.h b/Source/cmIfCommand.h
index a8a7b81..e49c21f 100644
--- a/Source/cmIfCommand.h
+++ b/Source/cmIfCommand.h
@@ -123,12 +123,14 @@ public:
" IF(variable1 OR variable2)\n"
"True if either variable would be considered true individually.\n"
" IF(COMMAND command-name)\n"
- "True if the given name is a file or directory.\n"
+ "True if the given name is a command that can be invoked.\n"
" IF(EXISTS file-name)\n"
" IF(EXISTS directory-name)\n"
- "True if the given name is a directory.\n"
+ "True if the named file or directory exists. "
+ "Behavior is well-defined only for full paths.\n"
" IF(IS_DIRECTORY directory-name)\n"
- "True if the named file or directory exists.\n"
+ "True if the given name is a directory. "
+ "Behavior is well-defined only for full paths.\n"
" IF(variable MATCHES regex)\n"
" IF(string MATCHES regex)\n"
"True if the given string or variable's value matches the given "
diff --git a/Source/cmInstallTargetGenerator.cxx b/Source/cmInstallTargetGenerator.cxx
index b7be4cb..860ecad 100644
--- a/Source/cmInstallTargetGenerator.cxx
+++ b/Source/cmInstallTargetGenerator.cxx
@@ -20,6 +20,7 @@
#include "cmLocalGenerator.h"
#include "cmMakefile.h"
#include "cmTarget.h"
+#include "cmake.h"
//----------------------------------------------------------------------------
cmInstallTargetGenerator
@@ -48,7 +49,8 @@ void cmInstallTargetGenerator::GenerateScript(std::ostream& os)
if(this->Target->NeedRelinkBeforeInstall())
{
fromDir = this->Target->GetMakefile()->GetStartOutputDirectory();
- fromDir += "/CMakeFiles/CMakeRelink.dir/";
+ fromDir += cmake::GetCMakeFilesDirectory();
+ fromDir += "/CMakeRelink.dir/";
}
else
{
@@ -361,7 +363,7 @@ void cmInstallTargetGenerator
{
os << "\n -change \"" << i->first << "\" \"" << i->second << "\"";
}
- os << "\n \"" << destination << "/"
+ os << "\n \"$ENV{DESTDIR}" << destination << "/"
<< this->GetScriptReference(this->Target, "REMAPPED", true) << "\")\n";
os << "ENDIF(" << component_test << ")\n";
}
diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx
index 8021765..b9675f9 100644
--- a/Source/cmLocalGenerator.cxx
+++ b/Source/cmLocalGenerator.cxx
@@ -52,7 +52,7 @@ void cmLocalGenerator::Configure()
{
// make sure the CMakeFiles dir is there
std::string filesDir = this->Makefile->GetStartOutputDirectory();
- filesDir += "/CMakeFiles";
+ filesDir += cmake::GetCMakeFilesDirectory();
cmSystemTools::MakeDirectory(filesDir.c_str());
// find & read the list file
@@ -1418,6 +1418,9 @@ void cmLocalGenerator::OutputLinkLibraries(std::ostream& fout,
outputRuntime && tgt.HaveInstallTreeRPATH() && linking_for_install;
bool use_build_rpath =
outputRuntime && tgt.HaveBuildTreeRPATH() && !linking_for_install;
+ bool use_link_rpath =
+ outputRuntime && linking_for_install &&
+ tgt.GetPropertyAsBool("INSTALL_RPATH_USE_LINK_PATH");
// Construct the RPATH.
std::vector<std::string> runtimeDirs;
@@ -1454,13 +1457,29 @@ void cmLocalGenerator::OutputLinkLibraries(std::ostream& fout,
&& libDir->find("${") == std::string::npos)
{
linkLibs += libPathFlag;
+ linkLibs += fullLibPath;
+ linkLibs += " ";
+
+ // Put this directory in the rpath if using build-tree rpath
+ // support or if using the link path as an rpath.
if(use_build_rpath)
{
- runtimeDirs.push_back( fullLibPath );
+ runtimeDirs.push_back(fullLibPath);
+ }
+ else if(use_link_rpath)
+ {
+ // Do not add any path inside the source or build tree.
+ const char* topSourceDir = this->Makefile->GetHomeDirectory();
+ const char* topBinaryDir = this->Makefile->GetHomeOutputDirectory();
+ if(!cmSystemTools::ComparePath(libDir->c_str(), topSourceDir) &&
+ !cmSystemTools::ComparePath(libDir->c_str(), topBinaryDir) &&
+ !cmSystemTools::IsSubDirectory(libDir->c_str(), topSourceDir) &&
+ !cmSystemTools::IsSubDirectory(libDir->c_str(), topBinaryDir))
+ {
+ runtimeDirs.push_back(fullLibPath);
+ }
}
}
- linkLibs += fullLibPath;
- linkLibs += " ";
}
}
diff --git a/Source/cmLocalGenerator.h b/Source/cmLocalGenerator.h
index ccc9bef..6e4c60e 100644
--- a/Source/cmLocalGenerator.h
+++ b/Source/cmLocalGenerator.h
@@ -160,8 +160,7 @@ public:
bool /* clear */) {};
/** Called from command-line hook to scan dependencies. */
- virtual bool ScanDependencies(std::vector<std::string> const& /* args */)
- {return true;};
+ virtual bool ScanDependencies(const char* /* tgtInfo */) { return true; }
/** Compute the list of link libraries and directories for the given
target and configuration. */
diff --git a/Source/cmLocalUnixMakefileGenerator3.cxx b/Source/cmLocalUnixMakefileGenerator3.cxx
index 95bf9aa..8f72567 100644
--- a/Source/cmLocalUnixMakefileGenerator3.cxx
+++ b/Source/cmLocalUnixMakefileGenerator3.cxx
@@ -48,6 +48,7 @@ cmLocalUnixMakefileGenerator3::cmLocalUnixMakefileGenerator3()
this->DefineWindowsNULL = false;
this->UnixCD = true;
this->ForceVerboseMakefiles=false;
+ this->ColorMakefile = false;
}
//----------------------------------------------------------------------------
@@ -75,6 +76,10 @@ void cmLocalUnixMakefileGenerator3::Generate()
// Setup our configuration variables for this directory.
this->ConfigureOutputPaths();
+ // Record whether color makefiles are enabled to avoid checking many
+ // times later.
+ this->ColorMakefile = this->Makefile->IsOn("CMAKE_COLOR_MAKEFILE");
+
// Generate the rule files for each target.
cmTargets& targets = this->Makefile->GetTargets();
std::string empty;
@@ -275,8 +280,10 @@ void cmLocalUnixMakefileGenerator3
depends.clear();
// Build the target for this pass.
+ std::string tmp = cmake::GetCMakeFilesDirectoryPostSlash();
+ tmp += "Makefile2";
commands.push_back(this->GetRecursiveMakeCall
- ("CMakeFiles/Makefile2",localName.c_str()));
+ (tmp.c_str(),localName.c_str()));
this->CreateCDCommand(commands,
this->Makefile->GetHomeOutputDirectory(),
this->Makefile->GetStartOutputDirectory());
@@ -291,6 +298,24 @@ void cmLocalUnixMakefileGenerator3
this->WriteMakeRule(ruleFileStream, "Convenience name for target.",
t->second.GetName(), depends, commands, true);
}
+
+ // Add a fast rule to build the target
+ std::string makefileName = this->GetRelativeTargetDirectory(t->second);
+ makefileName += "/build.make";
+ std::string makeTargetName =
+ this->GetRelativeTargetDirectory(t->second);
+ makeTargetName += "/build";
+ localName = t->second.GetName();
+ localName += "/fast";
+ depends.clear();
+ commands.clear();
+ commands.push_back(this->GetRecursiveMakeCall
+ (makefileName.c_str(), makeTargetName.c_str()));
+ this->CreateCDCommand(commands,
+ this->Makefile->GetHomeOutputDirectory(),
+ this->Makefile->GetStartOutputDirectory());
+ this->WriteMakeRule(ruleFileStream, "fast build rule for target.",
+ localName.c_str(), depends, commands, true);
}
}
}
@@ -299,7 +324,8 @@ void cmLocalUnixMakefileGenerator3
void cmLocalUnixMakefileGenerator3::WriteDirectoryInformationFile()
{
std::string infoFileName = this->Makefile->GetStartOutputDirectory();
- infoFileName += "/CMakeFiles/CMakeDirectoryInformation.cmake";
+ infoFileName += cmake::GetCMakeFilesDirectory();
+ infoFileName += "/CMakeDirectoryInformation.cmake";
// Open the output file.
cmGeneratedFileStream infoFileStream(infoFileName.c_str());
@@ -630,7 +656,8 @@ void cmLocalUnixMakefileGenerator3
// the --check-build-system flag.
{
// Build command to run CMake to check if anything needs regenerating.
- std::string cmakefileName = "CMakeFiles/Makefile.cmake";
+ std::string cmakefileName = cmake::GetCMakeFilesDirectoryPostSlash();
+ cmakefileName += "Makefile.cmake";
std::string runRule =
"$(CMAKE_COMMAND) -H$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR)";
runRule += " --check-build-system ";
@@ -761,9 +788,16 @@ cmLocalUnixMakefileGenerator3
::AppendCustomCommand(std::vector<std::string>& commands,
const cmCustomCommand& cc)
{
- std::vector<std::string> commands1;
+ // if the command specified a working directory use it.
+ const char* dir = this->Makefile->GetStartOutputDirectory();
+ const char* workingDir = cc.GetWorkingDirectory();
+ if(workingDir)
+ {
+ dir = workingDir;
+ }
// Add each command line to the set of commands.
+ std::vector<std::string> commands1;
for(cmCustomCommandLines::const_iterator cl = cc.GetCommandLines().begin();
cl != cc.GetCommandLines().end(); ++cl)
{
@@ -773,7 +807,12 @@ cmLocalUnixMakefileGenerator3
if (cmd.size())
{
cmSystemTools::ReplaceString(cmd, "/./", "/");
+ // Convert the command to a relative path only if the current
+ // working directory will be the start-output directory.
+ if(!workingDir)
+ {
cmd = this->Convert(cmd.c_str(),START_OUTPUT);
+ }
if(cmd.find("/") == cmd.npos &&
commandLine[0].find("/") != cmd.npos)
{
@@ -799,16 +838,11 @@ cmLocalUnixMakefileGenerator3
}
}
- // push back the custom commands
- const char* dir = this->Makefile->GetStartOutputDirectory();
- // if the command specified a working directory use it.
- if(cc.GetWorkingDirectory())
- {
- dir = cc.GetWorkingDirectory();
- }
+ // Setup the proper working directory for the commands.
this->CreateCDCommand(commands1, dir,
this->Makefile->GetHomeOutputDirectory());
+ // push back the custom commands
commands.insert(commands.end(), commands1.begin(), commands1.end());
}
@@ -860,8 +894,7 @@ cmLocalUnixMakefileGenerator3::AppendEcho(std::vector<std::string>& commands,
// Choose the color for the text.
std::string color_name;
#ifdef CMAKE_BUILD_WITH_CMAKE
- if(this->GlobalGenerator->GetToolSupportsColor() &&
- this->Makefile->IsOn("CMAKE_COLOR_MAKEFILE"))
+ if(this->GlobalGenerator->GetToolSupportsColor() && this->ColorMakefile)
{
// See cmake::ExecuteEchoColor in cmake.cxx for these options.
// This color set is readable on both black and white backgrounds.
@@ -1127,31 +1160,17 @@ cmLocalUnixMakefileGenerator3
}
//----------------------------------------------------------------------------
-bool
-cmLocalUnixMakefileGenerator3
-::ScanDependencies(std::vector<std::string> const& args)
+bool cmLocalUnixMakefileGenerator3::ScanDependencies(const char* tgtInfo)
{
- // Format of arguments is: $(CMAKE_COMMAND), cmake_depends,
- // GeneratorName, home_output_dir, start_output_dir, info file The
- // caller has ensured that all required arguments exist.
-
// The info file for this target
- std::string const& infoFile = args[5];
+ std::string const& infoFile = tgtInfo;
// Read the directory information file.
- cmake cm;
- cmGlobalGenerator gg;
- gg.SetCMakeInstance(&cm);
- std::auto_ptr<cmLocalGenerator> lg(gg.CreateLocalGenerator());
- lg->SetGlobalGenerator(&gg);
- cmMakefile* mf = lg->GetMakefile();
- mf->SetHomeOutputDirectory(args[3].c_str());
- mf->SetStartOutputDirectory(args[4].c_str());
- lg->SetupPathConversions();
-
+ cmMakefile* mf = this->Makefile;
bool haveDirectoryInfo = false;
- std::string dirInfoFile = args[4];
- dirInfoFile += "/CMakeFiles/CMakeDirectoryInformation.cmake";
+ std::string dirInfoFile = this->Makefile->GetStartOutputDirectory();
+ dirInfoFile += cmake::GetCMakeFilesDirectory();
+ dirInfoFile += "/CMakeDirectoryInformation.cmake";
if(mf->ReadListFile(0, dirInfoFile.c_str()) &&
!cmSystemTools::GetErrorOccuredFlag())
{
@@ -1283,7 +1302,7 @@ cmLocalUnixMakefileGenerator3
includeRegexScan.c_str(),
includeRegexComplain.c_str(),
generatedFiles, includeCacheFileName);
- scanner->SetHomeOutputDirectory(mf->GetHomeOutputDirectory());
+ scanner->SetLocalGenerator(this);
}
#ifdef CMAKE_BUILD_WITH_CMAKE
else if(lang == "Fortran")
@@ -1313,7 +1332,7 @@ cmLocalUnixMakefileGenerator3
++si;
// make sure the object file is relative to home output
std::string obj = *si;
- obj = lg->Convert(obj.c_str(),HOME_OUTPUT,MAKEFILE);
+ obj = this->Convert(obj.c_str(),HOME_OUTPUT,MAKEFILE);
scanner->Write(src.c_str(),obj.c_str(),
ruleFileStream, internalRuleFileStream);
}
@@ -1381,7 +1400,7 @@ void cmLocalUnixMakefileGenerator3
this->AppendEcho(commands, text,
cmLocalUnixMakefileGenerator3::EchoGlobal);
- // Utility targets store their rules in pre- and post-build commands.
+ // Global targets store their rules in pre- and post-build commands.
this->AppendCustomDepends(depends,
glIt->second.GetPreBuildCommands());
this->AppendCustomDepends(depends,
@@ -1390,8 +1409,27 @@ void cmLocalUnixMakefileGenerator3
glIt->second.GetPreBuildCommands());
this->AppendCustomCommands(commands,
glIt->second.GetPostBuildCommands());
+ std::string targetName = glIt->second.GetName();
this->WriteMakeRule(ruleFileStream, targetString.c_str(),
- glIt->first.c_str(), depends, commands, true);
+ targetName.c_str(), depends, commands, true);
+
+ // Provide a "/fast" version of the target.
+ depends.clear();
+ if(targetName == "install")
+ {
+ // Provide a fast install target that does not depend on all
+ // but has the same command.
+ depends.push_back("preinstall/fast");
+ }
+ else
+ {
+ // Just forward to the real target so at least it will work.
+ depends.push_back(targetName);
+ commands.clear();
+ }
+ targetName += "/fast";
+ this->WriteMakeRule(ruleFileStream, targetString.c_str(),
+ targetName.c_str(), depends, commands, true);
}
}
@@ -1408,11 +1446,45 @@ void cmLocalUnixMakefileGenerator3
depends.push_back("cmake_check_build_system");
- commands.push_back
- (this->GetRecursiveMakeCall("CMakeFiles/Makefile2",dir.c_str()));
+ std::string progressDir = this->Makefile->GetHomeOutputDirectory();
+ progressDir += cmake::GetCMakeFilesDirectory();
+ {
+ cmOStringStream progCmd;
+ progCmd << "$(CMAKE_COMMAND) -E cmake_progress_start "; // # src files
+ progCmd << this->Convert(progressDir.c_str(),
+ cmLocalGenerator::FULL,
+ cmLocalGenerator::SHELL);
+ cmGlobalUnixMakefileGenerator3 *gg =
+ static_cast<cmGlobalUnixMakefileGenerator3*>(this->GlobalGenerator);
+ int n = gg->GetNumberOfSourceFiles();
+ if(n > 100)
+ {
+ n = 100;
+ }
+ if (this->Parent)
+ {
+ n = 0;
+ }
+ progCmd << " " << n;
+ commands.push_back(progCmd.str());
+ }
+ std::string mf2Dir = cmake::GetCMakeFilesDirectoryPostSlash();
+ mf2Dir += "Makefile2";
+ commands.push_back(this->GetRecursiveMakeCall(mf2Dir.c_str(),
+ dir.c_str()));
this->CreateCDCommand(commands,
this->Makefile->GetHomeOutputDirectory(),
this->Makefile->GetStartOutputDirectory());
+ if (!this->Parent)
+ {
+ cmOStringStream progCmd;
+ progCmd << "$(CMAKE_COMMAND) -E cmake_progress_start "; // # 0
+ progCmd << this->Convert(progressDir.c_str(),
+ cmLocalGenerator::FULL,
+ cmLocalGenerator::SHELL);
+ progCmd << " 0";
+ commands.push_back(progCmd.str());
+ }
this->WriteMakeRule(ruleFileStream, "The main all target", "all",
depends, commands, true);
@@ -1422,8 +1494,8 @@ void cmLocalUnixMakefileGenerator3
dir = this->Convert(dir.c_str(),HOME_OUTPUT,MAKEFILE);
commands.clear();
depends.clear();
- commands.push_back
- (this->GetRecursiveMakeCall("CMakeFiles/Makefile2",dir.c_str()));
+ commands.push_back(this->GetRecursiveMakeCall(mf2Dir.c_str(),
+ dir.c_str()));
this->CreateCDCommand(commands,
this->Makefile->GetHomeOutputDirectory(),
this->Makefile->GetStartOutputDirectory());
@@ -1454,21 +1526,21 @@ void cmLocalUnixMakefileGenerator3
depends.push_back("cmake_check_build_system");
}
commands.push_back
- (this->GetRecursiveMakeCall("CMakeFiles/Makefile2", dir.c_str()));
+ (this->GetRecursiveMakeCall(mf2Dir.c_str(), dir.c_str()));
this->CreateCDCommand(commands,
this->Makefile->GetHomeOutputDirectory(),
this->Makefile->GetStartOutputDirectory());
this->WriteMakeRule(ruleFileStream, "Prepare targets for installation.",
"preinstall", depends, commands, true);
- commands.clear();
- depends.push_back("preinstall");
+ depends.clear();
this->WriteMakeRule(ruleFileStream, "Prepare targets for installation.",
"preinstall/fast", depends, commands, true);
// write the depend rule, really a recompute depends rule
depends.clear();
commands.clear();
- std::string cmakefileName = "CMakeFiles/Makefile.cmake";
+ std::string cmakefileName = cmake::GetCMakeFilesDirectoryPostSlash();
+ cmakefileName += "Makefile.cmake";
this->Convert(cmakefileName.c_str(),HOME_OUTPUT,
cmLocalGenerator::MAKEFILE);
std::string runRule =
@@ -1816,7 +1888,7 @@ cmLocalUnixMakefileGenerator3::ConvertToQuotedOutputPath(const char* p)
std::string
cmLocalUnixMakefileGenerator3::GetTargetDirectory(cmTarget& target)
{
- std::string dir = "CMakeFiles/";
+ std::string dir = cmake::GetCMakeFilesDirectoryPostSlash();
dir += target.GetName();
dir += ".dir";
return dir;
diff --git a/Source/cmLocalUnixMakefileGenerator3.h b/Source/cmLocalUnixMakefileGenerator3.h
index c96ca00..bb72d13 100644
--- a/Source/cmLocalUnixMakefileGenerator3.h
+++ b/Source/cmLocalUnixMakefileGenerator3.h
@@ -178,7 +178,7 @@ public:
/** Called from command-line hook to scan dependencies. */
- virtual bool ScanDependencies(std::vector<std::string> const& args);
+ virtual bool ScanDependencies(const char* tgtInfo);
/** Called from command-line hook to check dependencies. */
virtual void CheckDependencies(cmMakefile* mf, bool verbose,
@@ -280,11 +280,14 @@ protected:
cmTarget& target, const char* filename =0);
bool ForceVerboseMakefiles;
+ std::map<cmStdString, std::vector<int> > ProgressFiles;
+
private:
friend class cmMakefileTargetGenerator;
friend class cmMakefileExecutableTargetGenerator;
friend class cmMakefileLibraryTargetGenerator;
friend class cmMakefileUtilityTargetGenerator;
+ friend class cmGlobalUnixMakefileGenerator3;
std::map<cmStdString, IntegrityCheckSetMap> CheckDependFiles;
@@ -306,6 +309,10 @@ private:
std::string HomeRelativeOutputPath;
+ /* Copy the setting of CMAKE_COLOR_MAKEFILE from the makefile at the
+ beginning of generation to avoid many duplicate lookups. */
+ bool ColorMakefile;
+
std::map<cmStdString,std::vector<cmTarget *> > LocalObjectFiles;
/* does the work for each target */
diff --git a/Source/cmLocalVisualStudio7Generator.cxx b/Source/cmLocalVisualStudio7Generator.cxx
index 290adad..a5eb3cd 100644
--- a/Source/cmLocalVisualStudio7Generator.cxx
+++ b/Source/cmLocalVisualStudio7Generator.cxx
@@ -22,6 +22,8 @@
#include "cmCacheManager.h"
#include "cmake.h"
+#include <ctype.h> // for isspace
+
cmLocalVisualStudio7Generator::cmLocalVisualStudio7Generator()
{
this->Version = 7;
@@ -687,7 +689,7 @@ void cmLocalVisualStudio7Generator::OutputBuildTool(std::ostream& fout,
fout << "\t\t\t\tAdditionalOptions=\"" << libflags << "\"\n";
}
fout << "\t\t\t\tOutputFile=\""
- << this->ConvertToXMLOutputPathSingle(libpath.c_str()) << ".\"/>\n";
+ << this->ConvertToXMLOutputPathSingle(libpath.c_str()) << "\"/>\n";
break;
}
case cmTarget::SHARED_LIBRARY:
@@ -958,6 +960,12 @@ void cmLocalVisualStudio7Generator::OutputDefineFlags(const char* flags,
done = true;
}
+ // Remove trailing whitespace from the definition.
+ while(!define.empty() && isspace(define[define.size()-1]))
+ {
+ define = define.substr(0, define.size()-1);
+ }
+
// Double-quotes in the value of the definition must be escaped
// with a backslash. The entire definition should be quoted in
// the generated xml attribute to avoid confusing the VS parser.
@@ -1159,8 +1167,26 @@ void cmLocalVisualStudio7Generator
<< "\t\t\t\t\tName=\"" << aCompilerTool << "\"\n";
if(compileFlags.size())
{
+ std::string compileFlagsCopy = compileFlags;
+ std::map<cmStdString, cmStdString> fileFlagMap;
+ this->FillFlagMapFromCommandFlags
+ (fileFlagMap,
+ &cmLocalVisualStudio7GeneratorFlagTable[0],
+ compileFlagsCopy);
+ if(compileFlagsCopy.size() &&
+ compileFlagsCopy.find_first_not_of(" ")
+ != compileFlagsCopy.npos)
+ {
fout << "\t\t\t\t\tAdditionalOptions=\""
- << this->EscapeForXML(compileFlags.c_str()) << "\"\n";
+ << this->EscapeForXML(compileFlagsCopy.c_str()) << "\"\n";
+ }
+ for(std::map<cmStdString,
+ cmStdString>::iterator m = fileFlagMap.begin();
+ m != fileFlagMap.end(); ++m)
+ {
+ fout << "\t\t\t\t\t" << m->first << "=\""
+ << m->second << "\"\n";
+ }
}
if(additionalDeps.length())
{
diff --git a/Source/cmMacroCommand.cxx b/Source/cmMacroCommand.cxx
index c8565a9..e4de342 100644
--- a/Source/cmMacroCommand.cxx
+++ b/Source/cmMacroCommand.cxx
@@ -252,11 +252,14 @@ IsFunctionBlocked(const cmListFileFunction& lff, cmMakefile &mf)
{
// record commands until we hit the ENDMACRO
// at the ENDMACRO call we shift gears and start looking for invocations
- if(cmSystemTools::LowerCase(lff.Name) == "endmacro")
+ if(!cmSystemTools::Strucmp(lff.Name.c_str(),"macro"))
{
- std::vector<std::string> expandedArguments;
- mf.ExpandArguments(lff.Arguments, expandedArguments);
- if(!expandedArguments.empty() && (expandedArguments[0] == this->Args[0]))
+ this->Depth++;
+ }
+ else if(!cmSystemTools::Strucmp(lff.Name.c_str(),"endmacro"))
+ {
+ // if this is the endmacro for this macro then execute
+ if (!this->Depth)
{
std::string name = this->Args[0];
std::vector<std::string>::size_type cc;
@@ -280,6 +283,11 @@ IsFunctionBlocked(const cmListFileFunction& lff, cmMakefile &mf)
mf.RemoveFunctionBlocker(lff);
return true;
}
+ else
+ {
+ // decrement for each nested macro that ends
+ this->Depth--;
+ }
}
// if it wasn't an endmacro and we are not executing then we must be
@@ -292,15 +300,18 @@ IsFunctionBlocked(const cmListFileFunction& lff, cmMakefile &mf)
bool cmMacroFunctionBlocker::
ShouldRemove(const cmListFileFunction& lff, cmMakefile &mf)
{
- if(cmSystemTools::LowerCase(lff.Name) == "endmacro")
+ if(!cmSystemTools::Strucmp(lff.Name.c_str(),"endmacro"))
{
std::vector<std::string> expandedArguments;
mf.ExpandArguments(lff.Arguments, expandedArguments);
- if(!expandedArguments.empty() && (expandedArguments[0] == this->Args[0]))
+ if ((!expandedArguments.empty() &&
+ (expandedArguments[0] == this->Args[0]))
+ || mf.IsOn("CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS"))
{
return true;
}
}
+
return false;
}
diff --git a/Source/cmMacroCommand.h b/Source/cmMacroCommand.h
index 99e8b91..d93bdd8 100644
--- a/Source/cmMacroCommand.h
+++ b/Source/cmMacroCommand.h
@@ -28,7 +28,7 @@
class cmMacroFunctionBlocker : public cmFunctionBlocker
{
public:
- cmMacroFunctionBlocker() {}
+ cmMacroFunctionBlocker() {this->Depth=0;}
virtual ~cmMacroFunctionBlocker() {}
virtual bool IsFunctionBlocked(const cmListFileFunction&, cmMakefile &mf);
virtual bool ShouldRemove(const cmListFileFunction&, cmMakefile &mf);
@@ -36,6 +36,7 @@ public:
std::vector<std::string> Args;
std::vector<cmListFileFunction> Functions;
+ int Depth;
};
/** \class cmMacroCommand
diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx
index 866911d..d4cc69d 100644
--- a/Source/cmMakefile.cxx
+++ b/Source/cmMakefile.cxx
@@ -36,6 +36,8 @@
#include <cmsys/RegularExpression.hxx>
+#include <ctype.h> // for isspace
+
// default is not to be building executables
cmMakefile::cmMakefile()
{
@@ -265,7 +267,8 @@ bool cmMakefile::ExecuteCommand(const cmListFileFunction& lff)
cmOStringStream error;
error << "Error in cmake code at\n"
<< lff.FilePath << ":" << lff.Line << ":\n"
- << rm->GetError();
+ << rm->GetError() << std::endl
+ << "Current CMake stack: " << this->GetListFileStack().c_str();
cmSystemTools::Error(error.str().c_str());
return false;
}
@@ -281,7 +284,8 @@ bool cmMakefile::ExecuteCommand(const cmListFileFunction& lff)
cmOStringStream error;
error << "Error in cmake code at\n"
<< lff.FilePath << ":" << lff.Line << ":\n"
- << usedCommand->GetError();
+ << usedCommand->GetError() << std::endl
+ << "Current CMake stack: " << this->GetListFileStack().c_str();
cmSystemTools::Error(error.str().c_str());
result = false;
if ( this->GetCMakeInstance()->GetScriptMode() )
@@ -325,6 +329,7 @@ bool cmMakefile::ExecuteCommand(const cmListFileFunction& lff)
<< "Unknown CMake command \"" << lff.Name.c_str() << "\".";
cmSystemTools::Error(error.str().c_str());
result = false;
+ cmSystemTools::SetFatalErrorOccured();
}
}
@@ -803,7 +808,29 @@ void cmMakefile::AddDefineFlag(const char* flag)
void cmMakefile::RemoveDefineFlag(const char* flag)
{
- cmSystemTools::ReplaceString(this->DefineFlags, flag, " ");
+ // Check the length of the flag to remove.
+ std::string::size_type len = strlen(flag);
+ if(len < 1)
+ {
+ return;
+ }
+
+ // Remove all instances of the flag that are surrounded by
+ // whitespace or the beginning/end of the string.
+ for(std::string::size_type lpos = this->DefineFlags.find(flag, 0);
+ lpos != std::string::npos; lpos = this->DefineFlags.find(flag, lpos))
+ {
+ std::string::size_type rpos = lpos + len;
+ if((lpos <= 0 || isspace(this->DefineFlags[lpos-1])) &&
+ (rpos >= this->DefineFlags.size() || isspace(this->DefineFlags[rpos])))
+ {
+ this->DefineFlags.erase(lpos, len);
+ }
+ else
+ {
+ ++lpos;
+ }
+ }
}
void cmMakefile::AddLinkLibrary(const char* lib,
@@ -824,18 +851,39 @@ void cmMakefile::AddLinkLibraryForTarget(const char *target,
this->GetCMakeInstance()->GetGlobalGenerator()->FindTarget(0, lib);
if(tgt)
{
+ bool allowModules = true;
+ const char* versionValue
+ = this->GetDefinition("CMAKE_BACKWARDS_COMPATIBILITY");
+ if (versionValue && (atof(versionValue) >= 2.4) )
+ {
+ allowModules = false;
+ }
// if it is not a static or shared library then you can not link to it
if(!((tgt->GetType() == cmTarget::STATIC_LIBRARY) ||
(tgt->GetType() == cmTarget::SHARED_LIBRARY)))
{
cmOStringStream e;
- e << "Attempt to add link library " << lib
- << " which is not a library target to target "
- << tgt->GetType() << " " <<
- target << "\n";
+ e << "Attempt to add link target " << lib << " of type: "
+ << cmTarget::TargetTypeNames[(int)tgt->GetType()]
+ << "\nto target " << target
+ << ". You can only link to STATIC or SHARED libraries.";
+ // in older versions of cmake linking to modules was allowed
+ if( tgt->GetType() == cmTarget::MODULE_LIBRARY )
+ {
+ e <<
+ "\nTo allow linking of modules set "
+ "CMAKE_BACKWARDS_COMPATIBILITY to 2.2 or lower\n";
+ }
+ // if no modules are allowed then this is always an error
+ if(!allowModules ||
+ // if we allow modules but the type is not a module then it is
+ // still an error
+ (allowModules && tgt->GetType() != cmTarget::MODULE_LIBRARY))
+ {
cmSystemTools::Error(e.str().c_str());
}
}
+ }
i->second.AddLinkLibrary( *this, target, lib, llt );
}
else
@@ -1667,8 +1715,16 @@ const char *cmMakefile::ExpandVariablesInString(std::string& source,
{
markerPos += markerStartSize; // move past marker
// find the end variable marker starting at the markerPos
+ // make sure it is a valid variable between
std::string::size_type endVariablePos =
- source.find(endVariableMarker, markerPos);
+ source.find_first_not_of(
+ "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_",
+ markerPos);
+ if(endVariablePos != std::string::npos &&
+ source[endVariablePos] != endVariableMarker)
+ {
+ endVariablePos = std::string::npos;
+ }
if(endVariablePos == std::string::npos)
{
// no end marker found so add the bogus start
@@ -1815,6 +1871,11 @@ void cmMakefile::AddDefaultDefinitions()
this->AddDefinition("CMAKE_MINOR_VERSION", temp);
sprintf(temp, "%d", cmMakefile::GetMajorVersion());
this->AddDefinition("CMAKE_MAJOR_VERSION", temp);
+ sprintf(temp, "%d", cmMakefile::GetPatchVersion());
+ this->AddDefinition("CMAKE_PATCH_VERSION", temp);
+
+ this->AddDefinition("CMAKE_FILES_DIRECTORY",
+ cmake::GetCMakeFilesDirectory());
}
#if defined(CMAKE_BUILD_WITH_CMAKE)
@@ -2001,10 +2062,21 @@ cmSourceFile* cmMakefile::GetSource(const char* sourceName) const
{
// if the source is provided with a full path use it, otherwise
// by default it is in the current source dir
- std::string path = cmSystemTools::GetFilenamePath(sourceName);
- if (path.empty())
+ std::string path;
+ if (cmSystemTools::FileIsFullPath(sourceName))
+ {
+ path = cmSystemTools::GetFilenamePath(sourceName);
+ }
+ else
{
path = this->GetCurrentDirectory();
+ // even though it is not a full path, it may still be relative
+ std::string subpath = cmSystemTools::GetFilenamePath(sourceName);
+ if (!subpath.empty())
+ {
+ path += "/";
+ path += cmSystemTools::GetFilenamePath(sourceName);
+ }
}
std::string sname =
@@ -2684,3 +2756,17 @@ std::vector<cmTest*> *cmMakefile::GetTests()
return &this->Tests;
}
+std::string cmMakefile::GetListFileStack()
+{
+ std::string tmp;
+ for (std::deque<cmStdString>::iterator i = this->ListFileStack.begin();
+ i != this->ListFileStack.end(); ++i)
+ {
+ if (i != this->ListFileStack.begin())
+ {
+ tmp += ";";
+ }
+ tmp += *i;
+ }
+ return tmp;
+}
diff --git a/Source/cmMakefile.h b/Source/cmMakefile.h
index 172ab7a..7751a03 100644
--- a/Source/cmMakefile.h
+++ b/Source/cmMakefile.h
@@ -539,6 +539,11 @@ public:
void AddCMakeDependFile(const char* file)
{ this->ListFiles.push_back(file);}
+ /**
+ * Get the list file stack as a string
+ */
+ std::string GetListFileStack();
+
/**
* Get the vector of files created by this makefile
*/
diff --git a/Source/cmMakefileExecutableTargetGenerator.cxx b/Source/cmMakefileExecutableTargetGenerator.cxx
index c999106..03b0cd2 100644
--- a/Source/cmMakefileExecutableTargetGenerator.cxx
+++ b/Source/cmMakefileExecutableTargetGenerator.cxx
@@ -22,6 +22,7 @@
#include "cmMakefile.h"
#include "cmSourceFile.h"
#include "cmTarget.h"
+#include "cmake.h"
//----------------------------------------------------------------------------
void cmMakefileExecutableTargetGenerator::WriteRuleFiles()
@@ -29,12 +30,15 @@ void cmMakefileExecutableTargetGenerator::WriteRuleFiles()
// create the build.make file and directory, put in the common blocks
this->CreateRuleFile();
- // Add in any rules for custom commands
- this->WriteCustomCommandsForTarget();
-
- // write in rules for object files
+ // write rules used to help build object files
this->WriteCommonCodeRules();
+ // write in rules for object files and custom commands
+ this->WriteTargetBuildRules();
+
+ // write the per-target per-language flags
+ this->WriteTargetLanguageFlags();
+
// Write the dependency generation rule.
this->WriteTargetDependRules();
@@ -165,7 +169,8 @@ void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink)
if(relink)
{
outpath = this->Makefile->GetStartOutputDirectory();
- outpath += "/CMakeFiles/CMakeRelink.dir";
+ outpath += cmake::GetCMakeFilesDirectory();
+ outpath += "/CMakeRelink.dir";
cmSystemTools::MakeDirectory(outpath.c_str());
outpath += "/";
}
@@ -311,7 +316,6 @@ void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink)
symlink += targetOutPathReal;
symlink += " ";
symlink += targetOutPath;
- commands.push_back(symlink);
commands1.clear();
commands1.push_back(symlink);
this->LocalGenerator->CreateCDCommand(commands1,
@@ -380,19 +384,8 @@ void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink)
depends, commands, false);
}
- // Write convenience targets.
- std::string dir = this->Makefile->GetStartOutputDirectory();
- dir += "/";
- dir += this->LocalGenerator->GetTargetDirectory(*this->Target);
- std::string buildTargetRuleName = dir;
- buildTargetRuleName += relink?"/preinstall":"/build";
- buildTargetRuleName =
- this->Convert(buildTargetRuleName.c_str(),
- cmLocalGenerator::HOME_OUTPUT,
- cmLocalGenerator::MAKEFILE);
- this->LocalGenerator->WriteConvenienceRule(*this->BuildFileStream,
- targetFullPath.c_str(),
- buildTargetRuleName.c_str());
+ // Write the main driver rule to build everything in this target.
+ this->WriteTargetDriverRule(targetFullPath.c_str(), relink);
// Clean all the possible executable names and symlinks and object files.
this->CleanFiles.insert(this->CleanFiles.end(),
diff --git a/Source/cmMakefileLibraryTargetGenerator.cxx b/Source/cmMakefileLibraryTargetGenerator.cxx
index 330465f..2c16755 100644
--- a/Source/cmMakefileLibraryTargetGenerator.cxx
+++ b/Source/cmMakefileLibraryTargetGenerator.cxx
@@ -22,6 +22,9 @@
#include "cmMakefile.h"
#include "cmSourceFile.h"
#include "cmTarget.h"
+#include "cmake.h"
+
+#include <memory> // auto_ptr
//----------------------------------------------------------------------------
void cmMakefileLibraryTargetGenerator::WriteRuleFiles()
@@ -29,12 +32,15 @@ void cmMakefileLibraryTargetGenerator::WriteRuleFiles()
// create the build.make file and directory, put in the common blocks
this->CreateRuleFile();
- // Add in any rules for custom commands
- this->WriteCustomCommandsForTarget();
-
- // write in rules for object files
+ // write rules used to help build object files
this->WriteCommonCodeRules();
+ // write in rules for object files and custom commands
+ this->WriteTargetBuildRules();
+
+ // write the per-target per-language flags
+ this->WriteTargetLanguageFlags();
+
// Write the dependency generation rule.
this->WriteTargetDependRules();
@@ -241,7 +247,8 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules
if(relink)
{
outpath = this->Makefile->GetStartOutputDirectory();
- outpath += "/CMakeFiles/CMakeRelink.dir";
+ outpath += cmake::GetCMakeFilesDirectory();
+ outpath += "/CMakeRelink.dir";
cmSystemTools::MakeDirectory(outpath.c_str());
outpath += "/";
}
@@ -371,9 +378,48 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules
->AppendCustomCommands(commands, this->Target->GetPreLinkCommands());
}
+ // Open the link script if it will be used.
+ bool useLinkScript = false;
+ std::string linkScriptName;
+ std::auto_ptr<cmGeneratedFileStream> linkScriptStream;
+ if(this->GlobalGenerator->GetUseLinkScript() &&
+ (this->Target->GetType() == cmTarget::STATIC_LIBRARY ||
+ this->Target->GetType() == cmTarget::SHARED_LIBRARY ||
+ this->Target->GetType() == cmTarget::MODULE_LIBRARY))
+ {
+ useLinkScript = true;
+ linkScriptName = this->TargetBuildDirectoryFull;
+ if(relink)
+ {
+ linkScriptName += "/relink.txt";
+ }
+ else
+ {
+ linkScriptName += "/link.txt";
+ }
+ std::auto_ptr<cmGeneratedFileStream> lss(
+ new cmGeneratedFileStream(linkScriptName.c_str()));
+ linkScriptStream = lss;
+ }
+
+ std::vector<std::string> link_script_commands;
+
// Construct the main link rule.
std::string linkRule = this->Makefile->GetRequiredDefinition(linkRuleVar);
+ if(useLinkScript)
+ {
+ cmSystemTools::ExpandListArgument(linkRule, link_script_commands);
+ std::string link_command = "$(CMAKE_COMMAND) -E cmake_link_script ";
+ link_command += this->Convert(linkScriptName.c_str(),
+ cmLocalGenerator::START_OUTPUT,
+ cmLocalGenerator::SHELL);
+ link_command += " --verbose=$(VERBOSE)";
+ commands1.push_back(link_command);
+ }
+ else
+ {
cmSystemTools::ExpandListArgument(linkRule, commands1);
+ }
this->LocalGenerator->CreateCDCommand
(commands1,
this->Makefile->GetStartOutputDirectory(),
@@ -413,11 +459,19 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules
std::string variableName;
std::string variableNameExternal;
this->WriteObjectsVariable(variableName, variableNameExternal);
- std::string buildObjs = "$(";
+ std::string buildObjs;
+ if(useLinkScript)
+ {
+ this->WriteObjectsString(buildObjs);
+ }
+ else
+ {
+ buildObjs = "$(";
buildObjs += variableName;
buildObjs += ") $(";
buildObjs += variableNameExternal;
buildObjs += ")";
+ }
std::string cleanObjs = "$(";
cleanObjs += variableName;
cleanObjs += ")";
@@ -425,7 +479,7 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules
vars.TargetPDB = targetOutPathPDB.c_str();
vars.Language = linkLanguage;
vars.Objects = buildObjs.c_str();
- std::string objdir = "CMakeFiles/";
+ std::string objdir = cmake::GetCMakeFilesDirectoryPostSlash();
objdir += this->Target->GetName();
objdir += ".dir";
vars.ObjectDir = objdir.c_str();
@@ -488,13 +542,40 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules
vars.LanguageCompileFlags = langFlags.c_str();
// Expand placeholders in the commands.
this->LocalGenerator->TargetImplib = targetOutPathImport;
+ if(useLinkScript)
+ {
+ for(std::vector<std::string>::iterator i = link_script_commands.begin();
+ i != link_script_commands.end(); ++i)
+ {
+ this->LocalGenerator->ExpandRuleVariables(*i, vars);
+ }
+ }
+ else
+ {
for(std::vector<std::string>::iterator i = commands.begin();
i != commands.end(); ++i)
{
this->LocalGenerator->ExpandRuleVariables(*i, vars);
}
+ }
this->LocalGenerator->TargetImplib = "";
+ // Optionally convert the build rule to use a script to avoid long
+ // command lines in the make shell.
+ if(useLinkScript)
+ {
+ for(std::vector<std::string>::iterator cmd = link_script_commands.begin();
+ cmd != link_script_commands.end(); ++cmd)
+ {
+ // Do not write out empty commands or commands beginning in the
+ // shell no-op ":".
+ if(!cmd->empty() && (*cmd)[0] != ':')
+ {
+ (*linkScriptStream) << *cmd << "\n";
+ }
+ }
+ }
+
// Write the build rule.
this->LocalGenerator->WriteMakeRule(*this->BuildFileStream, 0,
targetFullPathReal.c_str(),
@@ -522,18 +603,8 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules
depends, commands, false);
}
- // Write convenience targets.
- std::string dir = this->Makefile->GetStartOutputDirectory();
- dir += "/";
- dir += this->LocalGenerator->GetTargetDirectory(*this->Target);
- std::string buildTargetRuleName = dir;
- buildTargetRuleName += relink?"/preinstall":"/build";
- buildTargetRuleName =
- this->Convert(buildTargetRuleName.c_str(),
- cmLocalGenerator::HOME_OUTPUT,cmLocalGenerator::MAKEFILE);
- this->LocalGenerator->WriteConvenienceRule(*this->BuildFileStream,
- targetFullPath.c_str(),
- buildTargetRuleName.c_str());
+ // Write the main driver rule to build everything in this target.
+ this->WriteTargetDriverRule(targetFullPath.c_str(), relink);
// Clean all the possible library names and symlinks and object files.
this->CleanFiles.insert(this->CleanFiles.end(),
diff --git a/Source/cmMakefileTargetGenerator.cxx b/Source/cmMakefileTargetGenerator.cxx
index f3434d0..a4f03c8 100644
--- a/Source/cmMakefileTargetGenerator.cxx
+++ b/Source/cmMakefileTargetGenerator.cxx
@@ -23,6 +23,7 @@
#include "cmMakefile.h"
#include "cmSourceFile.h"
#include "cmTarget.h"
+#include "cmake.h"
#include "cmMakefileExecutableTargetGenerator.h"
#include "cmMakefileLibraryTargetGenerator.h"
@@ -99,7 +100,7 @@ void cmMakefileTargetGenerator::CreateRuleFile()
}
//----------------------------------------------------------------------------
-void cmMakefileTargetGenerator::WriteCustomCommandsForTarget()
+void cmMakefileTargetGenerator::WriteTargetBuildRules()
{
// write the custom commands for this target
// Look for files registered for cleaning in this directory.
@@ -110,7 +111,56 @@ void cmMakefileTargetGenerator::WriteCustomCommandsForTarget()
cmSystemTools::ExpandListArgument(additional_clean_files,
this->CleanFiles);
}
- this->WriteCustomCommands();
+
+ // add custom commands to the clean rules?
+ const char* clean_no_custom =
+ this->Makefile->GetProperty("CLEAN_NO_CUSTOM");
+ bool clean = cmSystemTools::IsOff(clean_no_custom);
+
+ // First generate the object rule files. Save a list of all object
+ // files for this target.
+ const std::vector<cmSourceFile*>& sources = this->Target->GetSourceFiles();
+ for(std::vector<cmSourceFile*>::const_iterator source = sources.begin();
+ source != sources.end(); ++source)
+ {
+ if(cmCustomCommand* cc = (*source)->GetCustomCommand())
+ {
+ this->GenerateCustomRuleFile(*cc);
+ if (clean)
+ {
+ const std::vector<std::string>& outputs = cc->GetOutputs();
+ for(std::vector<std::string>::const_iterator o = outputs.begin();
+ o != outputs.end(); ++o)
+ {
+ this->CleanFiles.push_back
+ (this->Convert(o->c_str(),
+ cmLocalGenerator::START_OUTPUT,
+ cmLocalGenerator::UNCHANGED));
+ }
+ }
+ }
+ else if(!(*source)->GetPropertyAsBool("HEADER_FILE_ONLY"))
+ {
+ if(!this->GlobalGenerator->IgnoreFile
+ ((*source)->GetSourceExtension().c_str()))
+ {
+ // Generate this object file's rule file.
+ this->WriteObjectRuleFiles(*(*source));
+ }
+ else if((*source)->GetPropertyAsBool("EXTERNAL_OBJECT"))
+ {
+ // This is an external object file. Just add it.
+ this->ExternalObjects.push_back((*source)->GetFullPath());
+ }
+ else
+ {
+ // We only get here if a source file is not an external object
+ // and has an extension that is listed as an ignored file type
+ // for this language. No message or diagnosis should be
+ // given.
+ }
+ }
+ }
}
@@ -159,37 +209,11 @@ void cmMakefileTargetGenerator::WriteCommonCodeRules()
cmLocalGenerator::HOME_OUTPUT,
cmLocalGenerator::MAKEFILE)
<< "\n\n";
+}
- // First generate the object rule files. Save a list of all object
- // files for this target.
- const std::vector<cmSourceFile*>& sources = this->Target->GetSourceFiles();
- for(std::vector<cmSourceFile*>::const_iterator source = sources.begin();
- source != sources.end(); ++source)
- {
- if(!(*source)->GetPropertyAsBool("HEADER_FILE_ONLY") &&
- !(*source)->GetCustomCommand())
- {
- if(!this->GlobalGenerator->IgnoreFile
- ((*source)->GetSourceExtension().c_str()))
- {
- // Generate this object file's rule file.
- this->WriteObjectRuleFiles(*(*source));
- }
- else if((*source)->GetPropertyAsBool("EXTERNAL_OBJECT"))
- {
- // This is an external object file. Just add it.
- this->ExternalObjects.push_back((*source)->GetFullPath());
- }
- else
- {
- // We only get here if a source file is not an external object
- // and has an extension that is listed as an ignored file type
- // for this language. No message or diagnosis should be
- // given.
- }
- }
- }
-
+//----------------------------------------------------------------------------
+void cmMakefileTargetGenerator::WriteTargetLanguageFlags()
+{
// write language flags for target
std::map<cmStdString,cmLocalUnixMakefileGenerator3::IntegrityCheckSet>&
checkSet =
@@ -374,6 +398,27 @@ cmMakefileTargetGenerator
// Construct the build message.
std::vector<std::string> no_commands;
std::vector<std::string> commands;
+
+ // add in a progress call if needed
+ cmGlobalUnixMakefileGenerator3* gg =
+ static_cast<cmGlobalUnixMakefileGenerator3*>(this->GlobalGenerator);
+ int prog = gg->ShouldAddProgressRule();
+
+ std::string progressDir = this->Makefile->GetHomeOutputDirectory();
+ progressDir += cmake::GetCMakeFilesDirectory();
+ cmOStringStream progCmd;
+ progCmd << "$(CMAKE_COMMAND) -E cmake_progress_report ";
+ progCmd << this->LocalGenerator->Convert(progressDir.c_str(),
+ cmLocalGenerator::FULL,
+ cmLocalGenerator::SHELL);
+ if (prog)
+ {
+ progCmd << " " << prog;
+ this->LocalGenerator->ProgressFiles[this->Target->GetName()].
+ push_back(prog);
+ }
+ commands.push_back(progCmd.str());
+
std::string buildEcho = "Building ";
buildEcho += lang;
buildEcho += " object ";
@@ -581,20 +626,31 @@ void cmMakefileTargetGenerator::WriteTargetDependRules()
cmLocalGenerator::FULL, cmLocalGenerator::SHELL))
<< " && ";
#endif
- depCmd << "$(CMAKE_COMMAND) -E cmake_depends "
- << " \""
+ // Generate a call this signature:
+ //
+ // cmake -E cmake_depends <generator>
+ // <home-src-dir> <start-src-dir>
+ // <home-out-dir> <start-out-dir>
+ // <dep-info>
+ //
+ // This gives the dependency scanner enough information to recreate
+ // the state of our local generator sufficiently for its needs.
+ depCmd << "$(CMAKE_COMMAND) -E cmake_depends \""
<< this->GlobalGenerator->GetName() << "\" "
- << this->LocalGenerator->Convert
- (this->Makefile->GetHomeOutputDirectory(),
- cmLocalGenerator::FULL,cmLocalGenerator::SHELL)
+ << this->Convert(this->Makefile->GetHomeDirectory(),
+ cmLocalGenerator::FULL, cmLocalGenerator::SHELL)
<< " "
- << this->LocalGenerator->Convert
- (this->Makefile->GetStartOutputDirectory(),
- cmLocalGenerator::FULL,cmLocalGenerator::SHELL)
+ << this->Convert(this->Makefile->GetStartDirectory(),
+ cmLocalGenerator::FULL, cmLocalGenerator::SHELL)
+ << " "
+ << this->Convert(this->Makefile->GetHomeOutputDirectory(),
+ cmLocalGenerator::FULL, cmLocalGenerator::SHELL)
+ << " "
+ << this->Convert(this->Makefile->GetStartOutputDirectory(),
+ cmLocalGenerator::FULL, cmLocalGenerator::SHELL)
<< " "
<< this->Convert(this->InfoFileNameFull.c_str(),
- cmLocalGenerator::FULL,
- cmLocalGenerator::SHELL);
+ cmLocalGenerator::FULL, cmLocalGenerator::SHELL);
commands.push_back(depCmd.str());
// Write the rule.
@@ -624,39 +680,6 @@ void cmMakefileTargetGenerator
}
//----------------------------------------------------------------------------
-void cmMakefileTargetGenerator::WriteCustomCommands()
-{
- // add custom commands to the clean rules?
- const char* clean_no_custom =
- this->Makefile->GetProperty("CLEAN_NO_CUSTOM");
- bool clean = cmSystemTools::IsOff(clean_no_custom);
-
- // Generate the rule files for each custom command.
- const std::vector<cmSourceFile*> &classes =
- this->Makefile->GetSourceFiles();
- for(std::vector<cmSourceFile*>::const_iterator i = classes.begin();
- i != classes.end(); i++)
- {
- if(cmCustomCommand* cc = (*i)->GetCustomCommand())
- {
- this->GenerateCustomRuleFile(*cc);
- if (clean)
- {
- const std::vector<std::string>& outputs = cc->GetOutputs();
- for(std::vector<std::string>::const_iterator o = outputs.begin();
- o != outputs.end(); ++o)
- {
- this->CleanFiles.push_back
- (this->Convert(o->c_str(),
- cmLocalGenerator::START_OUTPUT,
- cmLocalGenerator::UNCHANGED));
- }
- }
- }
- }
-}
-
-//----------------------------------------------------------------------------
void cmMakefileTargetGenerator
::GenerateCustomRuleFile(const cmCustomCommand& cc)
{
@@ -785,6 +808,112 @@ cmMakefileTargetGenerator
*this->BuildFileStream << "\n" << "\n";
}
+//----------------------------------------------------------------------------
+void
+cmMakefileTargetGenerator
+::WriteObjectsString(std::string& buildObjs)
+{
+ std::string object;
+ const char* no_quoted =
+ this->Makefile->GetDefinition("CMAKE_NO_QUOTED_OBJECTS");
+ const char* space = "";
+ for(std::vector<std::string>::const_iterator i = this->Objects.begin();
+ i != this->Objects.end(); ++i)
+ {
+ if ( this->ExtraContent.find(i->c_str()) != this->ExtraContent.end() )
+ {
+ continue;
+ }
+ buildObjs += space;
+ space = " ";
+ if(no_quoted)
+ {
+ buildObjs +=
+ this->Convert(i->c_str(), cmLocalGenerator::START_OUTPUT,
+ cmLocalGenerator::SHELL);
+ }
+ else
+ {
+ buildObjs +=
+ this->LocalGenerator->ConvertToQuotedOutputPath(i->c_str());
+ }
+ }
+ for(std::vector<std::string>::const_iterator i =
+ this->ExternalObjects.begin();
+ i != this->ExternalObjects.end(); ++i)
+ {
+ buildObjs += space;
+ space = " ";
+ if(no_quoted)
+ {
+ buildObjs +=
+ this->Convert(i->c_str(), cmLocalGenerator::START_OUTPUT,
+ cmLocalGenerator::SHELL);
+ }
+ else
+ {
+ buildObjs +=
+ this->LocalGenerator->ConvertToQuotedOutputPath(i->c_str());
+ }
+ }
+}
+
+//----------------------------------------------------------------------------
+void cmMakefileTargetGenerator::WriteTargetDriverRule(const char* main_output,
+ bool relink)
+{
+ // Compute the name of the driver target.
+ std::string dir = this->Makefile->GetStartOutputDirectory();
+ dir += "/";
+ dir += this->LocalGenerator->GetTargetDirectory(*this->Target);
+ std::string buildTargetRuleName = dir;
+ buildTargetRuleName += relink?"/preinstall":"/build";
+ buildTargetRuleName = this->Convert(buildTargetRuleName.c_str(),
+ cmLocalGenerator::HOME_OUTPUT,
+ cmLocalGenerator::MAKEFILE);
+
+ // Build the list of target outputs to drive.
+ std::vector<std::string> depends;
+ if(main_output)
+ {
+ depends.push_back(main_output);
+ }
+
+ const char* comment = 0;
+ if(relink)
+ {
+ // Setup the comment for the preinstall driver.
+ comment = "Rule to relink during preinstall.";
+ }
+ else
+ {
+ // Setup the comment for the main build driver.
+ comment = "Rule to build all files generated by this target.";
+
+ // Make sure all custom command outputs in this target are built.
+ const std::vector<cmSourceFile*>& sources =
+ this->Target->GetSourceFiles();
+ for(std::vector<cmSourceFile*>::const_iterator source = sources.begin();
+ source != sources.end(); ++source)
+ {
+ if(cmCustomCommand* cc = (*source)->GetCustomCommand())
+ {
+ const std::vector<std::string>& outputs = cc->GetOutputs();
+ for(std::vector<std::string>::const_iterator o = outputs.begin();
+ o != outputs.end(); ++o)
+ {
+ depends.push_back(*o);
+ }
+ }
+ }
+ }
+
+ // Write the driver rule.
+ std::vector<std::string> no_commands;
+ this->LocalGenerator->WriteMakeRule(*this->BuildFileStream, comment,
+ buildTargetRuleName.c_str(),
+ depends, no_commands, true);
+}
//----------------------------------------------------------------------------
std::string cmMakefileTargetGenerator::GetFrameworkFlags()
diff --git a/Source/cmMakefileTargetGenerator.h b/Source/cmMakefileTargetGenerator.h
index c2422d7..a624305 100644
--- a/Source/cmMakefileTargetGenerator.h
+++ b/Source/cmMakefileTargetGenerator.h
@@ -55,11 +55,13 @@ protected:
// create the file and directory etc
void CreateRuleFile();
- // outputs the rules for any custom commands used by this target
- void WriteCustomCommandsForTarget();
+ // outputs the rules for object files and custom commands used by
+ // this target
+ void WriteTargetBuildRules();
// write some common code at the top of build.make
void WriteCommonCodeRules();
+ void WriteTargetLanguageFlags();
// write the provide require rules for this target
void WriteTargetRequiresRules();
@@ -83,14 +85,16 @@ protected:
void WriteObjectDependRules(cmSourceFile& source,
std::vector<std::string>& depends);
- // this is responsible for writing all of the rules for all this
- // directories custom commands (but not utility targets)
- void WriteCustomCommands();
+ // write the build rule for a custom command
void GenerateCustomRuleFile(const cmCustomCommand& cc);
// write out the variable that lists the objects for this target
void WriteObjectsVariable(std::string& variableName,
std::string& variableNameExternal);
+ void WriteObjectsString(std::string& buildObjs);
+
+ // write the driver rule to build target outputs
+ void WriteTargetDriverRule(const char* main_output, bool relink);
// Return the a string with -F flags on apple
std::string GetFrameworkFlags();
diff --git a/Source/cmMakefileUtilityTargetGenerator.cxx b/Source/cmMakefileUtilityTargetGenerator.cxx
index 474f850..51a848f 100644
--- a/Source/cmMakefileUtilityTargetGenerator.cxx
+++ b/Source/cmMakefileUtilityTargetGenerator.cxx
@@ -33,7 +33,7 @@ void cmMakefileUtilityTargetGenerator::WriteRuleFiles()
<< "# Utility rule file for " << this->Target->GetName() << ".\n\n";
// write the custom commands for this target
- this->WriteCustomCommandsForTarget();
+ this->WriteTargetBuildRules();
// Collect the commands and dependencies.
std::vector<std::string> commands;
@@ -63,19 +63,8 @@ void cmMakefileUtilityTargetGenerator::WriteRuleFiles()
this->Target->GetName(),
depends, commands, true);
- // Write convenience targets.
- std::string dir = this->Makefile->GetStartOutputDirectory();
- dir += "/";
- dir += this->LocalGenerator->GetTargetDirectory(*this->Target);
- std::string buildTargetRuleName = dir;
- buildTargetRuleName += "/build";
- buildTargetRuleName =
- this->LocalGenerator->Convert(buildTargetRuleName.c_str(),
- cmLocalGenerator::HOME_OUTPUT,
- cmLocalGenerator::MAKEFILE);
- this->LocalGenerator->WriteConvenienceRule(*this->BuildFileStream,
- this->Target->GetName(),
- buildTargetRuleName.c_str());
+ // Write the main driver rule to build everything in this target.
+ this->WriteTargetDriverRule(this->Target->GetName(), false);
// Write clean target
this->WriteTargetCleanRules();
diff --git a/Source/cmMessageCommand.cxx b/Source/cmMessageCommand.cxx
index 2ba6fd7..5856b51 100644
--- a/Source/cmMessageCommand.cxx
+++ b/Source/cmMessageCommand.cxx
@@ -57,9 +57,10 @@ bool cmMessageCommand::InitialPass(std::vector<std::string> const& args)
message += *i;
}
- if (send_error)
+ if (send_error || fatal_error)
{
- cmSystemTools::Error(message.c_str());
+ //cmSystemTools::Error(message.c_str());
+ this->SetError(message.c_str());
}
else
{
@@ -76,6 +77,6 @@ bool cmMessageCommand::InitialPass(std::vector<std::string> const& args)
{
cmSystemTools::SetFatalErrorOccured();
}
- return true;
+ return (!send_error && !fatal_error);
}
diff --git a/Source/cmSetTargetPropertiesCommand.h b/Source/cmSetTargetPropertiesCommand.h
index 9bd3483..a605a77 100644
--- a/Source/cmSetTargetPropertiesCommand.h
+++ b/Source/cmSetTargetPropertiesCommand.h
@@ -112,6 +112,9 @@ public:
"There are a few properties used to specify RPATH rules. "
"INSTALL_RPATH is a semicolon-separated list specifying the rpath "
"to use in installed targets (for platforms that support it). "
+ "INSTALL_RPATH_USE_LINK_PATH is a boolean that if set to true will "
+ "append directories in the linker search path and outside the "
+ "project to the INSTALL_RPATH. "
"SKIP_BUILD_RPATH is a boolean specifying whether to skip automatic "
"generation of an rpath allowing the target to run from the "
"build tree. "
@@ -122,7 +125,8 @@ public:
"directory portion of the \"install_name\" field of shared libraries "
"on Mac OSX to use in the installed targets. "
"When the target is created the values of "
- "the variables CMAKE_INSTALL_RPATH, CMAKE_SKIP_BUILD_RPATH, "
+ "the variables CMAKE_INSTALL_RPATH, "
+ "CMAKE_INSTALL_RPATH_USE_LINK_PATH, CMAKE_SKIP_BUILD_RPATH, "
"CMAKE_BUILD_WITH_INSTALL_RPATH, and CMAKE_INSTALL_NAME_DIR "
"are used to initialize these properties.\n"
"PROJECT_LABEL can be used to change the name of "
diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx
index 0f34a97..26bc47d 100644
--- a/Source/cmTarget.cxx
+++ b/Source/cmTarget.cxx
@@ -23,6 +23,11 @@
#include <set>
#include <queue>
#include <stdlib.h> // required for atof
+const char* cmTarget::TargetTypeNames[] = {
+ "EXECUTABLE", "STATIC_LIBRARY",
+ "SHARED_LIBRARY", "MODULE_LIBRARY", "UTILITY", "GLOBAL_TARGET",
+ "INSTALL_FILES", "INSTALL_PROGRAMS", "INSTALL_DIRECTORY"
+};
//----------------------------------------------------------------------------
cmTarget::cmTarget()
@@ -58,6 +63,7 @@ void cmTarget::SetMakefile(cmMakefile* mf)
// Setup default property values.
this->SetPropertyDefault("INSTALL_NAME_DIR", "");
this->SetPropertyDefault("INSTALL_RPATH", "");
+ this->SetPropertyDefault("INSTALL_RPATH_USE_LINK_PATH", "OFF");
this->SetPropertyDefault("SKIP_BUILD_RPATH", "OFF");
this->SetPropertyDefault("BUILD_WITH_INSTALL_RPATH", "OFF");
@@ -1316,19 +1322,36 @@ void cmTarget::GetLibraryNamesInternal(std::string& name,
soversion = version;
}
+ // Get the components of the library name.
+ std::string prefix;
+ std::string base;
+ std::string suffix;
+ this->GetFullNameInternal(type, config, false, prefix, base, suffix);
+
// The library name.
- name = this->GetFullNameInternal(type, config, false);
+ name = prefix+base+suffix;
// The library's soname.
+#if defined(__APPLE__)
+ soName = prefix+base;
+#else
soName = name;
+#endif
if(soversion)
{
soName += ".";
soName += soversion;
}
+#if defined(__APPLE__)
+ soName += suffix;
+#endif
// The library's real name on disk.
+#if defined(__APPLE__)
+ realName = prefix+base;
+#else
realName = name;
+#endif
if(version)
{
realName += ".";
@@ -1339,6 +1362,9 @@ void cmTarget::GetLibraryNamesInternal(std::string& name,
realName += ".";
realName += soversion;
}
+#if defined(__APPLE__)
+ realName += suffix;
+#endif
// The import library name.
if(type == cmTarget::SHARED_LIBRARY)
diff --git a/Source/cmTarget.h b/Source/cmTarget.h
index 7980218..557461f 100644
--- a/Source/cmTarget.h
+++ b/Source/cmTarget.h
@@ -36,7 +36,7 @@ public:
enum TargetType { EXECUTABLE, STATIC_LIBRARY,
SHARED_LIBRARY, MODULE_LIBRARY, UTILITY, GLOBAL_TARGET,
INSTALL_FILES, INSTALL_PROGRAMS, INSTALL_DIRECTORY};
-
+ static const char* TargetTypeNames[];
enum CustomCommandType { PRE_BUILD, PRE_LINK, POST_BUILD };
/**
diff --git a/Source/cmTryCompileCommand.cxx b/Source/cmTryCompileCommand.cxx
index c7405ca..f3fe893 100644
--- a/Source/cmTryCompileCommand.cxx
+++ b/Source/cmTryCompileCommand.cxx
@@ -110,7 +110,9 @@ int cmTryCompileCommand::CoreTryCompileCode(
// signature
if (srcFileSignature)
{
- tmpString = argv[1] + "/CMakeFiles/CMakeTmp";
+ tmpString = argv[1];
+ tmpString += cmake::GetCMakeFilesDirectory();
+ tmpString += "/CMakeTmp";
binaryDirectory = tmpString.c_str();
}
// make sure the binary directory exists
diff --git a/Source/cmTryRunCommand.cxx b/Source/cmTryRunCommand.cxx
index ba7b481..f8f2e86 100644
--- a/Source/cmTryRunCommand.cxx
+++ b/Source/cmTryRunCommand.cxx
@@ -68,7 +68,9 @@ bool cmTryRunCommand::InitialPass(std::vector<std::string> const& argv)
tryCompile, false);
// now try running the command if it compiled
- std::string binaryDirectory = argv[2] + "/CMakeFiles/CMakeTmp";
+ std::string binaryDirectory = argv[2];
+ binaryDirectory += cmake::GetCMakeFilesDirectory();
+ binaryDirectory += "/CMakeTmp";
if (!res)
{
int retVal = -1;
diff --git a/Source/cmWhileCommand.cxx b/Source/cmWhileCommand.cxx
index 3c785d7..f88ed2b 100644
--- a/Source/cmWhileCommand.cxx
+++ b/Source/cmWhileCommand.cxx
@@ -28,7 +28,15 @@ IsFunctionBlocked(const cmListFileFunction& lff, cmMakefile &mf)
}
// at end of for each execute recorded commands
- if (cmSystemTools::LowerCase(lff.Name) == "endwhile")
+ if (!cmSystemTools::Strucmp(lff.Name.c_str(),"while"))
+ {
+ // record the number of while commands past this one
+ this->Depth++;
+ }
+ else if (!cmSystemTools::Strucmp(lff.Name.c_str(),"endwhile"))
+ {
+ // if this is the endwhile for this while loop then execute
+ if (!this->Depth)
{
char* errorString = 0;
@@ -53,6 +61,12 @@ IsFunctionBlocked(const cmListFileFunction& lff, cmMakefile &mf)
mf.RemoveFunctionBlocker(lff);
return true;
}
+ else
+ {
+ // decrement for each nested while that ends
+ this->Depth--;
+ }
+ }
// record the command
this->Functions.push_back(lff);
@@ -62,11 +76,12 @@ IsFunctionBlocked(const cmListFileFunction& lff, cmMakefile &mf)
}
bool cmWhileFunctionBlocker::
-ShouldRemove(const cmListFileFunction& lff, cmMakefile& )
+ShouldRemove(const cmListFileFunction& lff, cmMakefile& mf)
{
- if(cmSystemTools::LowerCase(lff.Name) == "endwhile")
+ if(!cmSystemTools::Strucmp(lff.Name.c_str(),"endwhile"))
{
- if (lff.Arguments == this->Args)
+ if (lff.Arguments == this->Args
+ || mf.IsOn("CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS"))
{
return true;
}
diff --git a/Source/cmWhileCommand.h b/Source/cmWhileCommand.h
index 10c261c..e1f44eb 100644
--- a/Source/cmWhileCommand.h
+++ b/Source/cmWhileCommand.h
@@ -29,7 +29,7 @@
class cmWhileFunctionBlocker : public cmFunctionBlocker
{
public:
- cmWhileFunctionBlocker() {Executing = false;}
+ cmWhileFunctionBlocker() {Executing = false; Depth=0;}
virtual ~cmWhileFunctionBlocker() {}
virtual bool IsFunctionBlocked(const cmListFileFunction& lff,
cmMakefile &mf);
@@ -39,6 +39,8 @@ public:
std::vector<cmListFileArgument> Args;
std::vector<cmListFileFunction> Functions;
bool Executing;
+private:
+ int Depth;
};
/** \class cmWhileCommand
diff --git a/Source/cmake.cxx b/Source/cmake.cxx
index 53b7526..2c64d2e 100644
--- a/Source/cmake.cxx
+++ b/Source/cmake.cxx
@@ -31,6 +31,9 @@
# include <cmsys/Terminal.h>
#endif
+# include <cmsys/Directory.hxx>
+#include <cmsys/Process.h>
+
// only build kdevelop generator on non-windows platforms
// when not bootstrapping cmake
#if !defined(_WIN32)
@@ -267,7 +270,16 @@ bool cmake::SetCacheArgs(const std::vector<std::string>& args)
std::string entry = arg.substr(2);
if(entry.size() == 0)
{
- entry = args[++i];
+ ++i;
+ if(i < args.size())
+ {
+ entry = args[i];
+ }
+ else
+ {
+ cmSystemTools::Error("-D must be followed with VAR=VALUE.");
+ return false;
+ }
}
std::string var, value;
cmCacheManager::CacheEntryType type = cmCacheManager::UNINITIALIZED;
@@ -291,7 +303,16 @@ bool cmake::SetCacheArgs(const std::vector<std::string>& args)
std::string path = arg.substr(2);
if ( path.size() == 0 )
{
- path = args[++i];
+ ++i;
+ if(i < args.size())
+ {
+ path = args[i];
+ }
+ else
+ {
+ cmSystemTools::Error("-C must be followed by a file name.");
+ return false;
+ }
}
std::cerr << "loading initial cache file " << path.c_str() << "\n";
this->ReadListFile(path.c_str());
@@ -299,6 +320,11 @@ bool cmake::SetCacheArgs(const std::vector<std::string>& args)
else if(arg.find("-P",0) == 0)
{
i++;
+ if(i >= args.size())
+ {
+ cmSystemTools::Error("-P must be followed by a file name.");
+ return false;
+ }
std::string path = args[i];
if ( path.size() == 0 )
{
@@ -425,7 +451,13 @@ void cmake::SetArgs(const std::vector<std::string>& args)
std::string value = arg.substr(2);
if(value.size() == 0)
{
- value = args[++i];
+ ++i;
+ if(i >= args.size())
+ {
+ cmSystemTools::Error("No generator specified for -G");
+ return;
+ }
+ value = args[i];
}
cmGlobalGenerator* gen =
this->CreateGlobalGenerator(value.c_str());
@@ -837,6 +869,19 @@ int cmake::ExecuteCMakeCommand(std::vector<std::string>& args)
return 0;
}
+ // Echo string no new line
+ else if (args[1] == "echo_append" )
+ {
+ unsigned int cc;
+ const char* space = "";
+ for ( cc = 2; cc < args.size(); cc ++ )
+ {
+ std::cout << space << args[cc];
+ space = " ";
+ }
+ return 0;
+ }
+
#if defined(CMAKE_BUILD_WITH_CMAKE)
// Command to create a symbolic link. Fails on platforms not
// supporting them.
@@ -855,15 +900,22 @@ int cmake::ExecuteCMakeCommand(std::vector<std::string>& args)
// Remove file
else if (args[1] == "remove" && args.size() > 2)
{
+ bool force = false;
for (std::string::size_type cc = 2; cc < args.size(); cc ++)
{
- if(args[cc] != "-f")
+ if(args[cc] == "\\-f" || args[cc] == "-f")
{
- if(args[cc] == "\\-f")
+ force = true;
+ }
+ else
+ {
+ // Complain if the file could not be removed, still exists,
+ // and the -f option was not given.
+ if(!cmSystemTools::RemoveFile(args[cc].c_str()) && !force &&
+ cmSystemTools::FileExists(args[cc].c_str()))
{
- args[cc] = "-f";
+ return 1;
}
- cmSystemTools::RemoveFile(args[cc].c_str());
}
}
return 0;
@@ -931,6 +983,67 @@ int cmake::ExecuteCMakeCommand(std::vector<std::string>& args)
return 1;
}
+ // Command to start progress for a build
+ else if (args[1] == "cmake_progress_start" && args.size() == 4)
+ {
+ // bascially remove the directory
+ std::string dirName = args[2];
+ dirName += "/Progress";
+ cmSystemTools::RemoveADirectory(dirName.c_str());
+ cmSystemTools::MakeDirectory(dirName.c_str());
+ // write the count into the directory
+ std::string fName = dirName;
+ fName += "/count.txt";
+ FILE *progFile = fopen(fName.c_str(),"w");
+ if (progFile)
+ {
+ int count = atoi(args[3].c_str());
+ fprintf(progFile,"%i\n",count);
+ fclose(progFile);
+ }
+ return 0;
+ }
+
+ // Command to report progress for a build
+ else if (args[1] == "cmake_progress_report" && args.size() >= 3)
+ {
+ std::string dirName = args[2];
+ dirName += "/Progress";
+ std::string fName;
+ FILE *progFile;
+ unsigned int i;
+ for (i = 3; i < args.size(); ++i)
+ {
+ fName = dirName;
+ fName += "/";
+ fName += args[i];
+ progFile = fopen(fName.c_str(),"w");
+ if (progFile)
+ {
+ fprintf(progFile,"empty");
+ fclose(progFile);
+ }
+ }
+ int fileNum = static_cast<int>
+ (cmsys::Directory::GetNumberOfFilesInDirectory(dirName.c_str()));
+ // read the count
+ fName = dirName;
+ fName += "/count.txt";
+ progFile = fopen(fName.c_str(),"r");
+ if (progFile)
+ {
+ int count = 0;
+ fscanf(progFile,"%i",&count);
+ if (count > 0)
+ {
+ // print the progress
+ fprintf(stdout,"[%3i%%] ",((fileNum-3)*100)/count);
+ }
+ fclose(progFile);
+ }
+ return 0;
+ }
+
// Command to create a symbolic link. Fails on platforms not
// supporting them.
else if (args[1] == "create_symlink" && args.size() == 4)
@@ -996,18 +1109,81 @@ int cmake::ExecuteCMakeCommand(std::vector<std::string>& args)
// Internal CMake dependency scanning support.
else if (args[1] == "cmake_depends" && args.size() >= 6)
{
+ // Create a cmake object instance to process dependencies.
cmake cm;
- cmGlobalGenerator *ggd = cm.CreateGlobalGenerator(args[2].c_str());
- if (ggd)
+ std::string gen;
+ std::string homeDir;
+ std::string startDir;
+ std::string homeOutDir;
+ std::string startOutDir;
+ std::string depInfo;
+ if(args.size() >= 8)
+ {
+ // Full signature:
+ //
+ // -E cmake_depends <generator>
+ // <home-src-dir> <start-src-dir>
+ // <home-out-dir> <start-out-dir>
+ // <dep-info>
+ //
+ // All paths are provided.
+ gen = args[2];
+ homeDir = args[3];
+ startDir = args[4];
+ homeOutDir = args[5];
+ startOutDir = args[6];
+ depInfo = args[7];
+ }
+ else
+ {
+ // Support older signature for existing makefiles:
+ //
+ // -E cmake_depends <generator>
+ // <home-out-dir> <start-out-dir>
+ // <dep-info>
+ //
+ // Just pretend the source directories are the same as the
+ // binary directories so at least scanning will work.
+ gen = args[2];
+ homeDir = args[3];
+ startDir = args[4];
+ homeOutDir = args[3];
+ startOutDir = args[3];
+ depInfo = args[5];
+ }
+
+ // Create a local generator configured for the directory in
+ // which dependencies will be scanned.
+ homeDir = cmSystemTools::CollapseFullPath(homeDir.c_str());
+ startDir = cmSystemTools::CollapseFullPath(startDir.c_str());
+ homeOutDir = cmSystemTools::CollapseFullPath(homeOutDir.c_str());
+ startOutDir = cmSystemTools::CollapseFullPath(startOutDir.c_str());
+ cm.SetHomeDirectory(homeDir.c_str());
+ cm.SetStartDirectory(startDir.c_str());
+ cm.SetHomeOutputDirectory(homeOutDir.c_str());
+ cm.SetStartOutputDirectory(startOutDir.c_str());
+ if(cmGlobalGenerator* ggd = cm.CreateGlobalGenerator(gen.c_str()))
{
- ggd->SetCMakeInstance(&cm);
+ cm.SetGlobalGenerator(ggd);
std::auto_ptr<cmLocalGenerator> lgd(ggd->CreateLocalGenerator());
lgd->SetGlobalGenerator(ggd);
- return lgd->ScanDependencies(args)? 0 : 2;
+ lgd->GetMakefile()->SetStartDirectory(startDir.c_str());
+ lgd->GetMakefile()->SetStartOutputDirectory(startOutDir.c_str());
+ lgd->GetMakefile()->MakeStartDirectoriesCurrent();
+ lgd->SetupPathConversions();
+
+ // Actually scan dependencies.
+ return lgd->ScanDependencies(depInfo.c_str())? 0 : 2;
}
return 1;
}
+ // Internal CMake link script support.
+ else if (args[1] == "cmake_link_script" && args.size() >= 3)
+ {
+ return cmake::ExecuteLinkScript(args);
+ }
+
#ifdef CMAKE_BUILD_WITH_CMAKE
// Internal CMake color makefile support.
else if (args[1] == "cmake_echo_color")
@@ -1865,9 +2041,7 @@ int cmake::CheckBuildSystem()
// This method will check the integrity of the build system if the
// option was given on the command line. It reads the given file to
- // determine whether CMake should rerun. If it does rerun then the
- // generation step will check the integrity of dependencies. If it
- // does not then we need to check the integrity here.
+ // determine whether CMake should rerun.
// If no file is provided for the check, we have to rerun.
if(this->CheckBuildSystemArgument.size() == 0)
@@ -1916,6 +2090,25 @@ int cmake::CheckBuildSystem()
return 1;
}
+ // Now that we know the generator used to build the project, use it
+ // to check the dependency integrity.
+ const char* genName = mf->GetDefinition("CMAKE_DEPENDS_GENERATOR");
+ if (!genName || genName[0] == '\0')
+ {
+ genName = "Unix Makefiles";
+ }
+ cmGlobalGenerator *ggd = this->CreateGlobalGenerator(genName);
+ if (ggd)
+ {
+ // Check the dependencies in case source files were removed.
+ std::auto_ptr<cmLocalGenerator> lgd(ggd->CreateLocalGenerator());
+ lgd->SetGlobalGenerator(ggd);
+ lgd->CheckDependencies(mf, verbose, this->ClearBuildSystem);
+
+ // Check for multiple output pairs.
+ ggd->CheckMultipleOutputs(mf, verbose);
+ }
+
// Get the set of dependencies and outputs.
const char* dependsStr = mf->GetDefinition("CMAKE_MAKEFILE_DEPENDS");
const char* outputsStr = mf->GetDefinition("CMAKE_MAKEFILE_OUTPUTS");
@@ -1960,24 +2153,6 @@ int cmake::CheckBuildSystem()
}
}
- // compute depends based on the generator specified
- const char* genName = mf->GetDefinition("CMAKE_DEPENDS_GENERATOR");
- if (!genName || genName[0] == '\0')
- {
- genName = "Unix Makefiles";
- }
- cmGlobalGenerator *ggd = this->CreateGlobalGenerator(genName);
- if (ggd)
- {
- // Check the dependencies in case source files were removed.
- std::auto_ptr<cmLocalGenerator> lgd(ggd->CreateLocalGenerator());
- lgd->SetGlobalGenerator(ggd);
- lgd->CheckDependencies(mf, verbose, this->ClearBuildSystem);
-
- // Check for multiple output pairs.
- ggd->CheckMultipleOutputs(mf, verbose);
- }
-
// No need to rerun.
return 0;
}
@@ -2193,7 +2368,7 @@ void cmake::GenerateGraphViz(const char* fileName)
std::map<cmStdString, int> targetDeps;
std::map<cmStdString, cmTarget*> targetPtrs;
std::map<cmStdString, cmStdString> targetNamesNodes;
- char tgtName[100];
+ char tgtName[2048];
int cnt = 0;
// First pass get the list of all cmake targets
for ( lit = localGenerators.begin(); lit != localGenerators.end(); ++ lit )
@@ -2474,3 +2649,101 @@ int cmake::ExecuteEchoColor(std::vector<std::string>&)
return 1;
}
#endif
+
+//----------------------------------------------------------------------------
+int cmake::ExecuteLinkScript(std::vector<std::string>& args)
+{
+ // The arguments are
+ // argv[0] == <cmake-executable>
+ // argv[1] == cmake_link_script
+ // argv[2] == <link-script-name>
+ // argv[3] == --verbose=?
+ bool verbose = false;
+ if(args.size() >= 4)
+ {
+ if(args[3].find("--verbose=") == 0)
+ {
+ if(!cmSystemTools::IsOff(args[3].substr(10).c_str()))
+ {
+ verbose = true;
+ }
+ }
+ }
+
+ // Allocate a process instance.
+ cmsysProcess* cp = cmsysProcess_New();
+ if(!cp)
+ {
+ std::cerr << "Error allocating process instance in link script."
+ << std::endl;
+ return 1;
+ }
+
+ // Children should share stdout and stderr with this process.
+ cmsysProcess_SetPipeShared(cp, cmsysProcess_Pipe_STDOUT, 1);
+ cmsysProcess_SetPipeShared(cp, cmsysProcess_Pipe_STDERR, 1);
+
+ // Run the command lines verbatim.
+ cmsysProcess_SetOption(cp, cmsysProcess_Option_Verbatim, 1);
+
+ // Read command lines from the script.
+ std::ifstream fin(args[2].c_str());
+ if(!fin)
+ {
+ std::cerr << "Error opening link script \""
+ << args[2] << "\"" << std::endl;
+ return 1;
+ }
+
+ // Run one command at a time.
+ std::string command;
+ int result = 0;
+ while(result == 0 && cmSystemTools::GetLineFromStream(fin, command))
+ {
+ // Setup this command line.
+ const char* cmd[2] = {command.c_str(), 0};
+ cmsysProcess_SetCommand(cp, cmd);
+
+ // Report the command if verbose output is enabled.
+ if(verbose)
+ {
+ std::cout << command << std::endl;
+ }
+
+ // Run the command and wait for it to exit.
+ cmsysProcess_Execute(cp);
+ cmsysProcess_WaitForExit(cp, 0);
+
+ // Report failure if any.
+ switch(cmsysProcess_GetState(cp))
+ {
+ case cmsysProcess_State_Exited:
+ {
+ int value = cmsysProcess_GetExitValue(cp);
+ if(value != 0)
+ {
+ result = value;
+ }
+ }
+ break;
+ case cmsysProcess_State_Exception:
+ std::cerr << "Error running link command: "
+ << cmsysProcess_GetExceptionString(cp) << std::endl;
+ result = 1;
+ break;
+ case cmsysProcess_State_Error:
+ std::cerr << "Error running link command: "
+ << cmsysProcess_GetErrorString(cp) << std::endl;
+ result = 2;
+ break;
+ default:
+ break;
+ };
+ }
+
+ // Free the process instance.
+ cmsysProcess_Delete(cp);
+
+ // Return the final resulting return value.
+ return result;
+}
diff --git a/Source/cmake.h b/Source/cmake.h
index b2cea7b..d63cf7e 100644
--- a/Source/cmake.h
+++ b/Source/cmake.h
@@ -67,6 +67,11 @@ class cmake
static unsigned int GetMinorVersion();
static const char *GetReleaseVersion();
+ ///! construct an instance of cmake
+ static const char *GetCMakeFilesDirectory() {return "/CMakeFiles";};
+ static const char *GetCMakeFilesDirectoryPostSlash() {
+ return "CMakeFiles/";};
+
//@{
/**
* Set/Get the home directory (or output directory) in the project. The
@@ -318,6 +323,7 @@ protected:
void GenerateGraphViz(const char* fileName);
static int ExecuteEchoColor(std::vector<std::string>& args);
+ static int ExecuteLinkScript(std::vector<std::string>& args);
cmVariableWatch* VariableWatch;
diff --git a/Source/cmakemain.cxx b/Source/cmakemain.cxx
index bb01116..c16cd1c 100644
--- a/Source/cmakemain.cxx
+++ b/Source/cmakemain.cxx
@@ -82,6 +82,9 @@ static const cmDocumentationEntry cmDocumentationOptions[] =
{"--graphviz=[file]", "Generate graphviz of dependencies.",
"Generate a graphviz input file that will contain all the library and "
"executable dependencies in the project."},
+ {"--debug-trycompile", "Do not delete the try compile directories..",
+ "Do not delete the files and directories created for try_compile calls. "
+ "This is useful in debugging failed try_compiles."},
{"--help-command cmd [file]", "Print help for a single command and exit.",
"Full documentation specific to the given command is displayed."},
{"--help-command-list [file]", "List available listfile commands and exit.",
@@ -236,10 +239,13 @@ int do_cmake(int ac, char** av)
{
cmSystemTools::Error("No script specified for argument -P");
}
+ else
+ {
script_mode = true;
args.push_back(av[i]);
i++;
args.push_back(av[i]);
+ }
}
else
{
diff --git a/Source/kwsys/CommandLineArguments.cxx b/Source/kwsys/CommandLineArguments.cxx
index b1ee992..cdf254f 100644
--- a/Source/kwsys/CommandLineArguments.cxx
+++ b/Source/kwsys/CommandLineArguments.cxx
@@ -364,7 +364,7 @@ void CommandLineArguments::DeleteRemainingArguments(int argc, char*** argv)
int cc;
for ( cc = 0; cc < argc; ++ cc )
{
- delete [] *argv[cc];
+ delete [] (*argv)[cc];
}
delete [] *argv;
}
diff --git a/Source/kwsys/Directory.cxx b/Source/kwsys/Directory.cxx
index 3f7e6ad..f7fb5e9 100644
--- a/Source/kwsys/Directory.cxx
+++ b/Source/kwsys/Directory.cxx
@@ -143,6 +143,47 @@ bool Directory::Load(const char* name)
return _findclose(srchHandle) != -1;
}
+unsigned long Directory::GetNumberOfFilesInDirectory(const char* name)
+{
+#if _MSC_VER < 1300
+ long srchHandle;
+#else
+ intptr_t srchHandle;
+#endif
+ char* buf;
+ size_t n = strlen(name);
+ if ( name[n - 1] == '/' )
+ {
+ buf = new char[n + 1 + 1];
+ sprintf(buf, "%s*", name);
+ }
+ else
+ {
+ buf = new char[n + 2 + 1];
+ sprintf(buf, "%s/*", name);
+ }
+ struct _finddata_t data; // data of current file
+
+ // Now put them into the file array
+ srchHandle = _findfirst(buf, &data);
+ delete [] buf;
+
+ if ( srchHandle == -1 )
+ {
+ return 0;
+ }
+
+ // Loop through names
+ unsigned long count = 0;
+ do
+ {
+ count++;
+ }
+ while ( _findnext(srchHandle, &data) != -1 );
+ _findclose(srchHandle);
+ return count;
+}
+
} // namespace KWSYS_NAMESPACE
#else
@@ -174,6 +215,24 @@ bool Directory::Load(const char* name)
return 1;
}
+unsigned long Directory::GetNumberOfFilesInDirectory(const char* name)
+{
+ DIR* dir = opendir(name);
+
+ if (!dir)
+ {
+ return 0;
+ }
+
+ unsigned long count = 0;
+ for (dirent* d = readdir(dir); d; d = readdir(dir) )
+ {
+ count++;
+ }
+ closedir(dir);
+ return count;
+}
+
} // namespace KWSYS_NAMESPACE
#endif
diff --git a/Source/kwsys/Directory.hxx.in b/Source/kwsys/Directory.hxx.in
index 22aafcc..ddb9104 100644
--- a/Source/kwsys/Directory.hxx.in
+++ b/Source/kwsys/Directory.hxx.in
@@ -48,6 +48,12 @@ public:
unsigned long GetNumberOfFiles() const;
/**
+ * Return the number of files in the specified directory.
+ * A higher performance static method.
+ */
+ static unsigned long GetNumberOfFilesInDirectory(const char*);
+
+ /**
* Return the file at the given index, the indexing is 0 based
*/
const char* GetFile(unsigned long) const;
diff --git a/Source/kwsys/Process.h.in b/Source/kwsys/Process.h.in
index 96d3225..3d2db7b 100644
--- a/Source/kwsys/Process.h.in
+++ b/Source/kwsys/Process.h.in
@@ -36,6 +36,7 @@
#define kwsysProcess_SetPipeShared kwsys_ns(Process_SetPipeShared)
#define kwsysProcess_Option_Detach kwsys_ns(Process_Option_Detach)
#define kwsysProcess_Option_HideWindow kwsys_ns(Process_Option_HideWindow)
+#define kwsysProcess_Option_Verbatim kwsys_ns(Process_Option_Verbatim)
#define kwsysProcess_GetOption kwsys_ns(Process_GetOption)
#define kwsysProcess_SetOption kwsys_ns(Process_SetOption)
#define kwsysProcess_Option_e kwsys_ns(Process_Option_e)
@@ -154,6 +155,13 @@ kwsysEXPORT void kwsysProcess_SetPipeShared(kwsysProcess* cp, int pipe,
* kwsysProcess_Option_HideWindow = Whether to hide window on Windows.
* 0 = No (default)
* 1 = Yes
+ *
+ * kwsysProcess_Option_Verbatim = Whether SetCommand and AddCommand
+ * should treat the first argument
+ * as a verbatim command line
+ * and ignore the rest of the arguments.
+ * 0 = No (default)
+ * 1 = Yes
*/
kwsysEXPORT int kwsysProcess_GetOption(kwsysProcess* cp, int optionId);
kwsysEXPORT void kwsysProcess_SetOption(kwsysProcess* cp, int optionId,
@@ -161,7 +169,8 @@ kwsysEXPORT void kwsysProcess_SetOption(kwsysProcess* cp, int optionId,
enum kwsysProcess_Option_e
{
kwsysProcess_Option_HideWindow,
- kwsysProcess_Option_Detach
+ kwsysProcess_Option_Detach,
+ kwsysProcess_Option_Verbatim
};
/**
@@ -343,6 +352,7 @@ kwsysEXPORT void kwsysProcess_Kill(kwsysProcess* cp);
# undef kwsysProcess_SetPipeShared
# undef kwsysProcess_Option_Detach
# undef kwsysProcess_Option_HideWindow
+# undef kwsysProcess_Option_Verbatim
# undef kwsysProcess_GetOption
# undef kwsysProcess_SetOption
# undef kwsysProcess_Option_e
diff --git a/Source/kwsys/ProcessUNIX.c b/Source/kwsys/ProcessUNIX.c
index 0f4d1bc..ea257b0 100644
--- a/Source/kwsys/ProcessUNIX.c
+++ b/Source/kwsys/ProcessUNIX.c
@@ -24,17 +24,18 @@
Implementation for UNIX
-On UNIX, a child process is forked to exec the program. Three
-output pipes from the child are read by the parent process using a
-select call to block until data are ready. Two of the pipes are
-stdout and stderr for the child. The third is a special error pipe
-that has two purposes. First, if the child cannot exec the program,
-the error is reported through the error pipe. Second, the error
-pipe is left open until the child exits. This is used in
-conjunction with the timeout on the select call to implement a
-timeout for program even when it closes stdout and stderr.
+On UNIX, a child process is forked to exec the program. Three output
+pipes are read by the parent process using a select call to block
+until data are ready. Two of the pipes are stdout and stderr for the
+child. The third is a special pipe populated by a signal handler to
+indicate that a child has terminated. This is used in conjunction
+with the timeout on the select call to implement a timeout for program
+even when it closes stdout and stderr and at the same time avoiding
+races.
+
*/
+
/*
TODO:
@@ -59,6 +60,7 @@ do.
#include <time.h> /* gettimeofday */
#include <signal.h> /* sigaction */
#include <dirent.h> /* DIR, dirent */
+#include <ctype.h> /* isspace */
/* The number of pipes for the child's output. The standard stdout
and stderr pipes are the first two. One more pipe is used to
@@ -68,7 +70,7 @@ do.
#define KWSYSPE_PIPE_COUNT 3
#define KWSYSPE_PIPE_STDOUT 0
#define KWSYSPE_PIPE_STDERR 1
-#define KWSYSPE_PIPE_TERM 2
+#define KWSYSPE_PIPE_SIGNAL 2
/* The maximum amount to read from a pipe at a time. */
#define KWSYSPE_PIPE_BUFFER_SIZE 1024
@@ -89,7 +91,6 @@ typedef struct kwsysProcessCreateInformation_s
int StdIn;
int StdOut;
int StdErr;
- int TermPipe;
int ErrorPipe[2];
} kwsysProcessCreateInformation;
@@ -99,6 +100,7 @@ static void kwsysProcessCleanup(kwsysProcess* cp, int error);
static void kwsysProcessCleanupDescriptor(int* pfd);
static int kwsysProcessCreate(kwsysProcess* cp, int prIndex,
kwsysProcessCreateInformation* si, int* readEnd);
+static void kwsysProcessDestroy(kwsysProcess* cp);
static int kwsysProcessSetupOutputPipeFile(int* p, const char* name);
static int kwsysProcessGetTimeoutTime(kwsysProcess* cp, double* userTimeout,
kwsysProcessTime* timeoutTime);
@@ -117,6 +119,11 @@ static void kwsysProcessRestoreDefaultSignalHandlers(void);
static pid_t kwsysProcessFork(kwsysProcess* cp,
kwsysProcessCreateInformation* si);
static void kwsysProcessKill(pid_t process_id);
+static int kwsysProcessesAdd(kwsysProcess* cp);
+static void kwsysProcessesRemove(kwsysProcess* cp);
+static void kwsysProcessesSignalHandler(int signum, siginfo_t* info,
+ void* ucontext);
+static char** kwsysProcessParseVerbatimCommand(const char* command);
/*--------------------------------------------------------------------------*/
/* Structure containing data used to implement the child's execution. */
@@ -126,9 +133,13 @@ struct kwsysProcess_s
char*** Commands;
int NumberOfCommands;
- /* Descriptors for the read ends of the child's output pipes. */
+ /* Descriptors for the read ends of the child's output pipes and
+ the signal pipe. */
int PipeReadEnds[KWSYSPE_PIPE_COUNT];
+ /* Write descriptor for child termination signal pipe. */
+ int SignalPipe;
+
/* Buffer for pipe data. */
char PipeBuffer[KWSYSPE_PIPE_BUFFER_SIZE];
@@ -150,6 +161,9 @@ struct kwsysProcess_s
/* Whether the child was created as a detached process. */
int Detached;
+ /* Whether to treat command lines as verbatim. */
+ int Verbatim;
+
/* Time at which the child started. Negative for no timeout. */
kwsysProcessTime StartTime;
@@ -159,15 +173,15 @@ struct kwsysProcess_s
/* Flag for whether the timeout expired. */
int TimeoutExpired;
- /* The old SIGCHLD handler. */
- struct sigaction OldSigChldAction;
-
/* The number of pipes left open during execution. */
int PipesLeft;
/* File descriptor set for call to select. */
fd_set PipeSet;
+ /* The number of children still executing. */
+ int CommandsLeft;
+
/* The current status of the child process. */
int State;
@@ -300,7 +314,7 @@ int kwsysProcess_AddCommand(kwsysProcess* cp, char const* const* command)
char*** newCommands;
/* Make sure we have a command to add. */
- if(!cp || !command)
+ if(!cp || !command || !*command)
{
return 0;
}
@@ -323,7 +337,22 @@ int kwsysProcess_AddCommand(kwsysProcess* cp, char const* const* command)
}
/* Add the new command. */
+ if(cp->Verbatim)
{
+ /* In order to run the given command line verbatim we need to
+ parse it. */
+ newCommands[cp->NumberOfCommands] =
+ kwsysProcessParseVerbatimCommand(*command);
+ if(!newCommands[cp->NumberOfCommands])
+ {
+ /* Out of memory. */
+ free(newCommands);
+ return 0;
+ }
+ }
+ else
+ {
+ /* Copy each argument string individually. */
char const* const* c = command;
int n = 0;
int i = 0;
@@ -483,6 +512,7 @@ int kwsysProcess_GetOption(kwsysProcess* cp, int optionId)
switch(optionId)
{
case kwsysProcess_Option_Detach: return cp->OptionDetach;
+ case kwsysProcess_Option_Verbatim: return cp->Verbatim;
default: return 0;
}
}
@@ -498,6 +528,7 @@ void kwsysProcess_SetOption(kwsysProcess* cp, int optionId, int value)
switch(optionId)
{
case kwsysProcess_Option_Detach: cp->OptionDetach = value; break;
+ case kwsysProcess_Option_Verbatim: cp->Verbatim = value; break;
default: break;
}
}
@@ -558,8 +589,7 @@ const char* kwsysProcess_GetExceptionString(kwsysProcess* cp)
void kwsysProcess_Execute(kwsysProcess* cp)
{
int i;
- struct sigaction newSigChldAction;
- kwsysProcessCreateInformation si = {-1, -1, -1, -1, {-1, -1}};
+ kwsysProcessCreateInformation si = {-1, -1, -1, {-1, -1}};
/* Do not execute a second copy simultaneously. */
if(!cp || cp->State == kwsysProcess_State_Executing)
@@ -597,15 +627,19 @@ void kwsysProcess_Execute(kwsysProcess* cp)
}
}
- /* We want no special handling of SIGCHLD. Repeat call until it is
- not interrupted. */
- memset(&newSigChldAction, 0, sizeof(struct sigaction));
- newSigChldAction.sa_handler = SIG_DFL;
- while((sigaction(SIGCHLD, &newSigChldAction, &cp->OldSigChldAction) < 0) &&
- (errno == EINTR));
+ /* If not running a detached child, add this object to the global
+ set of process objects that wish to be notified when a child
+ exits. */
+ if(!cp->OptionDetach)
+ {
+ if(!kwsysProcessesAdd(cp))
+ {
+ kwsysProcessCleanup(cp, 1);
+ return;
+ }
+ }
- /* Setup the stderr and termination pipes to be shared by all processes. */
- for(i=KWSYSPE_PIPE_STDERR; i < KWSYSPE_PIPE_COUNT; ++i)
+ /* Setup the stderr pipe to be shared by all processes. */
{
/* Create the pipe. */
int p[2];
@@ -616,15 +650,8 @@ void kwsysProcess_Execute(kwsysProcess* cp)
}
/* Store the pipe. */
- cp->PipeReadEnds[i] = p[0];
- if(i == KWSYSPE_PIPE_STDERR)
- {
+ cp->PipeReadEnds[KWSYSPE_PIPE_STDERR] = p[0];
si.StdErr = p[1];
- }
- else
- {
- si.TermPipe = p[1];
- }
/* Set close-on-exec flag on the pipe's ends. */
if((fcntl(p[0], F_SETFD, FD_CLOEXEC) < 0) ||
@@ -632,7 +659,6 @@ void kwsysProcess_Execute(kwsysProcess* cp)
{
kwsysProcessCleanup(cp, 1);
kwsysProcessCleanupDescriptor(&si.StdErr);
- kwsysProcessCleanupDescriptor(&si.TermPipe);
return;
}
}
@@ -645,7 +671,6 @@ void kwsysProcess_Execute(kwsysProcess* cp)
{
kwsysProcessCleanup(cp, 1);
kwsysProcessCleanupDescriptor(&si.StdErr);
- kwsysProcessCleanupDescriptor(&si.TermPipe);
return;
}
}
@@ -688,7 +713,6 @@ void kwsysProcess_Execute(kwsysProcess* cp)
{
kwsysProcessCleanupDescriptor(&si.StdErr);
}
- kwsysProcessCleanupDescriptor(&si.TermPipe);
kwsysProcessCleanupDescriptor(&si.ErrorPipe[0]);
kwsysProcessCleanupDescriptor(&si.ErrorPipe[1]);
return;
@@ -703,7 +727,6 @@ void kwsysProcess_Execute(kwsysProcess* cp)
{
kwsysProcessCleanupDescriptor(&si.StdErr);
}
- kwsysProcessCleanupDescriptor(&si.TermPipe);
/* Restore the working directory. */
if(cp->RealWorkingDirectory)
@@ -823,9 +846,10 @@ int kwsysProcess_WaitForData(kwsysProcess* cp, char** data, int* length,
if(n > 0)
{
/* We have data on this pipe. */
- if(i == KWSYSPE_PIPE_TERM)
+ if(i == KWSYSPE_PIPE_SIGNAL)
{
- /* This is data on the special termination pipe. Ignore it. */
+ /* A child process has terminated. */
+ kwsysProcessDestroy(cp);
}
else if(data && length)
{
@@ -970,7 +994,6 @@ int kwsysProcess_WaitForData(kwsysProcess* cp, char** data, int* length,
/*--------------------------------------------------------------------------*/
int kwsysProcess_WaitForExit(kwsysProcess* cp, double* userTimeout)
{
- int result = 0;
int status = 0;
int prPipe = 0;
@@ -989,26 +1012,6 @@ int kwsysProcess_WaitForExit(kwsysProcess* cp, double* userTimeout)
}
}
- /* Wait for each child to terminate. The process should have
- already exited because KWSYSPE_PIPE_TERM has been closed by this
- point. Repeat the call until it is not interrupted. */
- if(!cp->Detached)
- {
- int i;
- for(i=0; i < cp->NumberOfCommands; ++i)
- {
- while(((result = waitpid(cp->ForkPIDs[i],
- &cp->CommandExitCodes[i], 0)) < 0) &&
- (errno == EINTR));
- if(result <= 0 && cp->State != kwsysProcess_State_Error)
- {
- /* Unexpected error. Report the first time this happens. */
- strncpy(cp->ErrorMessage, strerror(errno), KWSYSPE_PIPE_BUFFER_SIZE);
- cp->State = kwsysProcess_State_Error;
- }
- }
- }
-
/* Check if there was an error in one of the waitpid calls. */
if(cp->State == kwsysProcess_State_Error)
{
@@ -1080,22 +1083,35 @@ void kwsysProcess_Kill(kwsysProcess* cp)
return;
}
+ /* Close all the pipe read ends. Do this before killing the
+ children because Cygwin has problems killing processes that are
+ blocking to wait for writing to their output pipes. First close
+ the child exit report pipe write end to avoid causing a SIGPIPE
+ when the child terminates and our signal handler tries to report
+ it. */
+ kwsysProcessCleanupDescriptor(&cp->SignalPipe);
+ for(i=0; i < KWSYSPE_PIPE_COUNT; ++i)
+ {
+ kwsysProcessCleanupDescriptor(&cp->PipeReadEnds[i]);
+ }
+ cp->PipesLeft = 0;
+
/* Kill the children. */
cp->Killed = 1;
for(i=0; i < cp->NumberOfCommands; ++i)
{
+ int status;
if(cp->ForkPIDs[i])
{
+ /* Kill the child. */
kwsysProcessKill(cp->ForkPIDs[i]);
- }
- }
- /* Close all the pipe read ends. */
- for(i=0; i < KWSYSPE_PIPE_COUNT; ++i)
- {
- kwsysProcessCleanupDescriptor(&cp->PipeReadEnds[i]);
+ /* Reap the child. Keep trying until the call is not
+ interrupted. */
+ while((waitpid(cp->ForkPIDs[i], &status, 0) < 0) && (errno == EINTR));
}
- cp->PipesLeft = 0;
+ }
+ cp->CommandsLeft = 0;
}
/*--------------------------------------------------------------------------*/
@@ -1107,6 +1123,7 @@ static int kwsysProcessInitialize(kwsysProcess* cp)
{
cp->PipeReadEnds[i] = -1;
}
+ cp->SignalPipe = -1;
cp->SelectError = 0;
cp->StartTime.tv_sec = -1;
cp->StartTime.tv_usec = -1;
@@ -1114,6 +1131,7 @@ static int kwsysProcessInitialize(kwsysProcess* cp)
cp->TimeoutTime.tv_usec = -1;
cp->TimeoutExpired = 0;
cp->PipesLeft = 0;
+ cp->CommandsLeft = 0;
FD_ZERO(&cp->PipeSet);
cp->State = kwsysProcess_State_Starting;
cp->Killed = 0;
@@ -1194,6 +1212,7 @@ static void kwsysProcessCleanup(kwsysProcess* cp, int error)
{
/* Kill the child. */
kwsysProcessKill(cp->ForkPIDs[i]);
+
/* Reap the child. Keep trying until the call is not
interrupted. */
while((waitpid(cp->ForkPIDs[i], &status, 0) < 0) &&
@@ -1209,9 +1228,13 @@ static void kwsysProcessCleanup(kwsysProcess* cp, int error)
}
}
- /* Restore the SIGCHLD handler. */
- while((sigaction(SIGCHLD, &cp->OldSigChldAction, 0) < 0) &&
- (errno == EINTR));
+ /* If not creating a detached child, remove this object from the
+ global set of process objects that wish to be notified when a
+ child exits. */
+ if(!cp->OptionDetach)
+ {
+ kwsysProcessesRemove(cp);
+ }
/* Free memory. */
if(cp->ForkPIDs)
@@ -1360,12 +1383,10 @@ static int kwsysProcessCreate(kwsysProcess* cp, int prIndex,
}
/* Clear the close-on-exec flag for stdin, stdout, and stderr.
- Also clear it for the termination pipe. All other pipe handles
- will be closed when exec succeeds. */
+ All other pipe handles will be closed when exec succeeds. */
fcntl(0, F_SETFD, 0);
fcntl(1, F_SETFD, 0);
fcntl(2, F_SETFD, 0);
- fcntl(si->TermPipe, F_SETFD, 0);
/* Restore all default signal handlers. */
kwsysProcessRestoreDefaultSignalHandlers();
@@ -1377,6 +1398,9 @@ static int kwsysProcessCreate(kwsysProcess* cp, int prIndex,
kwsysProcessChildErrorExit(si->ErrorPipe[1]);
}
+ /* A child has been created. */
+ ++cp->CommandsLeft;
+
/* We are done with the error reporting pipe write end. */
kwsysProcessCleanupDescriptor(&si->ErrorPipe[1]);
@@ -1425,6 +1449,47 @@ static int kwsysProcessCreate(kwsysProcess* cp, int prIndex,
}
/*--------------------------------------------------------------------------*/
+static void kwsysProcessDestroy(kwsysProcess* cp)
+{
+ /* A child process has terminated. Reap it if it is one handled by
+ this object. */
+ int i;
+ for(i=0; i < cp->NumberOfCommands; ++i)
+ {
+ if(cp->ForkPIDs[i])
+ {
+ int result;
+ while(((result = waitpid(cp->ForkPIDs[i],
+ &cp->CommandExitCodes[i], WNOHANG)) < 0) &&
+ (errno == EINTR));
+ if(result > 0)
+ {
+ /* This child has termianted. */
+ cp->ForkPIDs[i] = 0;
+ if(--cp->CommandsLeft == 0)
+ {
+ /* All children have terminated. Close the signal pipe
+ write end so that no more notifications are sent to this
+ object. */
+ kwsysProcessCleanupDescriptor(&cp->SignalPipe);
+
+ /* TODO: Once the children have terminated, switch
+ WaitForData to use a non-blocking read to get the
+ rest of the data from the pipe. This is needed when
+ grandchildren keep the output pipes open. */
+ }
+ }
+ else if(result < 0 && cp->State != kwsysProcess_State_Error)
+ {
+ /* Unexpected error. Report the first time this happens. */
+ strncpy(cp->ErrorMessage, strerror(errno), KWSYSPE_PIPE_BUFFER_SIZE);
+ cp->State = kwsysProcess_State_Error;
+ }
+ }
+ }
+}
+
+/*--------------------------------------------------------------------------*/
static int kwsysProcessSetupOutputPipeFile(int* p, const char* name)
{
int fout;
@@ -1909,12 +1974,15 @@ static pid_t kwsysProcessFork(kwsysProcess* cp,
#elif defined(__hpux) || defined(__sparc) || defined(__sgi) || defined(_AIX)
# define KWSYSPE_PS_COMMAND "ps -ef"
# define KWSYSPE_PS_FORMAT "%*s %d %d %*[^\n]\n"
+#elif defined(__CYGWIN__)
+# define KWSYSPE_PS_COMMAND "ps aux"
+# define KWSYSPE_PS_FORMAT "%d %d %*[^\n]\n"
#endif
/*--------------------------------------------------------------------------*/
static void kwsysProcessKill(pid_t process_id)
{
-#if defined(__linux__)
+#if defined(__linux__) || defined(__CYGWIN__)
DIR* procdir;
#endif
@@ -1922,7 +1990,7 @@ static void kwsysProcessKill(pid_t process_id)
kill(process_id, SIGSTOP);
/* Kill all children if we can find them. */
-#if defined(__linux__)
+#if defined(__linux__) || defined(__CYGWIN__)
/* First try using the /proc filesystem. */
if((procdir = opendir("/proc")) != NULL)
{
@@ -1980,8 +2048,8 @@ static void kwsysProcessKill(pid_t process_id)
}
else
#endif
-#if defined(KWSYSPE_PS_COMMAND)
{
+#if defined(KWSYSPE_PS_COMMAND)
/* Try running "ps" to get the process information. */
FILE* ps = popen(KWSYSPE_PS_COMMAND, "r");
@@ -2005,9 +2073,461 @@ static void kwsysProcessKill(pid_t process_id)
{
pclose(ps);
}
- }
#endif
+ }
/* Kill the process. */
kill(process_id, SIGKILL);
}
+
+/*--------------------------------------------------------------------------*/
+/* Global set of executing processes for use by the signal handler.
+ This global instance will be zero-initialized by the compiler. */
+typedef struct kwsysProcessInstances_s
+{
+ int Count;
+ int Size;
+ kwsysProcess** Processes;
+} kwsysProcessInstances;
+static kwsysProcessInstances kwsysProcesses;
+
+/* The old SIGCHLD handler. */
+static struct sigaction kwsysProcessesOldSigChldAction;
+
+/*--------------------------------------------------------------------------*/
+static void kwsysProcessesUpdate(kwsysProcessInstances* newProcesses)
+{
+ /* Block SIGCHLD while we update the set of pipes to check.
+ TODO: sigprocmask is undefined for threaded apps. See
+ pthread_sigmask. */
+ sigset_t newset;
+ sigset_t oldset;
+ sigemptyset(&newset);
+ sigaddset(&newset, SIGCHLD);
+ sigprocmask(SIG_BLOCK, &newset, &oldset);
+
+ /* Store the new set in that seen by the signal handler. */
+ kwsysProcesses = *newProcesses;
+
+ /* Restore the signal mask to the previous setting. */
+ sigprocmask(SIG_SETMASK, &oldset, 0);
+}
+
+/*--------------------------------------------------------------------------*/
+static int kwsysProcessesAdd(kwsysProcess* cp)
+{
+ /* Create a pipe through which the signal handler can notify the
+ given process object that a child has exited. */
+ {
+ /* Create the pipe. */
+ int oldfl[2];
+ int p[2];
+ if(pipe(p) < 0)
+ {
+ return 0;
+ }
+
+ /* Store the pipes now to be sure they are cleaned up later. */
+ cp->PipeReadEnds[KWSYSPE_PIPE_SIGNAL] = p[0];
+ cp->SignalPipe = p[1];
+
+ /* Switch the pipe to non-blocking mode so that reading a byte can
+ be an atomic test-and-set. */
+ if((oldfl[0] = fcntl(p[0], F_GETFL) < 0) ||
+ (oldfl[1] = fcntl(p[1], F_GETFL) < 0) ||
+ (fcntl(p[0], F_SETFL, oldfl[0] | O_NONBLOCK) < 0) ||
+ (fcntl(p[1], F_SETFL, oldfl[1] | O_NONBLOCK) < 0))
+ {
+ return 0;
+ }
+
+ /* The children do not need this pipe. Set close-on-exec flag on
+ the pipe's ends. */
+ if((fcntl(p[0], F_SETFD, FD_CLOEXEC) < 0) ||
+ (fcntl(p[1], F_SETFD, FD_CLOEXEC) < 0))
+ {
+ return 0;
+ }
+ }
+
+ /* Attempt to add the given signal pipe to the signal handler set. */
+ {
+
+ /* Make sure there is enough space for the new signal pipe. */
+ kwsysProcessInstances oldProcesses = kwsysProcesses;
+ kwsysProcessInstances newProcesses = oldProcesses;
+ if(oldProcesses.Count == oldProcesses.Size)
+ {
+ /* Start with enough space for a small number of process instances
+ and double the size each time more is needed. */
+ newProcesses.Size = oldProcesses.Size? oldProcesses.Size*2 : 4;
+
+ /* Try allocating the new block of memory. */
+ if((newProcesses.Processes = ((kwsysProcess**)
+ malloc(newProcesses.Size*
+ sizeof(kwsysProcess*)))))
+ {
+ /* Copy the old pipe set to the new memory. */
+ if(oldProcesses.Count > 0)
+ {
+ memcpy(newProcesses.Processes, oldProcesses.Processes,
+ (oldProcesses.Count * sizeof(kwsysProcess*)));
+ }
+ }
+ else
+ {
+ /* Failed to allocate memory for the new signal pipe set. */
+ return 0;
+ }
+ }
+
+ /* Append the new signal pipe to the set. */
+ newProcesses.Processes[newProcesses.Count++] = cp;
+
+ /* Store the new set in that seen by the signal handler. */
+ kwsysProcessesUpdate(&newProcesses);
+
+ /* Free the original pipes if new ones were allocated. */
+ if(newProcesses.Processes != oldProcesses.Processes)
+ {
+ free(oldProcesses.Processes);
+ }
+
+ /* If this is the first process, enable the signal handler. */
+ if(newProcesses.Count == 1)
+ {
+ /* Install our handler for SIGCHLD. Repeat call until it is not
+ interrupted. */
+ struct sigaction newSigChldAction;
+ memset(&newSigChldAction, 0, sizeof(struct sigaction));
+ newSigChldAction.sa_sigaction = kwsysProcessesSignalHandler;
+ newSigChldAction.sa_flags = SA_NOCLDSTOP | SA_RESTART | SA_SIGINFO;
+ while((sigaction(SIGCHLD, &newSigChldAction,
+ &kwsysProcessesOldSigChldAction) < 0) &&
+ (errno == EINTR));
+ }
+ }
+
+ return 1;
+}
+
+/*--------------------------------------------------------------------------*/
+static void kwsysProcessesRemove(kwsysProcess* cp)
+{
+ /* Attempt to remove the given signal pipe from the signal handler set. */
+ {
+ /* Find the given process in the set. */
+ kwsysProcessInstances newProcesses = kwsysProcesses;
+ int i;
+ for(i=0; i < newProcesses.Count; ++i)
+ {
+ if(newProcesses.Processes[i] == cp)
+ {
+ break;
+ }
+ }
+ if(i < newProcesses.Count)
+ {
+ /* Remove the process from the set. */
+ --newProcesses.Count;
+ for(; i < newProcesses.Count; ++i)
+ {
+ newProcesses.Processes[i] = newProcesses.Processes[i+1];
+ }
+
+ /* If this was the last process, disable the signal handler. */
+ if(newProcesses.Count == 0)
+ {
+ /* Restore the SIGCHLD handler. Repeat call until it is not
+ interrupted. */
+ while((sigaction(SIGCHLD, &kwsysProcessesOldSigChldAction, 0) < 0) &&
+ (errno == EINTR));
+
+ /* Free the table of process pointers since it is now empty.
+ This is safe because the signal handler has been removed. */
+ newProcesses.Size = 0;
+ free(newProcesses.Processes);
+ newProcesses.Processes = 0;
+ }
+
+ /* Store the new set in that seen by the signal handler. */
+ kwsysProcessesUpdate(&newProcesses);
+ }
+ }
+
+ /* Close the pipe through which the signal handler may have notified
+ the given process object that a child has exited. */
+ kwsysProcessCleanupDescriptor(&cp->SignalPipe);
+}
+
+/*--------------------------------------------------------------------------*/
+static void kwsysProcessesSignalHandler(int signum, siginfo_t* info,
+ void* ucontext)
+{
+ /* Signal all process objects that a child has terminated. */
+ int i;
+ (void)signum;
+ (void)info;
+ (void)ucontext;
+ for(i=0; i < kwsysProcesses.Count; ++i)
+ {
+ /* Set the pipe in a signalled state. */
+ char buf = 1;
+ kwsysProcess* cp = kwsysProcesses.Processes[i];
+ read(cp->PipeReadEnds[KWSYSPE_PIPE_SIGNAL], &buf, 1);
+ write(cp->SignalPipe, &buf, 1);
+ }
+}
+
+/*--------------------------------------------------------------------------*/
+static int kwsysProcessAppendByte(char* local,
+ char** begin, char** end,
+ int* size, char c)
+{
+ /* Allocate space for the character. */
+ if((*end - *begin) >= *size)
+ {
+ int length = *end - *begin;
+ char* newBuffer = (char*)malloc(*size*2);
+ if(!newBuffer)
+ {
+ return 0;
+ }
+ memcpy(newBuffer, *begin, length*sizeof(char));
+ if(*begin != local)
+ {
+ free(*begin);
+ }
+ *begin = newBuffer;
+ *end = *begin + length;
+ *size *= 2;
+ }
+
+ /* Store the character. */
+ *(*end)++ = c;
+ return 1;
+}
+
+/*--------------------------------------------------------------------------*/
+static int kwsysProcessAppendArgument(char** local,
+ char*** begin, char*** end,
+ int* size,
+ char* arg_local,
+ char** arg_begin, char** arg_end,
+ int* arg_size)
+{
+ /* Append a null-terminator to the argument string. */
+ if(!kwsysProcessAppendByte(arg_local, arg_begin, arg_end, arg_size, '\0'))
+ {
+ return 0;
+ }
+
+ /* Allocate space for the argument pointer. */
+ if((*end - *begin) >= *size)
+ {
+ int length = *end - *begin;
+ char** newPointers = (char**)malloc(*size*2*sizeof(char*));
+ if(!newPointers)
+ {
+ return 0;
+ }
+ memcpy(newPointers, *begin, length*sizeof(char*));
+ if(*begin != local)
+ {
+ free(*begin);
+ }
+ *begin = newPointers;
+ *end = *begin + length;
+ *size *= 2;
+ }
+
+ /* Allocate space for the argument string. */
+ **end = (char*)malloc(*arg_end - *arg_begin);
+ if(!**end)
+ {
+ return 0;
+ }
+
+ /* Store the argument in the command array. */
+ memcpy(**end, *arg_begin, *arg_end - *arg_begin);
+ ++(*end);
+
+ /* Reset the argument to be empty. */
+ *arg_end = *arg_begin;
+
+ return 1;
+}
+
+/*--------------------------------------------------------------------------*/
+#define KWSYSPE_LOCAL_BYTE_COUNT 1024
+#define KWSYSPE_LOCAL_ARGS_COUNT 32
+static char** kwsysProcessParseVerbatimCommand(const char* command)
+{
+ /* Create a buffer for argument pointers during parsing. */
+ char* local_pointers[KWSYSPE_LOCAL_ARGS_COUNT];
+ int pointers_size = KWSYSPE_LOCAL_ARGS_COUNT;
+ char** pointer_begin = local_pointers;
+ char** pointer_end = pointer_begin;
+
+ /* Create a buffer for argument strings during parsing. */
+ char local_buffer[KWSYSPE_LOCAL_BYTE_COUNT];
+ int buffer_size = KWSYSPE_LOCAL_BYTE_COUNT;
+ char* buffer_begin = local_buffer;
+ char* buffer_end = buffer_begin;
+
+ /* Parse the command string. Try to behave like a UNIX shell. */
+ char** newCommand = 0;
+ const char* c = command;
+ int in_argument = 0;
+ int in_escape = 0;
+ int in_single = 0;
+ int in_double = 0;
+ int failed = 0;
+ for(;*c; ++c)
+ {
+ if(in_escape)
+ {
+ /* This character is escaped so do no special handling. */
+ if(!in_argument)
+ {
+ in_argument = 1;
+ }
+ if(!kwsysProcessAppendByte(local_buffer, &buffer_begin,
+ &buffer_end, &buffer_size, *c))
+ {
+ failed = 1;
+ break;
+ }
+ in_escape = 0;
+ }
+ else if(*c == '\\' && !in_single)
+ {
+ /* The next character should be escaped. */
+ in_escape = 1;
+ }
+ else if(*c == '\'' && !in_double)
+ {
+ /* Enter or exit single-quote state. */
+ if(in_single)
+ {
+ in_single = 0;
+ }
+ else
+ {
+ in_single = 1;
+ if(!in_argument)
+ {
+ in_argument = 1;
+ }
+ }
+ }
+ else if(*c == '"' && !in_single)
+ {
+ /* Enter or exit double-quote state. */
+ if(in_double)
+ {
+ in_double = 0;
+ }
+ else
+ {
+ in_double = 1;
+ if(!in_argument)
+ {
+ in_argument = 1;
+ }
+ }
+ }
+ else if(isspace(*c))
+ {
+ if(in_argument)
+ {
+ if(in_single || in_double)
+ {
+ /* This space belongs to a quoted argument. */
+ if(!kwsysProcessAppendByte(local_buffer, &buffer_begin,
+ &buffer_end, &buffer_size, *c))
+ {
+ failed = 1;
+ break;
+ }
+ }
+ else
+ {
+ /* This argument has been terminated by whitespace. */
+ if(!kwsysProcessAppendArgument(local_pointers, &pointer_begin,
+ &pointer_end, &pointers_size,
+ local_buffer, &buffer_begin,
+ &buffer_end, &buffer_size))
+ {
+ failed = 1;
+ break;
+ }
+ in_argument = 0;
+ }
+ }
+ }
+ else
+ {
+ /* This character belong to an argument. */
+ if(!in_argument)
+ {
+ in_argument = 1;
+ }
+ if(!kwsysProcessAppendByte(local_buffer, &buffer_begin,
+ &buffer_end, &buffer_size, *c))
+ {
+ failed = 1;
+ break;
+ }
+ }
+ }
+
+ /* Finish the last argument. */
+ if(in_argument)
+ {
+ if(!kwsysProcessAppendArgument(local_pointers, &pointer_begin,
+ &pointer_end, &pointers_size,
+ local_buffer, &buffer_begin,
+ &buffer_end, &buffer_size))
+ {
+ failed = 1;
+ }
+ }
+
+ /* If we still have memory allocate space for the new command
+ buffer. */
+ if(!failed)
+ {
+ int n = pointer_end - pointer_begin;
+ newCommand = (char**)malloc((n+1)*sizeof(char*));
+ }
+
+ if(newCommand)
+ {
+ /* Copy the arguments into the new command buffer. */
+ int n = pointer_end - pointer_begin;
+ memcpy(newCommand, pointer_begin, sizeof(char*)*n);
+ newCommand[n] = 0;
+ }
+ else
+ {
+ /* Free arguments already allocated. */
+ while(pointer_end != pointer_begin)
+ {
+ free(*(--pointer_end));
+ }
+ }
+
+ /* Free temporary buffers. */
+ if(pointer_begin != local_pointers)
+ {
+ free(pointer_begin);
+ }
+ if(buffer_begin != local_buffer)
+ {
+ free(buffer_begin);
+ }
+
+ /* Return the final command buffer. */
+ return newCommand;
+}
diff --git a/Source/kwsys/ProcessWin32.c b/Source/kwsys/ProcessWin32.c
index 97e5706..6929c3e 100644
--- a/Source/kwsys/ProcessWin32.c
+++ b/Source/kwsys/ProcessWin32.c
@@ -104,8 +104,14 @@ static void kwsysProcessDestroy(kwsysProcess* cp, int event);
static int kwsysProcessSetupOutputPipeFile(PHANDLE handle, const char* name);
static int kwsysProcessSetupSharedPipe(DWORD nStdHandle, PHANDLE handle);
static void kwsysProcessCleanupHandle(PHANDLE h);
+static void kwsysProcessCleanupHandleSafe(PHANDLE h, DWORD nStdHandle);
static void kwsysProcessCleanup(kwsysProcess* cp, int error);
static void kwsysProcessCleanErrorMessage(kwsysProcess* cp);
+static int kwsysProcessComputeCommandLength(kwsysProcess* cp,
+ char const* const* command);
+static void kwsysProcessComputeCommandLine(kwsysProcess* cp,
+ char const* const* command,
+ char* cmd);
static int kwsysProcessGetTimeoutTime(kwsysProcess* cp, double* userTimeout,
kwsysProcessTime* timeoutTime);
static int kwsysProcessGetTimeoutLeft(kwsysProcessTime* timeoutTime,
@@ -205,6 +211,9 @@ struct kwsysProcess_s
/* Whether to hide the child process's window. */
int HideWindow;
+ /* Whether to treat command lines as verbatim. */
+ int Verbatim;
+
/* On Win9x platforms, the path to the forwarding executable. */
char* Win9x;
@@ -645,7 +654,7 @@ int kwsysProcess_AddCommand(kwsysProcess* cp, char const* const* command)
char** newCommands;
/* Make sure we have a command to add. */
- if(!cp || !command)
+ if(!cp || !command || !*command)
{
return 0;
}
@@ -675,66 +684,8 @@ int kwsysProcess_AddCommand(kwsysProcess* cp, char const* const* command)
because they come before the closing double-quote for the
argument. */
{
- char* cmd;
- char const* const* arg;
- int length = 0;
/* First determine the length of the final string. */
- for(arg = command; *arg; ++arg)
- {
- /* Keep track of how many backslashes have been encountered in a
- row in this argument. */
- int backslashes = 0;
- int spaces = 0;
- const char* c;
-
- /* Scan the string for spaces. If there are no spaces, we can
- pass the argument verbatim. */
- for(c=*arg; *c; ++c)
- {
- if(*c == ' ' || *c == '\t')
- {
- spaces = 1;
- break;
- }
- }
-
- /* Add the length of the argument, plus 1 for the space
- separating the arguments. */
- length += (int)strlen(*arg) + 1;
-
- if(spaces)
- {
- /* Add 2 for double quotes since spaces are present. */
- length += 2;
-
- /* Scan the string to find characters that need escaping. */
- for(c=*arg; *c; ++c)
- {
- if(*c == '\\')
- {
- /* Found a backslash. It may need to be escaped later. */
- ++backslashes;
- }
- else if(*c == '"')
- {
- /* Found a double-quote. We need to escape it and all
- immediately preceding backslashes. */
- length += backslashes + 1;
- backslashes = 0;
- }
- else
- {
- /* Found another character. This eliminates the possibility
- that any immediately preceding backslashes will be
- escaped. */
- backslashes = 0;
- }
- }
-
- /* We need to escape all ending backslashes. */
- length += backslashes;
- }
- }
+ int length = kwsysProcessComputeCommandLength(cp, command);
/* Allocate enough space for the command. We do not need an extra
byte for the terminating null because we allocated a space for
@@ -748,94 +699,8 @@ int kwsysProcess_AddCommand(kwsysProcess* cp, char const* const* command)
}
/* Construct the command line in the allocated buffer. */
- cmd = newCommands[cp->NumberOfCommands];
- for(arg = command; *arg; ++arg)
- {
- /* Keep track of how many backslashes have been encountered in a
- row in an argument. */
- int backslashes = 0;
- int spaces = 0;
- const char* c;
-
- /* Scan the string for spaces. If there are no spaces, we can
- pass the argument verbatim. */
- for(c=*arg; *c; ++c)
- {
- if(*c == ' ' || *c == '\t')
- {
- spaces = 1;
- break;
- }
- }
-
- /* Add the separating space if this is not the first argument. */
- if(arg != command)
- {
- *cmd++ = ' ';
- }
-
- if(spaces)
- {
- /* Add the opening double-quote for this argument. */
- *cmd++ = '"';
-
- /* Add the characters of the argument, possibly escaping them. */
- for(c=*arg; *c; ++c)
- {
- if(*c == '\\')
- {
- /* Found a backslash. It may need to be escaped later. */
- ++backslashes;
- *cmd++ = '\\';
- }
- else if(*c == '"')
- {
- /* Add enough backslashes to escape any that preceded the
- double-quote. */
- while(backslashes > 0)
- {
- --backslashes;
- *cmd++ = '\\';
- }
-
- /* Add the backslash to escape the double-quote. */
- *cmd++ = '\\';
-
- /* Add the double-quote itself. */
- *cmd++ = '"';
- }
- else
- {
- /* We encountered a normal character. This eliminates any
- escaping needed for preceding backslashes. Add the
- character. */
- backslashes = 0;
- *cmd++ = *c;
- }
- }
-
- /* Add enough backslashes to escape any trailing ones. */
- while(backslashes > 0)
- {
- --backslashes;
- *cmd++ = '\\';
- }
-
- /* Add the closing double-quote for this argument. */
- *cmd++ = '"';
- }
- else
- {
- /* No spaces. Add the argument verbatim. */
- for(c=*arg; *c; ++c)
- {
- *cmd++ = *c;
- }
- }
- }
-
- /* Add the terminating null character to the command line. */
- *cmd = 0;
+ kwsysProcessComputeCommandLine(cp, command,
+ newCommands[cp->NumberOfCommands]);
}
/* Save the new array of commands. */
@@ -967,6 +832,7 @@ int kwsysProcess_GetOption(kwsysProcess* cp, int optionId)
{
case kwsysProcess_Option_Detach: return cp->OptionDetach;
case kwsysProcess_Option_HideWindow: return cp->HideWindow;
+ case kwsysProcess_Option_Verbatim: return cp->Verbatim;
default: return 0;
}
}
@@ -983,6 +849,7 @@ void kwsysProcess_SetOption(kwsysProcess* cp, int optionId, int value)
{
case kwsysProcess_Option_Detach: cp->OptionDetach = value; break;
case kwsysProcess_Option_HideWindow: cp->HideWindow = value; break;
+ case kwsysProcess_Option_Verbatim: cp->Verbatim = value; break;
default: break;
}
}
@@ -1145,7 +1012,8 @@ void kwsysProcess_Execute(kwsysProcess* cp)
&si.StartupInfo.hStdError))
{
kwsysProcessCleanup(cp, 1);
- kwsysProcessCleanupHandle(&si.StartupInfo.hStdError);
+ kwsysProcessCleanupHandleSafe(&si.StartupInfo.hStdError,
+ STD_ERROR_HANDLE);
return;
}
}
@@ -1166,9 +1034,12 @@ void kwsysProcess_Execute(kwsysProcess* cp)
/* Release resources that may have been allocated for this
process before an error occurred. */
kwsysProcessCleanupHandle(&readEnd);
- kwsysProcessCleanupHandle(&si.StartupInfo.hStdInput);
- kwsysProcessCleanupHandle(&si.StartupInfo.hStdOutput);
- kwsysProcessCleanupHandle(&si.StartupInfo.hStdError);
+ kwsysProcessCleanupHandleSafe(&si.StartupInfo.hStdInput,
+ STD_INPUT_HANDLE);
+ kwsysProcessCleanupHandleSafe(&si.StartupInfo.hStdOutput,
+ STD_OUTPUT_HANDLE);
+ kwsysProcessCleanupHandleSafe(&si.StartupInfo.hStdError,
+ STD_ERROR_HANDLE);
kwsysProcessCleanupHandle(&si.ErrorPipeRead);
kwsysProcessCleanupHandle(&si.ErrorPipeWrite);
return;
@@ -1183,7 +1054,7 @@ void kwsysProcess_Execute(kwsysProcess* cp)
processes in the pipeline. The stdout and stdin pipes are not
shared among all children and are therefore closed by
kwsysProcessCreate after each child is created. */
- kwsysProcessCleanupHandle(&si.StartupInfo.hStdError);
+ kwsysProcessCleanupHandleSafe(&si.StartupInfo.hStdError, STD_ERROR_HANDLE);
/* Restore the working directory. */
if(cp->RealWorkingDirectory)
@@ -1493,7 +1364,7 @@ void kwsysProcess_Kill(kwsysProcess* cp)
/* Make sure we are executing a process. */
if(!cp || cp->State != kwsysProcess_State_Executing || cp->TimeoutExpired ||
- cp->Killed || cp->Terminated)
+ cp->Killed)
{
return;
}
@@ -1501,6 +1372,12 @@ void kwsysProcess_Kill(kwsysProcess* cp)
/* Disable the reading threads. */
kwsysProcessDisablePipeThreads(cp);
+ /* Skip actually killing the child if it has already terminated. */
+ if(cp->Terminated)
+ {
+ return;
+ }
+
/* Kill the children. */
cp->Killed = 1;
if(cp->Win9x)
@@ -1897,8 +1774,10 @@ int kwsysProcessCreate(kwsysProcess* cp, int index,
process's copies of the inherited stdout and stdin handles. The
stderr handle is shared among all children and is closed by
kwsysProcess_Execute after all children have been created. */
- kwsysProcessCleanupHandle(&si->StartupInfo.hStdInput);
- kwsysProcessCleanupHandle(&si->StartupInfo.hStdOutput);
+ kwsysProcessCleanupHandleSafe(&si->StartupInfo.hStdInput,
+ STD_INPUT_HANDLE);
+ kwsysProcessCleanupHandleSafe(&si->StartupInfo.hStdOutput,
+ STD_OUTPUT_HANDLE);
return 1;
}
@@ -1984,13 +1863,27 @@ int kwsysProcessSetupOutputPipeFile(PHANDLE phandle, const char* name)
/*--------------------------------------------------------------------------*/
int kwsysProcessSetupSharedPipe(DWORD nStdHandle, PHANDLE handle)
{
+ /* Check whether the handle to be shared is already inherited. */
+ DWORD flags;
+ int inherited = 0;
+ if(GetHandleInformation(GetStdHandle(nStdHandle), &flags) &&
+ (flags & HANDLE_FLAG_INHERIT))
+ {
+ inherited = 1;
+ }
+
/* Cleanup the previous handle. */
kwsysProcessCleanupHandle(handle);
- /* Duplicate the standard handle to be sure it is inherited and can
- be closed later. Do not close the original handle when
+ /* If the standard handle is not inherited then duplicate it to
+ create an inherited copy. Do not close the original handle when
duplicating! */
- if(DuplicateHandle(GetCurrentProcess(), GetStdHandle(nStdHandle),
+ if(inherited)
+ {
+ *handle = GetStdHandle(nStdHandle);
+ return 1;
+ }
+ else if(DuplicateHandle(GetCurrentProcess(), GetStdHandle(nStdHandle),
GetCurrentProcess(), handle,
0, TRUE, DUPLICATE_SAME_ACCESS))
{
@@ -2046,6 +1939,19 @@ void kwsysProcessCleanupHandle(PHANDLE h)
/*--------------------------------------------------------------------------*/
+/* Close the given handle if it is open and not a standard handle.
+ Reset its value to 0. */
+void kwsysProcessCleanupHandleSafe(PHANDLE h, DWORD nStdHandle)
+{
+ if(h && *h && (*h != GetStdHandle(nStdHandle)))
+ {
+ CloseHandle(*h);
+ *h = 0;
+ }
+}
+
+/*--------------------------------------------------------------------------*/
+
/* Close all handles created by kwsysProcess_Execute. */
void kwsysProcessCleanup(kwsysProcess* cp, int error)
{
@@ -2159,6 +2065,189 @@ void kwsysProcessCleanErrorMessage(kwsysProcess* cp)
}
/*--------------------------------------------------------------------------*/
+int kwsysProcessComputeCommandLength(kwsysProcess* cp,
+ char const* const* command)
+{
+ int length = 0;
+ if(cp->Verbatim)
+ {
+ /* Treat the first argument as a verbatim command line. Use its
+ length directly and add space for the null-terminator. */
+ length = (int)strlen(*command)+1;
+ }
+ else
+ {
+ /* Compute the length of the command line when it is converted to
+ a single string. Space for the null-terminator is allocated by
+ the whitespace character allocated for the first argument that
+ will not be used. */
+ char const* const* arg;
+ for(arg = command; *arg; ++arg)
+ {
+ /* Keep track of how many backslashes have been encountered in a
+ row in this argument. */
+ int backslashes = 0;
+ int spaces = 0;
+ const char* c;
+
+ /* Scan the string for spaces. If there are no spaces, we can
+ pass the argument verbatim. */
+ for(c=*arg; *c; ++c)
+ {
+ if(*c == ' ' || *c == '\t')
+ {
+ spaces = 1;
+ break;
+ }
+ }
+
+ /* Add the length of the argument, plus 1 for the space
+ separating the arguments. */
+ length += (int)strlen(*arg) + 1;
+
+ if(spaces)
+ {
+ /* Add 2 for double quotes since spaces are present. */
+ length += 2;
+
+ /* Scan the string to find characters that need escaping. */
+ for(c=*arg; *c; ++c)
+ {
+ if(*c == '\\')
+ {
+ /* Found a backslash. It may need to be escaped later. */
+ ++backslashes;
+ }
+ else if(*c == '"')
+ {
+ /* Found a double-quote. We need to escape it and all
+ immediately preceding backslashes. */
+ length += backslashes + 1;
+ backslashes = 0;
+ }
+ else
+ {
+ /* Found another character. This eliminates the possibility
+ that any immediately preceding backslashes will be
+ escaped. */
+ backslashes = 0;
+ }
+ }
+
+ /* We need to escape all ending backslashes. */
+ length += backslashes;
+ }
+ }
+ }
+
+ return length;
+}
+
+/*--------------------------------------------------------------------------*/
+void kwsysProcessComputeCommandLine(kwsysProcess* cp,
+ char const* const* command,
+ char* cmd)
+{
+ if(cp->Verbatim)
+ {
+ /* Copy the verbatim command line into the buffer. */
+ strcpy(cmd, *command);
+ }
+ else
+ {
+ /* Construct the command line in the allocated buffer. */
+ char const* const* arg;
+ for(arg = command; *arg; ++arg)
+ {
+ /* Keep track of how many backslashes have been encountered in a
+ row in an argument. */
+ int backslashes = 0;
+ int spaces = 0;
+ const char* c;
+
+ /* Scan the string for spaces. If there are no spaces, we can
+ pass the argument verbatim. */
+ for(c=*arg; *c; ++c)
+ {
+ if(*c == ' ' || *c == '\t')
+ {
+ spaces = 1;
+ break;
+ }
+ }
+
+ /* Add the separating space if this is not the first argument. */
+ if(arg != command)
+ {
+ *cmd++ = ' ';
+ }
+
+ if(spaces)
+ {
+ /* Add the opening double-quote for this argument. */
+ *cmd++ = '"';
+
+ /* Add the characters of the argument, possibly escaping them. */
+ for(c=*arg; *c; ++c)
+ {
+ if(*c == '\\')
+ {
+ /* Found a backslash. It may need to be escaped later. */
+ ++backslashes;
+ *cmd++ = '\\';
+ }
+ else if(*c == '"')
+ {
+ /* Add enough backslashes to escape any that preceded the
+ double-quote. */
+ while(backslashes > 0)
+ {
+ --backslashes;
+ *cmd++ = '\\';
+ }
+
+ /* Add the backslash to escape the double-quote. */
+ *cmd++ = '\\';
+
+ /* Add the double-quote itself. */
+ *cmd++ = '"';
+ }
+ else
+ {
+ /* We encountered a normal character. This eliminates any
+ escaping needed for preceding backslashes. Add the
+ character. */
+ backslashes = 0;
+ *cmd++ = *c;
+ }
+ }
+
+ /* Add enough backslashes to escape any trailing ones. */
+ while(backslashes > 0)
+ {
+ --backslashes;
+ *cmd++ = '\\';
+ }
+
+ /* Add the closing double-quote for this argument. */
+ *cmd++ = '"';
+ }
+ else
+ {
+ /* No spaces. Add the argument verbatim. */
+ for(c=*arg; *c; ++c)
+ {
+ *cmd++ = *c;
+ }
+ }
+ }
+
+ /* Add the terminating null character to the command line. */
+ *cmd = 0;
+ }
+}
+
+/*--------------------------------------------------------------------------*/
/* Get the time at which either the process or user timeout will
expire. Returns 1 if the user timeout is first, and 0 otherwise. */
int kwsysProcessGetTimeoutTime(kwsysProcess* cp, double* userTimeout,
diff --git a/Source/kwsys/Terminal.c b/Source/kwsys/Terminal.c
index 0837e10..e3265a1 100644
--- a/Source/kwsys/Terminal.c
+++ b/Source/kwsys/Terminal.c
@@ -142,10 +142,13 @@ static const char* kwsysTerminalVT100Names[] =
"con80x50",
"con80x60",
"console",
+ "cygwin",
"konsole",
"linux",
"msys",
"rxvt",
+ "rxvt-unicode",
+ "screen",
"vt100",
"xterm",
"xterm-color",
diff --git a/Source/kwsys/kwsysPlatformCxxTests.cmake b/Source/kwsys/kwsysPlatformCxxTests.cmake
index 6da82d6..7775457 100644
--- a/Source/kwsys/kwsysPlatformCxxTests.cmake
+++ b/Source/kwsys/kwsysPlatformCxxTests.cmake
@@ -7,10 +7,12 @@ MACRO(KWSYS_PLATFORM_CXX_TEST var description invert)
COMPILE_DEFINITIONS -DTEST_${var} ${KWSYS_PLATFORM_CXX_TEST_DEFINES}
OUTPUT_VARIABLE OUTPUT)
IF(${var}_COMPILED)
- FILE(APPEND ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/CMakeOutput.log
+ FILE(APPEND
+ ${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
"${description} compiled with the following output:\n${OUTPUT}\n\n")
ELSE(${var}_COMPILED)
- FILE(APPEND ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/CMakeError.log
+ FILE(APPEND
+ ${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
"${description} failed to compile with the following output:\n${OUTPUT}\n\n")
ENDIF(${var}_COMPILED)
IF(${invert} MATCHES INVERT)
diff --git a/Source/kwsys/testProcess.c b/Source/kwsys/testProcess.c
index 36222b9..57802b2 100644
--- a/Source/kwsys/testProcess.c
+++ b/Source/kwsys/testProcess.c
@@ -32,7 +32,7 @@
int runChild(const char* cmd[], int state, int exception, int value,
int share, int output, int delay, double timeout, int poll,
- int repeat);
+ int repeat, int disown);
int test1(int argc, const char* argv[])
{
@@ -84,14 +84,6 @@ int test4(int argc, const char* argv[])
return 0;
}
-/* Quick hack to test grandchild killing. */
-/*#define TEST5_GRANDCHILD_KILL*/
-#ifdef TEST5_GRANDCHILD_KILL
-# define TEST5_TIMEOUT 10
-#else
-# define TEST5_TIMEOUT 30
-#endif
-
int test5(int argc, const char* argv[])
{
int r;
@@ -99,18 +91,14 @@ int test5(int argc, const char* argv[])
(void)argc;
cmd[0] = argv[0];
cmd[1] = "run";
-#ifdef TEST5_GRANDCHILD_KILL
- cmd[2] = "3";
-#else
cmd[2] = "4";
-#endif
cmd[3] = 0;
fprintf(stdout, "Output on stdout before recursive test.\n");
fprintf(stderr, "Output on stderr before recursive test.\n");
fflush(stdout);
fflush(stderr);
r = runChild(cmd, kwsysProcess_State_Exception,
- kwsysProcess_Exception_Fault, 1, 1, 1, 0, 15, 0, 1);
+ kwsysProcess_Exception_Fault, 1, 1, 1, 0, 15, 0, 1, 0);
fprintf(stdout, "Output on stdout after recursive test.\n");
fprintf(stderr, "Output on stderr after recursive test.\n");
fflush(stdout);
@@ -163,10 +151,56 @@ int test7(int argc, const char* argv[])
return 0;
}
+int test8(int argc, const char* argv[])
+{
+ /* Create a disowned grandchild to test handling of processes
+ that exit before their children. */
+ int r;
+ const char* cmd[4];
+ (void)argc;
+ cmd[0] = argv[0];
+ cmd[1] = "run";
+ cmd[2] = "108";
+ cmd[3] = 0;
+ fprintf(stdout, "Output on stdout before grandchild test.\n");
+ fprintf(stderr, "Output on stderr before grandchild test.\n");
+ fflush(stdout);
+ fflush(stderr);
+ r = runChild(cmd, kwsysProcess_State_Disowned, kwsysProcess_Exception_None,
+ 1, 1, 1, 0, 10, 0, 1, 1);
+ fprintf(stdout, "Output on stdout after grandchild test.\n");
+ fprintf(stderr, "Output on stderr after grandchild test.\n");
+ fflush(stdout);
+ fflush(stderr);
+ return r;
+}
+
+int test8_grandchild(int argc, const char* argv[])
+{
+ (void)argc; (void)argv;
+ fprintf(stdout, "Output on stdout from grandchild before sleep.\n");
+ fprintf(stderr, "Output on stderr from grandchild before sleep.\n");
+ fflush(stdout);
+ fflush(stderr);
+ /* TODO: Instead of closing pipes here leave them open to make sure
+ the grandparent can stop listening when the parent exits. This
+ part of the test cannot be enabled until the feature is
+ implemented. */
+ fclose(stdout);
+ fclose(stderr);
+#if defined(_WIN32)
+ Sleep(15000);
+#else
+ sleep(15);
+#endif
+ return 0;
+}
+
+
int runChild2(kwsysProcess* kp,
const char* cmd[], int state, int exception, int value,
int share, int output, int delay, double timeout,
- int poll)
+ int poll, int disown)
{
int result = 0;
char* data = 0;
@@ -183,6 +217,10 @@ int runChild2(kwsysProcess* kp,
kwsysProcess_SetPipeShared(kp, kwsysProcess_Pipe_STDOUT, 1);
kwsysProcess_SetPipeShared(kp, kwsysProcess_Pipe_STDERR, 1);
}
+ if(disown)
+ {
+ kwsysProcess_SetOption(kp, kwsysProcess_Option_Detach, 1);
+ }
kwsysProcess_Execute(kp);
if(poll)
@@ -190,7 +228,7 @@ int runChild2(kwsysProcess* kp,
pUserTimeout = &userTimeout;
}
- if(!share)
+ if(!share && !disown)
{
int p;
while((p = kwsysProcess_WaitForData(kp, &data, &length, pUserTimeout)))
@@ -236,7 +274,14 @@ int runChild2(kwsysProcess* kp,
}
}
+ if(disown)
+ {
+ kwsysProcess_Disown(kp);
+ }
+ else
+ {
kwsysProcess_WaitForExit(kp, 0);
+ }
switch (kwsysProcess_GetState(kp))
{
@@ -258,6 +303,8 @@ int runChild2(kwsysProcess* kp,
kwsysProcess_GetExceptionString(kp));
result = ((exception != kwsysProcess_GetExitException(kp)) ||
(value != kwsysProcess_GetExitValue(kp))); break;
+ case kwsysProcess_State_Disowned:
+ printf("Child was disowned.\n"); break;
case kwsysProcess_State_Error:
printf("Error in administrating child process: [%s]\n",
kwsysProcess_GetErrorString(kp)); break;
@@ -301,7 +348,7 @@ int runChild2(kwsysProcess* kp,
int runChild(const char* cmd[], int state, int exception, int value,
int share, int output, int delay, double timeout,
- int poll, int repeat)
+ int poll, int repeat, int disown)
{
int result = 1;
kwsysProcess* kp = kwsysProcess_New();
@@ -313,7 +360,7 @@ int runChild(const char* cmd[], int state, int exception, int value,
while(repeat-- > 0)
{
result = runChild2(kp, cmd, state, exception, value, share,
- output, delay, timeout, poll);
+ output, delay, timeout, poll, disown);
}
kwsysProcess_Delete(kp);
return result;
@@ -347,7 +394,7 @@ int main(int argc, const char* argv[])
n = atoi(argv[2]);
}
/* Check arguments. */
- if(n >= 1 && n <= 7 && argc == 3)
+ if(((n >= 1 && n <= 8) || n == 108) && argc == 3)
{
/* This is the child process for a requested test number. */
switch (n)
@@ -359,14 +406,16 @@ int main(int argc, const char* argv[])
case 5: return test5(argc, argv);
case 6: test6(argc, argv); return 0;
case 7: return test7(argc, argv);
+ case 8: return test8(argc, argv);
+ case 108: return test8_grandchild(argc, argv);
}
fprintf(stderr, "Invalid test number %d.\n", n);
return 1;
}
- else if(n >= 1 && n <= 7)
+ else if(n >= 1 && n <= 8)
{
/* This is the parent process for a requested test number. */
- int states[7] =
+ int states[8] =
{
kwsysProcess_State_Exited,
kwsysProcess_State_Exited,
@@ -374,9 +423,10 @@ int main(int argc, const char* argv[])
kwsysProcess_State_Exception,
kwsysProcess_State_Exited,
kwsysProcess_State_Expired,
+ kwsysProcess_State_Exited,
kwsysProcess_State_Exited
};
- int exceptions[7] =
+ int exceptions[8] =
{
kwsysProcess_Exception_None,
kwsysProcess_Exception_None,
@@ -384,14 +434,15 @@ int main(int argc, const char* argv[])
kwsysProcess_Exception_Fault,
kwsysProcess_Exception_None,
kwsysProcess_Exception_None,
+ kwsysProcess_Exception_None,
kwsysProcess_Exception_None
};
- int values[7] = {0, 123, 1, 1, 0, 0, 0};
- int outputs[7] = {1, 1, 1, 1, 1, 0, 1};
- int delays[7] = {0, 0, 0, 0, 0, 1, 0};
- double timeouts[7] = {10, 10, 10, 10, TEST5_TIMEOUT, 10, -1};
- int polls[7] = {0, 0, 0, 0, 0, 0, 1};
- int repeat[7] = {2, 1, 1, 1, 1, 1, 1};
+ int values[8] = {0, 123, 1, 1, 0, 0, 0, 0};
+ int outputs[8] = {1, 1, 1, 1, 1, 0, 1, 1};
+ int delays[8] = {0, 0, 0, 0, 0, 1, 0, 0};
+ double timeouts[8] = {10, 10, 10, 10, 30, 10, -1, 10};
+ int polls[8] = {0, 0, 0, 0, 0, 0, 1, 0};
+ int repeat[8] = {2, 1, 1, 1, 1, 1, 1, 1};
int r;
const char* cmd[4];
#ifdef _WIN32
@@ -425,7 +476,7 @@ int main(int argc, const char* argv[])
fflush(stderr);
r = runChild(cmd, states[n-1], exceptions[n-1], values[n-1], 0,
outputs[n-1], delays[n-1], timeouts[n-1],
- polls[n-1], repeat[n-1]);
+ polls[n-1], repeat[n-1], 0);
fprintf(stdout, "Output on stdout after test %d.\n", n);
fprintf(stderr, "Output on stderr after test %d.\n", n);
fflush(stdout);
@@ -444,7 +495,7 @@ int main(int argc, const char* argv[])
int exception = kwsysProcess_Exception_None;
int value = 0;
double timeout = 0;
- int r = runChild(cmd, state, exception, value, 0, 1, 0, timeout, 0, 1);
+ int r = runChild(cmd, state, exception, value, 0, 1, 0, timeout, 0, 1, 0);
return r;
}
else