Merge topic 'output-compile-lines'
cdc2b41
Fix CompileCommandOutput test build on Windows7039d1f
Fix CompileCommandOutput test for Make tools not supporting spaces4268e3d
run_compile_commands: Cast istream::get() result to charc45c60b
run_compile_commands: Avoid extra stl vector conversion7c5be51
run_compile_commands: Avoid shadow in std::map<>::at workaround169bb05
Provide std::map<>::at for use in run_compile_commands4e2185c
Make std::map usage more portable in language=>flags/defines mapsa7e7a04
Fix run_compile_commands build on Apple GCC 3.3c9174c0
Fix signed/unsigned comparison in EscapeJSON8346a28
Only offer the compile command output feature on unix systems0e6b05f
Adds a test for the compile command line output.5674844
make compile command output optionalfe07b05
implement cxx command output65c0c24
cache flags and defines3f064ef
refactor flags and defines
This commit is contained in:
commit
e51bbc14f6
|
@ -50,6 +50,12 @@ IF(CMAKE_GENERATOR MATCHES "Makefiles")
|
||||||
IF(DEFINED CMAKE_RULE_MESSAGES)
|
IF(DEFINED CMAKE_RULE_MESSAGES)
|
||||||
SET_PROPERTY(GLOBAL PROPERTY RULE_MESSAGES ${CMAKE_RULE_MESSAGES})
|
SET_PROPERTY(GLOBAL PROPERTY RULE_MESSAGES ${CMAKE_RULE_MESSAGES})
|
||||||
ENDIF(DEFINED CMAKE_RULE_MESSAGES)
|
ENDIF(DEFINED CMAKE_RULE_MESSAGES)
|
||||||
|
IF(CMAKE_GENERATOR MATCHES "Unix Makefiles")
|
||||||
|
SET(CMAKE_EXPORT_COMPILE_COMMANDS OFF CACHE BOOL
|
||||||
|
"Enable/Disable output of compile commands during generation."
|
||||||
|
)
|
||||||
|
MARK_AS_ADVANCED(CMAKE_EXPORT_COMPILE_COMMANDS)
|
||||||
|
ENDIF(CMAKE_GENERATOR MATCHES "Unix Makefiles")
|
||||||
ENDIF(CMAKE_GENERATOR MATCHES "Makefiles")
|
ENDIF(CMAKE_GENERATOR MATCHES "Makefiles")
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -30,6 +30,7 @@ cmGlobalUnixMakefileGenerator3::cmGlobalUnixMakefileGenerator3()
|
||||||
#else
|
#else
|
||||||
this->UseLinkScript = true;
|
this->UseLinkScript = true;
|
||||||
#endif
|
#endif
|
||||||
|
this->CommandDatabase = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void cmGlobalUnixMakefileGenerator3
|
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()
|
void cmGlobalUnixMakefileGenerator3::Generate()
|
||||||
{
|
{
|
||||||
// first do superclass method
|
// first do superclass method
|
||||||
|
@ -179,6 +191,35 @@ void cmGlobalUnixMakefileGenerator3::Generate()
|
||||||
// write the main makefile
|
// write the main makefile
|
||||||
this->WriteMainMakefile2();
|
this->WriteMainMakefile2();
|
||||||
this->WriteMainCMakefile();
|
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()
|
void cmGlobalUnixMakefileGenerator3::WriteMainMakefile2()
|
||||||
|
|
|
@ -112,6 +112,10 @@ public:
|
||||||
/** Record per-target progress information. */
|
/** Record per-target progress information. */
|
||||||
void RecordTargetProgress(cmMakefileTargetGenerator* tg);
|
void RecordTargetProgress(cmMakefileTargetGenerator* tg);
|
||||||
|
|
||||||
|
void AddCXXCompileCommand(const std::string &sourceFile,
|
||||||
|
const std::string &workingDirectory,
|
||||||
|
const std::string &compileCommand);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void WriteMainMakefile2();
|
void WriteMainMakefile2();
|
||||||
void WriteMainCMakefile();
|
void WriteMainCMakefile();
|
||||||
|
@ -176,6 +180,8 @@ protected:
|
||||||
size_t CountProgressMarksInTarget(cmTarget* target,
|
size_t CountProgressMarksInTarget(cmTarget* target,
|
||||||
std::set<cmTarget*>& emitted);
|
std::set<cmTarget*>& emitted);
|
||||||
size_t CountProgressMarksInAll(cmLocalUnixMakefileGenerator3* lg);
|
size_t CountProgressMarksInAll(cmLocalUnixMakefileGenerator3* lg);
|
||||||
|
|
||||||
|
cmGeneratedFileStream *CommandDatabase;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -249,32 +249,56 @@ void cmMakefileTargetGenerator::WriteCommonCodeRules()
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
void cmMakefileTargetGenerator::WriteTargetLanguageFlags()
|
std::string cmMakefileTargetGenerator::GetFlags(const std::string &l)
|
||||||
{
|
{
|
||||||
// write language flags for target
|
ByLanguageMap::iterator i = this->FlagsByLanguage.find(l);
|
||||||
std::set<cmStdString> languages;
|
if (i == this->FlagsByLanguage.end())
|
||||||
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)
|
|
||||||
{
|
|
||||||
const char *lang = l->c_str();
|
|
||||||
std::string flags;
|
std::string flags;
|
||||||
std::string defines;
|
const char *lang = l.c_str();
|
||||||
|
|
||||||
bool shared = ((this->Target->GetType() == cmTarget::SHARED_LIBRARY) ||
|
bool shared = ((this->Target->GetType() == cmTarget::SHARED_LIBRARY) ||
|
||||||
(this->Target->GetType() == cmTarget::MODULE_LIBRARY));
|
(this->Target->GetType() == cmTarget::MODULE_LIBRARY));
|
||||||
|
|
||||||
|
// Add language feature flags.
|
||||||
|
this->AddFeatureFlags(flags, lang);
|
||||||
|
|
||||||
|
this->LocalGenerator->AddArchitectureFlags(flags, this->Target,
|
||||||
|
lang, this->ConfigName);
|
||||||
|
|
||||||
|
// Fortran-specific flags computed for this target.
|
||||||
|
if(l == "Fortran")
|
||||||
|
{
|
||||||
|
this->AddFortranFlags(flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add shared-library flags if needed.
|
||||||
|
this->LocalGenerator->AddSharedFlags(flags, lang, shared);
|
||||||
|
|
||||||
|
// Add include directory flags.
|
||||||
|
this->AddIncludeFlags(flags, lang);
|
||||||
|
|
||||||
|
// Append old-style preprocessor definition flags.
|
||||||
|
this->LocalGenerator->
|
||||||
|
AppendFlags(flags, this->Makefile->GetDefineFlags());
|
||||||
|
|
||||||
|
// Add include directory flags.
|
||||||
|
this->LocalGenerator->
|
||||||
|
AppendFlags(flags,this->GetFrameworkFlags().c_str());
|
||||||
|
|
||||||
|
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.
|
// Add the export symbol definition for shared library objects.
|
||||||
if(const char* exportMacro = this->Target->GetExportMacro())
|
if(const char* exportMacro = this->Target->GetExportMacro())
|
||||||
{
|
{
|
||||||
|
@ -294,40 +318,41 @@ void cmMakefileTargetGenerator::WriteTargetLanguageFlags()
|
||||||
this->LocalGenerator->AppendDefines
|
this->LocalGenerator->AppendDefines
|
||||||
(defines, this->Target->GetProperty(defPropName.c_str()), lang);
|
(defines, this->Target->GetProperty(defPropName.c_str()), lang);
|
||||||
|
|
||||||
// Add language feature flags.
|
ByLanguageMap::value_type entry(l, defines);
|
||||||
this->AddFeatureFlags(flags, lang);
|
i = this->DefinesByLanguage.insert(entry).first;
|
||||||
|
}
|
||||||
|
return i->second;
|
||||||
|
}
|
||||||
|
|
||||||
this->LocalGenerator->AddArchitectureFlags(flags, this->Target,
|
void cmMakefileTargetGenerator::WriteTargetLanguageFlags()
|
||||||
lang, this->ConfigName);
|
{
|
||||||
|
// 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";
|
||||||
|
}
|
||||||
|
|
||||||
// Fortran-specific flags computed for this target.
|
for(std::set<cmStdString>::const_iterator l = languages.begin();
|
||||||
if(*l == "Fortran")
|
l != languages.end(); ++l)
|
||||||
{
|
{
|
||||||
this->AddFortranFlags(flags);
|
*this->FlagFileStream << *l << "_FLAGS = " << this->GetFlags(*l) << "\n\n";
|
||||||
}
|
*this->FlagFileStream << *l << "_DEFINES = " << this->GetDefines(*l) <<
|
||||||
|
"\n\n";
|
||||||
// Add shared-library flags if needed.
|
|
||||||
this->LocalGenerator->AddSharedFlags(flags, lang, shared);
|
|
||||||
|
|
||||||
// Add include directory flags.
|
|
||||||
this->AddIncludeFlags(flags, lang);
|
|
||||||
|
|
||||||
// Append old-style preprocessor definition flags.
|
|
||||||
this->LocalGenerator->
|
|
||||||
AppendFlags(flags, this->Makefile->GetDefineFlags());
|
|
||||||
|
|
||||||
// Add include directory flags.
|
|
||||||
this->LocalGenerator->
|
|
||||||
AppendFlags(flags,this->GetFrameworkFlags().c_str());
|
|
||||||
|
|
||||||
*this->FlagFileStream << lang << "_FLAGS = " << flags << "\n\n";
|
|
||||||
*this->FlagFileStream << lang << "_DEFINES = " << defines << "\n\n";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add target-specific flags.
|
// Add target-specific flags.
|
||||||
if(this->Target->GetProperty("COMPILE_FLAGS"))
|
if(this->Target->GetProperty("COMPILE_FLAGS"))
|
||||||
{
|
{
|
||||||
std::string flags;
|
std::string flags;
|
||||||
this->LocalGenerator->AppendFlags
|
this->LocalGenerator->AppendFlags
|
||||||
(flags, this->Target->GetProperty("COMPILE_FLAGS"));
|
(flags, this->Target->GetProperty("COMPILE_FLAGS"));
|
||||||
*this->FlagFileStream << "# TARGET_FLAGS = " << flags << "\n\n";
|
*this->FlagFileStream << "# TARGET_FLAGS = " << flags << "\n\n";
|
||||||
|
@ -641,6 +666,9 @@ cmMakefileTargetGenerator
|
||||||
vars.Flags = flags.c_str();
|
vars.Flags = flags.c_str();
|
||||||
vars.Defines = defines.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.
|
// Construct the compile rules.
|
||||||
{
|
{
|
||||||
std::string compileRuleVar = "CMAKE_";
|
std::string compileRuleVar = "CMAKE_";
|
||||||
|
@ -651,6 +679,23 @@ cmMakefileTargetGenerator
|
||||||
std::vector<std::string> compileCommands;
|
std::vector<std::string> compileCommands;
|
||||||
cmSystemTools::ExpandListArgument(compileRule, 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.
|
// Expand placeholders in the commands.
|
||||||
for(std::vector<std::string>::iterator i = compileCommands.begin();
|
for(std::vector<std::string>::iterator i = compileCommands.begin();
|
||||||
i != compileCommands.end(); ++i)
|
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 &&
|
bool do_preprocess_rules = lang_is_c_or_cxx &&
|
||||||
this->LocalGenerator->GetCreatePreprocessedSourceRules();
|
this->LocalGenerator->GetCreatePreprocessedSourceRules();
|
||||||
bool do_assembly_rules = lang_is_c_or_cxx &&
|
bool do_assembly_rules = lang_is_c_or_cxx &&
|
||||||
|
|
|
@ -216,6 +216,12 @@ protected:
|
||||||
std::string MacContentDirectory;
|
std::string MacContentDirectory;
|
||||||
std::set<cmStdString> MacContentFolders;
|
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.
|
// Target-wide Fortran module output directory.
|
||||||
bool FortranModuleDirectoryComputed;
|
bool FortranModuleDirectoryComputed;
|
||||||
std::string FortranModuleDirectory;
|
std::string FortranModuleDirectory;
|
||||||
|
|
|
@ -445,6 +445,13 @@ public:
|
||||||
args.push_back(*arg);
|
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);
|
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,
|
std::string cmSystemTools::EscapeWindowsShellArgument(const char* arg,
|
||||||
int shell_flags)
|
int shell_flags)
|
||||||
{
|
{
|
||||||
|
|
|
@ -237,6 +237,8 @@ public:
|
||||||
/** Parse arguments out of a unix command line string. */
|
/** Parse arguments out of a unix command line string. */
|
||||||
static void ParseUnixCommandLine(const char* command,
|
static void ParseUnixCommandLine(const char* command,
|
||||||
std::vector<std::string>& args);
|
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
|
/** Compute an escaped version of the given argument for use in a
|
||||||
windows shell. See kwsys/System.h.in for details. */
|
windows shell. See kwsys/System.h.in for details. */
|
||||||
|
|
|
@ -30,3 +30,8 @@ endif()
|
||||||
foreach(test ${CMakeLib_TESTS})
|
foreach(test ${CMakeLib_TESTS})
|
||||||
add_test(CMakeLib.${test} CMakeLibTests ${test})
|
add_test(CMakeLib.${test} CMakeLibTests ${test})
|
||||||
endforeach()
|
endforeach()
|
||||||
|
|
||||||
|
if(TEST_CompileCommandOutput)
|
||||||
|
add_executable(runcompilecommands run_compile_commands.cxx)
|
||||||
|
target_link_libraries(runcompilecommands CMakeLib)
|
||||||
|
endif()
|
||||||
|
|
|
@ -0,0 +1,141 @@
|
||||||
|
#include "cmSystemTools.h"
|
||||||
|
|
||||||
|
class CompileCommandParser {
|
||||||
|
public:
|
||||||
|
class CommandType: public std::map<cmStdString, cmStdString>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
cmStdString const& at(cmStdString const& k) const
|
||||||
|
{
|
||||||
|
const_iterator i = this->find(k);
|
||||||
|
if(i != this->end()) { return i->second; }
|
||||||
|
static cmStdString emptyString;
|
||||||
|
return emptyString;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
typedef std::vector<CommandType> TranslationUnitsType;
|
||||||
|
|
||||||
|
CompileCommandParser(std::ifstream *input)
|
||||||
|
{
|
||||||
|
this->Input = input;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Parse()
|
||||||
|
{
|
||||||
|
NextNonWhitespace();
|
||||||
|
ParseTranslationUnits();
|
||||||
|
}
|
||||||
|
|
||||||
|
const TranslationUnitsType& GetTranslationUnits()
|
||||||
|
{
|
||||||
|
return this->TranslationUnits;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void ParseTranslationUnits()
|
||||||
|
{
|
||||||
|
this->TranslationUnits = TranslationUnitsType();
|
||||||
|
ExpectOrDie('[', "at start of compile command file");
|
||||||
|
do
|
||||||
|
{
|
||||||
|
ParseTranslationUnit();
|
||||||
|
this->TranslationUnits.push_back(this->Command);
|
||||||
|
} while(Expect(','));
|
||||||
|
ExpectOrDie(']', "at end of array");
|
||||||
|
}
|
||||||
|
|
||||||
|
void ParseTranslationUnit()
|
||||||
|
{
|
||||||
|
this->Command = CommandType();
|
||||||
|
if(!Expect('{')) return;
|
||||||
|
if(Expect('}')) return;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
ParseString();
|
||||||
|
std::string name = this->String;
|
||||||
|
ExpectOrDie(':', "between name and value");
|
||||||
|
ParseString();
|
||||||
|
std::string value = this->String;
|
||||||
|
this->Command[name] = value;
|
||||||
|
} while(Expect(','));
|
||||||
|
ExpectOrDie('}', "at end of object");
|
||||||
|
}
|
||||||
|
|
||||||
|
void ParseString()
|
||||||
|
{
|
||||||
|
this->String.clear();
|
||||||
|
if(!Expect('"')) return;
|
||||||
|
while (!Expect('"'))
|
||||||
|
{
|
||||||
|
Expect('\\');
|
||||||
|
this->String.push_back(C);
|
||||||
|
Next();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Expect(char c)
|
||||||
|
{
|
||||||
|
if(this->C == c)
|
||||||
|
{
|
||||||
|
NextNonWhitespace();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ExpectOrDie(char c, const std::string & message)
|
||||||
|
{
|
||||||
|
if (!Expect(c))
|
||||||
|
ErrorExit(std::string("'") + c + "' expected " + message + ".");
|
||||||
|
}
|
||||||
|
|
||||||
|
void NextNonWhitespace()
|
||||||
|
{
|
||||||
|
do { Next(); } while (IsWhitespace());
|
||||||
|
}
|
||||||
|
|
||||||
|
void Next()
|
||||||
|
{
|
||||||
|
this->C = char(Input->get());
|
||||||
|
if (this->Input->bad()) ErrorExit("Unexpected end of file.");
|
||||||
|
}
|
||||||
|
|
||||||
|
void ErrorExit(const std::string &message) {
|
||||||
|
std::cout << "ERROR: " << message;
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsWhitespace()
|
||||||
|
{
|
||||||
|
return (this->C == ' ' || this->C == '\t' ||
|
||||||
|
this->C == '\n' || this->C == '\r');
|
||||||
|
}
|
||||||
|
|
||||||
|
char C;
|
||||||
|
TranslationUnitsType TranslationUnits;
|
||||||
|
CommandType Command;
|
||||||
|
std::string String;
|
||||||
|
std::ifstream *Input;
|
||||||
|
};
|
||||||
|
|
||||||
|
int main ()
|
||||||
|
{
|
||||||
|
std::ifstream file("compile_commands.json");
|
||||||
|
CompileCommandParser parser(&file);
|
||||||
|
parser.Parse();
|
||||||
|
for(CompileCommandParser::TranslationUnitsType::const_iterator
|
||||||
|
it = parser.GetTranslationUnits().begin(),
|
||||||
|
end = parser.GetTranslationUnits().end(); it != end; ++it)
|
||||||
|
{
|
||||||
|
std::vector<cmStdString> command;
|
||||||
|
cmSystemTools::ParseUnixCommandLine(it->at("command").c_str(), command);
|
||||||
|
if (!cmSystemTools::RunSingleCommand(
|
||||||
|
command, 0, 0, it->at("directory").c_str()))
|
||||||
|
{
|
||||||
|
std::cout << "ERROR: Failed to run command \""
|
||||||
|
<< command[0] << "\"" << std::endl;
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -11,6 +11,7 @@ MACRO(ADD_TEST_MACRO NAME COMMAND)
|
||||||
--build-generator ${CMAKE_TEST_GENERATOR}
|
--build-generator ${CMAKE_TEST_GENERATOR}
|
||||||
--build-makeprogram ${CMAKE_TEST_MAKEPROGRAM}
|
--build-makeprogram ${CMAKE_TEST_MAKEPROGRAM}
|
||||||
--build-project ${proj}
|
--build-project ${proj}
|
||||||
|
${${NAME}_EXTRA_OPTIONS}
|
||||||
--test-command ${COMMAND} ${ARGN})
|
--test-command ${COMMAND} ${ARGN})
|
||||||
LIST(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/${dir}")
|
LIST(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/${dir}")
|
||||||
ENDMACRO(ADD_TEST_MACRO)
|
ENDMACRO(ADD_TEST_MACRO)
|
||||||
|
@ -39,6 +40,10 @@ CONFIGURE_FILE(${CMake_SOURCE_DIR}/Tests/EnforceConfig.cmake.in
|
||||||
|
|
||||||
# Testing
|
# Testing
|
||||||
IF(BUILD_TESTING)
|
IF(BUILD_TESTING)
|
||||||
|
IF("${CMAKE_TEST_GENERATOR}" MATCHES "Unix Makefiles")
|
||||||
|
SET(TEST_CompileCommandOutput 1)
|
||||||
|
ENDIF()
|
||||||
|
|
||||||
ADD_SUBDIRECTORY(CMakeLib)
|
ADD_SUBDIRECTORY(CMakeLib)
|
||||||
|
|
||||||
# Collect a list of all test build directories.
|
# Collect a list of all test build directories.
|
||||||
|
@ -2031,6 +2036,13 @@ ${CMake_BINARY_DIR}/bin/cmake -DVERSION=master -P ${CMake_SOURCE_DIR}/Utilities/
|
||||||
ENDIF()
|
ENDIF()
|
||||||
SET_TESTS_PROPERTIES(Contracts.${project} PROPERTIES TIMEOUT ${timeout})
|
SET_TESTS_PROPERTIES(Contracts.${project} PROPERTIES TIMEOUT ${timeout})
|
||||||
ENDFOREACH()
|
ENDFOREACH()
|
||||||
|
|
||||||
|
IF(TEST_CompileCommandOutput)
|
||||||
|
SET(CompileCommandOutput_EXTRA_OPTIONS
|
||||||
|
--build-options -DMAKE_SUPPORTS_SPACES=${MAKE_IS_GNU})
|
||||||
|
ADD_TEST_MACRO(CompileCommandOutput
|
||||||
|
"${CMake_BINARY_DIR}/Tests/CMakeLib/runcompilecommands")
|
||||||
|
ENDIF()
|
||||||
ENDIF(BUILD_TESTING)
|
ENDIF(BUILD_TESTING)
|
||||||
|
|
||||||
SUBDIRS(CMakeTests)
|
SUBDIRS(CMakeTests)
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
# a simple C only test case
|
||||||
|
cmake_minimum_required (VERSION 2.6)
|
||||||
|
project (CompileCommandOutput CXX)
|
||||||
|
|
||||||
|
SET(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
||||||
|
set(CMAKE_DEBUG_POSTFIX "_test_debug_postfix")
|
||||||
|
IF(MAKE_SUPPORTS_SPACES)
|
||||||
|
SET(test1_srcs "file with spaces.cxx")
|
||||||
|
ELSE()
|
||||||
|
SET(test1_srcs "file_with_underscores.cxx")
|
||||||
|
ENDIF()
|
||||||
|
ADD_LIBRARY(test1 STATIC ${test1_srcs})
|
||||||
|
ADD_LIBRARY(test2 SHARED "../CompileCommandOutput/relative.cxx")
|
||||||
|
INCLUDE_DIRECTORIES(${CompileCommandOutput_SOURCE_DIR}/../../Source)
|
||||||
|
ADD_EXECUTABLE(CompileCommandOutput compile_command_output.cxx)
|
||||||
|
TARGET_LINK_LIBRARIES(CompileCommandOutput test1 test2)
|
|
@ -0,0 +1,9 @@
|
||||||
|
#include "file_with_underscores.h"
|
||||||
|
#include "relative.h"
|
||||||
|
|
||||||
|
int main (int argc, char** argv)
|
||||||
|
{
|
||||||
|
file_with_underscores();
|
||||||
|
relative();
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -0,0 +1 @@
|
||||||
|
#include "file_with_underscores.cxx"
|
|
@ -0,0 +1,3 @@
|
||||||
|
#include "file_with_underscores.h"
|
||||||
|
|
||||||
|
void file_with_underscores() {}
|
|
@ -0,0 +1 @@
|
||||||
|
void file_with_underscores();
|
|
@ -0,0 +1,3 @@
|
||||||
|
#include "relative.h"
|
||||||
|
|
||||||
|
void relative() {}
|
|
@ -0,0 +1,11 @@
|
||||||
|
#if defined(_WIN32)
|
||||||
|
# ifdef test2_EXPORTS
|
||||||
|
# define TEST2_EXPORT __declspec(dllexport)
|
||||||
|
# else
|
||||||
|
# define TEST2_EXPORT __declspec(dllimport)
|
||||||
|
# endif
|
||||||
|
#else
|
||||||
|
# define TEST2_EXPORT
|
||||||
|
#endif
|
||||||
|
|
||||||
|
TEST2_EXPORT void relative();
|
Loading…
Reference in New Issue