cmInstallCommand.cxx 59.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.  */
3
4
#include "cmInstallCommand.h"

5
#include <cstddef>
6
#include <set>
7
#include <sstream>
8
#include <utility>
9

10
11
12
13
14
15
#include <cm/memory>

#include "cmsys/Glob.hxx"

#include "cm_static_string_view.hxx"

16
#include "cmArgumentParser.h"
17
#include "cmExecutionStatus.h"
18
#include "cmExportSet.h"
19
#include "cmGeneratorExpression.h"
20
#include "cmGlobalGenerator.h"
21
#include "cmInstallCommandArguments.h"
22
#include "cmInstallDirectoryGenerator.h"
23
#include "cmInstallExportGenerator.h"
24
#include "cmInstallFilesGenerator.h"
25
#include "cmInstallGenerator.h"
26
27
#include "cmInstallScriptGenerator.h"
#include "cmInstallTargetGenerator.h"
28
#include "cmListFileCache.h"
29
#include "cmMakefile.h"
30
#include "cmMessageType.h"
31
32
#include "cmPolicies.h"
#include "cmStateTypes.h"
33
#include "cmStringAlgorithms.h"
34
#include "cmSubcommandTable.h"
35
#include "cmSystemTools.h"
36
#include "cmTarget.h"
37
#include "cmTargetExport.h"
38

39
namespace {
40

41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
class Helper
{
public:
  Helper(cmExecutionStatus& status)
    : Status(status)
    , Makefile(&status.GetMakefile())
  {
    this->DefaultComponentName = this->Makefile->GetSafeDefinition(
      "CMAKE_INSTALL_DEFAULT_COMPONENT_NAME");
    if (this->DefaultComponentName.empty()) {
      this->DefaultComponentName = "Unspecified";
    }
  }

  void SetError(std::string const& err) { this->Status.SetError(err); }

  bool MakeFilesFullPath(const char* modeName,
                         const std::vector<std::string>& relFiles,
                         std::vector<std::string>& absFiles);
  bool CheckCMP0006(bool& failure);

  std::string GetDestination(const cmInstallCommandArguments* args,
                             const std::string& varName,
                             const std::string& guess);
  std::string GetRuntimeDestination(const cmInstallCommandArguments* args);
  std::string GetSbinDestination(const cmInstallCommandArguments* args);
  std::string GetArchiveDestination(const cmInstallCommandArguments* args);
  std::string GetLibraryDestination(const cmInstallCommandArguments* args);
  std::string GetIncludeDestination(const cmInstallCommandArguments* args);
  std::string GetSysconfDestination(const cmInstallCommandArguments* args);
  std::string GetSharedStateDestination(const cmInstallCommandArguments* args);
  std::string GetLocalStateDestination(const cmInstallCommandArguments* args);
  std::string GetRunStateDestination(const cmInstallCommandArguments* args);
  std::string GetDataRootDestination(const cmInstallCommandArguments* args);
  std::string GetDataDestination(const cmInstallCommandArguments* args);
  std::string GetInfoDestination(const cmInstallCommandArguments* args);
  std::string GetLocaleDestination(const cmInstallCommandArguments* args);
  std::string GetManDestination(const cmInstallCommandArguments* args);
  std::string GetDocDestination(const cmInstallCommandArguments* args);
  std::string GetDestinationForType(const cmInstallCommandArguments* args,
                                    const std::string& type);

  cmExecutionStatus& Status;
  cmMakefile* Makefile;
  std::string DefaultComponentName;
};

88
std::unique_ptr<cmInstallTargetGenerator> CreateInstallTargetGenerator(
89
  cmTarget& target, const cmInstallCommandArguments& args, bool impLib,
90
91
  cmListFileBacktrace const& backtrace, const std::string& destination,
  bool forceOpt = false, bool namelink = false)
Alexander Neundorf's avatar
   
Alexander Neundorf committed
92
{
93
  cmInstallGenerator::MessageLevel message =
94
    cmInstallGenerator::SelectMessageLevel(target.GetMakefile());
95
  target.SetHaveInstallRule(true);
96
97
  const std::string& component =
    namelink ? args.GetNamelinkComponent() : args.GetComponent();
98
  auto g = cm::make_unique<cmInstallTargetGenerator>(
99
100
101
    target.GetName(), destination, impLib, args.GetPermissions(),
    args.GetConfigurations(), component, message, args.GetExcludeFromAll(),
    args.GetOptional() || forceOpt, backtrace);
102
  target.AddInstallGenerator(g.get());
103
  return g;
Alexander Neundorf's avatar
   
Alexander Neundorf committed
104
105
}

106
std::unique_ptr<cmInstallTargetGenerator> CreateInstallTargetGenerator(
107
108
109
110
111
112
113
114
115
  cmTarget& target, const cmInstallCommandArguments& args, bool impLib,
  cmListFileBacktrace const& backtrace, bool forceOpt = false,
  bool namelink = false)
{
  return CreateInstallTargetGenerator(target, args, impLib, backtrace,
                                      args.GetDestination(), forceOpt,
                                      namelink);
}

116
std::unique_ptr<cmInstallFilesGenerator> CreateInstallFilesGenerator(
117
  cmMakefile* mf, const std::vector<std::string>& absFiles,
118
119
  const cmInstallCommandArguments& args, bool programs,
  const std::string& destination)
Alexander Neundorf's avatar
   
Alexander Neundorf committed
120
{
121
  cmInstallGenerator::MessageLevel message =
122
    cmInstallGenerator::SelectMessageLevel(mf);
123
  return cm::make_unique<cmInstallFilesGenerator>(
124
125
126
    absFiles, destination, programs, args.GetPermissions(),
    args.GetConfigurations(), args.GetComponent(), message,
    args.GetExcludeFromAll(), args.GetRename(), args.GetOptional());
Alexander Neundorf's avatar
   
Alexander Neundorf committed
127
128
}

129
std::unique_ptr<cmInstallFilesGenerator> CreateInstallFilesGenerator(
130
131
132
133
134
135
136
  cmMakefile* mf, const std::vector<std::string>& absFiles,
  const cmInstallCommandArguments& args, bool programs)
{
  return CreateInstallFilesGenerator(mf, absFiles, args, programs,
                                     args.GetDestination());
}

137
std::set<std::string> const allowedTypes{
138
139
140
141
142
  "BIN",         "SBIN",       "LIB",      "INCLUDE", "SYSCONF",
  "SHAREDSTATE", "LOCALSTATE", "RUNSTATE", "DATA",    "INFO",
  "LOCALE",      "MAN",        "DOC",
};

143
144
bool HandleScriptMode(std::vector<std::string> const& args,
                      cmExecutionStatus& status)
145
{
146
  Helper helper(status);
147

148
  std::string component = helper.DefaultComponentName;
149
  int componentCount = 0;
150
  bool doing_script = false;
151
  bool doing_code = false;
152
  bool exclude_from_all = false;
153
154
155

  // Scan the args once for COMPONENT. Only allow one.
  //
156
157
158
159
160
161
162
  for (size_t i = 0; i < args.size(); ++i) {
    if (args[i] == "COMPONENT" && i + 1 < args.size()) {
      ++componentCount;
      ++i;
      component = args[i];
    }
    if (args[i] == "EXCLUDE_FROM_ALL") {
163
      exclude_from_all = true;
164
    }
165
  }
166

167
  if (componentCount > 1) {
168
169
170
    status.SetError("given more than one COMPONENT for the SCRIPT or CODE "
                    "signature of the INSTALL command. "
                    "Use multiple INSTALL commands with one COMPONENT each.");
171
    return false;
172
  }
173
174
175
176

  // Scan the args again, this time adding install generators each time we
  // encounter a SCRIPT or CODE arg:
  //
177
178
  for (std::string const& arg : args) {
    if (arg == "SCRIPT") {
179
      doing_script = true;
180
      doing_code = false;
181
    } else if (arg == "CODE") {
182
183
      doing_script = false;
      doing_code = true;
184
    } else if (arg == "COMPONENT") {
185
186
      doing_script = false;
      doing_code = false;
187
    } else if (doing_script) {
188
      doing_script = false;
189
      std::string script = arg;
190
      if (!cmSystemTools::FileIsFullPath(script)) {
191
        script =
192
          cmStrCat(helper.Makefile->GetCurrentSourceDirectory(), '/', arg);
193
194
      }
      if (cmSystemTools::FileIsDirectory(script)) {
195
        status.SetError("given a directory as value of SCRIPT argument.");
196
197
        return false;
      }
198
      helper.Makefile->AddInstallGenerator(
199
200
        cm::make_unique<cmInstallScriptGenerator>(script, false, component,
                                                  exclude_from_all));
201
    } else if (doing_code) {
202
      doing_code = false;
203
      std::string const& code = arg;
204
      helper.Makefile->AddInstallGenerator(
205
206
        cm::make_unique<cmInstallScriptGenerator>(code, true, component,
                                                  exclude_from_all));
207
    }
208
  }
209

210
  if (doing_script) {
211
    status.SetError("given no value for SCRIPT argument.");
212
    return false;
213
214
  }
  if (doing_code) {
215
    status.SetError("given no value for CODE argument.");
216
    return false;
217
  }
218

219
220
  // Tell the global generator about any installation component names
  // specified.
221
  helper.Makefile->GetGlobalGenerator()->AddInstallComponent(component);
222

223
224
225
  return true;
}

226
227
bool HandleTargetsMode(std::vector<std::string> const& args,
                       cmExecutionStatus& status)
228
{
229
230
  Helper helper(status);

231
232
  // This is the TARGETS mode.
  std::vector<cmTarget*> targets;
Alexander Neundorf's avatar
   
Alexander Neundorf committed
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
  struct ArgVectors
  {
    std::vector<std::string> Archive;
    std::vector<std::string> Library;
    std::vector<std::string> Runtime;
    std::vector<std::string> Object;
    std::vector<std::string> Framework;
    std::vector<std::string> Bundle;
    std::vector<std::string> Includes;
    std::vector<std::string> PrivateHeader;
    std::vector<std::string> PublicHeader;
    std::vector<std::string> Resource;
  };

  static auto const argHelper =
    cmArgumentParser<ArgVectors>{}
      .Bind("ARCHIVE"_s, &ArgVectors::Archive)
      .Bind("LIBRARY"_s, &ArgVectors::Library)
      .Bind("RUNTIME"_s, &ArgVectors::Runtime)
      .Bind("OBJECTS"_s, &ArgVectors::Object)
      .Bind("FRAMEWORK"_s, &ArgVectors::Framework)
      .Bind("BUNDLE"_s, &ArgVectors::Bundle)
      .Bind("INCLUDES"_s, &ArgVectors::Includes)
      .Bind("PRIVATE_HEADER"_s, &ArgVectors::PrivateHeader)
      .Bind("PUBLIC_HEADER"_s, &ArgVectors::PublicHeader)
      .Bind("RESOURCE"_s, &ArgVectors::Resource);

  std::vector<std::string> genericArgVector;
  ArgVectors const argVectors = argHelper.Parse(args, &genericArgVector);
Alexander Neundorf's avatar
   
Alexander Neundorf committed
263

Alexander Neundorf's avatar
Alexander Neundorf committed
264
265
266
  // now parse the generic args (i.e. the ones not specialized on LIBRARY/
  // ARCHIVE, RUNTIME etc. (see above)
  // These generic args also contain the targets and the export stuff
267
268
  std::vector<std::string> targetList;
  std::string exports;
Alexander Neundorf's avatar
   
Alexander Neundorf committed
269
  std::vector<std::string> unknownArgs;
270
  cmInstallCommandArguments genericArgs(helper.DefaultComponentName);
271
272
273
  genericArgs.Bind("TARGETS"_s, targetList);
  genericArgs.Bind("EXPORT"_s, exports);
  genericArgs.Parse(genericArgVector, &unknownArgs);
274
  bool success = genericArgs.Finalize();
Alexander Neundorf's avatar
   
Alexander Neundorf committed
275

276
277
278
279
280
281
282
283
284
  cmInstallCommandArguments archiveArgs(helper.DefaultComponentName);
  cmInstallCommandArguments libraryArgs(helper.DefaultComponentName);
  cmInstallCommandArguments runtimeArgs(helper.DefaultComponentName);
  cmInstallCommandArguments objectArgs(helper.DefaultComponentName);
  cmInstallCommandArguments frameworkArgs(helper.DefaultComponentName);
  cmInstallCommandArguments bundleArgs(helper.DefaultComponentName);
  cmInstallCommandArguments privateHeaderArgs(helper.DefaultComponentName);
  cmInstallCommandArguments publicHeaderArgs(helper.DefaultComponentName);
  cmInstallCommandArguments resourceArgs(helper.DefaultComponentName);
285
  cmInstallCommandIncludesArgument includesArgs;
Alexander Neundorf's avatar
   
Alexander Neundorf committed
286

287
  // now parse the args for specific parts of the target (e.g. LIBRARY,
Alexander Neundorf's avatar
Alexander Neundorf committed
288
  // RUNTIME, ARCHIVE etc.
289
290
291
292
293
294
295
296
297
298
  archiveArgs.Parse(argVectors.Archive, &unknownArgs);
  libraryArgs.Parse(argVectors.Library, &unknownArgs);
  runtimeArgs.Parse(argVectors.Runtime, &unknownArgs);
  objectArgs.Parse(argVectors.Object, &unknownArgs);
  frameworkArgs.Parse(argVectors.Framework, &unknownArgs);
  bundleArgs.Parse(argVectors.Bundle, &unknownArgs);
  privateHeaderArgs.Parse(argVectors.PrivateHeader, &unknownArgs);
  publicHeaderArgs.Parse(argVectors.PublicHeader, &unknownArgs);
  resourceArgs.Parse(argVectors.Resource, &unknownArgs);
  includesArgs.Parse(&argVectors.Includes, &unknownArgs);
Alexander Neundorf's avatar
   
Alexander Neundorf committed
299

300
  if (!unknownArgs.empty()) {
Alexander Neundorf's avatar
   
Alexander Neundorf committed
301
    // Unknown argument.
302
    status.SetError(
303
      cmStrCat("TARGETS given unknown argument \"", unknownArgs[0], "\"."));
Alexander Neundorf's avatar
   
Alexander Neundorf committed
304
    return false;
305
  }
Alexander Neundorf's avatar
   
Alexander Neundorf committed
306
307
308
309
310

  // apply generic args
  archiveArgs.SetGenericArguments(&genericArgs);
  libraryArgs.SetGenericArguments(&genericArgs);
  runtimeArgs.SetGenericArguments(&genericArgs);
311
  objectArgs.SetGenericArguments(&genericArgs);
Alexander Neundorf's avatar
   
Alexander Neundorf committed
312
313
314
  frameworkArgs.SetGenericArguments(&genericArgs);
  bundleArgs.SetGenericArguments(&genericArgs);
  privateHeaderArgs.SetGenericArguments(&genericArgs);
315
316
  publicHeaderArgs.SetGenericArguments(&genericArgs);
  resourceArgs.SetGenericArguments(&genericArgs);
Alexander Neundorf's avatar
   
Alexander Neundorf committed
317

318
  success = success && archiveArgs.Finalize();
Alexander Neundorf's avatar
   
Alexander Neundorf committed
319
320
  success = success && libraryArgs.Finalize();
  success = success && runtimeArgs.Finalize();
321
  success = success && objectArgs.Finalize();
Alexander Neundorf's avatar
   
Alexander Neundorf committed
322
323
324
  success = success && frameworkArgs.Finalize();
  success = success && bundleArgs.Finalize();
  success = success && privateHeaderArgs.Finalize();
325
326
  success = success && publicHeaderArgs.Finalize();
  success = success && resourceArgs.Finalize();
Alexander Neundorf's avatar
   
Alexander Neundorf committed
327

328
  if (!success) {
Alexander Neundorf's avatar
   
Alexander Neundorf committed
329
    return false;
330
  }
Alexander Neundorf's avatar
   
Alexander Neundorf committed
331

332
333
  // Enforce argument rules too complex to specify for the
  // general-purpose parser.
334
  if (archiveArgs.GetNamelinkOnly() || runtimeArgs.GetNamelinkOnly() ||
335
336
      objectArgs.GetNamelinkOnly() || frameworkArgs.GetNamelinkOnly() ||
      bundleArgs.GetNamelinkOnly() || privateHeaderArgs.GetNamelinkOnly() ||
337
      publicHeaderArgs.GetNamelinkOnly() || resourceArgs.GetNamelinkOnly()) {
338
    status.SetError(
339
      "TARGETS given NAMELINK_ONLY option not in LIBRARY group.  "
340
      "The NAMELINK_ONLY option may be specified only following LIBRARY.");
341
    return false;
342
343
  }
  if (archiveArgs.GetNamelinkSkip() || runtimeArgs.GetNamelinkSkip() ||
344
345
      objectArgs.GetNamelinkSkip() || frameworkArgs.GetNamelinkSkip() ||
      bundleArgs.GetNamelinkSkip() || privateHeaderArgs.GetNamelinkSkip() ||
346
      publicHeaderArgs.GetNamelinkSkip() || resourceArgs.GetNamelinkSkip()) {
347
    status.SetError(
348
      "TARGETS given NAMELINK_SKIP option not in LIBRARY group.  "
349
      "The NAMELINK_SKIP option may be specified only following LIBRARY.");
350
    return false;
351
  }
352
353
354
355
356
357
358
359
  if (archiveArgs.HasNamelinkComponent() ||
      runtimeArgs.HasNamelinkComponent() ||
      objectArgs.HasNamelinkComponent() ||
      frameworkArgs.HasNamelinkComponent() ||
      bundleArgs.HasNamelinkComponent() ||
      privateHeaderArgs.HasNamelinkComponent() ||
      publicHeaderArgs.HasNamelinkComponent() ||
      resourceArgs.HasNamelinkComponent()) {
360
    status.SetError(
361
362
363
364
365
      "TARGETS given NAMELINK_COMPONENT option not in LIBRARY group.  "
      "The NAMELINK_COMPONENT option may be specified only following "
      "LIBRARY.");
    return false;
  }
366
  if (libraryArgs.GetNamelinkOnly() && libraryArgs.GetNamelinkSkip()) {
367
368
    status.SetError("TARGETS given NAMELINK_ONLY and NAMELINK_SKIP.  "
                    "At most one of these two options may be specified.");
369
    return false;
370
  }
371
372
373
374
375
  if (!genericArgs.GetType().empty() || !archiveArgs.GetType().empty() ||
      !libraryArgs.GetType().empty() || !runtimeArgs.GetType().empty() ||
      !objectArgs.GetType().empty() || !frameworkArgs.GetType().empty() ||
      !bundleArgs.GetType().empty() || !privateHeaderArgs.GetType().empty() ||
      !publicHeaderArgs.GetType().empty() || !resourceArgs.GetType().empty()) {
376
    status.SetError(
377
378
      "TARGETS given TYPE option. The TYPE option may only be specified in "
      " install(FILES) and install(DIRECTORIES).");
379
380
    return false;
  }
381
382

  // Select the mode for installing symlinks to versioned shared libraries.
383
384
385
  cmInstallTargetGenerator::NamelinkModeType namelinkMode =
    cmInstallTargetGenerator::NamelinkModeNone;
  if (libraryArgs.GetNamelinkOnly()) {
386
    namelinkMode = cmInstallTargetGenerator::NamelinkModeOnly;
387
  } else if (libraryArgs.GetNamelinkSkip()) {
388
    namelinkMode = cmInstallTargetGenerator::NamelinkModeSkip;
389
  }
390

Alexander Neundorf's avatar
   
Alexander Neundorf committed
391
  // Check if there is something to do.
392
  if (targetList.empty()) {
Alexander Neundorf's avatar
   
Alexander Neundorf committed
393
    return true;
394
  }
Alexander Neundorf's avatar
   
Alexander Neundorf committed
395

396
  for (std::string const& tgt : targetList) {
397

398
399
    if (helper.Makefile->IsAlias(tgt)) {
      status.SetError(
400
        cmStrCat("TARGETS given target \"", tgt, "\" which is an alias."));
401
      return false;
402
    }
403
    // Lookup this target in the current directory.
404
    cmTarget* target = helper.Makefile->FindLocalNonAliasTarget(tgt);
405
406
    if (!target) {
      // If no local target has been found, find it in the global scope.
407
      cmTarget* const global_target =
408
        helper.Makefile->GetGlobalGenerator()->FindTarget(tgt, true);
409
410
411
      if (global_target && !global_target->IsImported()) {
        target = global_target;
      }
412
413
    }
    if (target) {
414
      // Found the target.  Check its type.
415
416
417
418
419
420
      if (target->GetType() != cmStateEnums::EXECUTABLE &&
          target->GetType() != cmStateEnums::STATIC_LIBRARY &&
          target->GetType() != cmStateEnums::SHARED_LIBRARY &&
          target->GetType() != cmStateEnums::MODULE_LIBRARY &&
          target->GetType() != cmStateEnums::OBJECT_LIBRARY &&
          target->GetType() != cmStateEnums::INTERFACE_LIBRARY) {
421
        status.SetError(
422
423
          cmStrCat("TARGETS given target \"", tgt,
                   "\" which is not an executable, library, or module."));
424
        return false;
Daniel Pfeifer's avatar
Daniel Pfeifer committed
425
      }
426
427
      // Store the target in the list to be installed.
      targets.push_back(target);
428
    } else {
429
      // Did not find the target.
430
      status.SetError(
431
        cmStrCat("TARGETS given target \"", tgt, "\" which does not exist."));
432
      return false;
433
    }
434
  }
435

436
437
438
439
  // Keep track of whether we will be performing an installation of
  // any files of the given type.
  bool installsArchive = false;
  bool installsLibrary = false;
440
  bool installsNamelink = false;
441
  bool installsRuntime = false;
442
  bool installsObject = false;
443
444
445
446
447
448
  bool installsFramework = false;
  bool installsBundle = false;
  bool installsPrivateHeader = false;
  bool installsPublicHeader = false;
  bool installsResource = false;

449
  // Generate install script code to install the given targets.
450
  for (cmTarget* ti : targets) {
451
    // Handle each target type.
452
    cmTarget& target = *ti;
453
454
455
456
457
458
459
460
461
462
    std::unique_ptr<cmInstallTargetGenerator> archiveGenerator;
    std::unique_ptr<cmInstallTargetGenerator> libraryGenerator;
    std::unique_ptr<cmInstallTargetGenerator> namelinkGenerator;
    std::unique_ptr<cmInstallTargetGenerator> runtimeGenerator;
    std::unique_ptr<cmInstallTargetGenerator> objectGenerator;
    std::unique_ptr<cmInstallTargetGenerator> frameworkGenerator;
    std::unique_ptr<cmInstallTargetGenerator> bundleGenerator;
    std::unique_ptr<cmInstallFilesGenerator> privateHeaderGenerator;
    std::unique_ptr<cmInstallFilesGenerator> publicHeaderGenerator;
    std::unique_ptr<cmInstallFilesGenerator> resourceGenerator;
Alexander Neundorf's avatar
   
Alexander Neundorf committed
463

464
465
466
467
    // Avoid selecting default destinations for PUBLIC_HEADER and
    // PRIVATE_HEADER if any artifacts are specified.
    bool artifactsSpecified = false;

468
469
470
    // Track whether this is a namelink-only rule.
    bool namelinkOnly = false;

471
    switch (target.GetType()) {
472
      case cmStateEnums::SHARED_LIBRARY: {
473
        // Shared libraries are handled differently on DLL and non-DLL
474
        // platforms.  All windows platforms are DLL platforms including
Alexander Neundorf's avatar
   
Alexander Neundorf committed
475
        // cygwin.  Currently no other platform is a DLL platform.
476
        if (target.IsDLLPlatform()) {
477
          // When in namelink only mode skip all libraries on Windows.
478
          if (namelinkMode == cmInstallTargetGenerator::NamelinkModeOnly) {
479
            continue;
480
          }
481

482
          // This is a DLL platform.
483
          if (!archiveArgs.GetDestination().empty()) {
484
            // The import library uses the ARCHIVE properties.
485
            archiveGenerator = CreateInstallTargetGenerator(
486
              target, archiveArgs, true, helper.Makefile->GetBacktrace());
487
            artifactsSpecified = true;
488
489
          }
          if (!runtimeArgs.GetDestination().empty()) {
490
            // The DLL uses the RUNTIME properties.
491
            runtimeGenerator = CreateInstallTargetGenerator(
492
              target, runtimeArgs, false, helper.Makefile->GetBacktrace());
493
            artifactsSpecified = true;
494
          }
495
          if (!archiveGenerator && !runtimeGenerator) {
496
            archiveGenerator = CreateInstallTargetGenerator(
497
498
              target, archiveArgs, true, helper.Makefile->GetBacktrace(),
              helper.GetArchiveDestination(nullptr));
499
            runtimeGenerator = CreateInstallTargetGenerator(
500
501
              target, runtimeArgs, false, helper.Makefile->GetBacktrace(),
              helper.GetRuntimeDestination(nullptr));
502
          }
503
        } else {
504
          // This is a non-DLL platform.
505
506
          // If it is marked with FRAMEWORK property use the FRAMEWORK set of
          // INSTALL properties. Otherwise, use the LIBRARY properties.
507
          if (target.IsFrameworkOnApple()) {
508
            // When in namelink only mode skip frameworks.
509
            if (namelinkMode == cmInstallTargetGenerator::NamelinkModeOnly) {
510
              continue;
511
            }
512

Alexander Neundorf's avatar
   
Alexander Neundorf committed
513
            // Use the FRAMEWORK properties.
514
            if (!frameworkArgs.GetDestination().empty()) {
515
              frameworkGenerator = CreateInstallTargetGenerator(
516
                target, frameworkArgs, false, helper.Makefile->GetBacktrace());
517
            } else {
518
              status.SetError(
519
520
521
                cmStrCat("TARGETS given no FRAMEWORK DESTINATION for shared "
                         "library FRAMEWORK target \"",
                         target.GetName(), "\"."));
522
              return false;
523
            }
524
          } else {
Alexander Neundorf's avatar
   
Alexander Neundorf committed
525
            // The shared library uses the LIBRARY properties.
526
527
528
            if (!libraryArgs.GetDestination().empty()) {
              artifactsSpecified = true;
            }
529
530
            if (namelinkMode != cmInstallTargetGenerator::NamelinkModeOnly) {
              libraryGenerator = CreateInstallTargetGenerator(
531
532
                target, libraryArgs, false, helper.Makefile->GetBacktrace(),
                helper.GetLibraryDestination(&libraryArgs));
533
534
535
536
537
              libraryGenerator->SetNamelinkMode(
                cmInstallTargetGenerator::NamelinkModeSkip);
            }
            if (namelinkMode != cmInstallTargetGenerator::NamelinkModeSkip) {
              namelinkGenerator = CreateInstallTargetGenerator(
538
539
                target, libraryArgs, false, helper.Makefile->GetBacktrace(),
                helper.GetLibraryDestination(&libraryArgs), false, true);
540
541
              namelinkGenerator->SetNamelinkMode(
                cmInstallTargetGenerator::NamelinkModeOnly);
542
            }
543
544
            namelinkOnly =
              (namelinkMode == cmInstallTargetGenerator::NamelinkModeOnly);
545
          }
546
        }
547
      } break;
548
      case cmStateEnums::STATIC_LIBRARY: {
549
550
551
552
553
554
555
556
557
558
        // If it is marked with FRAMEWORK property use the FRAMEWORK set of
        // INSTALL properties. Otherwise, use the LIBRARY properties.
        if (target.IsFrameworkOnApple()) {
          // When in namelink only mode skip frameworks.
          if (namelinkMode == cmInstallTargetGenerator::NamelinkModeOnly) {
            continue;
          }

          // Use the FRAMEWORK properties.
          if (!frameworkArgs.GetDestination().empty()) {
559
            frameworkGenerator = CreateInstallTargetGenerator(
560
              target, frameworkArgs, false, helper.Makefile->GetBacktrace());
561
          } else {
562
            status.SetError(
563
564
565
              cmStrCat("TARGETS given no FRAMEWORK DESTINATION for static "
                       "library FRAMEWORK target \"",
                       target.GetName(), "\"."));
566
567
            return false;
          }
568
        } else {
569
          // Static libraries use ARCHIVE properties.
570
571
572
          if (!archiveArgs.GetDestination().empty()) {
            artifactsSpecified = true;
          }
573
          archiveGenerator = CreateInstallTargetGenerator(
574
575
            target, archiveArgs, false, helper.Makefile->GetBacktrace(),
            helper.GetArchiveDestination(&archiveArgs));
576
        }
577
      } break;
578
      case cmStateEnums::MODULE_LIBRARY: {
579
        // Modules use LIBRARY properties.
580
        if (!libraryArgs.GetDestination().empty()) {
581
          libraryGenerator = CreateInstallTargetGenerator(
582
            target, libraryArgs, false, helper.Makefile->GetBacktrace());
583
          libraryGenerator->SetNamelinkMode(namelinkMode);
584
585
          namelinkOnly =
            (namelinkMode == cmInstallTargetGenerator::NamelinkModeOnly);
586
        } else {
587
          status.SetError(
588
589
590
            cmStrCat("TARGETS given no LIBRARY DESTINATION for module "
                     "target \"",
                     target.GetName(), "\"."));
591
592
          return false;
        }
593
      } break;
594
595
596
      case cmStateEnums::OBJECT_LIBRARY: {
        // Objects use OBJECT properties.
        if (!objectArgs.GetDestination().empty()) {
597
598
          // Verify that we know where the objects are to install them.
          std::string reason;
599
          if (!helper.Makefile->GetGlobalGenerator()
600
                 ->HasKnownObjectFileLocation(&reason)) {
601
            status.SetError(
602
603
              cmStrCat("TARGETS given OBJECT library \"", target.GetName(),
                       "\" whose objects may not be installed", reason, "."));
604
605
606
            return false;
          }

607
          objectGenerator = CreateInstallTargetGenerator(
608
            target, objectArgs, false, helper.Makefile->GetBacktrace());
609
        } else {
610
611
612
          // Installing an OBJECT library without a destination transforms
          // it to an INTERFACE library.  It installs no files but can be
          // exported.
613
614
        }
      } break;
615
      case cmStateEnums::EXECUTABLE: {
616
        if (target.IsAppBundleOnApple()) {
617
          // Application bundles use the BUNDLE properties.
618
          if (!bundleArgs.GetDestination().empty()) {
619
            bundleGenerator = CreateInstallTargetGenerator(
620
              target, bundleArgs, false, helper.Makefile->GetBacktrace());
621
          } else if (!runtimeArgs.GetDestination().empty()) {
622
            bool failure = false;
623
            if (helper.CheckCMP0006(failure)) {
624
625
              // For CMake 2.4 compatibility fallback to the RUNTIME
              // properties.
626
              bundleGenerator = CreateInstallTargetGenerator(
627
                target, runtimeArgs, false, helper.Makefile->GetBacktrace());
628
            } else if (failure) {
629
630
              return false;
            }
631
632
          }
          if (!bundleGenerator) {
633
634
635
            status.SetError(cmStrCat("TARGETS given no BUNDLE DESTINATION for "
                                     "MACOSX_BUNDLE executable target \"",
                                     target.GetName(), "\"."));
636
            return false;
637
          }
638
        } else {
639
          // Executables use the RUNTIME properties.
640
641
642
          if (!runtimeArgs.GetDestination().empty()) {
            artifactsSpecified = true;
          }
643
          runtimeGenerator = CreateInstallTargetGenerator(
644
645
            target, runtimeArgs, false, helper.Makefile->GetBacktrace(),
            helper.GetRuntimeDestination(&runtimeArgs));
646
        }
647
648
649
650

        // On DLL platforms an executable may also have an import
        // library.  Install it to the archive destination if it
        // exists.
651
652
        if ((target.IsDLLPlatform() || target.IsAIX()) &&
            !archiveArgs.GetDestination().empty() &&
653
            target.IsExecutableWithExports()) {
654
          // The import library uses the ARCHIVE properties.
655
          artifactsSpecified = true;
656
          archiveGenerator = CreateInstallTargetGenerator(
657
            target, archiveArgs, true, helper.Makefile->GetBacktrace(), true);
658
        }
659
      } break;
660
      case cmStateEnums::INTERFACE_LIBRARY:
661
662
663
        // Nothing to do. An INTERFACE_LIBRARY can be installed, but the
        // only effect of that is to make it exportable. It installs no
        // other files itself.
664
        break;
665
666
667
668
      default:
        // This should never happen due to the above type check.
        // Ignore the case.
        break;
669
    }
Alexander Neundorf's avatar
   
Alexander Neundorf committed
670

671
672
673
674
675
    // These well-known sets of files are installed *automatically* for
    // FRAMEWORK SHARED library targets on the Mac as part of installing the
    // FRAMEWORK.  For other target types or on other platforms, they are not
    // installed automatically and so we need to create install files
    // generators for them.
676
    bool createInstallGeneratorsForTargetFileSets = true;
Alexander Neundorf's avatar
   
Alexander Neundorf committed
677

678
    if (target.IsFrameworkOnApple()) {
679
      createInstallGeneratorsForTargetFileSets = false;
680
    }
Alexander Neundorf's avatar
   
Alexander Neundorf committed
681

682
    if (createInstallGeneratorsForTargetFileSets && !namelinkOnly) {
683
      const char* files = target.GetProperty("PRIVATE_HEADER");
684
      if ((files) && (*files)) {
685
        std::vector<std::string> relFiles = cmExpandedList(files);
686
        std::vector<std::string> absFiles;
687
        if (!helper.MakeFilesFullPath("PRIVATE_HEADER", relFiles, absFiles)) {
688
          return false;
689
        }
Alexander Neundorf's avatar
   
Alexander Neundorf committed
690

691
        // Create the files install generator.
692
693
694
695
696
697
698
699
700
701
702
        if (!artifactsSpecified ||
            !privateHeaderArgs.GetDestination().empty()) {
          privateHeaderGenerator = CreateInstallFilesGenerator(
            helper.Makefile, absFiles, privateHeaderArgs, false,
            helper.GetIncludeDestination(&privateHeaderArgs));
        } else {
          std::ostringstream e;
          e << "INSTALL TARGETS - target " << target.GetName() << " has "
            << "PRIVATE_HEADER files but no PRIVATE_HEADER DESTINATION.";
          cmSystemTools::Message(e.str(), "Warning");
        }
703
      }
704

705
      files = target.GetProperty("PUBLIC_HEADER");
706
      if ((files) && (*files)) {
707
        std::vector<std::string> relFiles = cmExpandedList(files);
708
        std::vector<std::string> absFiles;
709
        if (!helper.MakeFilesFullPath("PUBLIC_HEADER", relFiles, absFiles)) {
710
          return false;
711
        }
712

713
        // Create the files install generator.
714
715
716
717
718
719
720
721
722
723
724
        if (!artifactsSpecified ||
            !publicHeaderArgs.GetDestination().empty()) {
          publicHeaderGenerator = CreateInstallFilesGenerator(
            helper.Makefile, absFiles, publicHeaderArgs, false,
            helper.GetIncludeDestination(&publicHeaderArgs));
        } else {
          std::ostringstream e;
          e << "INSTALL TARGETS - target " << target.GetName() << " has "
            << "PUBLIC_HEADER files but no PUBLIC_HEADER DESTINATION.";
          cmSystemTools::Message(e.str(), "Warning");
        }
725
      }
726
727

      files = target.GetProperty("RESOURCE");
728
      if ((files) && (*files)) {
729
        std::vector<std::string> relFiles = cmExpandedList(files);
730
        std::vector<std::string> absFiles;
731
        if (!helper.MakeFilesFullPath("RESOURCE", relFiles, absFiles)) {
732
          return false;
733
        }
734
735

        // Create the files install generator.
736
        if (!resourceArgs.GetDestination().empty()) {
737
          resourceGenerator = CreateInstallFilesGenerator(
738
            helper.Makefile, absFiles, resourceArgs, false);
739
        } else {
740
741
742
743
          cmSystemTools::Message(
            cmStrCat("INSTALL TARGETS - target ", target.GetName(),
                     " has RESOURCE files but no RESOURCE DESTINATION."),
            "Warning");
744
        }
Alexander Neundorf's avatar
   
Alexander Neundorf committed
745
      }
746
    }
Alexander Neundorf's avatar
   
Alexander Neundorf committed
747

748
749
    // Add this install rule to an export if one was specified and
    // this is not a namelink-only rule.
750
    if (!exports.empty() && !namelinkOnly) {
751
      auto te = cm::make_unique<cmTargetExport>();
752
      te->TargetName = target.GetName();
753
754
755
756
757
758
759
      te->ArchiveGenerator = archiveGenerator.get();
      te->BundleGenerator = bundleGenerator.get();
      te->FrameworkGenerator = frameworkGenerator.get();
      te->HeaderGenerator = publicHeaderGenerator.get();
      te->LibraryGenerator = libraryGenerator.get();
      te->RuntimeGenerator = runtimeGenerator.get();
      te->ObjectsGenerator = objectGenerator.get();
760
      te->InterfaceIncludeDirectories =
761
        cmJoin(includesArgs.GetIncludeDirs(), ";");
762

763
      helper.Makefile->GetGlobalGenerator()
764
765
        ->GetExportSets()[exports]
        .AddTargetExport(std::move(te));
766
    }
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789

    // Keep track of whether we're installing anything in each category
    installsArchive = installsArchive || archiveGenerator;
    installsLibrary = installsLibrary || libraryGenerator;
    installsNamelink = installsNamelink || namelinkGenerator;
    installsRuntime = installsRuntime || runtimeGenerator;
    installsObject = installsObject || objectGenerator;
    installsFramework = installsFramework || frameworkGenerator;
    installsBundle = installsBundle || bundleGenerator;
    installsPrivateHeader = installsPrivateHeader || privateHeaderGenerator;
    installsPublicHeader = installsPublicHeader || publicHeaderGenerator;
    installsResource = installsResource || resourceGenerator;

    helper.Makefile->AddInstallGenerator(std::move(archiveGenerator));
    helper.Makefile->AddInstallGenerator(std::move(libraryGenerator));
    helper.Makefile->AddInstallGenerator(std::move(namelinkGenerator));
    helper.Makefile->AddInstallGenerator(std::move(runtimeGenerator));
    helper.Makefile->AddInstallGenerator(std::move(objectGenerator));
    helper.Makefile->AddInstallGenerator(std::move(frameworkGenerator));
    helper.Makefile->AddInstallGenerator(std::move(bundleGenerator));
    helper.Makefile->AddInstallGenerator(std::move(privateHeaderGenerator));
    helper.Makefile->AddInstallGenerator(std::move(publicHeaderGenerator));
    helper.Makefile->AddInstallGenerator(std::move(resourceGenerator));
790
  }
791

792
793
  // Tell the global generator about any installation component names
  // specified
794
  if (installsArchive) {
795
    helper.Makefile->GetGlobalGenerator()->AddInstallComponent(
796
      archiveArgs.GetComponent());
797
798
  }
  if (installsLibrary) {
799
    helper.Makefile->GetGlobalGenerator()->AddInstallComponent(
800
      libraryArgs.GetComponent());
801
  }
802
  if (installsNamelink) {
803
    helper.Makefile->GetGlobalGenerator()->AddInstallComponent(
804
      libraryArgs.GetNamelinkComponent());
805
  }
806
  if (installsRuntime) {
807
    helper.Makefile->GetGlobalGenerator()->AddInstallComponent(
808
      runtimeArgs.GetComponent());