cmake.cxx 80 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
#include "cmLinkLineComputer.h"
16
17
#include "cmLocalGenerator.h"
#include "cmMakefile.h"
18
#include "cmMessenger.h"
Stephen Kelly's avatar
Stephen Kelly committed
19
#include "cmState.h"
20
21
22
#include "cmSystemTools.h"
#include "cmTarget.h"
#include "cmTargetLinkLibraryType.h"
23
#include "cmUtils.hxx"
24
25
#include "cmVersionConfig.h"
#include "cm_auto_ptr.hxx"
Ken Martin's avatar
Ken Martin committed
26

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

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

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

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

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

Ken Martin's avatar
Ken Martin committed
50
51
// include the generator
#if defined(_WIN32) && !defined(__CYGWIN__)
52
53
54
55
56
57
58
59
60
#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"
61
#include "cmGlobalVisualStudio15Generator.h"
62
63
64
#include "cmGlobalVisualStudio71Generator.h"
#include "cmGlobalVisualStudio8Generator.h"
#include "cmGlobalVisualStudio9Generator.h"
65

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

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

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

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

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

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

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

109
110
111
112
113
114
115
116
117
118
119
120
#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;
121

122
123
124
125
126
127
128
129
130
131
132
133
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

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

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

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

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

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

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

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

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

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

  // 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.
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
  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
211
212
}

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

228
#if defined(CMAKE_BUILD_WITH_CMAKE)
229
Json::Value cmake::ReportCapabilitiesJson(bool haveServerMode) const
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
274
  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;
275
  obj["serverMode"] = haveServerMode;
276

277
278
279
280
  return obj;
}
#endif

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

  mf->SetArgcArgv(args);

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

  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");

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

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

559
560
    std::string definitions = mf->GetSafeDefinition("PACKAGE_DEFINITIONS");
    printf("%s %s\n", includeFlags.c_str(), definitions.c_str());
561
  } else if (mode == "LINK") {
562
563
564
565
566
567
568
569
    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);
570
571
    for (std::vector<std::string>::const_iterator libIt = libList.begin();
         libIt != libList.end(); ++libIt) {
572
      tgt->AddLinkLibrary(*mf, *libIt, GENERAL_LibraryType);
573
    }
574

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

578
    std::string linkLibs;
579
580
    std::string frameworkPath;
    std::string linkPath;
581
582
    std::string flags;
    std::string linkFlags;
583
    gg->CreateGenerationObjects();
584
    cmGeneratorTarget* gtgt = gg->FindGeneratorTarget(tgt->GetName());
585
    cmLocalGenerator* lg = gtgt->GetLocalGenerator();
586
587
588
    cmLinkLineComputer linkLineComputer(lg,
                                        lg->GetStateSnapshot().GetDirectory());
    lg->GetTargetFlags(&linkLineComputer, buildType, linkLibs, flags,
589
                       linkFlags, frameworkPath, linkPath, gtgt);
590
    linkLibs = frameworkPath + linkPath + linkLibs;
591

592
    printf("%s\n", linkLibs.c_str());
593

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

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

  return packageFound;
609
610
}

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

772
773
774
775
776
777
778
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;
779
  if (cmSystemTools::FileIsDirectory(arg)) {
780
781
782
783
784
785
    std::string path = cmSystemTools::CollapseFullPath(arg);
    cmSystemTools::ConvertToUnixSlashes(path);
    std::string cacheFile = path;
    cacheFile += "/CMakeCache.txt";
    std::string listFile = path;
    listFile += "/CMakeLists.txt";
786
    if (cmSystemTools::FileExists(cacheFile.c_str())) {
787
      cachePath = path;
788
789
    }
    if (cmSystemTools::FileExists(listFile.c_str())) {
790
791
      listPath = path;
    }
792
  } else if (cmSystemTools::FileExists(arg)) {
Brad King's avatar