Updates will be applied on October 27th between 12pm - 12:45pm EDT (UTC-0400). Gitlab may be slow during the maintenance window.

cmGlobalUnixMakefileGenerator3.cxx 34.1 KB
Newer Older
Ken Martin's avatar
Ken Martin committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/*=========================================================================

  Program:   CMake - Cross-Platform Makefile Generator3
  Module:    $RCSfile$
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

  Copyright (c) 2002 Kitware, Inc., Insight Consortium.  All rights reserved.
  See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.

     This software is distributed WITHOUT ANY WARRANTY; without even 
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/

#include "cmGlobalUnixMakefileGenerator3.h"
#include "cmLocalUnixMakefileGenerator3.h"
#include "cmMakefile.h"
#include "cmake.h"
#include "cmGeneratedFileStream.h"
Ken Martin's avatar
Ken Martin committed
23
24
#include "cmSourceFile.h"
#include "cmTarget.h"
Ken Martin's avatar
Ken Martin committed
25
26
27
28

cmGlobalUnixMakefileGenerator3::cmGlobalUnixMakefileGenerator3()
{
  // This type of makefile always requires unix style paths
Ken Martin's avatar
Ken Martin committed
29
30
  this->ForceUnixPaths = true;
  this->FindMakeProgramFile = "CMakeUnixFindMake.cmake";
31
  this->ToolSupportsColor = true;
Alexander Neundorf's avatar
   
Alexander Neundorf committed
32
33
  this->ForceVerboseMakefiles = false;

34
35
36
#ifdef _WIN32
  this->UseLinkScript = false;
#else
37
  this->UseLinkScript = true;
38
#endif
Ken Martin's avatar
Ken Martin committed
39
40
41
}

void cmGlobalUnixMakefileGenerator3
Alexander Neundorf's avatar
   
Alexander Neundorf committed
42
43
44
::EnableLanguage(std::vector<std::string>const& languages, 
                 cmMakefile *mf, 
                 bool optional)
Ken Martin's avatar
Ken Martin committed
45
{
Alexander Neundorf's avatar
   
Alexander Neundorf committed
46
  this->cmGlobalGenerator::EnableLanguage(languages, mf, optional);
Ken Martin's avatar
Ken Martin committed
47
48
49
50
  std::string path;
  for(std::vector<std::string>::const_iterator l = languages.begin();
      l != languages.end(); ++l)
    {
Bill Hoffman's avatar
Bill Hoffman committed
51
52
53
54
    if(*l == "NONE")
      {
      continue;
      }
Ken Martin's avatar
Ken Martin committed
55
56
57
58
59
60
61
    const char* lang = l->c_str();
    std::string langComp = "CMAKE_";
    langComp += lang;
    langComp += "_COMPILER";
    
    if(!mf->GetDefinition(langComp.c_str()))
      {
Ken Martin's avatar
Ken Martin committed
62
63
      cmSystemTools::Error(langComp.c_str(), 
                           " not set, after EnableLanguage");
Ken Martin's avatar
Ken Martin committed
64
65
      continue;
      }
66
    const char* name = mf->GetRequiredDefinition(langComp.c_str()); 
67
68
69
70
71
72
73
74
    if(!cmSystemTools::FileIsFullPath(name))
      {
      path = cmSystemTools::FindProgram(name);
      }
    else
      {
      path = name;
      }
Alexander Neundorf's avatar
   
Alexander Neundorf committed
75
76
    if((path.size() == 0 || !cmSystemTools::FileExists(path.c_str())) 
        && (optional==false))
Ken Martin's avatar
Ken Martin committed
77
78
79
      {
      std::string message = "your ";
      message += lang;
80
81
82
83
84
85
86
      message += " compiler: \"";
      message +=  name;
      message += "\" was not found.   Please set ";
      message += langComp;
      message += " to a valid compiler path or name.";
      cmSystemTools::Error(message.c_str());
      path = name;
Ken Martin's avatar
Ken Martin committed
87
      }
88
89
    std::string doc = lang;
    doc += " compiler.";
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
    const char* cname = this->GetCMakeInstance()->
      GetCacheManager()->GetCacheValue(langComp.c_str());
    std::string changeVars;
    if(cname && (path != cname))
      {
      const char* cvars = 
        this->GetCMakeInstance()->GetProperty(
          "__CMAKE_DELETE_CACHE_CHANGE_VARS_");
      if(cvars)
        {
        changeVars += cvars;
        changeVars += ";";
        }
      changeVars += langComp;
      changeVars += ";";
      changeVars += cname;
      this->GetCMakeInstance()->SetProperty(
        "__CMAKE_DELETE_CACHE_CHANGE_VARS_",
        changeVars.c_str());
      }
110
111
    mf->AddCacheDefinition(langComp.c_str(), path.c_str(),
                           doc.c_str(), cmCacheManager::FILEPATH);
Ken Martin's avatar
Ken Martin committed
112
113
114
115
116
117
118
119
120
121
122
123
    }
}

///! Create a local generator appropriate to this Global Generator
cmLocalGenerator *cmGlobalUnixMakefileGenerator3::CreateLocalGenerator()
{
  cmLocalGenerator* lg = new cmLocalUnixMakefileGenerator3;
  lg->SetGlobalGenerator(this);
  return lg;
}

//----------------------------------------------------------------------------
Ken Martin's avatar
Ken Martin committed
124
125
void cmGlobalUnixMakefileGenerator3
::GetDocumentation(cmDocumentationEntry& entry) const
Ken Martin's avatar
Ken Martin committed
126
{
127
128
129
  entry.Name = this->GetName();
  entry.Brief = "Generates standard UNIX makefiles.";
  entry.Full =
Ken Martin's avatar
Ken Martin committed
130
131
132
133
134
    "A hierarchy of UNIX makefiles is generated into the build tree.  Any "
    "standard UNIX-style make program can build the project through the "
    "default make target.  A \"make install\" target is also provided.";
}

Ken Martin's avatar
Ken Martin committed
135
136
137
//----------------------------------------------------------------------------
void cmGlobalUnixMakefileGenerator3::Generate() 
{
138
139
140
  // first do superclass method
  this->cmGlobalGenerator::Generate();

141
  // initialize progress
Ken Martin's avatar
Ken Martin committed
142
  unsigned int i;
143
  unsigned long total = 0;
Ken Martin's avatar
Ken Martin committed
144
145
  for (i = 0; i < this->LocalGenerators.size(); ++i)
    {
146
147
148
    cmLocalUnixMakefileGenerator3 *lg = 
      static_cast<cmLocalUnixMakefileGenerator3 *>(this->LocalGenerators[i]);
    total += lg->GetNumberOfProgressActions();
Ken Martin's avatar
Ken Martin committed
149
    }
Ken Martin's avatar
Ken Martin committed
150

151
152
153
154
155
156
157
  // write each target's progress.make this loop is done twice. Bascially the
  // Generate pass counts all the actions, the first loop below determines
  // how many actions have progress updates for each target and writes to
  // corrrect variable values for everything except the all targets. The
  // second loop actually writes out correct values for the all targets as
  // well. This is because the all targets require more information that is
  // computed in the first loop.
158
  unsigned long current = 0;
159
  for (i = 0; i < this->LocalGenerators.size(); ++i)
160
161
162
163
164
    {
    cmLocalUnixMakefileGenerator3 *lg = 
      static_cast<cmLocalUnixMakefileGenerator3 *>(this->LocalGenerators[i]);
    lg->WriteProgressVariables(total,current);
    }
165
  for (i = 0; i < this->LocalGenerators.size(); ++i)
166
167
    {
    cmLocalUnixMakefileGenerator3 *lg = 
168
169
      static_cast<cmLocalUnixMakefileGenerator3 *>(this->LocalGenerators[i]);
    lg->WriteAllProgressVariable();
170
171
    }
  
Ken Martin's avatar
Ken Martin committed
172
  // write the main makefile
173
  this->WriteMainMakefile2();
Ken Martin's avatar
Ken Martin committed
174
175
176
  this->WriteMainCMakefile();
}

177
178
179
180
181
182
183
void cmGlobalUnixMakefileGenerator3::WriteMainMakefile2()
{
  // Open the output file.  This should not be copy-if-different
  // because the check-build-system step compares the makefile time to
  // see if the build system must be regenerated.
  std::string makefileName = 
    this->GetCMakeInstance()->GetHomeOutputDirectory();
184
185
  makefileName += cmake::GetCMakeFilesDirectory();
  makefileName += "/Makefile2";
186
187
188
189
190
191
192
193
  cmGeneratedFileStream makefileStream(makefileName.c_str());
  if(!makefileStream)
    {
    return;
    }
 
  // get a local generator for some useful methods
  cmLocalUnixMakefileGenerator3 *lg = 
Ken Martin's avatar
Ken Martin committed
194
    static_cast<cmLocalUnixMakefileGenerator3 *>(this->LocalGenerators[0]);
195
196
197
    
  // Write the do not edit header.
  lg->WriteDisclaimer(makefileStream);
198

199
200
201
202
203
204
205
206
207
208
209
210
211
  // Write the main entry point target.  This must be the VERY first
  // target so that make with no arguments will run it.
  // Just depend on the all target to drive the build.
  std::vector<std::string> depends;
  std::vector<std::string> no_commands;
  depends.push_back("all");

  // Write the rule.
  lg->WriteMakeRule(makefileStream,
                    "Default target executed when no arguments are "
                    "given to make.",
                    "default_target",
                    depends,
212
                    no_commands, true);
213

214
  depends.clear();
215

216
217
  // The all and preinstall rules might never have any dependencies
  // added to them.
Ken Martin's avatar
Ken Martin committed
218
  if(this->EmptyRuleHackDepends != "")
219
    {
Ken Martin's avatar
Ken Martin committed
220
    depends.push_back(this->EmptyRuleHackDepends);
221
222
    }

223
224
225
  // Write and empty all:
  lg->WriteMakeRule(makefileStream, 
                    "The main recursive all target", "all", 
226
                    depends, no_commands, true);
227

228
229
230
231
232
  // Write an empty preinstall:
  lg->WriteMakeRule(makefileStream,
                    "The main recursive preinstall target", "preinstall",
                    depends, no_commands, true);

233
234
  // Write out the "special" stuff
  lg->WriteSpecialTargetsTop(makefileStream);
235
236
237
  
  // write the target convenience rules
  unsigned int i;
Ken Martin's avatar
Ken Martin committed
238
  for (i = 0; i < this->LocalGenerators.size(); ++i)
239
    {
Ken Martin's avatar
Ken Martin committed
240
241
    lg = 
      static_cast<cmLocalUnixMakefileGenerator3 *>(this->LocalGenerators[i]);
242
    this->WriteConvenienceRules2(makefileStream,lg);
243
244
    }

Ken Martin's avatar
Ken Martin committed
245
  lg = static_cast<cmLocalUnixMakefileGenerator3 *>(this->LocalGenerators[0]);
246
247
248
  lg->WriteSpecialTargetsBottom(makefileStream);
}

Ken Martin's avatar
Ken Martin committed
249

Ken Martin's avatar
Ken Martin committed
250
251
252
253
254
255
//----------------------------------------------------------------------------
void cmGlobalUnixMakefileGenerator3::WriteMainCMakefile()
{
  // Open the output file.  This should not be copy-if-different
  // because the check-build-system step compares the makefile time to
  // see if the build system must be regenerated.
Ken Martin's avatar
Ken Martin committed
256
257
  std::string cmakefileName = 
    this->GetCMakeInstance()->GetHomeOutputDirectory();
258
259
  cmakefileName += cmake::GetCMakeFilesDirectory();
  cmakefileName += "/Makefile.cmake";
Ken Martin's avatar
Ken Martin committed
260
261
262
263
264
  cmGeneratedFileStream cmakefileStream(cmakefileName.c_str());
  if(!cmakefileStream)
    {
    return;
    }
Ken Martin's avatar
Ken Martin committed
265
266
267
268
269

  std::string makefileName = 
    this->GetCMakeInstance()->GetHomeOutputDirectory();
  makefileName += "/Makefile";
  
Ken Martin's avatar
Ken Martin committed
270
271
  // get a local generator for some useful methods
  cmLocalUnixMakefileGenerator3 *lg = 
Ken Martin's avatar
Ken Martin committed
272
    static_cast<cmLocalUnixMakefileGenerator3 *>(this->LocalGenerators[0]);
Ken Martin's avatar
Ken Martin committed
273
274
275
276
    
  // Write the do not edit header.
  lg->WriteDisclaimer(cmakefileStream);

Ken Martin's avatar
Ken Martin committed
277
278
279
280
281
  // Save the generator name
  cmakefileStream
    << "# The generator used is:\n"
    << "SET(CMAKE_DEPENDS_GENERATOR \"" << this->GetName() << "\")\n\n";

Ken Martin's avatar
Ken Martin committed
282
283
  // for each cmMakefile get its list of dependencies
  std::vector<std::string> lfiles;
Ken Martin's avatar
Ken Martin committed
284
  for (unsigned int i = 0; i < this->LocalGenerators.size(); ++i)
Ken Martin's avatar
Ken Martin committed
285
    {
Ken Martin's avatar
Ken Martin committed
286
287
    lg = 
      static_cast<cmLocalUnixMakefileGenerator3 *>(this->LocalGenerators[i]);
Ken Martin's avatar
Ken Martin committed
288
289
290
291
292
293
294
295
296
297
298
299
  
    // Get the list of files contributing to this generation step.
    lfiles.insert(lfiles.end(),lg->GetMakefile()->GetListFiles().begin(),
                  lg->GetMakefile()->GetListFiles().end());
    }
  // Sort the list and remove duplicates.
  std::sort(lfiles.begin(), lfiles.end(), std::less<std::string>());
  std::vector<std::string>::iterator new_end = 
    std::unique(lfiles.begin(),lfiles.end());
  lfiles.erase(new_end, lfiles.end());

  // reset lg to the first makefile
Ken Martin's avatar
Ken Martin committed
300
  lg = static_cast<cmLocalUnixMakefileGenerator3 *>(this->LocalGenerators[0]);
Ken Martin's avatar
Ken Martin committed
301
302
303
304
305
306
307
308
309

  // Build the path to the cache file.
  std::string cache = this->GetCMakeInstance()->GetHomeOutputDirectory();
  cache += "/CMakeCache.txt";

  // Save the list to the cmake file.
  cmakefileStream
    << "# The top level Makefile was generated from the following files:\n"
    << "SET(CMAKE_MAKEFILE_DEPENDS\n"
Ken Martin's avatar
Ken Martin committed
310
311
312
    << "  \"" 
    << lg->Convert(cache.c_str(),
                   cmLocalGenerator::START_OUTPUT).c_str() << "\"\n";
Ken Martin's avatar
Ken Martin committed
313
314
315
316
  for(std::vector<std::string>::const_iterator i = lfiles.begin();
      i !=  lfiles.end(); ++i)
    {
    cmakefileStream
Ken Martin's avatar
Ken Martin committed
317
318
      << "  \"" 
      << lg->Convert(i->c_str(), cmLocalGenerator::START_OUTPUT).c_str()
Ken Martin's avatar
Ken Martin committed
319
320
321
322
323
324
325
      << "\"\n";
    }
  cmakefileStream
    << "  )\n\n";

  // Build the path to the cache check file.
  std::string check = this->GetCMakeInstance()->GetHomeOutputDirectory();
326
327
  check += cmake::GetCMakeFilesDirectory();
  check += "/cmake.check_cache";
Ken Martin's avatar
Ken Martin committed
328
329
330
331
332

  // Set the corresponding makefile in the cmake file.
  cmakefileStream
    << "# The corresponding makefile is:\n"
    << "SET(CMAKE_MAKEFILE_OUTPUTS\n"
Ken Martin's avatar
Ken Martin committed
333
334
335
336
337
338
    << "  \"" 
    << lg->Convert(makefileName.c_str(),
                   cmLocalGenerator::START_OUTPUT).c_str() << "\"\n"
    << "  \"" 
    << lg->Convert(check.c_str(),
                   cmLocalGenerator::START_OUTPUT).c_str() << "\"\n";
Ken Martin's avatar
Ken Martin committed
339
340
341

  // add in all the directory information files
  std::string tmpStr;
Ken Martin's avatar
Ken Martin committed
342
  for (unsigned int i = 0; i < this->LocalGenerators.size(); ++i)
Ken Martin's avatar
Ken Martin committed
343
    {
Ken Martin's avatar
Ken Martin committed
344
345
    lg = 
      static_cast<cmLocalUnixMakefileGenerator3 *>(this->LocalGenerators[i]);
Ken Martin's avatar
Ken Martin committed
346
    tmpStr = lg->GetMakefile()->GetStartOutputDirectory();
347
348
    tmpStr += cmake::GetCMakeFilesDirectory();
    tmpStr += "/CMakeDirectoryInformation.cmake";
349
    cmakefileStream << "  \"" << 
Ken Martin's avatar
Ken Martin committed
350
351
352
353
      lg->Convert(tmpStr.c_str(),cmLocalGenerator::HOME_OUTPUT).c_str() 
                    << "\"\n";
    const std::vector<std::string>& outfiles = 
      lg->GetMakefile()->GetOutputFiles();
354
355
356
357
    for(std::vector<std::string>::const_iterator k= outfiles.begin();
        k != outfiles.end(); ++k)
      {
      cmakefileStream << "  \"" << 
Ken Martin's avatar
Ken Martin committed
358
359
        lg->Convert(k->c_str(),cmLocalGenerator::HOME_OUTPUT).c_str() 
                      << "\"\n";
360
      }
Ken Martin's avatar
Ken Martin committed
361
362
    }
  cmakefileStream << "  )\n\n";
Ken Martin's avatar
Ken Martin committed
363

Ken Martin's avatar
Ken Martin committed
364
365
  this->WriteMainCMakefileLanguageRules(cmakefileStream, 
                                        this->LocalGenerators);
366
367
}

Ken Martin's avatar
Ken Martin committed
368
void cmGlobalUnixMakefileGenerator3
369
::WriteMainCMakefileLanguageRules(cmGeneratedFileStream& cmakefileStream,
Ken Martin's avatar
Ken Martin committed
370
371
                                  std::vector<cmLocalGenerator *> &lGenerators
                                  )
Ken Martin's avatar
Ken Martin committed
372
373
374
{
  cmLocalUnixMakefileGenerator3 *lg;

375
  // now list all the target info files
Ken Martin's avatar
Ken Martin committed
376
  cmakefileStream
377
    << "# Dependency information for all targets:\n";
Ken Martin's avatar
Ken Martin committed
378
  cmakefileStream
379
380
    << "SET(CMAKE_DEPEND_INFO_FILES\n";
  for (unsigned int i = 0; i < lGenerators.size(); ++i)
Ken Martin's avatar
Ken Martin committed
381
    {
382
383
384
385
    lg = static_cast<cmLocalUnixMakefileGenerator3 *>(lGenerators[i]);
    // for all of out targets
    for (cmTargets::iterator l = lg->GetMakefile()->GetTargets().begin();
         l != lg->GetMakefile()->GetTargets().end(); l++)
Ken Martin's avatar
Ken Martin committed
386
      {
387
388
389
      if((l->second.GetType() == cmTarget::EXECUTABLE) ||
         (l->second.GetType() == cmTarget::STATIC_LIBRARY) ||
         (l->second.GetType() == cmTarget::SHARED_LIBRARY) ||
390
391
         (l->second.GetType() == cmTarget::MODULE_LIBRARY) ||
         (l->second.GetType() == cmTarget::UTILITY))
392
393
394
395
396
397
        {
        std::string tname = lg->GetRelativeTargetDirectory(l->second);
        tname += "/DependInfo.cmake";
        cmSystemTools::ConvertToUnixSlashes(tname);
        cmakefileStream << "  \"" << tname.c_str() << "\"\n";
        }
Ken Martin's avatar
Ken Martin committed
398
399
      }
    }
400
  cmakefileStream << "  )\n";
Ken Martin's avatar
Ken Martin committed
401
402
}

Ken Martin's avatar
Ken Martin committed
403
404
405
//----------------------------------------------------------------------------
void
cmGlobalUnixMakefileGenerator3
406
407
408
409
::WriteDirectoryRule2(std::ostream& ruleFileStream,
                      cmLocalUnixMakefileGenerator3* lg,
                      const char* pass, bool check_all,
                      bool check_relink)
Ken Martin's avatar
Ken Martin committed
410
{
411
412
413
414
415
416
417
418
419
420
  // Get the relative path to the subdirectory from the top.
  std::string makeTarget = lg->GetMakefile()->GetStartOutputDirectory();
  makeTarget += "/";
  makeTarget += pass;

  // The directory-level rule should depend on the target-level rules
  // for all targets in the directory.
  std::vector<std::string> depends;
  for(cmTargets::iterator l = lg->GetMakefile()->GetTargets().begin();
      l != lg->GetMakefile()->GetTargets().end(); ++l)
421
    {
422
423
424
425
426
    if((l->second.GetType() == cmTarget::EXECUTABLE) ||
       (l->second.GetType() == cmTarget::STATIC_LIBRARY) ||
       (l->second.GetType() == cmTarget::SHARED_LIBRARY) ||
       (l->second.GetType() == cmTarget::MODULE_LIBRARY) ||
       (l->second.GetType() == cmTarget::UTILITY))
427
      {
428
      // Add this to the list of depends rules in this directory.
Ken Martin's avatar
Ken Martin committed
429
      if((!check_all || !l->second.GetPropertyAsBool("EXCLUDE_FROM_ALL")) &&
430
         (!check_relink || l->second.NeedRelinkBeforeInstall()))
431
        {
432
433
434
435
        std::string tname = lg->GetRelativeTargetDirectory(l->second);
        tname += "/";
        tname += pass;
        depends.push_back(tname);
436
437
        }
      }
438
439
    }

440
441
  // The directory-level rule should depend on the directory-level
  // rules of the subdirectories.
Ken Martin's avatar
Ken Martin committed
442
443
  for(std::vector<cmLocalGenerator*>::iterator sdi = 
        lg->GetChildren().begin(); sdi != lg->GetChildren().end(); ++sdi)
444
    {
445
446
447
448
449
450
    cmLocalUnixMakefileGenerator3* slg =
      static_cast<cmLocalUnixMakefileGenerator3*>(*sdi);
    std::string subdir = slg->GetMakefile()->GetStartOutputDirectory();
    subdir += "/";
    subdir += pass;
    depends.push_back(subdir);
451
    }
452
453
454

  // Work-around for makes that drop rules that have no dependencies
  // or commands.
Ken Martin's avatar
Ken Martin committed
455
  if(depends.empty() && this->EmptyRuleHackDepends != "")
456
    {
Ken Martin's avatar
Ken Martin committed
457
    depends.push_back(this->EmptyRuleHackDepends);
458
459
460
461
462
463
464
465
466
    }

  // Write the rule.
  std::string doc = "Convenience name for \"";
  doc += pass;
  doc += "\" pass in the directory.";
  std::vector<std::string> no_commands;
  lg->WriteMakeRule(ruleFileStream, doc.c_str(),
                    makeTarget.c_str(), depends, no_commands, true);
467
468
469
470
471
}

//----------------------------------------------------------------------------
void
cmGlobalUnixMakefileGenerator3
472
473
::WriteDirectoryRules2(std::ostream& ruleFileStream,
                       cmLocalUnixMakefileGenerator3* lg)
474
{
475
476
  // Only subdirectories need these rules.
  if(!lg->GetParent())
477
    {
478
    return;
479
    }
480

481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
  // Begin the directory-level rules section.
  std::string dir = lg->GetMakefile()->GetStartOutputDirectory();
  dir = lg->Convert(dir.c_str(), cmLocalGenerator::HOME_OUTPUT,
                    cmLocalGenerator::MAKEFILE);
  lg->WriteDivider(ruleFileStream);
  ruleFileStream
    << "# Directory level rules for directory "
    << dir << "\n\n";

  // Write directory-level rules for "all".
  this->WriteDirectoryRule2(ruleFileStream, lg, "all", true, false);

  // Write directory-level rules for "clean".
  this->WriteDirectoryRule2(ruleFileStream, lg, "clean", false, false);

  // Write directory-level rules for "preinstall".
497
  this->WriteDirectoryRule2(ruleFileStream, lg, "preinstall", true, true);
498
499
}

500

Ken Martin's avatar
Ken Martin committed
501
502
503
std::string cmGlobalUnixMakefileGenerator3
::GenerateBuildCommand(const char* makeProgram, const char *projectName, 
                       const char* additionalOptions, const char *targetName,
504
                       const char* config, bool ignoreErrors, bool fast)
505
506
507
508
509
{
  // Project name and config are not used yet.
  (void)projectName;
  (void)config;

Ken Martin's avatar
Ken Martin committed
510
511
512
  std::string makeCommand = 
    cmSystemTools::ConvertToUnixOutputPath(makeProgram);
  
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
  // Since we have full control over the invocation of nmake, let us
  // make it quiet.
  if ( strcmp(this->GetName(), "NMake Makefiles") == 0 )
    {
    makeCommand += " /NOLOGO ";
    }
  if ( ignoreErrors )
    {
    makeCommand += " -i";
    }
  if ( additionalOptions )
    {
    makeCommand += " ";
    makeCommand += additionalOptions;
    }
  if ( targetName && strlen(targetName))
    {
    cmLocalUnixMakefileGenerator3 *lg;
    if (this->LocalGenerators.size())
      {
Ken Martin's avatar
Ken Martin committed
533
534
      lg = static_cast<cmLocalUnixMakefileGenerator3 *>
        (this->LocalGenerators[0]);
535
536
537
      }
    else
      {
Ken Martin's avatar
Ken Martin committed
538
539
      lg = static_cast<cmLocalUnixMakefileGenerator3 *>
        (this->CreateLocalGenerator());
540
541
542
543
544
545
546
547
      // set the Start directories
      lg->GetMakefile()->SetStartDirectory
        (this->CMakeInstance->GetStartDirectory());
      lg->GetMakefile()->SetStartOutputDirectory
        (this->CMakeInstance->GetStartOutputDirectory());
      lg->GetMakefile()->MakeStartDirectoriesCurrent();
      }
    
Ken Martin's avatar
Ken Martin committed
548
    makeCommand += " \"";
549
    std::string tname = targetName;
550
551
552
553
    if(fast)
      {
      tname += "/fast";
      }
554
    tname = lg->Convert(tname.c_str(),cmLocalGenerator::HOME_OUTPUT,
Ken Martin's avatar
Ken Martin committed
555
                        cmLocalGenerator::MAKEFILE);
556
557
558
559
560
561
562
563
564
565
    makeCommand += tname.c_str();
    makeCommand += "\"";
    if (!this->LocalGenerators.size())
      {
      delete lg;
      }
    }
  return makeCommand;
}

566
567
568
569
//----------------------------------------------------------------------------
void
cmGlobalUnixMakefileGenerator3
::WriteConvenienceRules(std::ostream& ruleFileStream, 
570
                        std::set<cmStdString> &emitted)
571
572
573
574
575
{
  std::vector<std::string> depends;  
  std::vector<std::string> commands;

  depends.push_back("cmake_check_build_system");
576
577
578
579
  
  // write the target convenience rules
  unsigned int i;
  cmLocalUnixMakefileGenerator3 *lg;
Ken Martin's avatar
Ken Martin committed
580
  for (i = 0; i < this->LocalGenerators.size(); ++i)
581
    {
Ken Martin's avatar
Ken Martin committed
582
583
    lg = static_cast<cmLocalUnixMakefileGenerator3 *>
      (this->LocalGenerators[i]);
584
585
586
    // for each target Generate the rule files for each target.
    cmTargets& targets = lg->GetMakefile()->GetTargets();
    for(cmTargets::iterator t = targets.begin(); t != targets.end(); ++t)
587
      {
588
589
590
591
      // Don't emit the same rule twice (e.g. two targets with the same
      // simple name)
      if(t->second.GetName() &&
         strlen(t->second.GetName()) &&
Alexander Neundorf's avatar
   
Alexander Neundorf committed
592
593
594
595
596
597
598
599
         emitted.insert(t->second.GetName()).second &&
         // Handle user targets here.  Global targets are handled in
         // the local generator on a per-directory basis.
         ((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)))
600
        {
Alexander Neundorf's avatar
   
Alexander Neundorf committed
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
        // Add a rule to build the target by name.
        lg->WriteDivider(ruleFileStream);
        ruleFileStream
          << "# Target rules for targets named "
          << t->second.GetName() << "\n\n";
        
        // Write the rule.
        commands.clear();
        std::string tmp = cmake::GetCMakeFilesDirectoryPostSlash();
        tmp += "Makefile2";
        commands.push_back(lg->GetRecursiveMakeCall
                            (tmp.c_str(),t->second.GetName()));
        depends.clear();
        depends.push_back("cmake_check_build_system");
        lg->WriteMakeRule(ruleFileStream, 
                          "Build rule for target.",
                          t->second.GetName(), depends, commands,
                          true);
        
        // Add a fast rule to build the target
        std::string localName = lg->GetRelativeTargetDirectory(t->second);
        std::string makefileName;
        makefileName = localName;
        makefileName += "/build.make";          
        depends.clear();
        commands.clear();
        std::string makeTargetName = localName;
        makeTargetName += "/build";
        localName = t->second.GetName();
        localName += "/fast";
        commands.push_back(lg->GetRecursiveMakeCall
                            (makefileName.c_str(), makeTargetName.c_str()));
        lg->WriteMakeRule(ruleFileStream, "fast build rule for target.",
                          localName.c_str(), depends, commands, true);
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651

        // Add a local name for the rule to relink the target before
        // installation.
        if(t->second.NeedRelinkBeforeInstall())
          {
          makeTargetName = lg->GetRelativeTargetDirectory(t->second);
          makeTargetName += "/preinstall";
          localName = t->second.GetName();
          localName += "/preinstall";
          depends.clear();
          commands.clear();
          commands.push_back(lg->GetRecursiveMakeCall
                             (makefileName.c_str(), makeTargetName.c_str()));
          lg->WriteMakeRule(ruleFileStream,
                            "Manual pre-install relink rule for target.",
                            localName.c_str(), depends, commands, true);
          }
652
        }
653
654
655
656
657
658
659
660
661
      }
    }
}


//----------------------------------------------------------------------------
void
cmGlobalUnixMakefileGenerator3
::WriteConvenienceRules2(std::ostream& ruleFileStream, 
662
                         cmLocalUnixMakefileGenerator3 *lg)
663
664
665
666
667
668
{
  std::vector<std::string> depends;  
  std::vector<std::string> commands;
  std::string localName;
  std::string makeTargetName;

669

670
  // write the directory level rules for this local gen
671
  this->WriteDirectoryRules2(ruleFileStream,lg);
672
673
  
  depends.push_back("cmake_check_build_system");
674

Ken Martin's avatar
Ken Martin committed
675
  // for each target Generate the rule files for each target.
676
677
  cmTargets& targets = lg->GetMakefile()->GetTargets();
  for(cmTargets::iterator t = targets.begin(); t != targets.end(); ++t)
Ken Martin's avatar
Ken Martin committed
678
    {
Alexander Neundorf's avatar
   
Alexander Neundorf committed
679
680
681
682
683
684
685
    if (t->second.GetName()
     && strlen(t->second.GetName())
     && ((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)))
Ken Martin's avatar
Ken Martin committed
686
      {
687
      std::string makefileName;
Ken Martin's avatar
Ken Martin committed
688
689
      // Add a rule to build the target by name.
      localName = lg->GetRelativeTargetDirectory(t->second);
690
      makefileName = localName;
691
      makefileName += "/build.make";
692
      
693
      bool needRequiresStep = this->NeedRequiresStep(t->second);
Alexander Neundorf's avatar
   
Alexander Neundorf committed
694
695
696
697
698
699
700
      
      lg->WriteDivider(ruleFileStream);
      ruleFileStream
        << "# Target rules for target "
        << localName << "\n\n";
    
      commands.clear();        
701
702
703
704
705
706
707
      makeTargetName = localName;
      makeTargetName += "/depend";
      commands.push_back(lg->GetRecursiveMakeCall
                         (makefileName.c_str(),makeTargetName.c_str()));

      // add requires if we need it for this generator
      if (needRequiresStep)
708
        {
Alexander Neundorf's avatar
   
Alexander Neundorf committed
709
        makeTargetName = localName;
710
        makeTargetName += "/requires";
Alexander Neundorf's avatar
   
Alexander Neundorf committed
711
        commands.push_back(lg->GetRecursiveMakeCall
712
                           (makefileName.c_str(),makeTargetName.c_str()));
Alexander Neundorf's avatar
   
Alexander Neundorf committed
713
714
715
716
717
718
719
720
721
        }
      makeTargetName = localName;
      makeTargetName += "/build";
      commands.push_back(lg->GetRecursiveMakeCall
                          (makefileName.c_str(),makeTargetName.c_str()));
      
      // Write the rule.
      localName += "/all";
      depends.clear();
722

Alexander Neundorf's avatar
   
Alexander Neundorf committed
723
724
725
      std::string progressDir =
        lg->GetMakefile()->GetHomeOutputDirectory();
      progressDir += cmake::GetCMakeFilesDirectory();
726
727
        {
        cmOStringStream progCmd;
Alexander Neundorf's avatar
   
Alexander Neundorf committed
728
729
        progCmd << "$(CMAKE_COMMAND) -E cmake_progress_report "; 
        // all target counts
730
        progCmd << lg->Convert(progressDir.c_str(),
Alexander Neundorf's avatar
   
Alexander Neundorf committed
731
732
733
734
735
736
737
738
739
                                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;
          }
740
741
        commands.push_back(progCmd.str());
        }
Alexander Neundorf's avatar
   
Alexander Neundorf committed
742
743
744
745
746
747
748
749
750
      progressDir = "Built 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);
      
      // add the all/all dependency
751
      if(!this->IsExcluded(this->LocalGenerators[0], t->second))
752
        {
753
754
        depends.clear();
        depends.push_back(localName);
Alexander Neundorf's avatar
   
Alexander Neundorf committed
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
        commands.clear();
        lg->WriteMakeRule(ruleFileStream, "Include target in all.",
                          "all", depends, commands, true);
        }
      
      // 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);
      //
      std::set<cmStdString> emitted;
      progCmd << " " 
              << this->GetTargetTotalNumberOfActions(t->second,
                                                      emitted);
      commands.push_back(progCmd.str());
      }
      std::string tmp = cmake::GetCMakeFilesDirectoryPostSlash();
      tmp += "Makefile2";
      commands.push_back(lg->GetRecursiveMakeCall
                          (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);
      localName += "/rule";
      lg->WriteMakeRule(ruleFileStream, 
                        "Build rule for subdir invocation for target.",
                        localName.c_str(), depends, commands, true);
      
      // Add a target with the canonical name (no prefix, suffix or path).
      commands.clear();
      depends.clear();
      depends.push_back(localName);
      lg->WriteMakeRule(ruleFileStream, "Convenience name for target.",
                        t->second.GetName(), depends, commands, true);
      
      // Add rules to prepare the target for installation.
809
      if(t->second.NeedRelinkBeforeInstall())
Alexander Neundorf's avatar
   
Alexander Neundorf committed
810
        {
811
        localName = lg->GetRelativeTargetDirectory(t->second);
Alexander Neundorf's avatar
   
Alexander Neundorf committed
812
        localName += "/preinstall";
813
814
815
        depends.clear();
        commands.clear();
        commands.push_back(lg->GetRecursiveMakeCall
Alexander Neundorf's avatar
   
Alexander Neundorf committed
816
817
818
819
                            (makefileName.c_str(), localName.c_str()));
        lg->WriteMakeRule(ruleFileStream, 
                          "Pre-install relink rule for target.",
                          localName.c_str(), depends, commands, true);
820
821
822
823
824
825
826
827
828

        if(!this->IsExcluded(this->LocalGenerators[0], t->second))
          {
          depends.clear();
          depends.push_back(localName);
          commands.clear();
          lg->WriteMakeRule(ruleFileStream, "Prepare target for install.",
                            "preinstall", depends, commands, true);
          }
829
        }
Alexander Neundorf's avatar
   
Alexander Neundorf committed
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
      
      // add the clean rule
      localName = lg->GetRelativeTargetDirectory(t->second);
      makeTargetName = localName;
      makeTargetName += "/clean";
      depends.clear();
      commands.clear();
      commands.push_back(lg->GetRecursiveMakeCall
                          (makefileName.c_str(), makeTargetName.c_str()));
      lg->WriteMakeRule(ruleFileStream, "clean rule for target.",
                        makeTargetName.c_str(), depends, commands, true);
      commands.clear();
      depends.push_back(makeTargetName);
      lg->WriteMakeRule(ruleFileStream, "clean rule for target.",
                        "clean", depends, commands, true);
845
846
847
848
      }
    }
}

Ken Martin's avatar
Ken Martin committed
849
850
//----------------------------------------------------------------------------
int cmGlobalUnixMakefileGenerator3
Bill Hoffman's avatar
Bill Hoffman committed
851
::GetTargetTotalNumberOfActions(cmTarget & target,
852
                                std::set<cmStdString> &emitted)
Ken Martin's avatar
Ken Martin committed
853
{
854
855
  // do not double count
  int result = 0;
Ken Martin's avatar
Ken Martin committed
856

857
  if(emitted.insert(target.GetName()).second)
Ken Martin's avatar
Ken Martin committed
858
    {
859
860
861
862
863
    cmLocalUnixMakefileGenerator3 *lg = 
      static_cast<cmLocalUnixMakefileGenerator3 *>
      (target.GetMakefile()->GetLocalGenerator());
    result = static_cast<int>(lg->ProgressFiles[target.GetName()].size());
    
Bill Hoffman's avatar
Bill Hoffman committed
864
    TargetDependSet & depends = this->GetTargetDirectDepends(target);
865
    
Bill Hoffman's avatar
Bill Hoffman committed
866
    TargetDependSet::iterator i;
867
868
869
870
    for (i = depends.begin(); i != depends.end(); ++i)
      {
      result += this->GetTargetTotalNumberOfActions(**i, emitted);
      }
Ken Martin's avatar
Ken Martin committed
871
872
873
874
875
    }
  
  return result;
}

876
877
unsigned long cmGlobalUnixMakefileGenerator3
::GetNumberOfProgressActionsInAll(cmLocalUnixMakefileGenerator3 *lg)
878
879
{
  unsigned long result = 0;
880
  std::set<cmStdString> emitted;
Bill Hoffman's avatar
Bill Hoffman committed
881
882
  std::set<cmTarget *>& targets = this->LocalGeneratorToTargetMap[lg];
  for(std::set<cmTarget *>::iterator t = targets.begin();
883
      t != targets.end(); ++t)
884
    {
885
    result += this->GetTargetTotalNumberOfActions(**t,emitted);
886
887
888
889
    }
  return result;
}

Ken Martin's avatar
Ken Martin committed
890

891
892
893
894
//----------------------------------------------------------------------------
void
cmGlobalUnixMakefileGenerator3
::AppendGlobalTargetDepends(std::vector<std::string>& depends,
895
                            cmTarget& target)
896
{
897
  TargetDependSet const& depends_set = this->GetTargetDirectDepends(target);
898
899
  for(TargetDependSet::const_iterator i = depends_set.begin();
      i != depends_set.end(); ++i)
900
    {
901
    // Create the target-level dependency.
902
903
904
905
906
    cmTarget const* dep = *i;
    cmLocalUnixMakefileGenerator3* lg3 =
      static_cast<cmLocalUnixMakefileGenerator3*>
      (dep->GetMakefile()->GetLocalGenerator());
    std::string tgtName = lg3->GetRelativeTargetDirectory(*dep);
907
908
    tgtName += "/all";
    depends.push_back(tgtName);
909
910
    }
}
911
912

//----------------------------------------------------------------------------
913
914
void cmGlobalUnixMakefileGenerator3::WriteHelpRule
(std::ostream& ruleFileStream, cmLocalUnixMakefileGenerator3 *lg)
915
916
917
918
919
{
  // add the help target
  std::string path;
  std::vector<std::string> no_depends;
  std::vector<std::string> commands;
Ken Martin's avatar
Ken Martin committed
920
921
  lg->AppendEcho(commands,"The following are some of the valid targets "
                 "for this Makefile:");
922
923
924
925
  lg->AppendEcho(commands,"... all (the default if no target is provided)");
  lg->AppendEcho(commands,"... clean");
  lg->AppendEcho(commands,"... depend");
  
926
927
928
  // Keep track of targets already listed.
  std::set<cmStdString> emittedTargets;

929
930
  // for each local generator
  unsigned int i;
931
  cmLocalUnixMakefileGenerator3 *lg2;
Ken Martin's avatar
Ken Martin committed
932
  for (i = 0; i < this->LocalGenerators.size(); ++i)
933
    {
Ken Martin's avatar
Ken Martin committed
934
935
    lg2 = 
      static_cast<cmLocalUnixMakefileGenerator3 *>(this->LocalGenerators[i]);
936
937
938
    // for the passed in makefile or if this is the top Makefile wripte out
    // the targets
    if (lg2 == lg || !lg->GetParent())
939
      {
940
      // for each target Generate the rule files for each target.
Bill Hoffman's avatar
Bill Hoffman committed
941
      cmTargets& targets = lg2->GetMakefile()->GetTargets();
942
      for(cmTargets::iterator t = targets.begin(); t != targets.end(); ++t)
943
        {
944
945
946
947
        if((t->second.GetType() == cmTarget::EXECUTABLE) ||
           (t->second.GetType() == cmTarget::STATIC_LIBRARY) ||
           (t->second.GetType() == cmTarget::SHARED_LIBRARY) ||
           (t->second.GetType() == cmTarget::MODULE_LIBRARY) ||
948
           (t->second.GetType() == cmTarget::GLOBAL_TARGET) ||
949
           (t->second.GetType() == cmTarget::UTILITY))
950
          {
951
952
953
954
955
956
          if(emittedTargets.insert(t->second.GetName()).second)
            {
            path = "... ";
            path += t->second.GetName();
            lg->AppendEcho(commands,path.c_str());
            }
957
          }
958
        }
959
960
961
      std::vector<cmStdString> const& localHelp = lg->GetLocalHelp();
      for(std::vector<cmStdString>::const_iterator o = localHelp.begin();
          o != localHelp.end(); ++o)
962
        {
963
964
965
        path = "... ";
        path += *o;
        lg->AppendEcho(commands, path.c_str());
966
        }
967
968
969
970
      }
    }
  lg->WriteMakeRule(ruleFileStream, "Help Target",
                    "help:",
971
                    no_depends, commands, true);
972
973
974
  ruleFileStream << "\n\n";
}

975
976

bool cmGlobalUnixMakefileGenerator3
977
::NeedRequiresStep(cmTarget const& target)
978
{
979
980
981
982
  std::set<cmStdString> languages;
  target.GetLanguages(languages);
  for(std::set<cmStdString>::const_iterator l = languages.begin();
      l != languages.end(); ++l)
983
    {
984
985
986
987
    std::string var = "CMAKE_NEEDS_REQUIRES_STEP_";
    var += *l;
    var += "_FLAG";
    if(target.GetMakefile()->GetDefinition(var.c_str()))
988
989
990
991
992
993
      {
      return true;
      }
    }
  return false;
}