~ubuntu-branches/ubuntu/lucid/cmake/lucid

« back to all changes in this revision

Viewing changes to Source/CTest/cmCTestBuildHandler.cxx

  • Committer: Bazaar Package Importer
  • Author(s): Artur Rona
  • Date: 2009-12-16 11:11:54 UTC
  • mfrom: (3.1.9 sid)
  • Revision ID: james.westby@ubuntu.com-20091216111154-6accvv6yq86h2hkc
Tags: 2.8.0-5ubuntu1
* Merge from debian testing (LP: #497349). Remaining changes:
  - Keep the Replaces: on cmake-data to cover the Kubuntu version from
    Jaunty in case someone decides to do an (unsupported) Jaunty->Lucid
    upgrade.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*=========================================================================
2
 
 
3
 
  Program:   CMake - Cross-Platform Makefile Generator
4
 
  Module:    $RCSfile: cmCTestBuildHandler.cxx,v $
5
 
  Language:  C++
6
 
  Date:      $Date: 2009-01-13 18:03:54 $
7
 
  Version:   $Revision: 1.61.2.2 $
8
 
 
9
 
  Copyright (c) 2002 Kitware, Inc., Insight Consortium.  All rights reserved.
10
 
  See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.
11
 
 
12
 
     This software is distributed WITHOUT ANY WARRANTY; without even
13
 
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
14
 
     PURPOSE.  See the above copyright notices for more information.
15
 
 
16
 
=========================================================================*/
 
1
/*============================================================================
 
2
  CMake - Cross Platform Makefile Generator
 
3
  Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
 
4
 
 
5
  Distributed under the OSI-approved BSD License (the "License");
 
6
  see accompanying file Copyright.txt for details.
 
7
 
 
8
  This software is distributed WITHOUT ANY WARRANTY; without even the
 
9
  implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 
10
  See the License for more information.
 
11
============================================================================*/
17
12
 
18
13
#include "cmCTestBuildHandler.h"
19
14
 
23
18
#include "cmLocalGenerator.h"
24
19
#include "cmGlobalGenerator.h"
25
20
#include "cmGeneratedFileStream.h"
 
21
#include "cmXMLSafe.h"
 
22
#include "cmFileTimeComparison.h"
26
23
 
27
24
//#include <cmsys/RegularExpression.hxx>
28
25
#include <cmsys/Process.h>
 
26
#include <cmsys/Directory.hxx>
29
27
 
30
28
// used for sleep
31
29
#ifdef _WIN32
184
182
 
185
183
  this->LastErrorOrWarning = this->ErrorsAndWarnings.end();
186
184
 
 
185
  this->UseCTestLaunch = false;
187
186
}
188
187
 
189
188
//----------------------------------------------------------------------
196
195
  this->CustomErrorExceptions.clear();
197
196
  this->CustomWarningMatches.clear();
198
197
  this->CustomWarningExceptions.clear();
 
198
  this->ReallyCustomWarningMatches.clear();
 
199
  this->ReallyCustomWarningExceptions.clear();
199
200
  this->ErrorWarningFileLineRegex.clear();
200
201
 
201
202
  this->ErrorMatchRegex.clear();
226
227
 
227
228
  this->MaxErrors = 50;
228
229
  this->MaxWarnings = 50;
 
230
 
 
231
  this->UseCTestLaunch = false;
229
232
}
230
233
 
231
234
//----------------------------------------------------------------------
245
248
  this->CTest->PopulateCustomInteger(mf,
246
249
                             "CTEST_CUSTOM_MAXIMUM_NUMBER_OF_WARNINGS",
247
250
                             this->MaxWarnings);
 
251
 
 
252
  // Record the user-specified custom warning rules.
 
253
  if(const char* customWarningMatchers =
 
254
     mf->GetDefinition("CTEST_CUSTOM_WARNING_MATCH"))
 
255
    {
 
256
    cmSystemTools::ExpandListArgument(customWarningMatchers,
 
257
                                      this->ReallyCustomWarningMatches);
 
258
    }
 
259
  if(const char* customWarningExceptions =
 
260
     mf->GetDefinition("CTEST_CUSTOM_WARNING_EXCEPTION"))
 
261
    {
 
262
    cmSystemTools::ExpandListArgument(customWarningExceptions,
 
263
                                      this->ReallyCustomWarningExceptions);
 
264
    }
248
265
}
249
266
 
250
267
//----------------------------------------------------------------------
305
322
    return -1;
306
323
    }
307
324
 
 
325
  std::string const& useLaunchers =
 
326
    this->CTest->GetCTestConfiguration("UseLaunchers");
 
327
  this->UseCTestLaunch = cmSystemTools::IsOn(useLaunchers.c_str());
 
328
 
308
329
  // Create a last build log
309
330
  cmGeneratedFileStream ofs;
310
331
  double elapsed_time_start = cmSystemTools::GetTime();
419
440
  this->EndBuild = this->CTest->CurrentTime();
420
441
  this->EndBuildTime = cmSystemTools::GetTime();
421
442
  double elapsed_build_time = cmSystemTools::GetTime() - elapsed_time_start;
422
 
  if (res != cmsysProcess_State_Exited || retVal )
423
 
    {
424
 
    cmCTestLog(this->CTest, ERROR_MESSAGE, "Error(s) when building project"
425
 
      << std::endl);
426
 
    }
427
443
 
428
444
  // Cleanups strings in the errors and warnings list.
429
445
  t_ErrorsAndWarningsVector::iterator evit;
457
473
      }
458
474
    }
459
475
 
 
476
  // Generate XML output
 
477
  cmGeneratedFileStream xofs;
 
478
  if(!this->StartResultingXML(cmCTest::PartBuild, "Build", xofs))
 
479
    {
 
480
    cmCTestLog(this->CTest, ERROR_MESSAGE, "Cannot create build XML file"
 
481
      << std::endl);
 
482
    return -1;
 
483
    }
 
484
  this->GenerateXMLHeader(xofs);
 
485
  if(this->UseCTestLaunch)
 
486
    {
 
487
    this->GenerateXMLLaunched(xofs);
 
488
    }
 
489
  else
 
490
    {
 
491
    this->GenerateXMLLogScraped(xofs);
 
492
    }
 
493
  this->GenerateXMLFooter(xofs, elapsed_build_time);
 
494
 
 
495
  if (res != cmsysProcess_State_Exited || retVal || this->TotalErrors > 0)
 
496
    {
 
497
    cmCTestLog(this->CTest, ERROR_MESSAGE, "Error(s) when building project"
 
498
      << std::endl);
 
499
    }
 
500
 
460
501
  // Display message about number of errors and warnings
461
502
  cmCTestLog(this->CTest, HANDLER_OUTPUT, "   " << this->TotalErrors
462
503
    << (this->TotalErrors >= this->MaxErrors ? " or more" : "")
465
506
    << (this->TotalWarnings >= this->MaxWarnings ? " or more" : "")
466
507
    << " Compiler warnings" << std::endl);
467
508
 
468
 
  // Generate XML output
469
 
  cmGeneratedFileStream xofs;
470
 
  if( !this->StartResultingXML("Build", xofs))
471
 
    {
472
 
    cmCTestLog(this->CTest, ERROR_MESSAGE, "Cannot create build XML file"
473
 
      << std::endl);
474
 
    return -1;
475
 
    }
476
 
  this->GenerateDartBuildOutput(
477
 
    xofs, this->ErrorsAndWarnings, elapsed_build_time);
478
 
  return 0;
 
509
  return retVal;
479
510
}
480
511
 
481
 
//----------------------------------------------------------------------
482
 
void cmCTestBuildHandler::GenerateDartBuildOutput(
483
 
  std::ostream& os,
484
 
  std::vector<cmCTestBuildErrorWarning> ew,
485
 
  double elapsed_build_time)
 
512
//----------------------------------------------------------------------------
 
513
void cmCTestBuildHandler::GenerateXMLHeader(std::ostream& os)
486
514
{
487
 
  this->CTest->StartXML(os);
 
515
  this->CTest->StartXML(os, this->AppendXML);
488
516
  os << "<Build>\n"
489
517
     << "\t<StartDateTime>" << this->StartBuild << "</StartDateTime>\n"
490
518
     << "\t<StartBuildTime>" << 
491
519
    static_cast<unsigned int>(this->StartBuildTime)
492
520
     << "</StartBuildTime>\n"
493
521
     << "<BuildCommand>"
494
 
     << this->CTest->MakeXMLSafe(
 
522
     << cmXMLSafe(
495
523
       this->CTest->GetCTestConfiguration("MakeCommand"))
496
524
     << "</BuildCommand>" << std::endl;
497
 
 
 
525
}
 
526
 
 
527
//----------------------------------------------------------------------------
 
528
class cmCTestBuildHandler::FragmentCompare
 
529
{
 
530
public:
 
531
  FragmentCompare(cmFileTimeComparison* ftc): FTC(ftc) {}
 
532
  bool operator()(std::string const& l, std::string const& r)
 
533
    {
 
534
    // Order files by modification time.  Use lexicographic order
 
535
    // among files with the same time.
 
536
    int result;
 
537
    if(this->FTC->FileTimeCompare(l.c_str(), r.c_str(), &result) &&
 
538
       result != 0)
 
539
      {
 
540
      return result < 0;
 
541
      }
 
542
    else
 
543
      {
 
544
      return l < r;
 
545
      }
 
546
    }
 
547
private:
 
548
  cmFileTimeComparison* FTC;
 
549
};
 
550
 
 
551
//----------------------------------------------------------------------------
 
552
void cmCTestBuildHandler::GenerateXMLLaunched(std::ostream& os)
 
553
{
 
554
  if(this->CTestLaunchDir.empty())
 
555
    {
 
556
    return;
 
557
    }
 
558
 
 
559
  // Sort XML fragments in chronological order.
 
560
  cmFileTimeComparison ftc;
 
561
  FragmentCompare fragmentCompare(&ftc);
 
562
  typedef std::set<cmStdString, FragmentCompare> Fragments;
 
563
  Fragments fragments(fragmentCompare);
 
564
 
 
565
  // Identify fragments on disk.
 
566
  cmsys::Directory launchDir;
 
567
  launchDir.Load(this->CTestLaunchDir.c_str());
 
568
  unsigned long n = launchDir.GetNumberOfFiles();
 
569
  for(unsigned long i=0; i < n; ++i)
 
570
    {
 
571
    const char* fname = launchDir.GetFile(i);
 
572
    if(this->IsLaunchedErrorFile(fname))
 
573
      {
 
574
      fragments.insert(this->CTestLaunchDir + "/" + fname);
 
575
      ++this->TotalErrors;
 
576
      }
 
577
    else if(this->IsLaunchedWarningFile(fname))
 
578
      {
 
579
      fragments.insert(this->CTestLaunchDir + "/" + fname);
 
580
      ++this->TotalWarnings;
 
581
      }
 
582
    }
 
583
 
 
584
  // Copy the fragments into the final XML file.
 
585
  for(Fragments::const_iterator fi = fragments.begin();
 
586
      fi != fragments.end(); ++fi)
 
587
    {
 
588
    this->GenerateXMLLaunchedFragment(os, fi->c_str());
 
589
    }
 
590
}
 
591
 
 
592
//----------------------------------------------------------------------------
 
593
void cmCTestBuildHandler::GenerateXMLLogScraped(std::ostream& os)
 
594
{
 
595
  std::vector<cmCTestBuildErrorWarning>& ew = this->ErrorsAndWarnings;
498
596
  std::vector<cmCTestBuildErrorWarning>::iterator it;
499
597
 
500
598
  // only report the first 50 warnings and first 50 errors
501
 
  unsigned short numErrorsAllowed = this->MaxErrors;
502
 
  unsigned short numWarningsAllowed = this->MaxWarnings;
 
599
  int numErrorsAllowed = this->MaxErrors;
 
600
  int numWarningsAllowed = this->MaxWarnings;
503
601
  std::string srcdir = this->CTest->GetCTestConfiguration("SourceDirectory");
504
602
  // make sure the source dir is in the correct case on windows
505
603
  // via a call to collapse full path.
509
607
        it != ew.end() && (numErrorsAllowed || numWarningsAllowed); it++ )
510
608
    {
511
609
    cmCTestBuildErrorWarning *cm = &(*it);
512
 
    if (cm->Error && numErrorsAllowed ||
513
 
        !cm->Error && numWarningsAllowed)
 
610
    if ((cm->Error && numErrorsAllowed) ||
 
611
        (!cm->Error && numWarningsAllowed))
514
612
      {
515
613
      if (cm->Error)
516
614
        {
522
620
        }
523
621
      os << "\t<" << (cm->Error ? "Error" : "Warning") << ">\n"
524
622
         << "\t\t<BuildLogLine>" << cm->LogLine << "</BuildLogLine>\n"
525
 
         << "\t\t<Text>" << this->CTest->MakeXMLSafe(cm->Text)
 
623
         << "\t\t<Text>" << cmXMLSafe(cm->Text).Quotes(false)
526
624
         << "\n</Text>" << std::endl;
527
625
      std::vector<cmCTestCompileErrorWarningRex>::iterator rit;
528
626
      for ( rit = this->ErrorWarningFileLineRegex.begin();
575
673
            << "</SourceLineNumber>" << std::endl;
576
674
          }
577
675
        }
578
 
      os << "\t\t<PreContext>" << this->CTest->MakeXMLSafe(cm->PreContext)
 
676
      os << "\t\t<PreContext>" << cmXMLSafe(cm->PreContext).Quotes(false)
579
677
         << "</PreContext>\n"
580
 
         << "\t\t<PostContext>" << this->CTest->MakeXMLSafe(cm->PostContext);
 
678
         << "\t\t<PostContext>" << cmXMLSafe(cm->PostContext).Quotes(false);
581
679
      // is this the last warning or error, if so notify
582
 
      if (cm->Error && !numErrorsAllowed ||
583
 
          !cm->Error && !numWarningsAllowed)
 
680
      if ((cm->Error && !numErrorsAllowed) ||
 
681
          (!cm->Error && !numWarningsAllowed))
584
682
        {
585
683
        os << "\nThe maximum number of reported warnings or errors has been "
586
684
          "reached!!!\n";
591
689
         << std::endl;
592
690
      }
593
691
    }
 
692
}
 
693
 
 
694
//----------------------------------------------------------------------------
 
695
void cmCTestBuildHandler::GenerateXMLFooter(std::ostream& os,
 
696
                                            double elapsed_build_time)
 
697
{
594
698
  os << "\t<Log Encoding=\"base64\" Compression=\"/bin/gzip\">\n\t</Log>\n"
595
699
     << "\t<EndDateTime>" << this->EndBuild << "</EndDateTime>\n"
596
700
     << "\t<EndBuildTime>" << static_cast<unsigned int>(this->EndBuildTime)
601
705
  this->CTest->EndXML(os);
602
706
}
603
707
 
604
 
//######################################################################
605
 
//######################################################################
606
 
//######################################################################
607
 
//######################################################################
 
708
//----------------------------------------------------------------------------
 
709
void cmCTestBuildHandler::GenerateXMLLaunchedFragment(std::ostream& os,
 
710
                                                      const char* fname)
 
711
{
 
712
  std::ifstream fin(fname, std::ios::in | std::ios::binary);
 
713
  std::string line;
 
714
  while(cmSystemTools::GetLineFromStream(fin, line))
 
715
    {
 
716
    os << line << "\n";
 
717
    }
 
718
}
 
719
 
 
720
//----------------------------------------------------------------------------
 
721
bool cmCTestBuildHandler::IsLaunchedErrorFile(const char* fname)
 
722
{
 
723
  // error-{hash}.xml
 
724
  return (strncmp(fname, "error-", 6) == 0 &&
 
725
          strcmp(fname+strlen(fname)-4, ".xml") == 0);
 
726
}
 
727
 
 
728
//----------------------------------------------------------------------------
 
729
bool cmCTestBuildHandler::IsLaunchedWarningFile(const char* fname)
 
730
{
 
731
  // warning-{hash}.xml
 
732
  return (strncmp(fname, "warning-", 8) == 0 &&
 
733
          strcmp(fname+strlen(fname)-4, ".xml") == 0);
 
734
}
 
735
 
 
736
//######################################################################
 
737
//######################################################################
 
738
//######################################################################
 
739
//######################################################################
 
740
 
 
741
//----------------------------------------------------------------------------
 
742
class cmCTestBuildHandler::LaunchHelper
 
743
{
 
744
public:
 
745
  LaunchHelper(cmCTestBuildHandler* handler);
 
746
  ~LaunchHelper();
 
747
private:
 
748
  cmCTestBuildHandler* Handler;
 
749
  cmCTest* CTest;
 
750
 
 
751
  void WriteLauncherConfig();
 
752
  void WriteScrapeMatchers(const char* purpose,
 
753
                           std::vector<std::string> const& matchers);
 
754
};
 
755
 
 
756
//----------------------------------------------------------------------------
 
757
cmCTestBuildHandler::LaunchHelper::LaunchHelper(cmCTestBuildHandler* handler):
 
758
  Handler(handler), CTest(handler->CTest)
 
759
{
 
760
  std::string tag = this->CTest->GetCurrentTag();
 
761
  if(tag.empty())
 
762
    {
 
763
    // This is not for a dashboard submission, so there is no XML.
 
764
    // Skip enabling the launchers.
 
765
    this->Handler->UseCTestLaunch = false;
 
766
    }
 
767
  else
 
768
    {
 
769
    // Compute a directory in which to store launcher fragments.
 
770
    std::string& launchDir = this->Handler->CTestLaunchDir;
 
771
    launchDir = this->CTest->GetBinaryDir();
 
772
    launchDir += "/Testing/";
 
773
    launchDir += tag;
 
774
    launchDir += "/Build";
 
775
 
 
776
    // Clean out any existing launcher fragments.
 
777
    cmSystemTools::RemoveADirectory(launchDir.c_str());
 
778
 
 
779
    if(this->Handler->UseCTestLaunch)
 
780
      {
 
781
      // Enable launcher fragments.
 
782
      cmSystemTools::MakeDirectory(launchDir.c_str());
 
783
      this->WriteLauncherConfig();
 
784
      std::string launchEnv = "CTEST_LAUNCH_LOGS=";
 
785
      launchEnv += launchDir;
 
786
      cmSystemTools::PutEnv(launchEnv.c_str());
 
787
      }
 
788
    }
 
789
 
 
790
  // If not using launchers, make sure they passthru.
 
791
  if(!this->Handler->UseCTestLaunch)
 
792
    {
 
793
    cmSystemTools::UnsetEnv("CTEST_LAUNCH_LOGS");
 
794
    }
 
795
}
 
796
 
 
797
//----------------------------------------------------------------------------
 
798
cmCTestBuildHandler::LaunchHelper::~LaunchHelper()
 
799
{
 
800
  if(this->Handler->UseCTestLaunch)
 
801
    {
 
802
    cmSystemTools::UnsetEnv("CTEST_LAUNCH_LOGS");
 
803
    }
 
804
}
 
805
 
 
806
//----------------------------------------------------------------------------
 
807
void cmCTestBuildHandler::LaunchHelper::WriteLauncherConfig()
 
808
{
 
809
  this->WriteScrapeMatchers("Warning",
 
810
                            this->Handler->ReallyCustomWarningMatches);
 
811
  this->WriteScrapeMatchers("WarningSuppress",
 
812
                            this->Handler->ReallyCustomWarningExceptions);
 
813
 
 
814
  // Give some testing configuration information to the launcher.
 
815
  std::string fname = this->Handler->CTestLaunchDir;
 
816
  fname += "/CTestLaunchConfig.cmake";
 
817
  cmGeneratedFileStream fout(fname.c_str());
 
818
  std::string srcdir = this->CTest->GetCTestConfiguration("SourceDirectory");
 
819
  fout << "set(CTEST_SOURCE_DIRECTORY \"" << srcdir << "\")\n";
 
820
}
 
821
 
 
822
//----------------------------------------------------------------------------
 
823
void
 
824
cmCTestBuildHandler::LaunchHelper
 
825
::WriteScrapeMatchers(const char* purpose,
 
826
                      std::vector<std::string> const& matchers)
 
827
{
 
828
  if(matchers.empty())
 
829
    {
 
830
    return;
 
831
    }
 
832
  std::string fname = this->Handler->CTestLaunchDir;
 
833
  fname += "/Custom";
 
834
  fname += purpose;
 
835
  fname += ".txt";
 
836
  cmGeneratedFileStream fout(fname.c_str());
 
837
  for(std::vector<std::string>::const_iterator mi = matchers.begin();
 
838
      mi != matchers.end(); ++mi)
 
839
    {
 
840
    fout << *mi << "\n";
 
841
    }
 
842
}
608
843
 
609
844
//----------------------------------------------------------------------
610
845
int cmCTestBuildHandler::RunMakeCommand(const char* command,
634
869
    }
635
870
  cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, std::endl);
636
871
 
 
872
  // Optionally use make rule launchers to record errors and warnings.
 
873
  LaunchHelper launchHelper(this);
 
874
  static_cast<void>(launchHelper);
 
875
 
637
876
  // Now create process object
638
877
  cmsysProcess* cp = cmsysProcess_New();
639
878
  cmsysProcess_SetCommand(cp, &*argv.begin());
651
890
  cmCTestLog(this->CTest, HANDLER_OUTPUT,
652
891
    "   Each symbol represents " << tick_len << " bytes of output."
653
892
    << std::endl
654
 
    << "   '!' represents an error and '*' a warning." << std::endl
 
893
    << (this->UseCTestLaunch? "" :
 
894
        "   '!' represents an error and '*' a warning.\n")
655
895
    << "    " << std::flush);
656
896
 
657
897
  // Initialize building structures
757
997
    }
758
998
 
759
999
  cmsysProcess_Delete(cp);
760
 
 
761
1000
  return result;
762
1001
}
763
1002
 
929
1168
//----------------------------------------------------------------------
930
1169
int cmCTestBuildHandler::ProcessSingleLine(const char* data)
931
1170
{
 
1171
  if(this->UseCTestLaunch)
 
1172
    {
 
1173
    // No log scraping when using launchers.
 
1174
    return b_REGULAR_LINE;
 
1175
    }
 
1176
 
932
1177
  cmCTestLog(this->CTest, DEBUG, "Line: [" << data << "]" << std::endl);
933
1178
 
934
1179
  std::vector<cmsys::RegularExpression>::iterator it;