cmake.cxx 79.8 KB
Newer Older
1
2
/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
   file Copyright.txt or https://cmake.org/licensing for details.  */
Ken Martin's avatar
Ken Martin committed
3
#include "cmake.h"
Brad King's avatar
Brad King committed
4

5
6
#include "cmAlgorithms.h"
#include "cmCommands.h"
7
8
#include "cmDocumentation.h"
#include "cmDocumentationEntry.h"
9
10
#include "cmDocumentationFormatter.h"
#include "cmExternalMakefileProjectGenerator.h"
11
#include "cmFileTimeComparison.h"
12
13
14
#include "cmGeneratorTarget.h"
#include "cmGlobalGenerator.h"
#include "cmGlobalGeneratorFactory.h"
15
16
#include "cmLocalGenerator.h"
#include "cmMakefile.h"
17
#include "cmMessenger.h"
Stephen Kelly's avatar
Stephen Kelly committed
18
#include "cmState.h"
19
20
21
#include "cmSystemTools.h"
#include "cmTarget.h"
#include "cmTargetLinkLibraryType.h"
22
#include "cmUtils.hxx"
23
24
#include "cmVersionConfig.h"
#include "cm_auto_ptr.hxx"
Ken Martin's avatar
Ken Martin committed
25

26
#if defined(CMAKE_BUILD_WITH_CMAKE)
27
28
#include "cmGraphVizWriter.h"
#include "cmVariableWatch.h"
29

30
#include <cm_jsoncpp_writer.h>
31
#endif
32

33
34
35
// only build kdevelop generator on non-windows platforms
// when not bootstrapping cmake
#if !defined(_WIN32)
36
37
38
#if defined(CMAKE_BUILD_WITH_CMAKE)
#define CMAKE_USE_KDEVELOP
#endif
39
40
#endif

Alexander Neundorf's avatar
   
Alexander Neundorf committed
41
#if defined(CMAKE_BUILD_WITH_CMAKE)
42
#define CMAKE_USE_ECLIPSE
Alexander Neundorf's avatar
   
Alexander Neundorf committed
43
44
#endif

45
#if defined(__MINGW32__) && !defined(CMAKE_BUILD_WITH_CMAKE)
46
#define CMAKE_BOOT_MINGW
47
48
#endif

Ken Martin's avatar
Ken Martin committed
49
50
// include the generator
#if defined(_WIN32) && !defined(__CYGWIN__)
51
52
53
54
55
56
57
58
59
#if !defined(CMAKE_BOOT_MINGW)
#include "cmGlobalBorlandMakefileGenerator.h"
#include "cmGlobalGhsMultiGenerator.h"
#include "cmGlobalJOMMakefileGenerator.h"
#include "cmGlobalNMakeMakefileGenerator.h"
#include "cmGlobalVisualStudio10Generator.h"
#include "cmGlobalVisualStudio11Generator.h"
#include "cmGlobalVisualStudio12Generator.h"
#include "cmGlobalVisualStudio14Generator.h"
60
#include "cmGlobalVisualStudio15Generator.h"
61
62
63
#include "cmGlobalVisualStudio71Generator.h"
#include "cmGlobalVisualStudio8Generator.h"
#include "cmGlobalVisualStudio9Generator.h"
64

65
66
67
68
#define CMAKE_HAVE_VS_GENERATORS
#endif
#include "cmGlobalMSYSMakefileGenerator.h"
#include "cmGlobalMinGWMakefileGenerator.h"
Ken Martin's avatar
Ken Martin committed
69
#else
Ken Martin's avatar
Ken Martin committed
70
#endif
71
#if defined(CMAKE_USE_WMAKE)
72
#include "cmGlobalWatcomWMakeGenerator.h"
73
#endif
Ken Martin's avatar
Ken Martin committed
74
#include "cmGlobalUnixMakefileGenerator3.h"
75
#if defined(CMAKE_BUILD_WITH_CMAKE)
76
#include "cmGlobalNinjaGenerator.h"
77
#endif
78
#include "cmExtraCodeLiteGenerator.h"
79

80
#if !defined(CMAKE_BOOT_MINGW)
81
#include "cmExtraCodeBlocksGenerator.h"
Alexander Neundorf's avatar
   
Alexander Neundorf committed
82
#endif
83
#include "cmExtraKateGenerator.h"
84
#include "cmExtraSublimeTextGenerator.h"
Alexander Neundorf's avatar
   
Alexander Neundorf committed
85

86
#ifdef CMAKE_USE_KDEVELOP
87
#include "cmGlobalKdevelopGenerator.h"
88
#endif
Ken Martin's avatar
Ken Martin committed
89

Alexander Neundorf's avatar
   
Alexander Neundorf committed
90
#ifdef CMAKE_USE_ECLIPSE
91
#include "cmExtraEclipseCDT4Generator.h"
Alexander Neundorf's avatar
   
Alexander Neundorf committed
92
93
#endif

94
95
96
#if defined(__APPLE__)
#if defined(CMAKE_BUILD_WITH_CMAKE)
#include "cmGlobalXCodeGenerator.h"
97

98
99
100
101
#define CMAKE_USE_XCODE 1
#endif
#include <sys/resource.h>
#include <sys/time.h>
Ken Martin's avatar
Ken Martin committed
102
#endif
103

104
105
#include <sys/types.h>
// include sys/stat.h after sys/types.h
106
107
#include <sys/stat.h> // struct stat

108
109
110
111
112
113
114
115
116
117
118
119
#include <algorithm>
#include <cmsys/FStream.hxx>
#include <cmsys/Glob.hxx>
#include <cmsys/RegularExpression.hxx>
#include <iostream>
#include <sstream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <utility>

class cmCommand;
120

121
122
123
124
125
126
127
128
129
130
131
132
namespace {

#if defined(CMAKE_BUILD_WITH_CMAKE)
#ifdef CMake_HAVE_CXX_UNORDERED_MAP
typedef std::unordered_map<std::string, Json::Value> JsonValueMapType;
#else
typedef cmsys::hash_map<std::string, Json::Value> JsonValueMapType;
#endif
#endif

} // namespace

133
static bool cmakeCheckStampFile(const char* stampName);
134
static bool cmakeCheckStampList(const char* stampName);
135

136
137
138
void cmWarnUnusedCliWarning(const std::string& variable, int /*unused*/,
                            void* ctx, const char* /*unused*/,
                            const cmMakefile* /*unused*/)
139
140
141
142
143
{
  cmake* cm = reinterpret_cast<cmake*>(ctx);
  cm->MarkCliAsUsed(variable);
}

Bill Hoffman's avatar
Bill Hoffman committed
144
145
cmake::cmake()
{
Bill Hoffman's avatar
Bill Hoffman committed
146
  this->Trace = false;
Ben Boeckel's avatar
Ben Boeckel committed
147
  this->TraceExpand = false;
148
  this->WarnUninitialized = false;
149
  this->WarnUnused = false;
150
  this->WarnUnusedCli = true;
151
  this->CheckSystemVars = false;
152
  this->DebugOutput = false;
Ken Martin's avatar
Ken Martin committed
153
154
155
  this->DebugTryCompile = false;
  this->ClearBuildSystem = false;
  this->FileComparison = new cmFileTimeComparison;
Andy Cedilnik's avatar
Andy Cedilnik committed
156

157
  this->State = new cmState;
158
  this->CurrentSnapshot = this->State->CreateBaseSnapshot();
159
  this->Messenger = new cmMessenger(this->State);
Stephen Kelly's avatar
Stephen Kelly committed
160

161
162
#ifdef __APPLE__
  struct rlimit rlp;
163
164
165
166
  if (!getrlimit(RLIMIT_STACK, &rlp)) {
    if (rlp.rlim_cur != rlp.rlim_max) {
      rlp.rlim_cur = rlp.rlim_max;
      setrlimit(RLIMIT_STACK, &rlp);
167
    }
168
  }
169
170
#endif

Daniel Pfeifer's avatar
Daniel Pfeifer committed
171
172
173
  this->GlobalGenerator = CM_NULLPTR;
  this->ProgressCallback = CM_NULLPTR;
  this->ProgressCallbackClientData = CM_NULLPTR;
174
  this->CurrentWorkingMode = NORMAL_MODE;
175

176
#ifdef CMAKE_BUILD_WITH_CMAKE
Ken Martin's avatar
Ken Martin committed
177
  this->VariableWatch = new cmVariableWatch;
178
179
180
#endif

  this->AddDefaultGenerators();
Alexander Neundorf's avatar
   
Alexander Neundorf committed
181
  this->AddDefaultExtraGenerators();
182
183
  this->AddDefaultCommands();

184
185
  // Make sure we can capture the build tool output.
  cmSystemTools::EnableVSConsoleOutput();
186
187
188
189
190

  // Set up a list of source and header extensions
  // these are used to find files when the extension
  // is not given
  // The "c" extension MUST precede the "C" extension.
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
  this->SourceFileExtensions.push_back("c");
  this->SourceFileExtensions.push_back("C");

  this->SourceFileExtensions.push_back("c++");
  this->SourceFileExtensions.push_back("cc");
  this->SourceFileExtensions.push_back("cpp");
  this->SourceFileExtensions.push_back("cxx");
  this->SourceFileExtensions.push_back("m");
  this->SourceFileExtensions.push_back("M");
  this->SourceFileExtensions.push_back("mm");

  this->HeaderFileExtensions.push_back("h");
  this->HeaderFileExtensions.push_back("hh");
  this->HeaderFileExtensions.push_back("h++");
  this->HeaderFileExtensions.push_back("hm");
  this->HeaderFileExtensions.push_back("hpp");
  this->HeaderFileExtensions.push_back("hxx");
  this->HeaderFileExtensions.push_back("in");
  this->HeaderFileExtensions.push_back("txx");
Bill Hoffman's avatar
Bill Hoffman committed
210
211
}

212
213
cmake::~cmake()
{
Stephen Kelly's avatar
Stephen Kelly committed
214
  delete this->State;
215
  delete this->Messenger;
216
  if (this->GlobalGenerator) {
Ken Martin's avatar
Ken Martin committed
217
    delete this->GlobalGenerator;
Daniel Pfeifer's avatar
Daniel Pfeifer committed
218
    this->GlobalGenerator = CM_NULLPTR;
219
  }
220
  cmDeleteAll(this->Generators);
221
#ifdef CMAKE_BUILD_WITH_CMAKE
Ken Martin's avatar
Ken Martin committed
222
  delete this->VariableWatch;
223
#endif
Ken Martin's avatar
Ken Martin committed
224
  delete this->FileComparison;
Ken Martin's avatar
Ken Martin committed
225
226
}

227
#if defined(CMAKE_BUILD_WITH_CMAKE)
228
Json::Value cmake::ReportCapabilitiesJson(bool haveServerMode) const
229
{
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
  Json::Value obj = Json::objectValue;
  // Version information:
  Json::Value version = Json::objectValue;
  version["string"] = CMake_VERSION;
  version["major"] = CMake_VERSION_MAJOR;
  version["minor"] = CMake_VERSION_MINOR;
  version["suffix"] = CMake_VERSION_SUFFIX;
  version["isDirty"] = (CMake_VERSION_IS_DIRTY == 1);
  version["patch"] = CMake_VERSION_PATCH;

  obj["version"] = version;

  // Generators:
  std::vector<cmake::GeneratorInfo> generatorInfoList;
  this->GetRegisteredGenerators(generatorInfoList);

  JsonValueMapType generatorMap;
  for (std::vector<cmake::GeneratorInfo>::const_iterator i =
         generatorInfoList.begin();
       i != generatorInfoList.end(); ++i) {
    if (i->isAlias) { // skip aliases, they are there for compatibility reasons
                      // only
      continue;
    }

    if (i->extraName.empty()) {
      Json::Value gen = Json::objectValue;
      gen["name"] = i->name;
      gen["toolsetSupport"] = i->supportsToolset;
      gen["platformSupport"] = i->supportsPlatform;
      gen["extraGenerators"] = Json::arrayValue;
      generatorMap[i->name] = gen;
    } else {
      Json::Value& gen = generatorMap[i->baseName];
      gen["extraGenerators"].append(i->extraName);
    }
  }

  Json::Value generators = Json::arrayValue;
  for (JsonValueMapType::const_iterator i = generatorMap.begin();
       i != generatorMap.end(); ++i) {
    generators.append(i->second);
  }
  obj["generators"] = generators;
274
  obj["serverMode"] = haveServerMode;
275

276
277
278
279
  return obj;
}
#endif

280
std::string cmake::ReportCapabilities(bool haveServerMode) const
281
282
283
{
  std::string result;
#if defined(CMAKE_BUILD_WITH_CMAKE)
284
  Json::FastWriter writer;
285
  result = writer.write(this->ReportCapabilitiesJson(haveServerMode));
286
287
288
289
290
291
#else
  result = "Not supported";
#endif
  return result;
}

292
293
void cmake::CleanupCommandsAndMacros()
{
294
  this->CurrentSnapshot = this->State->Reset();
295
  this->State->RemoveUserDefinedCommands();
296
  this->CurrentSnapshot.SetDefaultDefinitions();
297
298
}

299
// Parse the args
300
bool cmake::SetCacheArgs(const std::vector<std::string>& args)
Andy Cedilnik's avatar
Andy Cedilnik committed
301
{
302
  bool findPackageMode = false;
303
  for (unsigned int i = 1; i < args.size(); ++i) {
304
    std::string arg = args[i];
305
    if (arg.find("-D", 0) == 0) {
306
      std::string entry = arg.substr(2);
307
      if (entry.empty()) {
308
        ++i;
309
        if (i < args.size()) {
310
          entry = args[i];
311
        } else {
Alexander Neundorf's avatar
   
Alexander Neundorf committed
312
          cmSystemTools::Error("-D must be followed with VAR=VALUE.");
313
          return false;
314
        }
315
      }
316
      std::string var, value;
317
      cmState::CacheEntryType type = cmState::UNINITIALIZED;
318
      if (cmState::ParseCacheEntry(entry, var, value, type)) {
319
320
321
        // The value is transformed if it is a filepath for example, so
        // we can't compare whether the value is already in the cache until
        // after we call AddCacheEntry.
322
323
        bool haveValue = false;
        std::string cachedValue;
324
325
        if (this->WarnUnusedCli) {
          if (const char* v = this->State->GetInitializedCacheValue(var)) {
326
327
328
            haveValue = true;
            cachedValue = v;
          }
329
        }
330

331
        this->AddCacheEntry(var, value.c_str(),
332
333
                            "No help, variable specified on the command line.",
                            type);
334

335
        if (this->WarnUnusedCli) {
336
          if (!haveValue ||
337
              cachedValue != this->State->GetInitializedCacheValue(var)) {
Stephen Kelly's avatar
Stephen Kelly committed
338
            this->WatchUnusedCli(var);
339
          }
340
        }
341
      } else {
342
343
        std::cerr << "Parse error in command line argument: " << arg << "\n"
                  << "Should be: VAR:type=value\n";
Alexander Neundorf's avatar
Alexander Neundorf committed
344
        cmSystemTools::Error("No cmake script provided.");
345
        return false;
346
      }
347
    } else if (cmHasLiteralPrefix(arg, "-W")) {
348
      std::string entry = arg.substr(2);
349
      if (entry.empty()) {
350
        ++i;
351
        if (i < args.size()) {
352
          entry = args[i];
353
        } else {
354
355
356
          cmSystemTools::Error("-W must be followed with [no-]<name>.");
          return false;
        }
357
      }
358
359
360

      std::string name;
      bool foundNo = false;
361
      bool foundError = false;
362
363
      unsigned int nameStartPosition = 0;

364
      if (entry.find("no-", nameStartPosition) == 0) {
365
366
        foundNo = true;
        nameStartPosition += 3;
367
      }
368

369
      if (entry.find("error=", nameStartPosition) == 0) {
370
371
        foundError = true;
        nameStartPosition += 6;
372
      }
373

374
      name = entry.substr(nameStartPosition);
375
      if (name.empty()) {
376
377
        cmSystemTools::Error("No warning name provided.");
        return false;
378
      }
379

380
      if (!foundNo && !foundError) {
381
        // -W<name>
382
383
384
385
386
        this->DiagLevels[name] = std::max(this->DiagLevels[name], DIAG_WARN);
      } else if (foundNo && !foundError) {
        // -Wno<name>
        this->DiagLevels[name] = DIAG_IGNORE;
      } else if (!foundNo && foundError) {
387
388
        // -Werror=<name>
        this->DiagLevels[name] = DIAG_ERROR;
389
      } else {
390
        // -Wno-error=<name>
391
        this->DiagLevels[name] = std::min(this->DiagLevels[name], DIAG_WARN);
392
      }
393
    } else if (arg.find("-U", 0) == 0) {
Alexander Neundorf's avatar
   
Alexander Neundorf committed
394
      std::string entryPattern = arg.substr(2);
395
      if (entryPattern.empty()) {
Alexander Neundorf's avatar
   
Alexander Neundorf committed
396
        ++i;
397
        if (i < args.size()) {
Alexander Neundorf's avatar
   
Alexander Neundorf committed
398
          entryPattern = args[i];
399
        } else {
Alexander Neundorf's avatar
   
Alexander Neundorf committed
400
401
402
          cmSystemTools::Error("-U must be followed with VAR.");
          return false;
        }
403
      }
Alexander Neundorf's avatar
   
Alexander Neundorf committed
404
      cmsys::RegularExpression regex(
Stephen Kelly's avatar
Stephen Kelly committed
405
        cmsys::Glob::PatternToRegex(entryPattern, true, true).c_str());
406
407
      // go through all cache entries and collect the vars which will be
      // removed
Alexander Neundorf's avatar
   
Alexander Neundorf committed
408
      std::vector<std::string> entriesToDelete;
Stephen Kelly's avatar
Stephen Kelly committed
409
      std::vector<std::string> cacheKeys = this->State->GetCacheEntryKeys();
410
      for (std::vector<std::string>::const_iterator it = cacheKeys.begin();
411
           it != cacheKeys.end(); ++it) {
412
        cmState::CacheEntryType t = this->State->GetCacheEntryType(*it);
413
414
        if (t != cmState::STATIC) {
          if (regex.find(it->c_str())) {
415
            entriesToDelete.push_back(*it);
Alexander Neundorf's avatar
   
Alexander Neundorf committed
416
417
          }
        }
418
      }
Alexander Neundorf's avatar
   
Alexander Neundorf committed
419
420

      // now remove them from the cache
421
422
423
      for (std::vector<std::string>::const_iterator currentEntry =
             entriesToDelete.begin();
           currentEntry != entriesToDelete.end(); ++currentEntry) {
Stephen Kelly's avatar
Stephen Kelly committed
424
        this->State->RemoveCacheEntry(*currentEntry);
Alexander Neundorf's avatar
   
Alexander Neundorf committed
425
      }
426
    } else if (arg.find("-C", 0) == 0) {
427
      std::string path = arg.substr(2);
428
      if (path.empty()) {
429
        ++i;
430
        if (i < args.size()) {
431
          path = args[i];
432
        } else {
433
434
          cmSystemTools::Error("-C must be followed by a file name.");
          return false;
435
        }
436
      }
437
      std::cout << "loading initial cache file " << path << "\n";
438
      this->ReadListFile(args, path.c_str());
439
    } else if (arg.find("-P", 0) == 0) {
440
      i++;
441
      if (i >= args.size()) {
442
443
        cmSystemTools::Error("-P must be followed by a file name.");
        return false;
444
      }
445
      std::string path = args[i];
446
      if (path.empty()) {
447
        cmSystemTools::Error("No cmake script provided.");
448
449
        return false;
      }
450
451
      this->ReadListFile(args, path.c_str());
    } else if (arg.find("--find-package", 0) == 0) {
452
      findPackageMode = true;
Ken Martin's avatar
Ken Martin committed
453
    }
454
  }
455

456
  if (findPackageMode) {
457
    return this->FindPackage(args);
458
  }
459

460
  return true;
Ken Martin's avatar
Ken Martin committed
461
462
}

463
void cmake::ReadListFile(const std::vector<std::string>& args,
464
                         const char* path)
Ken Martin's avatar
Ken Martin committed
465
466
{
  // if a generator was not yet created, temporarily create one
467
  cmGlobalGenerator* gg = this->GetGlobalGenerator();
Ken Martin's avatar
Ken Martin committed
468
  bool created = false;
Andy Cedilnik's avatar
Andy Cedilnik committed
469

Ken Martin's avatar
Ken Martin committed
470
  // if a generator was not specified use a generic one
471
  if (!gg) {
472
    gg = new cmGlobalGenerator(this);
Ken Martin's avatar
Ken Martin committed
473
    created = true;
474
  }
Ken Martin's avatar
Ken Martin committed
475
476

  // read in the list file to fill the cache
477
  if (path) {
478
    this->CurrentSnapshot = this->State->Reset();
479
480
481
482
    std::string homeDir = this->GetHomeDirectory();
    std::string homeOutputDir = this->GetHomeOutputDirectory();
    this->SetHomeDirectory(cmSystemTools::GetCurrentWorkingDirectory());
    this->SetHomeOutputDirectory(cmSystemTools::GetCurrentWorkingDirectory());
483
    cmState::Snapshot snapshot = this->GetCurrentSnapshot();
484
485
486
487
    snapshot.GetDirectory().SetCurrentBinary(
      cmSystemTools::GetCurrentWorkingDirectory());
    snapshot.GetDirectory().SetCurrentSource(
      cmSystemTools::GetCurrentWorkingDirectory());
488
    snapshot.SetDefaultDefinitions();
489
    CM_AUTO_PTR<cmMakefile> mf(new cmMakefile(gg, snapshot));
490
    if (this->GetWorkingMode() != NORMAL_MODE) {
491
492
      std::string file(cmSystemTools::CollapseFullPath(path));
      cmSystemTools::ConvertToUnixSlashes(file);
493
      mf->SetScriptModeFile(file.c_str());
494

495
      mf->SetArgcArgv(args);
496
497
    }
    if (!mf->ReadListFile(path)) {
498
      cmSystemTools::Error("Error processing file: ", path);
499
    }
500
501
    this->SetHomeDirectory(homeDir);
    this->SetHomeOutputDirectory(homeOutputDir);
502
  }
Andy Cedilnik's avatar
Andy Cedilnik committed
503

Ken Martin's avatar
Ken Martin committed
504
  // free generic one if generated
505
  if (created) {
Ken Martin's avatar
Ken Martin committed
506
    delete gg;
507
  }
508
509
}

510
511
bool cmake::FindPackage(const std::vector<std::string>& args)
{
512
513
  this->SetHomeDirectory(cmSystemTools::GetCurrentWorkingDirectory());
  this->SetHomeOutputDirectory(cmSystemTools::GetCurrentWorkingDirectory());
514

515
  // if a generator was not yet created, temporarily create one
516
  cmGlobalGenerator* gg = new cmGlobalGenerator(this);
517
518
  this->SetGlobalGenerator(gg);

519
  cmState::Snapshot snapshot = this->GetCurrentSnapshot();
520
521
522
523
  snapshot.GetDirectory().SetCurrentBinary(
    cmSystemTools::GetCurrentWorkingDirectory());
  snapshot.GetDirectory().SetCurrentSource(
    cmSystemTools::GetCurrentWorkingDirectory());
524
  // read in the list file to fill the cache
525
  snapshot.SetDefaultDefinitions();
526
527
  cmMakefile* mf = new cmMakefile(gg, snapshot);
  gg->AddMakefile(mf);
528
529
530
531

  mf->SetArgcArgv(args);

  std::string systemFile = mf->GetModulesFile("CMakeFindPackageMode.cmake");
532
  mf->ReadListFile(systemFile.c_str());
533
534
535
536
537
538
539

  std::string language = mf->GetSafeDefinition("LANGUAGE");
  std::string mode = mf->GetSafeDefinition("MODE");
  std::string packageName = mf->GetSafeDefinition("NAME");
  bool packageFound = mf->IsOn("PACKAGE_FOUND");
  bool quiet = mf->IsOn("PACKAGE_QUIET");

540
541
  if (!packageFound) {
    if (!quiet) {
542
543
      printf("%s not found.\n", packageName.c_str());
    }
544
545
  } else if (mode == "EXIST") {
    if (!quiet) {
546
547
      printf("%s found.\n", packageName.c_str());
    }
548
  } else if (mode == "COMPILE") {
549
550
551
552
    std::string includes = mf->GetSafeDefinition("PACKAGE_INCLUDE_DIRS");
    std::vector<std::string> includeDirs;
    cmSystemTools::ExpandListArgument(includes, includeDirs);

553
554
    gg->CreateGenerationObjects();
    cmLocalGenerator* lg = gg->LocalGenerators[0];
Daniel Pfeifer's avatar
Daniel Pfeifer committed
555
556
    std::string includeFlags =
      lg->GetIncludeFlags(includeDirs, CM_NULLPTR, language);
557

558
559
    std::string definitions = mf->GetSafeDefinition("PACKAGE_DEFINITIONS");
    printf("%s %s\n", includeFlags.c_str(), definitions.c_str());
560
  } else if (mode == "LINK") {
561
562
563
564
565
566
567
568
    const char* targetName = "dummy";
    std::vector<std::string> srcs;
    cmTarget* tgt = mf->AddExecutable(targetName, srcs, true);
    tgt->SetProperty("LINKER_LANGUAGE", language.c_str());

    std::string libs = mf->GetSafeDefinition("PACKAGE_LIBRARIES");
    std::vector<std::string> libList;
    cmSystemTools::ExpandListArgument(libs, libList);
569
570
571
572
    for (std::vector<std::string>::const_iterator libIt = libList.begin();
         libIt != libList.end(); ++libIt) {
      mf->AddLinkLibraryForTarget(targetName, *libIt, GENERAL_LibraryType);
    }
573

574
575
576
    std::string buildType = mf->GetSafeDefinition("CMAKE_BUILD_TYPE");
    buildType = cmSystemTools::UpperCase(buildType);

577
    std::string linkLibs;
578
579
    std::string frameworkPath;
    std::string linkPath;
580
581
    std::string flags;
    std::string linkFlags;
582
    gg->CreateGenerationObjects();
583
    cmGeneratorTarget* gtgt = gg->FindGeneratorTarget(tgt->GetName());
584
    cmLocalGenerator* lg = gtgt->GetLocalGenerator();
585
586
    lg->GetTargetFlags(buildType, linkLibs, flags, linkFlags, frameworkPath,
                       linkPath, gtgt, false);
587
    linkLibs = frameworkPath + linkPath + linkLibs;
588

589
    printf("%s\n", linkLibs.c_str());
590

591
592
593
594
595
596
597
598
599
    /*    if ( use_win32 )
          {
          tgt->SetProperty("WIN32_EXECUTABLE", "ON");
          }
        if ( use_macbundle)
          {
          tgt->SetProperty("MACOSX_BUNDLE", "ON");
          }*/
  }
600
601

  // free generic one if generated
602
603
  //  this->SetGlobalGenerator(0); // setting 0-pointer is not possible
  //  delete gg; // this crashes inside the cmake instance
604
605

  return packageFound;
606
607
}

Ken Martin's avatar
Ken Martin committed
608
// Parse the args
Ben Boeckel's avatar
Ben Boeckel committed
609
610
void cmake::SetArgs(const std::vector<std::string>& args,
                    bool directoriesSetBefore)
Ken Martin's avatar
Ken Martin committed
611
{
612
  bool directoriesSet = directoriesSetBefore;
613
  bool haveToolset = false;
614
  bool havePlatform = false;
615
  for (unsigned int i = 1; i < args.size(); ++i) {
616
    std::string arg = args[i];
617
    if (arg.find("-H", 0) == 0) {
Bill Hoffman's avatar
Bill Hoffman committed
618
      directoriesSet = true;
Ken Martin's avatar
Ken Martin committed
619
      std::string path = arg.substr(2);
620
      path = cmSystemTools::CollapseFullPath(path);
621
      cmSystemTools::ConvertToUnixSlashes(path);
Stephen Kelly's avatar
Stephen Kelly committed
622
      this->SetHomeDirectory(path);
623
    } else if (arg.find("-S", 0) == 0) {
624
      // There is no local generate anymore.  Ignore -S option.
625
    } else if (arg.find("-O", 0) == 0) {
626
      // There is no local generate anymore.  Ignore -O option.
627
    } else if (arg.find("-B", 0) == 0) {
Bill Hoffman's avatar
Bill Hoffman committed
628
      directoriesSet = true;
Ken Martin's avatar
Ken Martin committed
629
      std::string path = arg.substr(2);
630
      path = cmSystemTools::CollapseFullPath(path);
631
      cmSystemTools::ConvertToUnixSlashes(path);
Stephen Kelly's avatar
Stephen Kelly committed
632
      this->SetHomeOutputDirectory(path);
633
634
    } else if ((i < args.size() - 2) &&
               (arg.find("--check-build-system", 0) == 0)) {
Ken Martin's avatar
Ken Martin committed
635
636
      this->CheckBuildSystemArgument = args[++i];
      this->ClearBuildSystem = (atoi(args[++i].c_str()) > 0);
637
638
    } else if ((i < args.size() - 1) &&
               (arg.find("--check-stamp-file", 0) == 0)) {
639
      this->CheckStampFile = args[++i];
640
641
    } else if ((i < args.size() - 1) &&
               (arg.find("--check-stamp-list", 0) == 0)) {
642
      this->CheckStampList = args[++i];
643
    }
644
#if defined(CMAKE_HAVE_VS_GENERATORS)
645
646
    else if ((i < args.size() - 1) &&
             (arg.find("--vs-solution-file", 0) == 0)) {
647
      this->VSSolutionFile = args[++i];
648
    }
649
#endif
650
    else if (arg.find("-D", 0) == 0) {
651
      // skip for now
652
    } else if (arg.find("-U", 0) == 0) {
Alexander Neundorf's avatar
   
Alexander Neundorf committed
653
      // skip for now
654
    } else if (arg.find("-C", 0) == 0) {
655
      // skip for now
656
    } else if (arg.find("-P", 0) == 0) {
657
      // skip for now
658
      i++;
659
    } else if (arg.find("--find-package", 0) == 0) {
660
661
      // skip for now
      i++;
662
    } else if (arg.find("-W", 0) == 0) {
663
      // skip for now
664
    } else if (arg.find("--graphviz=", 0) == 0) {
665
      std::string path = arg.substr(strlen("--graphviz="));
666
      path = cmSystemTools::CollapseFullPath(path);
667
      cmSystemTools::ConvertToUnixSlashes(path);
Ken Martin's avatar
Ken Martin committed
668
      this->GraphVizFile = path;
669
      if (this->GraphVizFile.empty()) {
670
671
        cmSystemTools::Error("No file specified for --graphviz");
      }
672
    } else if (arg.find("--debug-trycompile", 0) == 0) {
673
674
      std::cout << "debug trycompile on\n";
      this->DebugTryCompileOn();
675
    } else if (arg.find("--debug-output", 0) == 0) {
676
      std::cout << "Running with debug output on.\n";
677
      this->SetDebugOutputOn(true);
678
    } else if (arg.find("--trace-expand", 0) == 0) {
Ben Boeckel's avatar
Ben Boeckel committed
679
680
681
      std::cout << "Running with expanded trace output on.\n";
      this->SetTrace(true);
      this->SetTraceExpand(true);
682
683
684
685
686
    } else if (arg.find("--trace-source=", 0) == 0) {
      std::string file = arg.substr(strlen("--trace-source="));
      cmSystemTools::ConvertToUnixSlashes(file);
      this->AddTraceSource(file);
      this->SetTrace(true);
687
    } else if (arg.find("--trace", 0) == 0) {
Bill Hoffman's avatar
Bill Hoffman committed
688
689
      std::cout << "Running with trace output on.\n";
      this->SetTrace(true);
Ben Boeckel's avatar
Ben Boeckel committed
690
      this->SetTraceExpand(false);
691
    } else if (arg.find("--warn-uninitialized", 0) == 0) {
692
693
      std::cout << "Warn about uninitialized values.\n";
      this->SetWarnUninitialized(true);
694
    } else if (arg.find("--warn-unused-vars", 0) == 0) {
695
      std::cout << "Finding unused variables.\n";
696
      this->SetWarnUnused(true);
697
698
699
    } else if (arg.find("--no-warn-unused-cli", 0) == 0) {
      std::cout << "Not searching for unused variables given on the "
                << "command line.\n";
700
      this->SetWarnUnusedCli(false);
701
702
703
    } else if (arg.find("--check-system-vars", 0) == 0) {
      std::cout << "Also check system files when warning about unused and "
                << "uninitialized variables.\n";
704
      this->SetCheckSystemVars(true);
705
    } else if (arg.find("-A", 0) == 0) {
706
      std::string value = arg.substr(2);
707
      if (value.empty()) {
708
        ++i;
709
        if (i >= args.size()) {
710
711
712
          cmSystemTools::Error("No platform specified for -A");
          return;
        }
713
714
715
        value = args[i];
      }
      if (havePlatform) {
716
717
        cmSystemTools::Error("Multiple -A options not allowed");
        return;
718
      }
719
720
      this->GeneratorPlatform = value;
      havePlatform = true;
721
    } else if (arg.find("-T", 0) == 0) {
722
      std::string value = arg.substr(2);
723
      if (value.empty()) {
724
        ++i;
725
        if (i >= args.size()) {
726
727
728
          cmSystemTools::Error("No toolset specified for -T");
          return;
        }
729
730
731
        value = args[i];
      }
      if (haveToolset) {
732
733
        cmSystemTools::Error("Multiple -T options not allowed");
        return;
734
      }
735
736
      this->GeneratorToolset = value;
      haveToolset = true;
737
    } else if (arg.find("-G", 0) == 0) {
Bill Hoffman's avatar
Bill Hoffman committed
738
      std::string value = arg.substr(2);
739
      if (value.empty()) {
740
        ++i;
741
        if (i >= args.size()) {
742
          cmSystemTools::Error("No generator specified for -G");
743
          this->PrintGeneratorList();
744
          return;
745
        }
746
747
748
749
        value = args[i];
      }
      cmGlobalGenerator* gen = this->CreateGlobalGenerator(value);
      if (!gen) {
Bill Hoffman's avatar
Bill Hoffman committed
750
751
        cmSystemTools::Error("Could not create named generator ",
                             value.c_str());
752
        this->PrintGeneratorList();
753
      } else {
Ken Martin's avatar
Ken Martin committed
754
        this->SetGlobalGenerator(gen);
Bill Hoffman's avatar
Bill Hoffman committed
755
      }
756
    }
757
    // no option assume it is the path to the source
758
    else {
759
      directoriesSet = true;
760
      this->SetDirectoriesFromFile(arg.c_str());
Ken Martin's avatar
Ken Martin committed
761
    }
762
763
764
765
766
  }
  if (!directoriesSet) {
    this->SetHomeOutputDirectory(cmSystemTools::GetCurrentWorkingDirectory());
    this->SetHomeDirectory(cmSystemTools::GetCurrentWorkingDirectory());
  }
Ken Martin's avatar
Ken Martin committed
767
768
}

769
770
771
772
773
774
775
void cmake::SetDirectoriesFromFile(const char* arg)
{
  // Check if the argument refers to a CMakeCache.txt or
  // CMakeLists.txt file.
  std::string listPath;
  std::string cachePath;
  bool argIsFile = false;
776
  if (cmSystemTools::FileIsDirectory(arg)) {
777
778
779
780
781
782
    std::string path = cmSystemTools::CollapseFullPath(arg);
    cmSystemTools::ConvertToUnixSlashes(path);
    std::string cacheFile = path;
    cacheFile += "/CMakeCache.txt";
    std::string listFile = path;
    listFile += "/CMakeLists.txt";
783
    if (cmSystemTools::FileExists(cacheFile.c_str())) {
784
      cachePath = path;
785
786
    }
    if (cmSystemTools::FileExists(listFile.c_str())) {
787
788
      listPath = path;
    }
789
  } else if (cmSystemTools::FileExists(arg)) {
790
791
    argIsFile = true;
    std::string fullPath = cmSystemTools::CollapseFullPath(arg);
Stephen Kelly's avatar
Stephen Kelly committed
792
    std::string name = cmSystemTools::GetFilenameName(fullPath);
793
    name = cmSystemTools::LowerCase(name);