cmLocalGenerator.cxx 92.9 KB
Newer Older
Ken Martin's avatar
Ken Martin committed
1
2
/*=========================================================================

3
  Program:   CMake - Cross-Platform Makefile Generator
Ken Martin's avatar
Ken Martin committed
4
5
6
7
8
  Module:    $RCSfile$
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

9
10
  Copyright (c) 2002 Kitware, Inc., Insight Consortium.  All rights reserved.
  See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.
Ken Martin's avatar
Ken Martin committed
11

12
13
     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
Ken Martin's avatar
Ken Martin committed
14
15
16
17
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/
#include "cmLocalGenerator.h"
18

19
#include "cmComputeLinkInformation.h"
20
#include "cmGeneratedFileStream.h"
Ken Martin's avatar
updates    
Ken Martin committed
21
#include "cmGlobalGenerator.h"
22
#include "cmInstallGenerator.h"
23
#include "cmInstallFilesGenerator.h"
24
25
#include "cmInstallScriptGenerator.h"
#include "cmInstallTargetGenerator.h"
Ken Martin's avatar
Ken Martin committed
26
#include "cmMakefile.h"
27
#include "cmSourceFile.h"
28
#include "cmTest.h"
29
30
#include "cmake.h"

31
32
33
34
35
#if defined(CMAKE_BUILD_WITH_CMAKE)
# define CM_LG_ENCODE_OBJECT_NAMES
# include <cmsys/MD5.h>
#endif

36
37
#include <cmsys/System.h>

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

40
41
#include <assert.h>

Ken Martin's avatar
Ken Martin committed
42
43
cmLocalGenerator::cmLocalGenerator()
{
Ken Martin's avatar
Ken Martin committed
44
45
46
47
  this->Makefile = new cmMakefile;
  this->Makefile->SetLocalGenerator(this);
  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
}

void cmLocalGenerator::Configure()
{
Alexander Neundorf's avatar
   
Alexander Neundorf committed
72
73
  cmLocalGenerator* previousLg = 
                        this->GetGlobalGenerator()->GetCurrentLocalGenerator();
Alexander Neundorf's avatar
   
Alexander Neundorf committed
74
75
  this->GetGlobalGenerator()->SetCurrentLocalGenerator(this);

76
  // make sure the CMakeFiles dir is there
Ken Martin's avatar
Ken Martin committed
77
  std::string filesDir = this->Makefile->GetStartOutputDirectory();
78
  filesDir += cmake::GetCMakeFilesDirectory();
79
80
  cmSystemTools::MakeDirectory(filesDir.c_str());
  
Ken Martin's avatar
Ken Martin committed
81
  // find & read the list file
Ken Martin's avatar
Ken Martin committed
82
  std::string currentStart = this->Makefile->GetStartDirectory();
Ken Martin's avatar
Ken Martin committed
83
  currentStart += "/CMakeLists.txt";
Ken Martin's avatar
Ken Martin committed
84
  this->Makefile->ReadListFile(currentStart.c_str());
85

86
87
88
89
90
91
92
93
94
95
  // at the end of the ReadListFile handle any old style subdirs
  // first get all the subdirectories
  std::vector<cmLocalGenerator *> subdirs = this->GetChildren();
  
  // 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
96
      this->Makefile->ConfigureSubDirectory(*sdi);
97
98
      }
    }  
99

100
101
  // Check whether relative paths should be used for optionally
  // relative paths.
Ken Martin's avatar
Ken Martin committed
102
  this->UseRelativePaths = this->Makefile->IsOn("CMAKE_USE_RELATIVE_PATHS");
103

104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
  // 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());
      }
    }
139
  this->ObjectMaxPathViolations.clear();
140
141
  }

142
  this->Configured = true;
Alexander Neundorf's avatar
   
Alexander Neundorf committed
143
144

  this->GetGlobalGenerator()->SetCurrentLocalGenerator(previousLg);
145
146
147
148
}

void cmLocalGenerator::SetupPathConversions()
{  
149
  // Setup the current output directory components for use by
150
151
152
  // Convert
  std::string outdir; 
  outdir =
Ken Martin's avatar
Ken Martin committed
153
154
    cmSystemTools::CollapseFullPath(this->Makefile->GetHomeDirectory());
  cmSystemTools::SplitPath(outdir.c_str(), this->HomeDirectoryComponents);
155
  outdir =
Ken Martin's avatar
Ken Martin committed
156
157
    cmSystemTools::CollapseFullPath(this->Makefile->GetStartDirectory());
  cmSystemTools::SplitPath(outdir.c_str(), this->StartDirectoryComponents);
Ken Martin's avatar
Ken Martin committed
158
159
160
161
162
163
164
165
166
167

  outdir = cmSystemTools::CollapseFullPath
    (this->Makefile->GetHomeOutputDirectory());
  cmSystemTools::SplitPath(outdir.c_str(), 
                           this->HomeOutputDirectoryComponents);

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

170

Ken Martin's avatar
updates    
Ken Martin committed
171
172
void cmLocalGenerator::SetGlobalGenerator(cmGlobalGenerator *gg)
{
Ken Martin's avatar
Ken Martin committed
173
  this->GlobalGenerator = gg;
Ken Martin's avatar
updates    
Ken Martin committed
174
175

  // setup the home directories
176
  this->Makefile->GetProperties().SetCMakeInstance(gg->GetCMakeInstance());
Ken Martin's avatar
Ken Martin committed
177
  this->Makefile->SetHomeDirectory(
Ken Martin's avatar
updates    
Ken Martin committed
178
    gg->GetCMakeInstance()->GetHomeDirectory());
Ken Martin's avatar
Ken Martin committed
179
  this->Makefile->SetHomeOutputDirectory(
Ken Martin's avatar
updates    
Ken Martin committed
180
    gg->GetCMakeInstance()->GetHomeOutputDirectory());
Brad King's avatar
Brad King committed
181
}
Ken Martin's avatar
Ken Martin committed
182
183

void cmLocalGenerator::ConfigureFinalPass()
184
{
Ken Martin's avatar
Ken Martin committed
185
  this->Makefile->ConfigureFinalPass();
Ken Martin's avatar
Ken Martin committed
186
}
187

Alexander Neundorf's avatar
   
Alexander Neundorf committed
188
189
190
191
192
193
194
195
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)
    {
    // INCLUDE_EXTERNAL_MSPROJECT command only affects the workspace
    // so don't build a projectfile for it
196
    if (strncmp(t->first.c_str(), "INCLUDE_EXTERNAL_MSPROJECT", 26) != 0)
Alexander Neundorf's avatar
   
Alexander Neundorf committed
197
      {
198
      const char* projectFilename = 0;
Alexander Neundorf's avatar
   
Alexander Neundorf committed
199
200
      if (this->IsMakefileGenerator == false)  // only use of this variable
        {
201
        projectFilename = t->second.GetName();
Alexander Neundorf's avatar
   
Alexander Neundorf committed
202
        }
203
      t->second.TraceDependencies(projectFilename);
Alexander Neundorf's avatar
   
Alexander Neundorf committed
204
205
206
207
      }
    }
}

208
209
void cmLocalGenerator::GenerateTestFiles()
{
Ken Martin's avatar
Ken Martin committed
210
  if ( !this->Makefile->IsOn("CMAKE_TESTING_ENABLED") )
211
212
213
    {
    return;
    }
Ken Martin's avatar
Ken Martin committed
214
  std::string file = this->Makefile->GetStartOutputDirectory();
215
  file += "/";
Ken Martin's avatar
Ken Martin committed
216
217
  file += "CTestTestfile.cmake";

218
219
220
221
  cmGeneratedFileStream fout(file.c_str());
  fout.SetCopyIfDifferent(true);

  fout << "# CMake generated Testfile for " << std::endl
Ken Martin's avatar
Ken Martin committed
222
223
224
225
226
227
228
229
230
231
       << "# Source directory: " 
       << this->Makefile->GetStartDirectory() << std::endl
       << "# Build directory: " 
       << this->Makefile->GetStartOutputDirectory() << std::endl
       << "# " << std::endl
       << "# This file replicates the SUBDIRS() and ADD_TEST() commands "
       << "from the source" << std::endl
       << "# tree CMakeLists.txt file, skipping any SUBDIRS() or "
       << "ADD_TEST() commands" << std::endl
       << "# that are excluded by CMake control structures, i.e. IF() "
Ken Martin's avatar
Ken Martin committed
232
       << "commands." << std::endl;
Ken Martin's avatar
Ken Martin committed
233
234
235
  
  const char* testIncludeFile = 
    this->Makefile->GetProperty("TEST_INCLUDE_FILE");
236
237
238
239
  if ( testIncludeFile )
    {
    fout << "INCLUDE(\"" << testIncludeFile << "\")" << std::endl;
    }
Ken Martin's avatar
Ken Martin committed
240
  
Ken Martin's avatar
Ken Martin committed
241
  const std::vector<cmTest*> *tests = this->Makefile->GetTests();
242
243
244
245
246
247
  std::vector<cmTest*>::const_iterator it;
  for ( it = tests->begin(); it != tests->end(); ++ it )
    {
    cmTest* test = *it;
    fout << "ADD_TEST(";
    fout << test->GetName() << " \"" << test->GetCommand() << "\"";
Ken Martin's avatar
Ken Martin committed
248
    
249
    std::vector<cmStdString>::const_iterator argit;
Andy Cedilnik's avatar
Andy Cedilnik committed
250
    for (argit = test->GetArguments().begin();
Ken Martin's avatar
Ken Martin committed
251
         argit != test->GetArguments().end(); ++argit)
252
253
254
255
      {
      // Just double-quote all arguments so they are re-parsed
      // correctly by the test system.
      fout << " \"";
Ken Martin's avatar
Ken Martin committed
256
257
      for(std::string::const_iterator c = argit->begin(); 
          c != argit->end(); ++c)
258
259
260
261
262
263
264
265
266
267
268
269
270
        {
        // Escape quotes within arguments.  We should escape
        // backslashes too but we cannot because it makes the result
        // inconsistent with previous behavior of this command.
        if((*c == '"'))
          {
          fout << '\\';
          }
        fout << *c;
        }
      fout << "\"";
      }
    fout << ")" << std::endl;
271
272
    cmPropertyMap::const_iterator pit;
    cmPropertyMap* mpit = &test->GetProperties();
273
274
275
276
277
    if ( mpit->size() )
      {
      fout << "SET_TESTS_PROPERTIES(" << test->GetName() << " PROPERTIES ";
      for ( pit = mpit->begin(); pit != mpit->end(); ++ pit )
        {
278
        fout << " " << pit->first.c_str() << " \"";
279
        const char* value = pit->second.GetValue();
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
        for ( ; *value; ++ value )
          {
          switch ( *value )
            {
          case '\\':
          case '"':
          case ' ':
          case '#':
          case '(':
          case ')':
          case '$':
          case '^':
            fout << "\\" << *value;
            break;
          case '\t':
            fout << "\\t";
            break;
          case '\n':
            fout << "\\n";
            break;
          case '\r':
            fout << "\\r";
            break;
          default:
            fout << *value;
            }
          }
        fout << "\"";
308
309
310
        }
      fout << ")" << std::endl;
      }
311
312
313
314
315
316
    }
  if ( this->Children.size())
    {
    size_t i;
    for(i = 0; i < this->Children.size(); ++i)
      {
317
      fout << "SUBDIRS(";
318
      std::string outP = 
Ken Martin's avatar
Ken Martin committed
319
        this->Children[i]->GetMakefile()->GetStartOutputDirectory();
320
321
      fout << this->Convert(outP.c_str(),START_OUTPUT);
      fout << ")" << std::endl;
322
323
324
325
      }
    }
}

326
//----------------------------------------------------------------------------
327
328
void cmLocalGenerator::GenerateInstallRules()
{
329
  // Compute the install prefix.
Ken Martin's avatar
Ken Martin committed
330
  const char* prefix = this->Makefile->GetDefinition("CMAKE_INSTALL_PREFIX");
331
332
333
334
335
336
337
338
#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
339
    const char* project_name = this->Makefile->GetDefinition("PROJECT_NAME");
340
341
342
343
344
345
346
347
348
349
350
351
    if(project_name && project_name[0])
      {
      prefix_win32 += "/Program Files/";
      prefix_win32 += project_name;
      }
    else
      {
      prefix_win32 += "/InstalledCMakeProject";
      }
    prefix = prefix_win32.c_str();
    }
#else
352
353
354
355
  if (!prefix)
    {
    prefix = "/usr/local";
    }
356
#endif
357

358
359
  // Compute the set of configurations.
  std::vector<std::string> configurationTypes;
Ken Martin's avatar
Ken Martin committed
360
361
  if(const char* types = 
     this->Makefile->GetDefinition("CMAKE_CONFIGURATION_TYPES"))
362
363
364
365
366
367
    {
    cmSystemTools::ExpandListArgument(types, configurationTypes);
    }
  const char* config = 0;
  if(configurationTypes.empty())
    {
Ken Martin's avatar
Ken Martin committed
368
    config = this->Makefile->GetDefinition("CMAKE_BUILD_TYPE");
369
370
    }

371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
  // 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";
    }

395
  // Create the install script file.
Ken Martin's avatar
Ken Martin committed
396
397
398
  std::string file = this->Makefile->GetStartOutputDirectory();
  std::string homedir = this->Makefile->GetHomeOutputDirectory();
  std::string currdir = this->Makefile->GetCurrentOutputDirectory();
399
  cmSystemTools::ConvertToUnixSlashes(file);
400
401
402
403
404
405
406
  cmSystemTools::ConvertToUnixSlashes(homedir);
  cmSystemTools::ConvertToUnixSlashes(currdir);
  int toplevel_install = 0;
  if ( currdir == homedir )
    {
    toplevel_install = 1;
    }
407
  file += "/cmake_install.cmake";
408
409
  cmGeneratedFileStream fout(file.c_str());
  fout.SetCopyIfDifferent(true);
410

411
412
  // Write the header.
  fout << "# Install script for directory: "
Ken Martin's avatar
Ken Martin committed
413
414
       << this->Makefile->GetCurrentDirectory() << std::endl << std::endl;
  fout << "# Set the install prefix" << std::endl
Ken Martin's avatar
Ken Martin committed
415
416
417
418
419
420
       << "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;
421

422
  // Write support code for generating per-configuration install rules.
423
424
  fout <<
    "# Set the install configuration name.\n"
425
    "IF(NOT DEFINED CMAKE_INSTALL_CONFIG_NAME)\n"
426
427
428
429
    "  IF(BUILD_TYPE)\n"
    "    STRING(REGEX REPLACE \"^[^A-Za-z0-9_]+\" \"\"\n"
    "           CMAKE_INSTALL_CONFIG_NAME \"${BUILD_TYPE}\")\n"
    "  ELSE(BUILD_TYPE)\n"
430
    "    SET(CMAKE_INSTALL_CONFIG_NAME \"" << default_config << "\")\n"
431
    "  ENDIF(BUILD_TYPE)\n"
Ken Martin's avatar
Ken Martin committed
432
433
    "  MESSAGE(STATUS \"Install configuration: "
    "\\\"${CMAKE_INSTALL_CONFIG_NAME}\\\"\")\n"
434
    "ENDIF(NOT DEFINED CMAKE_INSTALL_CONFIG_NAME)\n"
435
    "\n";
436

437
438
439
440
441
442
443
444
445
446
447
448
449
  // 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";

450
451
452
453
454
455
456
457
458
459
460
461
  // 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";
    }

462
463
  // Ask each install generator to write its code.
  std::vector<cmInstallGenerator*> const& installers =
Ken Martin's avatar
Ken Martin committed
464
    this->Makefile->GetInstallGenerators();
Ken Martin's avatar
Ken Martin committed
465
466
  for(std::vector<cmInstallGenerator*>::const_iterator 
        gi = installers.begin();
467
      gi != installers.end(); ++gi)
468
    {
469
    (*gi)->Generate(fout, config, configurationTypes);
470
471
    }

472
473
  // Write rules from old-style specification stored in targets.
  this->GenerateTargetInstallRules(fout, config, configurationTypes);
474

475
  // Include install scripts from subdirectories.
476
  if(!this->Children.empty())
477
    {
478
479
    fout << "IF(NOT CMAKE_INSTALL_LOCAL_ONLY)\n";
    fout << "  # Include the install script for each subdirectory.\n";
480
481
    for(std::vector<cmLocalGenerator*>::const_iterator
          ci = this->Children.begin(); ci != this->Children.end(); ++ci)
482
      {
483
      if(!(*ci)->GetMakefile()->GetPropertyAsBool("EXCLUDE_FROM_ALL"))
484
485
486
        {
        std::string odir = (*ci)->GetMakefile()->GetStartOutputDirectory();
        cmSystemTools::ConvertToUnixSlashes(odir);
487
        fout << "  INCLUDE(\"" <<  odir.c_str()
488
489
             << "/cmake_install.cmake\")" << std::endl;
        }
490
      }
491
    fout << "\n";
Alexander Neundorf's avatar
   
Alexander Neundorf committed
492
    fout << "ENDIF(NOT CMAKE_INSTALL_LOCAL_ONLY)\n\n";
493
    }
494
495

  // Record the install manifest.
496
497
  if ( toplevel_install )
    {
498
499
500
501
502
503
    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
504
      "ENDIF(CMAKE_INSTALL_COMPONENT)\n\n";
505
506
507
508
509
510
511
512
    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}\" "
513
514
515
      << "\"${file}\\n\")" << std::endl
      << "ENDFOREACH(file)" << std::endl;
    }
516
517
}

518
//----------------------------------------------------------------------------
519
void cmLocalGenerator::GenerateTargetManifest()
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
{
  // Collect the set of configuration types.
  std::vector<std::string> configNames;
  if(const char* configurationTypes =
     this->Makefile->GetDefinition("CMAKE_CONFIGURATION_TYPES"))
    {
    cmSystemTools::ExpandListArgument(configurationTypes, configNames);
    }
  else if(const char* buildType =
          this->Makefile->GetDefinition("CMAKE_BUILD_TYPE"))
    {
    if(*buildType)
      {
      configNames.push_back(buildType);
      }
    }

  // 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;
542
    if(configNames.empty())
543
      {
544
545
546
547
548
549
      target.GenerateTargetManifest(0);
      }
    else
      {
      for(std::vector<std::string>::iterator ci = configNames.begin();
          ci != configNames.end(); ++ci)
550
        {
551
552
        const char* config = ci->c_str();
        target.GenerateTargetManifest(config);
553
554
555
556
557
        }
      }
    }
}

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

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

    // 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);
608
    }
609
610

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

  // 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()
    );
633
634
635
636
637
638
639
}

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
640
641
  std::vector<cmSourceFile*> const& classes = target.GetSourceFiles();
  for(std::vector<cmSourceFile*>::const_iterator i = classes.begin();
642
      i != classes.end(); ++i)
643
644
645
646
647
    {
    cmSourceFile* sf = *i;
    if(!sf->GetCustomCommand() &&
       !sf->GetPropertyAsBool("HEADER_FILE_ONLY") &&
       !sf->GetPropertyAsBool("EXTERNAL_OBJECT"))
648
      {
649
650
651
652
      std::string dir_max;
      dir_max += this->Makefile->GetCurrentOutputDirectory();
      dir_max += "/";
      std::string obj = this->GetObjectFileNameWithoutTarget(*sf, dir_max);
653
      if(!obj.empty())
654
        {
Ken Martin's avatar
Ken Martin committed
655
        std::string ofname = this->Makefile->GetCurrentOutputDirectory();
656
        ofname += "/";
657
        ofname += obj;
658
        objVector.push_back(ofname);
Ken Martin's avatar
Ken Martin committed
659
660
        this->AddCustomCommandToCreateObject(ofname.c_str(), 
                                             llang, *(*i), target);
661
        objs += this->Convert(ofname.c_str(),START_OUTPUT,MAKEFILE);
662
663
664
665
666
667
668
        objs += " ";
        }
      }
    }
  std::string createRule = "CMAKE_";
  createRule += llang;
  createRule += target.GetCreateRuleVariable();
669
  std::string targetName = target.GetFullName();
670
671
672
673
674
675
676
677
  // Executable :
  // Shared Library:
  // Static Library:
  // Shared Module:
  std::string linkLibs; // should be set
  std::string flags; // should be set
  std::string linkFlags; // should be set 
  this->GetTargetFlags(linkLibs, flags, linkFlags, target);
678
679
680
  cmLocalGenerator::RuleVariables vars;
  vars.Language = llang;
  vars.Objects = objs.c_str();
681
  vars.ObjectDir = ".";
682
683
684
685
  vars.Target = targetName.c_str();
  vars.LinkLibraries = linkLibs.c_str();
  vars.Flags = flags.c_str();
  vars.LinkFlags = linkFlags.c_str();
686
687
688
689
690
 
  std::string langFlags;
  this->AddLanguageFlags(langFlags, llang, 0);
  vars.LanguageCompileFlags = langFlags.c_str();
  
691
692
693
694
695
696
697
698
699
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
  cmCustomCommandLines commandLines;
  std::vector<std::string> rules;
  rules.push_back(this->Makefile->GetRequiredDefinition(createRule.c_str()));
  std::vector<std::string> commands;
  cmSystemTools::ExpandList(rules, commands);  
  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()
    );
727
  target.AddSourceFile
Ken Martin's avatar
Ken Martin committed
728
    (this->Makefile->GetSource(targetFullPath.c_str()));
729
}
730

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

// List of variables that are replaced when
// rules are expanced.  These variables are
// replaced in the form <var> with GetSafeDefinition(var).
// ${LANG} is replaced in the variable first with all enabled 
// languages.
static const char* ruleReplaceVars[] =
{
Bill Hoffman's avatar
Bill Hoffman committed
777
  "CMAKE_${LANG}_COMPILER",
778
779
780
781
782
783
784
785
786
787
788
  "CMAKE_SHARED_LIBRARY_CREATE_${LANG}_FLAGS",
  "CMAKE_SHARED_MODULE_CREATE_${LANG}_FLAGS",
  "CMAKE_SHARED_MODULE_${LANG}_FLAGS", 
  "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",
789
  "CMAKE_LINKER",
790
791
792
  0
};

Bill Hoffman's avatar
Bill Hoffman committed
793
794
std::string
cmLocalGenerator::ExpandRuleVariable(std::string const& variable,
795
                                     const RuleVariables& replaceValues)
796
{
797
  if(replaceValues.LinkFlags)
798
    {
Bill Hoffman's avatar
Bill Hoffman committed
799
800
    if(variable == "LINK_FLAGS")
      {
801
      return replaceValues.LinkFlags;
Bill Hoffman's avatar
Bill Hoffman committed
802
      }
803
    }
804
  if(replaceValues.Flags)
805
    {
Bill Hoffman's avatar
Bill Hoffman committed
806
807
    if(variable == "FLAGS")
      {
808
      return replaceValues.Flags;
Bill Hoffman's avatar
Bill Hoffman committed
809
      }
810
811
    }
    
812
  if(replaceValues.Source)
813
    {
Bill Hoffman's avatar
Bill Hoffman committed
814
815
    if(variable == "SOURCE")
      {
816
      return replaceValues.Source;
Bill Hoffman's avatar
Bill Hoffman committed
817
      }
818
    }
819
820
821
822
823
824
825
826
827
828
829
830
831
832
  if(replaceValues.PreprocessedSource)
    {
    if(variable == "PREPROCESSED_SOURCE")
      {
      return replaceValues.PreprocessedSource;
      }
    }
  if(replaceValues.AssemblySource)
    {
    if(variable == "ASSEMBLY_SOURCE")
      {
      return replaceValues.AssemblySource;
      }
    }
833
  if(replaceValues.Object)
834
    {
Bill Hoffman's avatar
Bill Hoffman committed
835
836
    if(variable == "OBJECT")
      {
837
      return replaceValues.Object;
Bill Hoffman's avatar
Bill Hoffman committed
838
      }
839
    }
840
841
842
843
844
845
846
  if(replaceValues.ObjectDir)
    {
    if(variable == "OBJECT_DIR")
      {
      return replaceValues.ObjectDir;
      }
    }
847
  if(replaceValues.Objects)
848
    {
Bill Hoffman's avatar
Bill Hoffman committed
849
850
    if(variable == "OBJECTS")
      {
851
      return replaceValues.Objects;
Bill Hoffman's avatar
Bill Hoffman committed
852
      }
853
    }
854
  if(replaceValues.ObjectsQuoted)
855
    {
Bill Hoffman's avatar
Bill Hoffman committed
856
857
    if(variable == "OBJECTS_QUOTED")
      {
858
      return replaceValues.ObjectsQuoted;
Bill Hoffman's avatar
Bill Hoffman committed
859
      }
860
    }
861
862
863
864
  if(replaceValues.Defines && variable == "DEFINES")
    {
    return replaceValues.Defines;
    }
865
866
867
868
869
870
871
872
  if(replaceValues.TargetPDB )
    {
    if(variable == "TARGET_PDB")
      {
      return replaceValues.TargetPDB;
      }
    }

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


void 
cmLocalGenerator::ExpandRuleVariables(std::string& s,
1033
                                      const RuleVariables& replaceValues)
Bill Hoffman's avatar
Bill Hoffman committed
1034
1035
{
  std::vector<std::string> enabledLanguages;
Ken Martin's avatar
Ken Martin committed
1036
  this->GlobalGenerator->GetEnabledLanguages(enabledLanguages);
Bill Hoffman's avatar
Bill Hoffman committed
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
  std::string::size_type start = s.find('<');
  // no variables to expand
  if(start == s.npos)
    {
    return;
    }
  std::string::size_type pos = 0;
  std::string expandedInput;
  while(start != s.npos && start < s.size()-2)
    {
    std::string::size_type end = s.find('>', start);
    // if we find a < with no > we are done
    if(end == s.npos)
      {
      return;
      }
    char c = s[start+1];
    // if the next char after the < is not A-Za-z then
    // skip it and try to find the next < in the string
    if(!isalpha(c))
      {
      start = s.find('<', start+1);
      }
    else
      {
      // extract the var
      std::string var = s.substr(start+1,  end - start-1);
1064
1065
      std::string replace = this->ExpandRuleVariable(var,
                                                     replaceValues);
Bill Hoffman's avatar
Bill Hoffman committed
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
      expandedInput += s.substr(pos, start-pos);
      expandedInput += replace;
      // move to next one
      start = s.find('<', start+var.size()+2);
      pos = end+1;
      }
    }
  // add the rest of the input
  expandedInput += s.substr(pos, s.size()-pos);
  s = expandedInput;
1076
1077
}

1078
1079
1080
1081
//----------------------------------------------------------------------------
std::string
cmLocalGenerator::ConvertToOutputForExistingCommon(const char* remote,
                                                   std::string const& result)
1082
{
1083
1084
1085
1086
1087
  // If this is a windows shell, the result has a space, and the path
  // already exists, we can use a short-path to reference it without a
  // space.
  if(this->WindowsShell && result.find(' ') != result.npos &&
     cmSystemTools::FileExists(remote))
1088
    {
1089
1090
    std<