summaryrefslogtreecommitdiffstats
path: root/Source
diff options
context:
space:
mode:
authorBrad King <brad.king@kitware.com>2011-05-24 18:48:14 (GMT)
committerCMake Topic Stage <kwrobot@kitware.com>2011-05-24 18:48:14 (GMT)
commite51bbc14f6c23087e5c1acd48f556de27d0bfdaa (patch)
tree048068a82996ac61495f5554065ea7803e5b5548 /Source
parentc5e00bf0b25fb816a80215c4c110d319c6cce079 (diff)
parentcdc2b41cc2161b21192460bb92da40c6d4c6107f (diff)
downloadCMake-e51bbc14f6c23087e5c1acd48f556de27d0bfdaa.zip
CMake-e51bbc14f6c23087e5c1acd48f556de27d0bfdaa.tar.gz
CMake-e51bbc14f6c23087e5c1acd48f556de27d0bfdaa.tar.bz2
Merge topic 'output-compile-lines'
cdc2b41 Fix CompileCommandOutput test build on Windows 7039d1f Fix CompileCommandOutput test for Make tools not supporting spaces 4268e3d run_compile_commands: Cast istream::get() result to char c45c60b run_compile_commands: Avoid extra stl vector conversion 7c5be51 run_compile_commands: Avoid shadow in std::map<>::at workaround 169bb05 Provide std::map<>::at for use in run_compile_commands 4e2185c Make std::map usage more portable in language=>flags/defines maps a7e7a04 Fix run_compile_commands build on Apple GCC 3.3 c9174c0 Fix signed/unsigned comparison in EscapeJSON 8346a28 Only offer the compile command output feature on unix systems 0e6b05f Adds a test for the compile command line output. 5674844 make compile command output optional fe07b05 implement cxx command output 65c0c24 cache flags and defines 3f064ef refactor flags and defines
Diffstat (limited to 'Source')
-rw-r--r--Source/cmGlobalUnixMakefileGenerator3.cxx41
-rw-r--r--Source/cmGlobalUnixMakefileGenerator3.h6
-rw-r--r--Source/cmMakefileTargetGenerator.cxx133
-rw-r--r--Source/cmMakefileTargetGenerator.h6
-rw-r--r--Source/cmSystemTools.cxx16
-rw-r--r--Source/cmSystemTools.h2
6 files changed, 159 insertions, 45 deletions
diff --git a/Source/cmGlobalUnixMakefileGenerator3.cxx b/Source/cmGlobalUnixMakefileGenerator3.cxx
index 55ff87e..169d77d 100644
--- a/Source/cmGlobalUnixMakefileGenerator3.cxx
+++ b/Source/cmGlobalUnixMakefileGenerator3.cxx
@@ -30,6 +30,7 @@ cmGlobalUnixMakefileGenerator3::cmGlobalUnixMakefileGenerator3()
#else
this->UseLinkScript = true;
#endif
+ this->CommandDatabase = NULL;
}
void cmGlobalUnixMakefileGenerator3
@@ -138,6 +139,17 @@ void cmGlobalUnixMakefileGenerator3
}
//----------------------------------------------------------------------------
+std::string EscapeJSON(const std::string& s) {
+ std::string result;
+ for (std::string::size_type i = 0; i < s.size(); ++i) {
+ if (s[i] == '"' || s[i] == '\\') {
+ result += '\\';
+ }
+ result += s[i];
+ }
+ return result;
+}
+
void cmGlobalUnixMakefileGenerator3::Generate()
{
// first do superclass method
@@ -179,6 +191,35 @@ void cmGlobalUnixMakefileGenerator3::Generate()
// write the main makefile
this->WriteMainMakefile2();
this->WriteMainCMakefile();
+
+ if (this->CommandDatabase != NULL) {
+ *this->CommandDatabase << std::endl << "]";
+ delete this->CommandDatabase;
+ this->CommandDatabase = NULL;
+ }
+}
+
+void cmGlobalUnixMakefileGenerator3::AddCXXCompileCommand(
+ const std::string &sourceFile, const std::string &workingDirectory,
+ const std::string &compileCommand) {
+ if (this->CommandDatabase == NULL)
+ {
+ std::string commandDatabaseName =
+ std::string(this->GetCMakeInstance()->GetHomeOutputDirectory())
+ + "/compile_commands.json";
+ this->CommandDatabase =
+ new cmGeneratedFileStream(commandDatabaseName.c_str());
+ *this->CommandDatabase << "[" << std::endl;
+ } else {
+ *this->CommandDatabase << "," << std::endl;
+ }
+ *this->CommandDatabase << "{" << std::endl
+ << " \"directory\": \"" << EscapeJSON(workingDirectory) << "\","
+ << std::endl
+ << " \"command\": \"" << EscapeJSON(compileCommand) << "\","
+ << std::endl
+ << " \"file\": \"" << EscapeJSON(sourceFile) << "\""
+ << std::endl << "}";
}
void cmGlobalUnixMakefileGenerator3::WriteMainMakefile2()
diff --git a/Source/cmGlobalUnixMakefileGenerator3.h b/Source/cmGlobalUnixMakefileGenerator3.h
index 11174d7..d21d5b9 100644
--- a/Source/cmGlobalUnixMakefileGenerator3.h
+++ b/Source/cmGlobalUnixMakefileGenerator3.h
@@ -112,6 +112,10 @@ public:
/** Record per-target progress information. */
void RecordTargetProgress(cmMakefileTargetGenerator* tg);
+ void AddCXXCompileCommand(const std::string &sourceFile,
+ const std::string &workingDirectory,
+ const std::string &compileCommand);
+
protected:
void WriteMainMakefile2();
void WriteMainCMakefile();
@@ -176,6 +180,8 @@ protected:
size_t CountProgressMarksInTarget(cmTarget* target,
std::set<cmTarget*>& emitted);
size_t CountProgressMarksInAll(cmLocalUnixMakefileGenerator3* lg);
+
+ cmGeneratedFileStream *CommandDatabase;
};
#endif
diff --git a/Source/cmMakefileTargetGenerator.cxx b/Source/cmMakefileTargetGenerator.cxx
index 69320da..d0df8f0 100644
--- a/Source/cmMakefileTargetGenerator.cxx
+++ b/Source/cmMakefileTargetGenerator.cxx
@@ -249,51 +249,17 @@ void cmMakefileTargetGenerator::WriteCommonCodeRules()
}
//----------------------------------------------------------------------------
-void cmMakefileTargetGenerator::WriteTargetLanguageFlags()
+std::string cmMakefileTargetGenerator::GetFlags(const std::string &l)
{
- // write language flags for target
- std::set<cmStdString> languages;
- this->Target->GetLanguages(languages);
- // put the compiler in the rules.make file so that if it changes
- // things rebuild
- for(std::set<cmStdString>::const_iterator l = languages.begin();
- l != languages.end(); ++l)
- {
- cmStdString compiler = "CMAKE_";
- compiler += *l;
- compiler += "_COMPILER";
- *this->FlagFileStream << "# compile " << l->c_str() << " with " <<
- this->Makefile->GetSafeDefinition(compiler.c_str()) << "\n";
- }
-
- for(std::set<cmStdString>::const_iterator l = languages.begin();
- l != languages.end(); ++l)
+ ByLanguageMap::iterator i = this->FlagsByLanguage.find(l);
+ if (i == this->FlagsByLanguage.end())
{
- const char *lang = l->c_str();
std::string flags;
- std::string defines;
+ const char *lang = l.c_str();
+
bool shared = ((this->Target->GetType() == cmTarget::SHARED_LIBRARY) ||
(this->Target->GetType() == cmTarget::MODULE_LIBRARY));
- // Add the export symbol definition for shared library objects.
- if(const char* exportMacro = this->Target->GetExportMacro())
- {
- this->LocalGenerator->AppendDefines(defines, exportMacro, lang);
- }
-
- // Add preprocessor definitions for this target and configuration.
- this->LocalGenerator->AppendDefines
- (defines, this->Makefile->GetProperty("COMPILE_DEFINITIONS"), lang);
- this->LocalGenerator->AppendDefines
- (defines, this->Target->GetProperty("COMPILE_DEFINITIONS"), lang);
- std::string defPropName = "COMPILE_DEFINITIONS_";
- defPropName +=
- cmSystemTools::UpperCase(this->LocalGenerator->ConfigurationName);
- this->LocalGenerator->AppendDefines
- (defines, this->Makefile->GetProperty(defPropName.c_str()), lang);
- this->LocalGenerator->AppendDefines
- (defines, this->Target->GetProperty(defPropName.c_str()), lang);
-
// Add language feature flags.
this->AddFeatureFlags(flags, lang);
@@ -301,7 +267,7 @@ void cmMakefileTargetGenerator::WriteTargetLanguageFlags()
lang, this->ConfigName);
// Fortran-specific flags computed for this target.
- if(*l == "Fortran")
+ if(l == "Fortran")
{
this->AddFortranFlags(flags);
}
@@ -320,14 +286,73 @@ void cmMakefileTargetGenerator::WriteTargetLanguageFlags()
this->LocalGenerator->
AppendFlags(flags,this->GetFrameworkFlags().c_str());
- *this->FlagFileStream << lang << "_FLAGS = " << flags << "\n\n";
- *this->FlagFileStream << lang << "_DEFINES = " << defines << "\n\n";
+ ByLanguageMap::value_type entry(l, flags);
+ i = this->FlagsByLanguage.insert(entry).first;
+ }
+ return i->second;
+}
+
+std::string cmMakefileTargetGenerator::GetDefines(const std::string &l)
+{
+ ByLanguageMap::iterator i = this->DefinesByLanguage.find(l);
+ if (i == this->DefinesByLanguage.end())
+ {
+ std::string defines;
+ const char *lang = l.c_str();
+ // Add the export symbol definition for shared library objects.
+ if(const char* exportMacro = this->Target->GetExportMacro())
+ {
+ this->LocalGenerator->AppendDefines(defines, exportMacro, lang);
+ }
+
+ // Add preprocessor definitions for this target and configuration.
+ this->LocalGenerator->AppendDefines
+ (defines, this->Makefile->GetProperty("COMPILE_DEFINITIONS"), lang);
+ this->LocalGenerator->AppendDefines
+ (defines, this->Target->GetProperty("COMPILE_DEFINITIONS"), lang);
+ std::string defPropName = "COMPILE_DEFINITIONS_";
+ defPropName +=
+ cmSystemTools::UpperCase(this->LocalGenerator->ConfigurationName);
+ this->LocalGenerator->AppendDefines
+ (defines, this->Makefile->GetProperty(defPropName.c_str()), lang);
+ this->LocalGenerator->AppendDefines
+ (defines, this->Target->GetProperty(defPropName.c_str()), lang);
+
+ ByLanguageMap::value_type entry(l, defines);
+ i = this->DefinesByLanguage.insert(entry).first;
+ }
+ return i->second;
+}
+
+void cmMakefileTargetGenerator::WriteTargetLanguageFlags()
+{
+ // write language flags for target
+ std::set<cmStdString> languages;
+ this->Target->GetLanguages(languages);
+ // put the compiler in the rules.make file so that if it changes
+ // things rebuild
+ for(std::set<cmStdString>::const_iterator l = languages.begin();
+ l != languages.end(); ++l)
+ {
+ cmStdString compiler = "CMAKE_";
+ compiler += *l;
+ compiler += "_COMPILER";
+ *this->FlagFileStream << "# compile " << l->c_str() << " with " <<
+ this->Makefile->GetSafeDefinition(compiler.c_str()) << "\n";
+ }
+
+ for(std::set<cmStdString>::const_iterator l = languages.begin();
+ l != languages.end(); ++l)
+ {
+ *this->FlagFileStream << *l << "_FLAGS = " << this->GetFlags(*l) << "\n\n";
+ *this->FlagFileStream << *l << "_DEFINES = " << this->GetDefines(*l) <<
+ "\n\n";
}
// Add target-specific flags.
if(this->Target->GetProperty("COMPILE_FLAGS"))
{
- std::string flags;
+ std::string flags;
this->LocalGenerator->AppendFlags
(flags, this->Target->GetProperty("COMPILE_FLAGS"));
*this->FlagFileStream << "# TARGET_FLAGS = " << flags << "\n\n";
@@ -641,6 +666,9 @@ cmMakefileTargetGenerator
vars.Flags = flags.c_str();
vars.Defines = defines.c_str();
+ bool lang_is_c_or_cxx = ((strcmp(lang, "C") == 0) ||
+ (strcmp(lang, "CXX") == 0));
+
// Construct the compile rules.
{
std::string compileRuleVar = "CMAKE_";
@@ -651,6 +679,23 @@ cmMakefileTargetGenerator
std::vector<std::string> compileCommands;
cmSystemTools::ExpandListArgument(compileRule, compileCommands);
+ if (this->Makefile->IsOn("CMAKE_EXPORT_COMPILE_COMMANDS") &&
+ lang_is_c_or_cxx && compileCommands.size() == 1)
+ {
+ std::string compileCommand = compileCommands[0];
+ this->LocalGenerator->ExpandRuleVariables(compileCommand, vars);
+ std::string workingDirectory =
+ this->LocalGenerator->Convert(
+ this->Makefile->GetStartOutputDirectory(), cmLocalGenerator::FULL);
+ compileCommand.replace(compileCommand.find(langFlags),
+ langFlags.size(), this->GetFlags(lang));
+ std::string langDefines = std::string("$(") + lang + "_DEFINES)";
+ compileCommand.replace(compileCommand.find(langDefines),
+ langDefines.size(), this->GetDefines(lang));
+ this->GlobalGenerator->AddCXXCompileCommand(
+ source.GetFullPath(), workingDirectory, compileCommand);
+ }
+
// Expand placeholders in the commands.
for(std::vector<std::string>::iterator i = compileCommands.begin();
i != compileCommands.end(); ++i)
@@ -691,8 +736,6 @@ cmMakefileTargetGenerator
}
}
- bool lang_is_c_or_cxx = ((strcmp(lang, "C") == 0) ||
- (strcmp(lang, "CXX") == 0));
bool do_preprocess_rules = lang_is_c_or_cxx &&
this->LocalGenerator->GetCreatePreprocessedSourceRules();
bool do_assembly_rules = lang_is_c_or_cxx &&
diff --git a/Source/cmMakefileTargetGenerator.h b/Source/cmMakefileTargetGenerator.h
index bd26795..b68f8bf 100644
--- a/Source/cmMakefileTargetGenerator.h
+++ b/Source/cmMakefileTargetGenerator.h
@@ -216,6 +216,12 @@ protected:
std::string MacContentDirectory;
std::set<cmStdString> MacContentFolders;
+ typedef std::map<cmStdString, cmStdString> ByLanguageMap;
+ std::string GetFlags(const std::string &l);
+ ByLanguageMap FlagsByLanguage;
+ std::string GetDefines(const std::string &l);
+ ByLanguageMap DefinesByLanguage;
+
// Target-wide Fortran module output directory.
bool FortranModuleDirectoryComputed;
std::string FortranModuleDirectory;
diff --git a/Source/cmSystemTools.cxx b/Source/cmSystemTools.cxx
index b992054..dc63568 100644
--- a/Source/cmSystemTools.cxx
+++ b/Source/cmSystemTools.cxx
@@ -445,6 +445,13 @@ public:
args.push_back(*arg);
}
}
+ void Store(std::vector<cmStdString>& args) const
+ {
+ for(char** arg = this->ArgV; arg && *arg; ++arg)
+ {
+ args.push_back(*arg);
+ }
+ }
};
//----------------------------------------------------------------------------
@@ -456,6 +463,15 @@ void cmSystemTools::ParseUnixCommandLine(const char* command,
argv.Store(args);
}
+//----------------------------------------------------------------------------
+void cmSystemTools::ParseUnixCommandLine(const char* command,
+ std::vector<cmStdString>& args)
+{
+ // Invoke the underlying parser.
+ cmSystemToolsArgV argv = cmsysSystem_Parse_CommandForUnix(command, 0);
+ argv.Store(args);
+}
+
std::string cmSystemTools::EscapeWindowsShellArgument(const char* arg,
int shell_flags)
{
diff --git a/Source/cmSystemTools.h b/Source/cmSystemTools.h
index 78b9abf..fc85d4a 100644
--- a/Source/cmSystemTools.h
+++ b/Source/cmSystemTools.h
@@ -237,6 +237,8 @@ public:
/** Parse arguments out of a unix command line string. */
static void ParseUnixCommandLine(const char* command,
std::vector<std::string>& args);
+ static void ParseUnixCommandLine(const char* command,
+ std::vector<cmStdString>& args);
/** Compute an escaped version of the given argument for use in a
windows shell. See kwsys/System.h.in for details. */