cmake.cxx 85.4 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
#include "cmDocumentationFormatter.h"
10
#include "cmDuration.h"
11
#include "cmExternalMakefileProjectGenerator.h"
12
#include "cmFileTimeComparison.h"
13
14
15
#include "cmGeneratorTarget.h"
#include "cmGlobalGenerator.h"
#include "cmGlobalGeneratorFactory.h"
16
#include "cmLinkLineComputer.h"
17
18
#include "cmLocalGenerator.h"
#include "cmMakefile.h"
19
#include "cmMessenger.h"
Stephen Kelly's avatar
Stephen Kelly committed
20
#include "cmState.h"
21
#include "cmStateDirectory.h"
22
23
24
#include "cmSystemTools.h"
#include "cmTarget.h"
#include "cmTargetLinkLibraryType.h"
25
#include "cmUtils.hxx"
26
#include "cmVersionConfig.h"
27
#include "cmWorkingDirectory.h"
28
#include "cm_sys_stat.h"
Ken Martin's avatar
Ken Martin committed
29

30
#if defined(CMAKE_BUILD_WITH_CMAKE)
31
#  include "cm_jsoncpp_writer.h"
32

33
34
35
#  include "cmGraphVizWriter.h"
#  include "cmVariableWatch.h"
#  include <unordered_map>
36
#endif
37

Alexander Neundorf's avatar
   
Alexander Neundorf committed
38
#if defined(CMAKE_BUILD_WITH_CMAKE)
39
#  define CMAKE_USE_ECLIPSE
Alexander Neundorf's avatar
   
Alexander Neundorf committed
40
41
#endif

42
#if defined(__MINGW32__) && !defined(CMAKE_BUILD_WITH_CMAKE)
43
#  define CMAKE_BOOT_MINGW
44
45
#endif

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

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

76
#if !defined(CMAKE_BOOT_MINGW)
77
#  include "cmExtraCodeBlocksGenerator.h"
Alexander Neundorf's avatar
   
Alexander Neundorf committed
78
#endif
79
#include "cmExtraKateGenerator.h"
80
#include "cmExtraSublimeTextGenerator.h"
Alexander Neundorf's avatar
   
Alexander Neundorf committed
81

Alexander Neundorf's avatar
   
Alexander Neundorf committed
82
#ifdef CMAKE_USE_ECLIPSE
83
#  include "cmExtraEclipseCDT4Generator.h"
Alexander Neundorf's avatar
   
Alexander Neundorf committed
84
85
#endif

86
#if defined(__APPLE__)
87
88
#  if defined(CMAKE_BUILD_WITH_CMAKE)
#    include "cmGlobalXCodeGenerator.h"
89

90
91
92
93
#    define CMAKE_USE_XCODE 1
#  endif
#  include <sys/resource.h>
#  include <sys/time.h>
Ken Martin's avatar
Ken Martin committed
94
#endif
95

96
97
98
#include "cmsys/FStream.hxx"
#include "cmsys/Glob.hxx"
#include "cmsys/RegularExpression.hxx"
99
#include <algorithm>
100
#include <cstring>
101
#include <iostream>
102
#include <iterator>
103
#include <memory> // IWYU pragma: keep
104
105
106
107
108
#include <sstream>
#include <stdio.h>
#include <stdlib.h>
#include <utility>

109
110
111
namespace {

#if defined(CMAKE_BUILD_WITH_CMAKE)
112
typedef std::unordered_map<std::string, Json::Value> JsonValueMapType;
113
114
115
116
#endif

} // namespace

117
118
static bool cmakeCheckStampFile(const char* stampName, bool verbose = true);
static bool cmakeCheckStampList(const char* stampList, bool verbose = true);
119

120
121
122
void cmWarnUnusedCliWarning(const std::string& variable, int /*unused*/,
                            void* ctx, const char* /*unused*/,
                            const cmMakefile* /*unused*/)
123
124
125
126
127
{
  cmake* cm = reinterpret_cast<cmake*>(ctx);
  cm->MarkCliAsUsed(variable);
}

128
cmake::cmake(Role role)
Bill Hoffman's avatar
Bill Hoffman committed
129
{
Bill Hoffman's avatar
Bill Hoffman committed
130
  this->Trace = false;
Ben Boeckel's avatar
Ben Boeckel committed
131
  this->TraceExpand = false;
132
  this->WarnUninitialized = false;
133
  this->WarnUnused = false;
134
  this->WarnUnusedCli = true;
135
  this->CheckSystemVars = false;
136
  this->DebugOutput = false;
Ken Martin's avatar
Ken Martin committed
137
138
139
  this->DebugTryCompile = false;
  this->ClearBuildSystem = false;
  this->FileComparison = new cmFileTimeComparison;
Andy Cedilnik's avatar
Andy Cedilnik committed
140

141
  this->State = new cmState;
142
  this->CurrentSnapshot = this->State->CreateBaseSnapshot();
143
  this->Messenger = new cmMessenger(this->State);
Stephen Kelly's avatar
Stephen Kelly committed
144

145
146
#ifdef __APPLE__
  struct rlimit rlp;
147
148
149
150
  if (!getrlimit(RLIMIT_STACK, &rlp)) {
    if (rlp.rlim_cur != rlp.rlim_max) {
      rlp.rlim_cur = rlp.rlim_max;
      setrlimit(RLIMIT_STACK, &rlp);
151
    }
152
  }
153
154
#endif

Daniel Pfeifer's avatar
Daniel Pfeifer committed
155
156
157
  this->GlobalGenerator = nullptr;
  this->ProgressCallback = nullptr;
  this->ProgressCallbackClientData = nullptr;
158
  this->CurrentWorkingMode = NORMAL_MODE;
159

160
#ifdef CMAKE_BUILD_WITH_CMAKE
Ken Martin's avatar
Ken Martin committed
161
  this->VariableWatch = new cmVariableWatch;
162
163
164
#endif

  this->AddDefaultGenerators();
Alexander Neundorf's avatar
   
Alexander Neundorf committed
165
  this->AddDefaultExtraGenerators();
166
167
168
169
170
171
  if (role == RoleScript || role == RoleProject) {
    this->AddScriptingCommands();
  }
  if (role == RoleProject) {
    this->AddProjectCommands();
  }
172

173
174
  // Make sure we can capture the build tool output.
  cmSystemTools::EnableVSConsoleOutput();
175
176
177
178
179

  // 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.
180
181
182
183
184
185
186
  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");
187
  this->SourceFileExtensions.push_back("cu");
188
189
190
191
  this->SourceFileExtensions.push_back("m");
  this->SourceFileExtensions.push_back("M");
  this->SourceFileExtensions.push_back("mm");

192
193
194
195
196
  std::copy(this->SourceFileExtensions.begin(),
            this->SourceFileExtensions.end(),
            std::inserter(this->SourceFileExtensionsSet,
                          this->SourceFileExtensionsSet.end()));

197
198
199
200
201
202
203
204
  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");
205
206
207
208
209

  std::copy(this->HeaderFileExtensions.begin(),
            this->HeaderFileExtensions.end(),
            std::inserter(this->HeaderFileExtensionsSet,
                          this->HeaderFileExtensionsSet.end()));
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 = 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
  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;
247
248
  for (cmake::GeneratorInfo const& gi : generatorInfoList) {
    if (gi.isAlias) { // skip aliases, they are there for compatibility reasons
249
250
251
252
                      // only
      continue;
    }

253
    if (gi.extraName.empty()) {
254
      Json::Value gen = Json::objectValue;
255
256
257
      gen["name"] = gi.name;
      gen["toolsetSupport"] = gi.supportsToolset;
      gen["platformSupport"] = gi.supportsPlatform;
258
      gen["extraGenerators"] = Json::arrayValue;
259
      generatorMap[gi.name] = gen;
260
    } else {
261
262
      Json::Value& gen = generatorMap[gi.baseName];
      gen["extraGenerators"].append(gi.extraName);
263
264
265
266
    }
  }

  Json::Value generators = Json::arrayValue;
267
268
  for (auto const& i : generatorMap) {
    generators.append(i.second);
269
270
  }
  obj["generators"] = generators;
271
  obj["serverMode"] = haveServerMode;
272

273
274
275
276
  return obj;
}
#endif

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

289
290
void cmake::CleanupCommandsAndMacros()
{
291
  this->CurrentSnapshot = this->State->Reset();
292
  this->State->RemoveUserDefinedCommands();
293
  this->CurrentSnapshot.SetDefaultDefinitions();
294
295
}

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

328
        this->AddCacheEntry(var, value.c_str(),
329
330
                            "No help, variable specified on the command line.",
                            type);
331

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

      std::string name;
      bool foundNo = false;
358
      bool foundError = false;
359
360
      unsigned int nameStartPosition = 0;

361
      if (entry.find("no-", nameStartPosition) == 0) {
362
363
        foundNo = true;
        nameStartPosition += 3;
364
      }
365

366
      if (entry.find("error=", nameStartPosition) == 0) {
367
368
        foundError = true;
        nameStartPosition += 6;
369
      }
370

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

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

      // now remove them from the cache
417
418
      for (std::string const& currentEntry : entriesToDelete) {
        this->State->RemoveCacheEntry(currentEntry);
Alexander Neundorf's avatar
   
Alexander Neundorf committed
419
      }
420
    } else if (arg.find("-C", 0) == 0) {
421
      std::string path = arg.substr(2);
422
      if (path.empty()) {
423
        ++i;
424
        if (i < args.size()) {
425
          path = args[i];
426
        } else {
427
428
          cmSystemTools::Error("-C must be followed by a file name.");
          return false;
429
        }
430
      }
431
      std::cout << "loading initial cache file " << path << "\n";
432
      this->ReadListFile(args, path.c_str());
433
    } else if (arg.find("-P", 0) == 0) {
434
      i++;
435
      if (i >= args.size()) {
436
437
        cmSystemTools::Error("-P must be followed by a file name.");
        return false;
438
      }
439
      std::string path = args[i];
440
      if (path.empty()) {
441
        cmSystemTools::Error("No cmake script provided.");
442
443
        return false;
      }
444
445
      // Register fake project commands that hint misuse in script mode.
      GetProjectCommandsInScriptMode(this->State);
446
447
      this->ReadListFile(args, path.c_str());
    } else if (arg.find("--find-package", 0) == 0) {
448
      findPackageMode = true;
Ken Martin's avatar
Ken Martin committed
449
    }
450
  }
451

452
  if (findPackageMode) {
453
    return this->FindPackage(args);
454
  }
455

456
  return true;
Ken Martin's avatar
Ken Martin committed
457
458
}

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

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

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

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

Ken Martin's avatar
Ken Martin committed
500
  // free generic one if generated
501
  if (created) {
Ken Martin's avatar
Ken Martin committed
502
    delete gg;
503
  }
504
505
}

506
507
bool cmake::FindPackage(const std::vector<std::string>& args)
{
508
509
  this->SetHomeDirectory(cmSystemTools::GetCurrentWorkingDirectory());
  this->SetHomeOutputDirectory(cmSystemTools::GetCurrentWorkingDirectory());
510

511
  // if a generator was not yet created, temporarily create one
512
  cmGlobalGenerator* gg = new cmGlobalGenerator(this);
513
514
  this->SetGlobalGenerator(gg);

515
  cmStateSnapshot snapshot = this->GetCurrentSnapshot();
516
517
518
519
  snapshot.GetDirectory().SetCurrentBinary(
    cmSystemTools::GetCurrentWorkingDirectory());
  snapshot.GetDirectory().SetCurrentSource(
    cmSystemTools::GetCurrentWorkingDirectory());
520
  // read in the list file to fill the cache
521
  snapshot.SetDefaultDefinitions();
522
523
  cmMakefile* mf = new cmMakefile(gg, snapshot);
  gg->AddMakefile(mf);
524
525
526
527

  mf->SetArgcArgv(args);

  std::string systemFile = mf->GetModulesFile("CMakeFindPackageMode.cmake");
528
  mf->ReadListFile(systemFile.c_str());
529
530
531
532
533
534
535

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

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

549
550
    gg->CreateGenerationObjects();
    cmLocalGenerator* lg = gg->LocalGenerators[0];
Daniel Pfeifer's avatar
Daniel Pfeifer committed
551
    std::string includeFlags =
Daniel Pfeifer's avatar
Daniel Pfeifer committed
552
      lg->GetIncludeFlags(includeDirs, nullptr, language);
553

554
555
    std::string definitions = mf->GetSafeDefinition("PACKAGE_DEFINITIONS");
    printf("%s %s\n", includeFlags.c_str(), definitions.c_str());
556
  } else if (mode == "LINK") {
557
558
559
560
561
562
563
564
    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);
565
566
    for (std::string const& lib : libList) {
      tgt->AddLinkLibrary(*mf, lib, GENERAL_LibraryType);
567
    }
568

569
570
571
    std::string buildType = mf->GetSafeDefinition("CMAKE_BUILD_TYPE");
    buildType = cmSystemTools::UpperCase(buildType);

572
    std::string linkLibs;
573
574
    std::string frameworkPath;
    std::string linkPath;
575
576
    std::string flags;
    std::string linkFlags;
577
    gg->CreateGenerationObjects();
578
    cmGeneratorTarget* gtgt = gg->FindGeneratorTarget(tgt->GetName());
579
    cmLocalGenerator* lg = gtgt->GetLocalGenerator();
580
581
582
    cmLinkLineComputer linkLineComputer(lg,
                                        lg->GetStateSnapshot().GetDirectory());
    lg->GetTargetFlags(&linkLineComputer, buildType, linkLibs, flags,
583
                       linkFlags, frameworkPath, linkPath, gtgt);
584
    linkLibs = frameworkPath + linkPath + linkLibs;
585

586
    printf("%s\n", linkLibs.c_str());
587

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

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

  return packageFound;
603
604
}

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

Bill Hoffman's avatar
Bill Hoffman committed
752
        cmSystemTools::Error("Could not create named generator ",
753
                             value.c_str(), kdevError);
754
        this->PrintGeneratorList();
755
      } else {
Ken Martin's avatar
Ken Martin committed
756
        this->SetGlobalGenerator(gen);
Bill Hoffman's avatar
Bill Hoffman committed
757
      }
758
    }
759
    // no option assume it is the path to the source
760
    else {
761
      directoriesSet = true;
762
      this->SetDirectoriesFromFile(arg.c_str());
Ken Martin's avatar
Ken Martin committed
763
    }
764
765
766
767
768
  }
  if (!directoriesSet) {
    this->SetHomeOutputDirectory(cmSystemTools::GetCurrentWorkingDirectory());
    this->SetHomeDirectory(cmSystemTools::GetCurrentWorkingDirectory());
  }
Ken Martin's avatar
Ken Martin committed
769
770
}

771
772
773
774
775
776
777
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;
778
  if (cmSystemTools::FileIsDirectory(arg)) {
779
780
781
782
783
784
    std::string path = cmSystemTools::CollapseFullPath(arg);
    cmSystemTools::ConvertToUnixSlashes(path);
    std::string cacheFile = path;
    cacheFile += "/CMakeCache.txt";
    std::string listFile = path;
    listFile += "/CMakeLists.txt";
785
    if (cmSystemTools::FileExists(cacheFile)) {
786
      cachePath = path;
787