From 0e6b05fcba61a1b113b841dd2b3e1e5060866d0e Mon Sep 17 00:00:00 2001 From: Manuel Klimek Date: Thu, 31 Mar 2011 16:55:00 -0700 Subject: [PATCH] Adds a test for the compile command line output. --- Tests/CMakeLib/CMakeLists.txt | 3 + Tests/CMakeLib/run_compile_commands.cxx | 132 ++++++++++++++++++ Tests/CMakeLists.txt | 3 + Tests/CompileCommandOutput/CMakeLists.txt | 11 ++ .../compile_command_output.cxx | 9 ++ .../CompileCommandOutput/file with spaces.cxx | 3 + Tests/CompileCommandOutput/file with spaces.h | 1 + Tests/CompileCommandOutput/relative.cxx | 3 + Tests/CompileCommandOutput/relative.h | 1 + 9 files changed, 166 insertions(+) create mode 100644 Tests/CMakeLib/run_compile_commands.cxx create mode 100644 Tests/CompileCommandOutput/CMakeLists.txt create mode 100644 Tests/CompileCommandOutput/compile_command_output.cxx create mode 100644 Tests/CompileCommandOutput/file with spaces.cxx create mode 100644 Tests/CompileCommandOutput/file with spaces.h create mode 100644 Tests/CompileCommandOutput/relative.cxx create mode 100644 Tests/CompileCommandOutput/relative.h diff --git a/Tests/CMakeLib/CMakeLists.txt b/Tests/CMakeLib/CMakeLists.txt index bda2fa5f8..78155457f 100644 --- a/Tests/CMakeLib/CMakeLists.txt +++ b/Tests/CMakeLib/CMakeLists.txt @@ -30,3 +30,6 @@ endif() foreach(test ${CMakeLib_TESTS}) add_test(CMakeLib.${test} CMakeLibTests ${test}) endforeach() + +ADD_EXECUTABLE(runcompilecommands run_compile_commands.cxx) +TARGET_LINK_LIBRARIES(runcompilecommands CMakeLib) diff --git a/Tests/CMakeLib/run_compile_commands.cxx b/Tests/CMakeLib/run_compile_commands.cxx new file mode 100644 index 000000000..c9251678a --- /dev/null +++ b/Tests/CMakeLib/run_compile_commands.cxx @@ -0,0 +1,132 @@ +#include "cmSystemTools.h" + +class CompileCommandParser { +public: + typedef std::map CommandType; + typedef std::vector 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 = 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 std_command; + cmSystemTools::ParseUnixCommandLine(it->at("command").c_str(), std_command); + std::vector command(std_command.begin(), std_command.end()); + 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; +} diff --git a/Tests/CMakeLists.txt b/Tests/CMakeLists.txt index 157814e05..126eaddd2 100644 --- a/Tests/CMakeLists.txt +++ b/Tests/CMakeLists.txt @@ -2031,6 +2031,9 @@ ${CMake_BINARY_DIR}/bin/cmake -DVERSION=master -P ${CMake_SOURCE_DIR}/Utilities/ ENDIF() SET_TESTS_PROPERTIES(Contracts.${project} PROPERTIES TIMEOUT ${timeout}) ENDFOREACH() + + ADD_TEST_MACRO(CompileCommandOutput + "${CMake_BINARY_DIR}/Tests/CMakeLib/runcompilecommands") ENDIF(BUILD_TESTING) SUBDIRS(CMakeTests) diff --git a/Tests/CompileCommandOutput/CMakeLists.txt b/Tests/CompileCommandOutput/CMakeLists.txt new file mode 100644 index 000000000..ac39b8bb3 --- /dev/null +++ b/Tests/CompileCommandOutput/CMakeLists.txt @@ -0,0 +1,11 @@ +# 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") +ADD_LIBRARY(test1 STATIC "file with spaces.cxx") +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) diff --git a/Tests/CompileCommandOutput/compile_command_output.cxx b/Tests/CompileCommandOutput/compile_command_output.cxx new file mode 100644 index 000000000..9487c896c --- /dev/null +++ b/Tests/CompileCommandOutput/compile_command_output.cxx @@ -0,0 +1,9 @@ +#include "file with spaces.h" +#include "relative.h" + +int main (int argc, char** argv) +{ + file_with_spaces(); + relative(); + return 0; +} diff --git a/Tests/CompileCommandOutput/file with spaces.cxx b/Tests/CompileCommandOutput/file with spaces.cxx new file mode 100644 index 000000000..5759319df --- /dev/null +++ b/Tests/CompileCommandOutput/file with spaces.cxx @@ -0,0 +1,3 @@ +#include "file with spaces.h" + +void file_with_spaces() {} diff --git a/Tests/CompileCommandOutput/file with spaces.h b/Tests/CompileCommandOutput/file with spaces.h new file mode 100644 index 000000000..49b686c00 --- /dev/null +++ b/Tests/CompileCommandOutput/file with spaces.h @@ -0,0 +1 @@ +void file_with_spaces(); diff --git a/Tests/CompileCommandOutput/relative.cxx b/Tests/CompileCommandOutput/relative.cxx new file mode 100644 index 000000000..eae11e226 --- /dev/null +++ b/Tests/CompileCommandOutput/relative.cxx @@ -0,0 +1,3 @@ +#include "relative.h" + +void relative() {} diff --git a/Tests/CompileCommandOutput/relative.h b/Tests/CompileCommandOutput/relative.h new file mode 100644 index 000000000..2168035cc --- /dev/null +++ b/Tests/CompileCommandOutput/relative.h @@ -0,0 +1 @@ +void relative();