cmLocalGenerator.cxx 96.7 KB
Newer Older
1
2
3
/*============================================================================
  CMake - Cross Platform Makefile Generator
  Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
Ken Martin's avatar
Ken Martin committed
4

5
6
  Distributed under the OSI-approved BSD License (the "License");
  see accompanying file Copyright.txt for details.
Ken Martin's avatar
Ken Martin committed
7

8
9
10
11
  This software is distributed WITHOUT ANY WARRANTY; without even the
  implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  See the License for more information.
============================================================================*/
Ken Martin's avatar
Ken Martin committed
12
#include "cmLocalGenerator.h"
13

14
#include "cmComputeLinkInformation.h"
15
#include "cmGeneratedFileStream.h"
Ken Martin's avatar
updates    
Ken Martin committed
16
#include "cmGlobalGenerator.h"
17
#include "cmInstallGenerator.h"
18
#include "cmInstallFilesGenerator.h"
19
20
#include "cmInstallScriptGenerator.h"
#include "cmInstallTargetGenerator.h"
Ken Martin's avatar
Ken Martin committed
21
#include "cmMakefile.h"
22
#include "cmSourceFile.h"
23
#include "cmTest.h"
24
#include "cmTestGenerator.h"
25
#include "cmVersion.h"
26
27
#include "cmake.h"

28
29
30
31
32
#if defined(CMAKE_BUILD_WITH_CMAKE)
# define CM_LG_ENCODE_OBJECT_NAMES
# include <cmsys/MD5.h>
#endif

33
34
#include <cmsys/System.h>

35
#include <ctype.h> // for isalpha
Ken Martin's avatar
Ken Martin committed
36

37
38
#include <assert.h>

39
40
41
42
#if defined(__HAIKU__)
#include <StorageKit.h>
#endif

Ken Martin's avatar
Ken Martin committed
43
44
cmLocalGenerator::cmLocalGenerator()
{
45
  this->Makefile = 0; // moved to after set on global
Ken Martin's avatar
Ken Martin committed
46
47
  this->Parent = 0;
  this->WindowsShell = false;
48
  this->WindowsVSIDE = false;
49
  this->WatcomWMake = false;
50
  this->MinGWMake = false;
51
  this->NMake = false;
52
  this->MSYSShell = false;
53
  this->LinkScriptShell = false;
Ken Martin's avatar
Ken Martin committed
54
55
  this->IgnoreLibPrefix = false;
  this->UseRelativePaths = false;
56
  this->Configured = false;
57
  this->EmitUniversalBinaryFlags = true;
Alexander Neundorf's avatar
   
Alexander Neundorf committed
58
  this->IsMakefileGenerator = false;
59
  this->RelativePathsConfigured = false;
60
  this->PathConversionsSetup = false;
61
62
  this->BackwardsCompatibility = 0;
  this->BackwardsCompatibilityFinal = false;
Ken Martin's avatar
Ken Martin committed
63
64
65
66
}

cmLocalGenerator::~cmLocalGenerator()
{
Ken Martin's avatar
Ken Martin committed
67
  delete this->Makefile;
Ken Martin's avatar
Ken Martin committed
68
69
}

70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
//----------------------------------------------------------------------------
class cmLocalGeneratorCurrent
{
  cmGlobalGenerator* GG;
  cmLocalGenerator* LG;
public:
  cmLocalGeneratorCurrent(cmLocalGenerator* lg)
    {
    this->GG = lg->GetGlobalGenerator();
    this->LG = this->GG->GetCurrentLocalGenerator();
    this->GG->SetCurrentLocalGenerator(lg);
    }
  ~cmLocalGeneratorCurrent()
    {
    this->GG->SetCurrentLocalGenerator(this->LG);
    }
};

//----------------------------------------------------------------------------
Ken Martin's avatar
Ken Martin committed
89
90
void cmLocalGenerator::Configure()
{
91
92
93
  // Manage the global generator's current local generator.
  cmLocalGeneratorCurrent clg(this);
  static_cast<void>(clg);
Alexander Neundorf's avatar
   
Alexander Neundorf committed
94

95
  // make sure the CMakeFiles dir is there
Ken Martin's avatar
Ken Martin committed
96
  std::string filesDir = this->Makefile->GetStartOutputDirectory();
97
  filesDir += cmake::GetCMakeFilesDirectory();
98
  cmSystemTools::MakeDirectory(filesDir.c_str());
99

Ken Martin's avatar
Ken Martin committed
100
  // find & read the list file
101
  this->ReadInputFile();
102

103
104
105
  // at the end of the ReadListFile handle any old style subdirs
  // first get all the subdirectories
  std::vector<cmLocalGenerator *> subdirs = this->GetChildren();
106

107
108
109
110
111
112
  // for each subdir recurse
  std::vector<cmLocalGenerator *>::iterator sdi = subdirs.begin();
  for (; sdi != subdirs.end(); ++sdi)
    {
    if (!(*sdi)->Configured)
      {
Ken Martin's avatar
Ken Martin committed
113
      this->Makefile->ConfigureSubDirectory(*sdi);
114
      }
115
    }
116

117
118
  // Check whether relative paths should be used for optionally
  // relative paths.
Ken Martin's avatar
Ken Martin committed
119
  this->UseRelativePaths = this->Makefile->IsOn("CMAKE_USE_RELATIVE_PATHS");
120

121
122
123
124
125
126
127
128
  this->ComputeObjectMaxPath();

  this->Configured = true;
}

//----------------------------------------------------------------------------
void cmLocalGenerator::ComputeObjectMaxPath()
{
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
  // Choose a maximum object file name length.
#if defined(_WIN32) || defined(__CYGWIN__)
  this->ObjectPathMax = 250;
#else
  this->ObjectPathMax = 1000;
#endif
  const char* plen = this->Makefile->GetDefinition("CMAKE_OBJECT_PATH_MAX");
  if(plen && *plen)
    {
    unsigned int pmax;
    if(sscanf(plen, "%u", &pmax) == 1)
      {
      if(pmax >= 128)
        {
        this->ObjectPathMax = pmax;
        }
      else
        {
        cmOStringStream w;
        w << "CMAKE_OBJECT_PATH_MAX is set to " << pmax
          << ", which is less than the minimum of 128.  "
          << "The value will be ignored.";
        this->Makefile->IssueMessage(cmake::AUTHOR_WARNING, w.str());
        }
      }
    else
      {
      cmOStringStream w;
      w << "CMAKE_OBJECT_PATH_MAX is set to \"" << plen
        << "\", which fails to parse as a positive integer.  "
        << "The value will be ignored.";
      this->Makefile->IssueMessage(cmake::AUTHOR_WARNING, w.str());
      }
    }
163
  this->ObjectMaxPathViolations.clear();
164
165
}

166
167
168
//----------------------------------------------------------------------------
void cmLocalGenerator::ReadInputFile()
{
169
  // Look for the CMakeLists.txt file.
170
171
  std::string currentStart = this->Makefile->GetStartDirectory();
  currentStart += "/CMakeLists.txt";
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
  if(cmSystemTools::FileExists(currentStart.c_str(), true))
    {
    this->Makefile->ReadListFile(currentStart.c_str());
    return;
    }

  if(!this->Parent)
    {
    return;
    }

  // The file is missing.  Check policy CMP0014.
  cmMakefile* mf = this->Parent->GetMakefile();
  cmOStringStream e;
  e << "The source directory\n"
    << "  " << this->Makefile->GetStartDirectory() << "\n"
    << "does not contain a CMakeLists.txt file.";
  switch (mf->GetPolicyStatus(cmPolicies::CMP0014))
    {
    case cmPolicies::WARN:
      // Print the warning.
      e << "\n"
        << "CMake does not support this case but it used "
        << "to work accidentally and is being allowed for "
        << "compatibility."
        << "\n"
        << mf->GetPolicies()->GetPolicyWarning(cmPolicies::CMP0014);
      mf->IssueMessage(cmake::AUTHOR_WARNING, e.str());
    case cmPolicies::OLD:
      // OLD behavior does not warn.
      return;
    case cmPolicies::REQUIRED_IF_USED:
    case cmPolicies::REQUIRED_ALWAYS:
      e << "\n"
        << mf->GetPolicies()->GetRequiredPolicyError(cmPolicies::CMP0014);
    case cmPolicies::NEW:
      // NEW behavior prints the error.
      mf->IssueMessage(cmake::FATAL_ERROR, e.str());
      break;
    }
212
213
}

214
void cmLocalGenerator::SetupPathConversions()
215
{
216
  // Setup the current output directory components for use by
217
  // Convert
218
  std::string outdir;
219
  outdir =
Ken Martin's avatar
Ken Martin committed
220
221
    cmSystemTools::CollapseFullPath(this->Makefile->GetHomeDirectory());
  cmSystemTools::SplitPath(outdir.c_str(), this->HomeDirectoryComponents);
222
  outdir =
Ken Martin's avatar
Ken Martin committed
223
224
    cmSystemTools::CollapseFullPath(this->Makefile->GetStartDirectory());
  cmSystemTools::SplitPath(outdir.c_str(), this->StartDirectoryComponents);
Ken Martin's avatar
Ken Martin committed
225
226
227

  outdir = cmSystemTools::CollapseFullPath
    (this->Makefile->GetHomeOutputDirectory());
228
  cmSystemTools::SplitPath(outdir.c_str(),
Ken Martin's avatar
Ken Martin committed
229
230
231
232
                           this->HomeOutputDirectoryComponents);

  outdir = cmSystemTools::CollapseFullPath
    (this->Makefile->GetStartOutputDirectory());
233
  cmSystemTools::SplitPath(outdir.c_str(),
Ken Martin's avatar
Ken Martin committed
234
                           this->StartOutputDirectoryComponents);
Ken Martin's avatar
Ken Martin committed
235
}
Ken Martin's avatar
updates    
Ken Martin committed
236

237

Ken Martin's avatar
updates    
Ken Martin committed
238
239
void cmLocalGenerator::SetGlobalGenerator(cmGlobalGenerator *gg)
{
Ken Martin's avatar
Ken Martin committed
240
  this->GlobalGenerator = gg;
241
242
  this->Makefile = new cmMakefile;
  this->Makefile->SetLocalGenerator(this);
Ken Martin's avatar
updates    
Ken Martin committed
243
244

  // setup the home directories
245
  this->Makefile->GetProperties().SetCMakeInstance(gg->GetCMakeInstance());
Ken Martin's avatar
Ken Martin committed
246
  this->Makefile->SetHomeDirectory(
Ken Martin's avatar
updates    
Ken Martin committed
247
    gg->GetCMakeInstance()->GetHomeDirectory());
Ken Martin's avatar
Ken Martin committed
248
  this->Makefile->SetHomeOutputDirectory(
Ken Martin's avatar
updates    
Ken Martin committed
249
    gg->GetCMakeInstance()->GetHomeOutputDirectory());
Brad King's avatar
Brad King committed
250
}
Ken Martin's avatar
Ken Martin committed
251
252

void cmLocalGenerator::ConfigureFinalPass()
253
{
Ken Martin's avatar
Ken Martin committed
254
  this->Makefile->ConfigureFinalPass();
Ken Martin's avatar
Ken Martin committed
255
}
256

Alexander Neundorf's avatar
   
Alexander Neundorf committed
257
258
259
260
261
262
void cmLocalGenerator::TraceDependencies()
{
  // Generate the rule files for each target.
  cmTargets& targets = this->Makefile->GetTargets();
  for(cmTargets::iterator t = targets.begin(); t != targets.end(); ++t)
    {
263
264
    const char* projectFilename = 0;
    if (this->IsMakefileGenerator == false)  // only use of this variable
Alexander Neundorf's avatar
   
Alexander Neundorf committed
265
      {
266
      projectFilename = t->second.GetName();
Alexander Neundorf's avatar
   
Alexander Neundorf committed
267
      }
268
    t->second.TraceDependencies(projectFilename);
Alexander Neundorf's avatar
   
Alexander Neundorf committed
269
270
271
    }
}

272
273
void cmLocalGenerator::GenerateTestFiles()
{
Ken Martin's avatar
Ken Martin committed
274
  if ( !this->Makefile->IsOn("CMAKE_TESTING_ENABLED") )
275
276
277
    {
    return;
    }
278
279
280

  // Compute the set of configurations.
  std::vector<std::string> configurationTypes;
281
282
  const char* config =
    this->Makefile->GetConfigurations(configurationTypes, false);
283

Ken Martin's avatar
Ken Martin committed
284
  std::string file = this->Makefile->GetStartOutputDirectory();
285
  file += "/";
Ken Martin's avatar
Ken Martin committed
286
287
  file += "CTestTestfile.cmake";

288
289
290
291
  cmGeneratedFileStream fout(file.c_str());
  fout.SetCopyIfDifferent(true);

  fout << "# CMake generated Testfile for " << std::endl
292
       << "# Source directory: "
Ken Martin's avatar
Ken Martin committed
293
       << this->Makefile->GetStartDirectory() << std::endl
294
       << "# Build directory: "
Ken Martin's avatar
Ken Martin committed
295
296
       << this->Makefile->GetStartOutputDirectory() << std::endl
       << "# " << std::endl
Ken Martin's avatar
Ken Martin committed
297
298
299
300
       << "# This file includes the relevent testing commands "
       << "required for " << std::endl
       << "# testing this directory and lists subdirectories to "
       << "be tested as well." << std::endl;
301
302

  const char* testIncludeFile =
Ken Martin's avatar
Ken Martin committed
303
    this->Makefile->GetProperty("TEST_INCLUDE_FILE");
304
305
306
307
  if ( testIncludeFile )
    {
    fout << "INCLUDE(\"" << testIncludeFile << "\")" << std::endl;
    }
308
309
310
311
312
313

  // Ask each test generator to write its code.
  std::vector<cmTestGenerator*> const&
    testers = this->Makefile->GetTestGenerators();
  for(std::vector<cmTestGenerator*>::const_iterator gi = testers.begin();
      gi != testers.end(); ++gi)
314
    {
315
    (*gi)->Generate(fout, config, configurationTypes);
316
317
318
319
320
321
    }
  if ( this->Children.size())
    {
    size_t i;
    for(i = 0; i < this->Children.size(); ++i)
      {
322
      fout << "SUBDIRS(";
323
      std::string outP =
Ken Martin's avatar
Ken Martin committed
324
        this->Children[i]->GetMakefile()->GetStartOutputDirectory();
325
326
      fout << this->Convert(outP.c_str(),START_OUTPUT);
      fout << ")" << std::endl;
327
328
329
330
      }
    }
}

331
//----------------------------------------------------------------------------
332
333
void cmLocalGenerator::GenerateInstallRules()
{
334
  // Compute the install prefix.
Ken Martin's avatar
Ken Martin committed
335
  const char* prefix = this->Makefile->GetDefinition("CMAKE_INSTALL_PREFIX");
336
337
338
339
340
341
342
343
#if defined(_WIN32) && !defined(__CYGWIN__)
  std::string prefix_win32;
  if(!prefix)
    {
    if(!cmSystemTools::GetEnv("SystemDrive", prefix_win32))
      {
      prefix_win32 = "C:";
      }
Ken Martin's avatar
Ken Martin committed
344
    const char* project_name = this->Makefile->GetDefinition("PROJECT_NAME");
345
346
347
348
349
350
351
352
353
354
355
    if(project_name && project_name[0])
      {
      prefix_win32 += "/Program Files/";
      prefix_win32 += project_name;
      }
    else
      {
      prefix_win32 += "/InstalledCMakeProject";
      }
    prefix = prefix_win32.c_str();
    }
356
357
358
359
360
361
362
363
364
365
366
367
368
#elif defined(__HAIKU__)
  if (!prefix)
    {
    BPath dir;
    if (find_directory(B_COMMON_DIRECTORY, &dir) == B_OK)
      {
      prefix = dir.Path();
      }
    else
      {
      prefix = "/boot/common";
      }
    }
369
#else
370
371
372
373
  if (!prefix)
    {
    prefix = "/usr/local";
    }
374
#endif
375

376
377
  // Compute the set of configurations.
  std::vector<std::string> configurationTypes;
378
379
  const char* config =
    this->Makefile->GetConfigurations(configurationTypes, false);
380

381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
  // Choose a default install configuration.
  const char* default_config = config;
  const char* default_order[] = {"RELEASE", "MINSIZEREL",
                                 "RELWITHDEBINFO", "DEBUG", 0};
  for(const char** c = default_order; *c && !default_config; ++c)
    {
    for(std::vector<std::string>::iterator i = configurationTypes.begin();
        i != configurationTypes.end(); ++i)
      {
      if(cmSystemTools::UpperCase(*i) == *c)
        {
        default_config = i->c_str();
        }
      }
    }
  if(!default_config && !configurationTypes.empty())
    {
    default_config = configurationTypes[0].c_str();
    }
  if(!default_config)
    {
    default_config = "Release";
    }

405
  // Create the install script file.
Ken Martin's avatar
Ken Martin committed
406
407
408
  std::string file = this->Makefile->GetStartOutputDirectory();
  std::string homedir = this->Makefile->GetHomeOutputDirectory();
  std::string currdir = this->Makefile->GetCurrentOutputDirectory();
409
  cmSystemTools::ConvertToUnixSlashes(file);
410
411
412
413
414
415
416
  cmSystemTools::ConvertToUnixSlashes(homedir);
  cmSystemTools::ConvertToUnixSlashes(currdir);
  int toplevel_install = 0;
  if ( currdir == homedir )
    {
    toplevel_install = 1;
    }
417
  file += "/cmake_install.cmake";
418
419
  cmGeneratedFileStream fout(file.c_str());
  fout.SetCopyIfDifferent(true);
420

421
422
  // Write the header.
  fout << "# Install script for directory: "
Ken Martin's avatar
Ken Martin committed
423
424
       << this->Makefile->GetCurrentDirectory() << std::endl << std::endl;
  fout << "# Set the install prefix" << std::endl
Ken Martin's avatar
Ken Martin committed
425
426
427
428
429
430
       << "IF(NOT DEFINED CMAKE_INSTALL_PREFIX)" << std::endl
       << "  SET(CMAKE_INSTALL_PREFIX \"" << prefix << "\")" << std::endl
       << "ENDIF(NOT DEFINED CMAKE_INSTALL_PREFIX)" << std::endl
       << "STRING(REGEX REPLACE \"/$\" \"\" CMAKE_INSTALL_PREFIX "
       << "\"${CMAKE_INSTALL_PREFIX}\")" << std::endl
       << std::endl;
431

432
  // Write support code for generating per-configuration install rules.
433
434
  fout <<
    "# Set the install configuration name.\n"
435
    "IF(NOT DEFINED CMAKE_INSTALL_CONFIG_NAME)\n"
436
437
438
439
    "  IF(BUILD_TYPE)\n"
    "    STRING(REGEX REPLACE \"^[^A-Za-z0-9_]+\" \"\"\n"
    "           CMAKE_INSTALL_CONFIG_NAME \"${BUILD_TYPE}\")\n"
    "  ELSE(BUILD_TYPE)\n"
440
    "    SET(CMAKE_INSTALL_CONFIG_NAME \"" << default_config << "\")\n"
441
    "  ENDIF(BUILD_TYPE)\n"
Ken Martin's avatar
Ken Martin committed
442
443
    "  MESSAGE(STATUS \"Install configuration: "
    "\\\"${CMAKE_INSTALL_CONFIG_NAME}\\\"\")\n"
444
    "ENDIF(NOT DEFINED CMAKE_INSTALL_CONFIG_NAME)\n"
445
    "\n";
446

447
448
449
450
451
452
453
454
455
456
457
458
459
  // Write support code for dealing with component-specific installs.
  fout <<
    "# Set the component getting installed.\n"
    "IF(NOT CMAKE_INSTALL_COMPONENT)\n"
    "  IF(COMPONENT)\n"
    "    MESSAGE(STATUS \"Install component: \\\"${COMPONENT}\\\"\")\n"
    "    SET(CMAKE_INSTALL_COMPONENT \"${COMPONENT}\")\n"
    "  ELSE(COMPONENT)\n"
    "    SET(CMAKE_INSTALL_COMPONENT)\n"
    "  ENDIF(COMPONENT)\n"
    "ENDIF(NOT CMAKE_INSTALL_COMPONENT)\n"
    "\n";

460
461
462
463
464
465
466
467
468
469
470
471
  // Copy user-specified install options to the install code.
  if(const char* so_no_exe =
     this->Makefile->GetDefinition("CMAKE_INSTALL_SO_NO_EXE"))
    {
    fout <<
      "# Install shared libraries without execute permission?\n"
      "IF(NOT DEFINED CMAKE_INSTALL_SO_NO_EXE)\n"
      "  SET(CMAKE_INSTALL_SO_NO_EXE \"" << so_no_exe << "\")\n"
      "ENDIF(NOT DEFINED CMAKE_INSTALL_SO_NO_EXE)\n"
      "\n";
    }

472
473
  // Ask each install generator to write its code.
  std::vector<cmInstallGenerator*> const& installers =
Ken Martin's avatar
Ken Martin committed
474
    this->Makefile->GetInstallGenerators();
475
  for(std::vector<cmInstallGenerator*>::const_iterator
Ken Martin's avatar
Ken Martin committed
476
        gi = installers.begin();
477
      gi != installers.end(); ++gi)
478
    {
479
    (*gi)->Generate(fout, config, configurationTypes);
480
481
    }

482
483
  // Write rules from old-style specification stored in targets.
  this->GenerateTargetInstallRules(fout, config, configurationTypes);
484

485
  // Include install scripts from subdirectories.
486
  if(!this->Children.empty())
487
    {
488
489
    fout << "IF(NOT CMAKE_INSTALL_LOCAL_ONLY)\n";
    fout << "  # Include the install script for each subdirectory.\n";
490
491
    for(std::vector<cmLocalGenerator*>::const_iterator
          ci = this->Children.begin(); ci != this->Children.end(); ++ci)
492
      {
493
      if(!(*ci)->GetMakefile()->GetPropertyAsBool("EXCLUDE_FROM_ALL"))
494
495
496
        {
        std::string odir = (*ci)->GetMakefile()->GetStartOutputDirectory();
        cmSystemTools::ConvertToUnixSlashes(odir);
497
        fout << "  INCLUDE(\"" <<  odir.c_str()
498
499
             << "/cmake_install.cmake\")" << std::endl;
        }
500
      }
501
    fout << "\n";
Alexander Neundorf's avatar
   
Alexander Neundorf committed
502
    fout << "ENDIF(NOT CMAKE_INSTALL_LOCAL_ONLY)\n\n";
503
    }
504
505

  // Record the install manifest.
506
507
  if ( toplevel_install )
    {
508
509
510
511
512
513
    fout <<
      "IF(CMAKE_INSTALL_COMPONENT)\n"
      "  SET(CMAKE_INSTALL_MANIFEST \"install_manifest_"
      "${CMAKE_INSTALL_COMPONENT}.txt\")\n"
      "ELSE(CMAKE_INSTALL_COMPONENT)\n"
      "  SET(CMAKE_INSTALL_MANIFEST \"install_manifest.txt\")\n"
Alexander Neundorf's avatar
   
Alexander Neundorf committed
514
      "ENDIF(CMAKE_INSTALL_COMPONENT)\n\n";
515
516
517
518
519
520
521
522
    fout
      << "FILE(WRITE \""
      << homedir.c_str() << "/${CMAKE_INSTALL_MANIFEST}\" "
      << "\"\")" << std::endl;
    fout
      << "FOREACH(file ${CMAKE_INSTALL_MANIFEST_FILES})" << std::endl
      << "  FILE(APPEND \""
      << homedir.c_str() << "/${CMAKE_INSTALL_MANIFEST}\" "
523
524
525
      << "\"${file}\\n\")" << std::endl
      << "ENDFOREACH(file)" << std::endl;
    }
526
527
}

528
//----------------------------------------------------------------------------
529
void cmLocalGenerator::GenerateTargetManifest()
530
531
532
{
  // Collect the set of configuration types.
  std::vector<std::string> configNames;
533
  this->Makefile->GetConfigurations(configNames);
534
535
536
537
538
539

  // Add our targets to the manifest for each configuration.
  cmTargets& targets = this->Makefile->GetTargets();
  for(cmTargets::iterator t = targets.begin(); t != targets.end(); ++t)
    {
    cmTarget& target = t->second;
540
    if(configNames.empty())
541
      {
542
543
544
545
546
547
      target.GenerateTargetManifest(0);
      }
    else
      {
      for(std::vector<std::string>::iterator ci = configNames.begin();
          ci != configNames.end(); ++ci)
548
        {
549
550
        const char* config = ci->c_str();
        target.GenerateTargetManifest(config);
551
552
553
554
555
        }
      }
    }
}

556
557
void cmLocalGenerator::AddCustomCommandToCreateObject(const char* ofname,
                                                      const char* lang,
558
                                                      cmSourceFile& source,
Bill Hoffman's avatar
Bill Hoffman committed
559
                                                      cmTarget& )
560
{
561
  std::string objectDir = cmSystemTools::GetFilenamePath(std::string(ofname));
562
  objectDir = this->Convert(objectDir.c_str(),START_OUTPUT,SHELL);
563
  std::string objectFile = this->Convert(ofname,START_OUTPUT,SHELL);
564
  std::string sourceFile =
565
    this->Convert(source.GetFullPath().c_str(),START_OUTPUT,SHELL,true);
566
567
568
569
  std::string varString = "CMAKE_";
  varString += lang;
  varString += "_COMPILE_OBJECT";
  std::vector<std::string> rules;
Ken Martin's avatar
Ken Martin committed
570
  rules.push_back(this->Makefile->GetRequiredDefinition(varString.c_str()));
571
572
573
574
  varString = "CMAKE_";
  varString += lang;
  varString += "_FLAGS";
  std::string flags;
Ken Martin's avatar
Ken Martin committed
575
  flags += this->Makefile->GetSafeDefinition(varString.c_str());
576
  flags += " ";
577
578
579
580
581
    {
    std::vector<std::string> includes;
    this->GetIncludeDirectories(includes, lang);
    flags += this->GetIncludeFlags(includes, lang);
    }
582
  flags += this->Makefile->GetDefineFlags();
583
584
585

  // Construct the command lines.
  cmCustomCommandLines commandLines;
586
587
  std::vector<std::string> commands;
  cmSystemTools::ExpandList(rules, commands);
588
589
590
591
  cmLocalGenerator::RuleVariables vars;
  vars.Language = lang;
  vars.Source = sourceFile.c_str();
  vars.Object = objectFile.c_str();
592
  vars.ObjectDir = objectDir.c_str();
593
  vars.Flags = flags.c_str();
594
595
596
  for(std::vector<std::string>::iterator i = commands.begin();
      i != commands.end(); ++i)
    {
597
    // Expand the full command line string.
598
    this->ExpandRuleVariables(*i, vars);
599
600
601
602
603
604
605
606
607
608
609
610

    // Parse the string to get the custom command line.
    cmCustomCommandLine commandLine;
    std::vector<cmStdString> cmd = cmSystemTools::ParseArguments(i->c_str());
    for(std::vector<cmStdString>::iterator a = cmd.begin();
        a != cmd.end(); ++a)
      {
      commandLine.push_back(*a);
      }

    // Store this command line.
    commandLines.push_back(commandLine);
611
    }
612
613

  // Check for extra object-file dependencies.
614
615
616
617
618
  std::vector<std::string> depends;
  const char* additionalDeps = source.GetProperty("OBJECT_DEPENDS");
  if(additionalDeps)
    {
    cmSystemTools::ExpandListArgument(additionalDeps, depends);
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
    }

  // Generate a meaningful comment for the command.
  std::string comment = "Building ";
  comment += lang;
  comment += " object ";
  comment += this->Convert(ofname, START_OUTPUT);

  // Add the custom command to build the object file.
  this->Makefile->AddCustomCommandToOutput(
    ofname,
    depends,
    source.GetFullPath().c_str(),
    commandLines,
    comment.c_str(),
    this->Makefile->GetStartOutputDirectory()
    );
636
637
638
639
640
641
642
}

void cmLocalGenerator::AddBuildTargetRule(const char* llang, cmTarget& target)
{
  cmStdString objs;
  std::vector<std::string> objVector;
  // Add all the sources outputs to the depends of the target
643
644
  std::vector<cmSourceFile*> const& classes = target.GetSourceFiles();
  for(std::vector<cmSourceFile*>::const_iterator i = classes.begin();
645
      i != classes.end(); ++i)
646
647
648
649
650
    {
    cmSourceFile* sf = *i;
    if(!sf->GetCustomCommand() &&
       !sf->GetPropertyAsBool("HEADER_FILE_ONLY") &&
       !sf->GetPropertyAsBool("EXTERNAL_OBJECT"))
651
      {
652
653
654
655
      std::string dir_max;
      dir_max += this->Makefile->GetCurrentOutputDirectory();
      dir_max += "/";
      std::string obj = this->GetObjectFileNameWithoutTarget(*sf, dir_max);
656
      if(!obj.empty())
657
        {
Ken Martin's avatar
Ken Martin committed
658
        std::string ofname = this->Makefile->GetCurrentOutputDirectory();
659
        ofname += "/";
660
        ofname += obj;
661
        objVector.push_back(ofname);
662
        this->AddCustomCommandToCreateObject(ofname.c_str(),
Ken Martin's avatar
Ken Martin committed
663
                                             llang, *(*i), target);
664
        objs += this->Convert(ofname.c_str(),START_OUTPUT,MAKEFILE);
665
666
667
668
669
670
671
        objs += " ";
        }
      }
    }
  std::string createRule = "CMAKE_";
  createRule += llang;
  createRule += target.GetCreateRuleVariable();
672
  std::string targetName = target.GetFullName();
673
674
675
676
677
678
  // Executable :
  // Shared Library:
  // Static Library:
  // Shared Module:
  std::string linkLibs; // should be set
  std::string flags; // should be set
679
  std::string linkFlags; // should be set
680
  this->GetTargetFlags(linkLibs, flags, linkFlags, target);
681
682
683
  cmLocalGenerator::RuleVariables vars;
  vars.Language = llang;
  vars.Objects = objs.c_str();
684
  vars.ObjectDir = ".";
685
686
687
688
  vars.Target = targetName.c_str();
  vars.LinkLibraries = linkLibs.c_str();
  vars.Flags = flags.c_str();
  vars.LinkFlags = linkFlags.c_str();
689

690
691
  std::string langFlags;
  this->AddLanguageFlags(langFlags, llang, 0);
692
  this->AddArchitectureFlags(langFlags, &target, llang, 0);
693
  vars.LanguageCompileFlags = langFlags.c_str();
694

695
696
697
698
  cmCustomCommandLines commandLines;
  std::vector<std::string> rules;
  rules.push_back(this->Makefile->GetRequiredDefinition(createRule.c_str()));
  std::vector<std::string> commands;
699
  cmSystemTools::ExpandList(rules, commands);
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
  for(std::vector<std::string>::iterator i = commands.begin();
      i != commands.end(); ++i)
    {
    // Expand the full command line string.
    this->ExpandRuleVariables(*i, vars);
    // Parse the string to get the custom command line.
    cmCustomCommandLine commandLine;
    std::vector<cmStdString> cmd = cmSystemTools::ParseArguments(i->c_str());
    for(std::vector<cmStdString>::iterator a = cmd.begin();
        a != cmd.end(); ++a)
      {
      commandLine.push_back(*a);
      }

    // Store this command line.
    commandLines.push_back(commandLine);
    }
  std::string targetFullPath = target.GetFullPath();
  // Generate a meaningful comment for the command.
  std::string comment = "Linking ";
  comment += llang;
  comment += " target ";
  comment += this->Convert(targetFullPath.c_str(), START_OUTPUT);
  this->Makefile->AddCustomCommandToOutput(
    targetFullPath.c_str(),
    objVector,
    0,
    commandLines,
    comment.c_str(),
    this->Makefile->GetStartOutputDirectory()
    );
731
  target.AddSourceFile
Ken Martin's avatar
Ken Martin committed
732
    (this->Makefile->GetSource(targetFullPath.c_str()));
733
}
734

735

Ken Martin's avatar
Ken Martin committed
736
737
void cmLocalGenerator
::CreateCustomTargetsAndCommands(std::set<cmStdString> const& lang)
738
{
Ken Martin's avatar
Ken Martin committed
739
  cmTargets &tgts = this->Makefile->GetTargets();
740
  for(cmTargets::iterator l = tgts.begin();
741
742
743
744
      l != tgts.end(); l++)
    {
    cmTarget& target = l->second;
    switch(target.GetType())
745
      {
746
747
748
      case cmTarget::STATIC_LIBRARY:
      case cmTarget::SHARED_LIBRARY:
      case cmTarget::MODULE_LIBRARY:
749
      case cmTarget::EXECUTABLE:
750
        {
751
        const char* llang = target.GetLinkerLanguage();
752
753
        if(!llang)
          {
Ken Martin's avatar
Ken Martin committed
754
755
756
          cmSystemTools::Error
            ("CMake can not determine linker language for target:",
             target.GetName());
757
758
          return;
          }
759
760
761
762
763
764
765
        // if the language is not in the set lang then create custom
        // commands to build the target
        if(lang.count(llang) == 0)
          {
          this->AddBuildTargetRule(llang, target);
          }
        }
766
        break;
767
      default:
768
769
770
771
772
773
774
775
        break;
      }
    }
}

// List of variables that are replaced when
// rules are expanced.  These variables are
// replaced in the form <var> with GetSafeDefinition(var).
776
// ${LANG} is replaced in the variable first with all enabled
777
778
779
// languages.
static const char* ruleReplaceVars[] =
{
Bill Hoffman's avatar
Bill Hoffman committed
780
  "CMAKE_${LANG}_COMPILER",
781
782
  "CMAKE_SHARED_LIBRARY_CREATE_${LANG}_FLAGS",
  "CMAKE_SHARED_MODULE_CREATE_${LANG}_FLAGS",
783
  "CMAKE_SHARED_MODULE_${LANG}_FLAGS",
784
785
786
787
788
789
790
791
  "CMAKE_SHARED_LIBRARY_${LANG}_FLAGS",
  "CMAKE_${LANG}_LINK_FLAGS",
  "CMAKE_SHARED_LIBRARY_SONAME_${LANG}_FLAG",
  "CMAKE_${LANG}_ARCHIVE",
  "CMAKE_AR",
  "CMAKE_CURRENT_SOURCE_DIR",
  "CMAKE_CURRENT_BINARY_DIR",
  "CMAKE_RANLIB",
792
  "CMAKE_LINKER",
793
794
795
  0
};

Bill Hoffman's avatar
Bill Hoffman committed
796
797
std::string
cmLocalGenerator::ExpandRuleVariable(std::string const& variable,
798
                                     const RuleVariables& replaceValues)
799
{
800
  if(replaceValues.LinkFlags)
801
    {
Bill Hoffman's avatar
Bill Hoffman committed
802
803
    if(variable == "LINK_FLAGS")
      {
804
      return replaceValues.LinkFlags;
Bill Hoffman's avatar
Bill Hoffman committed
805
      }
806
    }
807
  if(replaceValues.Flags)
808
    {
Bill Hoffman's avatar
Bill Hoffman committed
809
810
    if(variable == "FLAGS")
      {
811
      return replaceValues.Flags;
Bill Hoffman's avatar
Bill Hoffman committed
812
      }
813
    }
814

815
  if(replaceValues.Source)
816
    {
Bill Hoffman's avatar
Bill Hoffman committed
817
818
    if(variable == "SOURCE")
      {
819
      return replaceValues.Source;
Bill Hoffman's avatar
Bill Hoffman committed
820
      }
821
    }
822
823
824
825
826
827
828
829
830
831
832
833
834
835
  if(replaceValues.PreprocessedSource)
    {
    if(variable == "PREPROCESSED_SOURCE")
      {
      return replaceValues.PreprocessedSource;
      }
    }
  if(replaceValues.AssemblySource)
    {
    if(variable == "ASSEMBLY_SOURCE")
      {
      return replaceValues.AssemblySource;
      }
    }
836
  if(replaceValues.Object)
837
    {
Bill Hoffman's avatar
Bill Hoffman committed
838
839
    if(variable == "OBJECT")
      {
840
      return replaceValues.Object;
Bill Hoffman's avatar
Bill Hoffman committed
841
      }
842
    }
843
844
845
846
847
848
849
  if(replaceValues.ObjectDir)
    {
    if(variable == "OBJECT_DIR")
      {
      return replaceValues.ObjectDir;
      }
    }
850
  if(replaceValues.Objects)
851
    {
Bill Hoffman's avatar
Bill Hoffman committed
852
853
    if(variable == "OBJECTS")
      {
854
      return replaceValues.Objects;
Bill Hoffman's avatar
Bill Hoffman committed
855
      }
856
    }
857
  if(replaceValues.ObjectsQuoted)
858
    {
Bill Hoffman's avatar
Bill Hoffman committed
859
860
    if(variable == "OBJECTS_QUOTED")
      {
861
      return replaceValues.ObjectsQuoted;
Bill Hoffman's avatar
Bill Hoffman committed
862
      }
863
    }
864
865
866
867
  if(replaceValues.Defines && variable == "DEFINES")
    {
    return replaceValues.Defines;
    }
868
869
870
871
872
873
874
875
  if(replaceValues.TargetPDB )
    {
    if(variable == "TARGET_PDB")
      {
      return replaceValues.TargetPDB;
      }
    }

876
  if(replaceValues.Target)
877
    {
Bill Hoffman's avatar
Bill Hoffman committed
878
879
    if(variable == "TARGET_QUOTED")
      {
880
      std::string targetQuoted = replaceValues.Target;
Bill Hoffman's avatar
Bill Hoffman committed
881
882
883
      if(targetQuoted.size() && targetQuoted[0] != '\"')
        {
        targetQuoted = '\"';
884
        targetQuoted += replaceValues.Target;
Bill Hoffman's avatar
Bill Hoffman committed
885
886
        targetQuoted += '\"';
        }
887
      return targetQuoted;
Bill Hoffman's avatar
Bill Hoffman committed
888
      }
889
890
891
892
893
894
895
896
897
898
    if(variable == "TARGET_UNQUOTED")
      {
      std::string unquoted = replaceValues.Target;
      std::string::size_type sz = unquoted.size();
      if(sz > 2 && unquoted[0] == '\"' && unquoted[sz-1] == '\"')
        {
        unquoted = unquoted.substr(1, sz-2);
        }
      return unquoted;
      }
899
    if(replaceValues.LanguageCompileFlags)
900
      {
901
902
903
904
      if(variable == "LANGUAGE_COMPILE_FLAGS")
        {
        return replaceValues.LanguageCompileFlags;
        }
905
      }
906
    if(replaceValues.Target)
907
      {
908
909
910
911
      if(variable == "TARGET")
        {
        return replaceValues.Target;
        }
912
      }
913
914
    if(variable == "TARGET_IMPLIB")
      {
Ken Martin's avatar
Ken Martin committed
915
      return this->TargetImplib;
916
      }
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
    if(variable == "TARGET_VERSION_MAJOR")
      {
      if(replaceValues.TargetVersionMajor)
        {
        return replaceValues.TargetVersionMajor;
        }
      else
        {
        return "0";
        }
      }
    if(variable == "TARGET_VERSION_MINOR")
      {
      if(replaceValues.TargetVersionMinor)
        {
        return replaceValues.TargetVersionMinor;
        }
      else
        {
        return "0";
        }
      }
939
    if(replaceValues.Target)
Bill Hoffman's avatar
Bill Hoffman committed
940
      {
941
      if(variable == "TARGET_BASE")
Bill Hoffman's avatar
Bill Hoffman committed
942
        {
943
944
945
946
947
        // Strip the last extension off the target name.
        std::string targetBase = replaceValues.Target;
        std::string::size_type pos = targetBase.rfind(".");
        if(pos != targetBase.npos)
          {
948
        return targetBase.substr(0, pos);
949
950
951
952
953
          }
        else
          {
          return targetBase;
          }
Bill Hoffman's avatar
Bill Hoffman committed
954
        }
955
956
      }
    }
957
  if(replaceValues.TargetSOName)
958
    {
Bill Hoffman's avatar
Bill Hoffman committed
959
    if(variable == "TARGET_SONAME")
960
      {
961
      if(replaceValues.Language)
962
        {
Bill Hoffman's avatar
Bill Hoffman committed
963
        std::string name = "CMAKE_SHARED_LIBRARY_SONAME_";
964
        name += replaceValues.Language;
Bill Hoffman's avatar
Bill Hoffman committed
965
        name += "_FLAG";
Ken Martin's avatar
Ken Martin committed
966
        if(this->Makefile->GetDefinition(name.c_str()))
Bill Hoffman's avatar
Bill Hoffman committed
967
          {
968
          return replaceValues.TargetSOName;
Bill Hoffman's avatar
Bill Hoffman committed
969
          }
970
        }
Bill Hoffman's avatar
Bill Hoffman committed
971
      return "";
972
973
      }
    }
974
975
976
977
978
979
980
  if(replaceValues.TargetInstallNameDir)
    {
    if(variable == "TARGET_INSTALLNAME_DIR")
      {
      return replaceValues.TargetInstallNameDir;
      }
    }
981
  if(replaceValues.LinkLibraries)
982
    {
Bill Hoffman's avatar
Bill Hoffman committed
983
984
    if(variable == "LINK_LIBRARIES")
      {
985
      return replaceValues.LinkLibraries;
Bill Hoffman's avatar
Bill Hoffman committed
986
      }
987
    }
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
  if(replaceValues.Language)
    {
    if(variable == "LANGUAGE")
      {
      return replaceValues.Language;
      }
    }
  if(replaceValues.CMTarget)
    {
    if(variable == "TARGET_NAME")
      {
      return replaceValues.CMTarget->GetName();
      }
    if(variable == "TARGET_TYPE")
      {
Nicolas Despres's avatar
Nicolas Despres committed
1003
      return cmTarget::GetTargetTypeName(replaceValues.CMTarget->GetType());
1004
1005
1006
1007
1008
1009
1010
1011
1012
      }
    }
  if(replaceValues.Output)
    {
    if(variable == "OUTPUT")
      {
      return replaceValues.Output;
      }
    }
1013
1014
1015
  if(variable == "CMAKE_COMMAND")
    {
    const char* cmcommand =
1016
      this->GetMakefile()->GetDefinition("CMAKE_COMMAND");
1017
1018
    return this->Convert(cmcommand, FULL, SHELL);
    }
Bill Hoffman's avatar
Bill Hoffman committed
1019
  std::vector<std::string> enabledLanguages;
Ken Martin's avatar
Ken Martin committed
1020
  this->GlobalGenerator->GetEnabledLanguages(enabledLanguages);
1021
1022
1023
1024
  // loop over language specific replace variables
  int pos = 0;
  while(ruleReplaceVars[pos])
    {
1025
1026
1027
    for(std::vector<std::string>::iterator i = enabledLanguages.begin();
        i != enabledLanguages.end(); ++i)
      {
1028
      const char* lang = i->c_str();
Bill Hoffman's avatar
Bill Hoffman committed
1029
      std::string actualReplace = ruleReplaceVars[pos];
1030
      // If this is the compiler then look for the extra variable
1031
      // _COMPILER_ARG1 which must be the first argument to the compiler
1032
1033
1034
1035
1036
      const char* compilerArg1 = 0;
      if(actualReplace == "CMAKE_${LANG}_COMPILER")
        {
        std::string arg1 = actualReplace + "_ARG1";
        cmSystemTools::ReplaceString(arg1, "${LANG}", lang);
Ken Martin's avatar
Ken Martin committed
1037
        compilerArg1 = this->Makefile->GetDefinition(arg1.c_str());
1038
        }
Bill Hoffman's avatar
Bill Hoffman committed
1039
      if(actualReplace.find("${LANG}") != actualReplace.npos)
1040
        {
Bill Hoffman's avatar
Bill Hoffman committed
1041
        cmSystemTools::ReplaceString(actualReplace, "${LANG}", lang);
1042
        }
Bill Hoffman's avatar
Bill Hoffman committed
1043
      if(actualReplace == variable)
1044
        {
1045
        std::string replace =
Ken Martin's avatar
Ken Martin committed
1046
          this->Makefile->GetSafeDefinition(variable.c_str());
Bill Hoffman's avatar
Bill Hoffman committed
1047
1048