cmInstallTargetGenerator.cxx 28 KB
Newer Older
1
2
3
/*============================================================================
  CMake - Cross Platform Makefile Generator
  Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
4

5
6
  Distributed under the OSI-approved BSD License (the "License");
  see accompanying file Copyright.txt for details.
7

8
9
10
11
  This software is distributed WITHOUT ANY WARRANTY; without even the
  implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  See the License for more information.
============================================================================*/
12
13
#include "cmInstallTargetGenerator.h"

14
#include "cmComputeLinkInformation.h"
15
#include "cmGeneratorExpression.h"
16
17
#include "cmGlobalGenerator.h"
#include "cmLocalGenerator.h"
18
#include "cmMakefile.h"
19
#include "cmGeneratorTarget.h"
20
#include "cmake.h"
21
#include "cmGeneratorTarget.h"
22

23
24
#include <assert.h>

25
26
//----------------------------------------------------------------------------
cmInstallTargetGenerator
27
28
::cmInstallTargetGenerator(const std::string& targetName,
                           const char* dest, bool implib,
29
                           const char* file_permissions,
30
                           std::vector<std::string> const& configurations,
31
32
33
                           const char* component,
                           MessageLevel message,
                           bool optional):
34
35
36
  cmInstallGenerator(dest, configurations, component, message),
  TargetName(targetName),
  Target(0),
37
38
39
  FilePermissions(file_permissions),
  ImportLibrary(implib),
  Optional(optional)
40
{
41
  this->ActionsPerConfig = true;
42
  this->NamelinkMode = NamelinkModeNone;
43
44
45
46
47
48
49
50
51
52
53
}

//----------------------------------------------------------------------------
cmInstallTargetGenerator
::~cmInstallTargetGenerator()
{
}

//----------------------------------------------------------------------------
void cmInstallTargetGenerator::GenerateScript(std::ostream& os)
{
54
55
56
  // Warn if installing an exclude-from-all target.
  if(this->Target->GetPropertyAsBool("EXCLUDE_FROM_ALL"))
    {
57
    std::ostringstream msg;
58
59
60
61
62
63
64
    msg << "WARNING: Target \"" << this->Target->GetName()
        << "\" has EXCLUDE_FROM_ALL set and will not be built by default "
        << "but an install rule has been provided for it.  CMake does "
        << "not define behavior for this case.";
    cmSystemTools::Message(msg.str().c_str(), "Warning");
    }

65
66
67
68
  // Perform the main install script generation.
  this->cmInstallGenerator::GenerateScript(os);
}

69
70
//----------------------------------------------------------------------------
void cmInstallTargetGenerator::GenerateScriptForConfig(std::ostream& os,
71
72
                                                    const std::string& config,
                                                    Indent const& indent)
73
{
74
75
  // Compute the build tree directory from which to copy the target.
  std::string fromDirConfig;
76
  if(this->Target->NeedRelinkBeforeInstall(config))
77
    {
78
    fromDirConfig =
79
        this->Target->GetLocalGenerator()->GetCurrentBinaryDirectory();
80
81
82
83
84
    fromDirConfig += cmake::GetCMakeFilesDirectory();
    fromDirConfig += "/CMakeRelink.dir/";
    }
  else
    {
85
    fromDirConfig =
86
        this->Target->GetDirectory(config, this->ImportLibrary);
87
88
    fromDirConfig += "/";
    }
89
  std::string toDir =
90
    this->ConvertToAbsoluteDestination(this->GetDestination(config));
91
  toDir += "/";
92

93
  // Compute the list of files to install for this target.
94
95
  std::vector<std::string> filesFrom;
  std::vector<std::string> filesTo;
96
  std::string literal_args;
Stephen Kelly's avatar
Stephen Kelly committed
97
  cmState::TargetType targetType = this->Target->GetType();
98
99
100
  cmInstallType type = cmInstallType();
  switch(targetType)
    {
101
102
103
104
105
    case cmState::EXECUTABLE: type = cmInstallType_EXECUTABLE; break;
    case cmState::STATIC_LIBRARY: type = cmInstallType_STATIC_LIBRARY; break;
    case cmState::SHARED_LIBRARY: type = cmInstallType_SHARED_LIBRARY; break;
    case cmState::MODULE_LIBRARY: type = cmInstallType_MODULE_LIBRARY; break;
    case cmState::INTERFACE_LIBRARY:
106
107
      // Not reachable. We never create a cmInstallTargetGenerator for
      // an INTERFACE_LIBRARY.
108
      assert(0 && "INTERFACE_LIBRARY targets have no installable outputs.");
109
      break;
110
111
112
113
    case cmState::OBJECT_LIBRARY:
    case cmState::UTILITY:
    case cmState::GLOBAL_TARGET:
    case cmState::UNKNOWN_LIBRARY:
114
      this->Target->GetLocalGenerator()->IssueMessage(cmake::INTERNAL_ERROR,
115
116
117
        "cmInstallTargetGenerator created with non-installable target.");
      return;
    }
118
  if(targetType == cmState::EXECUTABLE)
119
    {
120
121
122
    // There is a bug in cmInstallCommand if this fails.
    assert(this->NamelinkMode == NamelinkModeNone);

123
124
125
126
    std::string targetName;
    std::string targetNameReal;
    std::string targetNameImport;
    std::string targetNamePDB;
127
    this->Target->GetExecutableNames(targetName, targetNameReal,
128
129
130
131
                                     targetNameImport, targetNamePDB,
                                     config);
    if(this->ImportLibrary)
      {
132
133
134
135
      std::string from1 = fromDirConfig + targetNameImport;
      std::string to1 = toDir + targetNameImport;
      filesFrom.push_back(from1);
      filesTo.push_back(to1);
136
      std::string targetNameImportLib;
137
      if(this->Target->GetImplibGNUtoMS(targetNameImport,
138
139
140
141
142
                                        targetNameImportLib))
        {
        filesFrom.push_back(fromDirConfig + targetNameImportLib);
        filesTo.push_back(toDir + targetNameImportLib);
        }
143
144

      // An import library looks like a static library.
145
      type = cmInstallType_STATIC_LIBRARY;
146
147
      }
    else
148
      {
149
150
      std::string from1 = fromDirConfig + targetName;
      std::string to1 = toDir + targetName;
151
152

      // Handle OSX Bundles.
153
      if(this->Target->IsAppBundleOnApple())
154
        {
Gregor Jasny's avatar
Gregor Jasny committed
155
156
        cmMakefile const* mf = this->Target->Target->GetMakefile();

157
        // Install the whole app bundle directory.
158
        type = cmInstallType_DIRECTORY;
159
        literal_args += " USE_SOURCE_PERMISSIONS";
160
161
162
        from1 += ".app";

        // Tweaks apply to the binary inside the bundle.
Gregor Jasny's avatar
Gregor Jasny committed
163
164
165
166
167
        to1 += ".app/";
        if(!mf->PlatformIsAppleIos())
          {
          to1 += "Contents/MacOS/";
          }
168
        to1 += targetName;
169
170
171
        }
      else
        {
172
        // Tweaks apply to the real file, so list it first.
173
174
        if(targetNameReal != targetName)
          {
175
176
177
178
          std::string from2 = fromDirConfig + targetNameReal;
          std::string to2 = toDir += targetNameReal;
          filesFrom.push_back(from2);
          filesTo.push_back(to2);
179
          }
180
        }
181
182
183

      filesFrom.push_back(from1);
      filesTo.push_back(to1);
184
185
      }
    }
186
  else
187
    {
188
189
190
191
192
    std::string targetName;
    std::string targetNameSO;
    std::string targetNameReal;
    std::string targetNameImport;
    std::string targetNamePDB;
193
    this->Target->GetLibraryNames(targetName, targetNameSO,
194
                                          targetNameReal,
195
196
197
198
                                  targetNameImport, targetNamePDB,
                                  config);
    if(this->ImportLibrary)
      {
199
200
201
      // There is a bug in cmInstallCommand if this fails.
      assert(this->NamelinkMode == NamelinkModeNone);

202
203
204
205
      std::string from1 = fromDirConfig + targetNameImport;
      std::string to1 = toDir + targetNameImport;
      filesFrom.push_back(from1);
      filesTo.push_back(to1);
206
      std::string targetNameImportLib;
207
      if(this->Target->GetImplibGNUtoMS(targetNameImport,
208
209
210
211
212
                                        targetNameImportLib))
        {
        filesFrom.push_back(fromDirConfig + targetNameImportLib);
        filesTo.push_back(toDir + targetNameImportLib);
        }
213
214

      // An import library looks like a static library.
215
      type = cmInstallType_STATIC_LIBRARY;
216
      }
217
    else if(this->Target->IsFrameworkOnApple())
218
      {
219
220
221
      // There is a bug in cmInstallCommand if this fails.
      assert(this->NamelinkMode == NamelinkModeNone);

222
      // Install the whole framework directory.
223
      type = cmInstallType_DIRECTORY;
224
      literal_args += " USE_SOURCE_PERMISSIONS";
225
226
227

      std::string from1 = fromDirConfig + targetName;
      from1 = cmSystemTools::GetFilenamePath(from1);
228

229
      // Tweaks apply to the binary inside the bundle.
230
      std::string to1 = toDir + targetNameReal;
231

232
      filesFrom.push_back(from1);
233
234
      filesTo.push_back(to1);
      }
235
    else if(this->Target->IsCFBundleOnApple())
236
237
238
239
240
241
242
243
244
245
      {
      // Install the whole app bundle directory.
      type = cmInstallType_DIRECTORY;
      literal_args += " USE_SOURCE_PERMISSIONS";

      std::string targetNameBase = targetName.substr(0, targetName.find('/'));

      std::string from1 = fromDirConfig + targetNameBase;
      std::string to1 = toDir + targetName;

246
247
      filesFrom.push_back(from1);
      filesTo.push_back(to1);
248
      }
249
250
    else
      {
251
      bool haveNamelink = false;
252
253
254
255
256
257

      // Library link name.
      std::string fromName = fromDirConfig + targetName;
      std::string toName = toDir + targetName;

      // Library interface name.
258
      std::string fromSOName;
259
      std::string toSOName;
260
261
      if(targetNameSO != targetName)
        {
262
        haveNamelink = true;
263
264
        fromSOName = fromDirConfig + targetNameSO;
        toSOName = toDir + targetNameSO;
265
        }
266
267
268
269

      // Library implementation name.
      std::string fromRealName;
      std::string toRealName;
270
271
272
      if(targetNameReal != targetName &&
         targetNameReal != targetNameSO)
        {
273
        haveNamelink = true;
274
275
        fromRealName = fromDirConfig + targetNameReal;
        toRealName = toDir + targetNameReal;
276
277
278
279
280
281
282
283
284
        }

      // Add the names based on the current namelink mode.
      if(haveNamelink)
        {
        // With a namelink we need to check the mode.
        if(this->NamelinkMode == NamelinkModeOnly)
          {
          // Install the namelink only.
285
286
          filesFrom.push_back(fromName);
          filesTo.push_back(toName);
287
288
289
290
291
292
          }
        else
          {
          // Install the real file if it has its own name.
          if(!fromRealName.empty())
            {
293
294
            filesFrom.push_back(fromRealName);
            filesTo.push_back(toRealName);
295
296
297
298
299
            }

          // Install the soname link if it has its own name.
          if(!fromSOName.empty())
            {
300
301
            filesFrom.push_back(fromSOName);
            filesTo.push_back(toSOName);
302
303
304
305
306
            }

          // Install the namelink if it is not to be skipped.
          if(this->NamelinkMode != NamelinkModeSkip)
            {
307
308
            filesFrom.push_back(fromName);
            filesTo.push_back(toName);
309
310
311
312
313
314
315
316
317
            }
          }
        }
      else
        {
        // Without a namelink there will be only one file.  Install it
        // if this is not a namelink-only rule.
        if(this->NamelinkMode != NamelinkModeOnly)
          {
318
319
          filesFrom.push_back(fromName);
          filesTo.push_back(toName);
320
          }
321
322
        }
      }
323
324
    }

325
326
327
  // If this fails the above code is buggy.
  assert(filesFrom.size() == filesTo.size());

328
  // Skip this rule if no files are to be installed for the target.
329
  if(filesFrom.empty())
330
331
332
333
    {
    return;
    }

334
  // Add pre-installation tweaks.
335
336
  this->AddTweak(os, indent, config, filesTo,
                 &cmInstallTargetGenerator::PreReplacementTweaks);
337

338
  // Write code to install the target file.
339
  const char* no_dir_permissions = 0;
340
  const char* no_rename = 0;
341
  bool optional = this->Optional || this->ImportLibrary;
342
  this->AddInstallRule(os, this->GetDestination(config),
343
                       type, filesFrom, optional,
344
                       this->FilePermissions.c_str(), no_dir_permissions,
345
346
                       no_rename, literal_args.c_str(),
                       indent);
347

348
  // Add post-installation tweaks.
349
350
  this->AddTweak(os, indent, config, filesTo,
                 &cmInstallTargetGenerator::PostReplacementTweaks);
351
352
}

353
354
355
356
357
358
//----------------------------------------------------------------------------
std::string
cmInstallTargetGenerator::GetDestination(std::string const& config) const
{
  cmGeneratorExpression ge;
  return ge.Parse(this->Destination)
359
    ->Evaluate(this->Target->GetLocalGenerator(), config);
360
361
}

362
363
//----------------------------------------------------------------------------
std::string
364
cmInstallTargetGenerator::GetInstallFilename(const std::string& config) const
Alexander Neundorf's avatar
   
Alexander Neundorf committed
365
{
366
  NameType nameType = this->ImportLibrary? NameImplib : NameNormal;
367
  return
368
    cmInstallTargetGenerator::GetInstallFilename(this->Target, config,
369
                                                 nameType);
Alexander Neundorf's avatar
   
Alexander Neundorf committed
370
371
}

Alexander Neundorf's avatar
   
Alexander Neundorf committed
372
//----------------------------------------------------------------------------
373
std::string
374
cmInstallTargetGenerator::GetInstallFilename(cmGeneratorTarget const* target,
375
                                             const std::string& config,
376
                                             NameType nameType)
Alexander Neundorf's avatar
   
Alexander Neundorf committed
377
378
379
{
  std::string fname;
  // Compute the name of the library.
380
  if(target->GetType() == cmState::EXECUTABLE)
Alexander Neundorf's avatar
   
Alexander Neundorf committed
381
382
383
384
385
    {
    std::string targetName;
    std::string targetNameReal;
    std::string targetNameImport;
    std::string targetNamePDB;
386
    target->GetExecutableNames(targetName, targetNameReal,
Alexander Neundorf's avatar
   
Alexander Neundorf committed
387
388
                               targetNameImport, targetNamePDB,
                               config);
389
    if(nameType == NameImplib)
Alexander Neundorf's avatar
   
Alexander Neundorf committed
390
391
      {
      // Use the import library name.
392
      if(!target->GetImplibGNUtoMS(targetNameImport, fname,
393
394
395
396
                                   "${CMAKE_IMPORT_LIBRARY_SUFFIX}"))
        {
        fname = targetNameImport;
        }
Alexander Neundorf's avatar
   
Alexander Neundorf committed
397
      }
398
399
400
401
402
    else if(nameType == NameReal)
      {
      // Use the canonical name.
      fname = targetNameReal;
      }
Alexander Neundorf's avatar
   
Alexander Neundorf committed
403
404
405
406
407
408
409
410
411
412
413
414
415
    else
      {
      // Use the canonical name.
      fname = targetName;
      }
    }
  else
    {
    std::string targetName;
    std::string targetNameSO;
    std::string targetNameReal;
    std::string targetNameImport;
    std::string targetNamePDB;
416
    target->GetLibraryNames(targetName, targetNameSO, targetNameReal,
Alexander Neundorf's avatar
   
Alexander Neundorf committed
417
                            targetNameImport, targetNamePDB, config);
418
    if(nameType == NameImplib)
Alexander Neundorf's avatar
   
Alexander Neundorf committed
419
420
      {
      // Use the import library name.
421
      if(!target->GetImplibGNUtoMS(targetNameImport, fname,
422
423
424
425
                                   "${CMAKE_IMPORT_LIBRARY_SUFFIX}"))
        {
        fname = targetNameImport;
        }
Alexander Neundorf's avatar
   
Alexander Neundorf committed
426
      }
427
    else if(nameType == NameSO)
Alexander Neundorf's avatar
   
Alexander Neundorf committed
428
429
430
431
      {
      // Use the soname.
      fname = targetNameSO;
      }
432
433
434
435
436
    else if(nameType == NameReal)
      {
      // Use the real name.
      fname = targetNameReal;
      }
Alexander Neundorf's avatar
   
Alexander Neundorf committed
437
438
439
440
441
442
443
444
445
446
    else
      {
      // Use the canonical name.
      fname = targetName;
      }
    }

  return fname;
}

447
448
void cmInstallTargetGenerator::Compute(cmLocalGenerator* lg)
{
449
  this->Target = lg->FindGeneratorTarget(this->TargetName);
450
451
}

452
453
454
//----------------------------------------------------------------------------
void
cmInstallTargetGenerator
455
::AddTweak(std::ostream& os, Indent const& indent, const std::string& config,
456
457
           std::string const& file, TweakMethod tweak)
{
458
  std::ostringstream tw;
459
460
461
462
  (this->*tweak)(tw, indent.Next(), config, file);
  std::string tws = tw.str();
  if(!tws.empty())
    {
463
    os << indent << "if(EXISTS \"" << file << "\" AND\n"
464
465
       << indent << "   NOT IS_SYMLINK \"" << file << "\")\n";
    os << tws;
466
    os << indent << "endif()\n";
467
468
469
470
471
472
    }
}

//----------------------------------------------------------------------------
void
cmInstallTargetGenerator
473
::AddTweak(std::ostream& os, Indent const& indent, const std::string& config,
474
475
476
477
478
479
480
481
482
483
           std::vector<std::string> const& files, TweakMethod tweak)
{
  if(files.size() == 1)
    {
    // Tweak a single file.
    this->AddTweak(os, indent, config, this->GetDestDirPath(files[0]), tweak);
    }
  else
    {
    // Generate a foreach loop to tweak multiple files.
484
    std::ostringstream tw;
485
486
487
488
489
    this->AddTweak(tw, indent.Next(), config, "${file}", tweak);
    std::string tws = tw.str();
    if(!tws.empty())
      {
      Indent indent2 = indent.Next().Next();
490
      os << indent << "foreach(file\n";
491
492
493
494
495
496
497
      for(std::vector<std::string>::const_iterator i = files.begin();
          i != files.end(); ++i)
        {
        os << indent2 << "\"" << this->GetDestDirPath(*i) << "\"\n";
        }
      os << indent2 << ")\n";
      os << tws;
498
      os << indent << "endforeach()\n";
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
      }
    }
}

//----------------------------------------------------------------------------
std::string cmInstallTargetGenerator::GetDestDirPath(std::string const& file)
{
  // Construct the path of the file on disk after installation on
  // which tweaks may be performed.
  std::string toDestDirPath = "$ENV{DESTDIR}";
  if(file[0] != '/' && file[0] != '$')
    {
    toDestDirPath += "/";
    }
  toDestDirPath += file;
  return toDestDirPath;
}

//----------------------------------------------------------------------------
void cmInstallTargetGenerator::PreReplacementTweaks(std::ostream& os,
                                                    Indent const& indent,
520
                                                    const std::string& config,
521
522
523
524
525
526
527
                                                    std::string const& file)
{
  this->AddRPathCheckRule(os, indent, config, file);
}

//----------------------------------------------------------------------------
void cmInstallTargetGenerator::PostReplacementTweaks(std::ostream& os,
528
529
530
                                                    Indent const& indent,
                                                    const std::string& config,
                                                    std::string const& file)
531
532
533
534
535
536
537
{
  this->AddInstallNamePatchRule(os, indent, config, file);
  this->AddChrpathPatchRule(os, indent, config, file);
  this->AddRanlibRule(os, indent, file);
  this->AddStripRule(os, indent, file);
}

538
539
540
//----------------------------------------------------------------------------
void
cmInstallTargetGenerator
541
::AddInstallNamePatchRule(std::ostream& os, Indent const& indent,
542
543
                          const std::string& config,
                          std::string const& toDestDirPath)
544
{
545
  if(this->ImportLibrary ||
546
547
548
     !(this->Target->GetType() == cmState::SHARED_LIBRARY ||
       this->Target->GetType() == cmState::MODULE_LIBRARY ||
       this->Target->GetType() == cmState::EXECUTABLE))
549
    {
550
    return;
551
    }
552

553
  // Fix the install_name settings in installed binaries.
554
555
  std::string installNameTool = this->Target->Target->GetMakefile()
      ->GetSafeDefinition("CMAKE_INSTALL_NAME_TOOL");
556

557
  if(installNameTool.empty())
Alexander Neundorf's avatar
Alexander Neundorf committed
558
559
560
561
    {
    return;
    }

562
563
  // Build a map of build-tree install_name to install-tree install_name for
  // shared libraries linked to this target.
564
  std::map<std::string, std::string> install_name_remap;
565
  if(cmComputeLinkInformation* cli = this->Target->GetLinkInformation(config))
566
    {
567
    std::set<cmGeneratorTarget const*> const& sharedLibs
568
                                            = cli->GetSharedLibrariesLinked();
569
570
    for(std::set<cmGeneratorTarget const*>::const_iterator j
        = sharedLibs.begin(); j != sharedLibs.end(); ++j)
571
      {
572
      cmGeneratorTarget const* tgt = *j;
573
574
575
576
577
578
579

      // The install_name of an imported target does not change.
      if(tgt->IsImported())
        {
        continue;
        }

580
581
582
      // If the build tree and install tree use different path
      // components of the install_name field then we need to create a
      // mapping to be applied after installation.
583
584
      std::string for_build = tgt->GetInstallNameDirForBuildTree(config);
      std::string for_install = tgt->GetInstallNameDirForInstallTree();
585
586
587
588
589
      if(for_build != for_install)
        {
        // The directory portions differ.  Append the filename to
        // create the mapping.
        std::string fname =
590
          this->GetInstallFilename(tgt, config, NameSO);
591

592
593
        // Map from the build-tree install_name.
        for_build += fname;
594

595
        // Map to the install-tree install_name.
596
597
598
599
        for_install += fname;

        // Store the mapping entry.
        install_name_remap[for_build] = for_install;
600
601
602
603
604
605
        }
      }
    }

  // Edit the install_name of the target itself if necessary.
  std::string new_id;
606
  if(this->Target->GetType() == cmState::SHARED_LIBRARY)
607
    {
608
    std::string for_build =
609
      this->Target->GetInstallNameDirForBuildTree(config);
610
    std::string for_install =
611
      this->Target->GetInstallNameDirForInstallTree();
612

613
    if(this->Target->IsFrameworkOnApple() && for_install.empty())
614
      {
615
616
617
618
      // Frameworks seem to have an id corresponding to their own full
      // path.
      // ...
      // for_install = fullDestPath_without_DESTDIR_or_name;
619
      }
620
621
622

    // If the install name will change on installation set the new id
    // on the installed file.
623
624
625
626
    if(for_build != for_install)
      {
      // Prepare to refer to the install-tree install_name.
      new_id = for_install;
627
      new_id += this->GetInstallFilename(this->Target, config, NameSO);
628
629
630
631
632
633
634
      }
    }

  // Write a rule to run install_name_tool to set the install-tree
  // install_name value and references.
  if(!new_id.empty() || !install_name_remap.empty())
    {
635
    os << indent << "execute_process(COMMAND \"" << installNameTool;
Alexander Neundorf's avatar
   
Alexander Neundorf committed
636
    os << "\"";
637
638
    if(!new_id.empty())
      {
639
      os << "\n" << indent << "  -id \"" << new_id << "\"";
640
      }
641
    for(std::map<std::string, std::string>::const_iterator
642
643
644
          i = install_name_remap.begin();
        i != install_name_remap.end(); ++i)
      {
645
646
      os << "\n" << indent << "  -change \""
         << i->first << "\" \"" << i->second << "\"";
647
      }
648
    os << "\n" << indent << "  \"" << toDestDirPath << "\")\n";
649
650
    }
}
Alexander Neundorf's avatar
   
Alexander Neundorf committed
651

652
653
654
655
//----------------------------------------------------------------------------
void
cmInstallTargetGenerator
::AddRPathCheckRule(std::ostream& os, Indent const& indent,
656
657
                    const std::string& config,
                    std::string const& toDestDirPath)
658
659
{
  // Skip the chrpath if the target does not need it.
660
  if(this->ImportLibrary || !this->Target->IsChrpathUsed(config))
661
662
663
    {
    return;
    }
664
  // Skip if on Apple
665
666
  if(this->Target->Target->GetMakefile()
     ->IsOn("CMAKE_PLATFORM_HAS_INSTALLNAME"))
667
668
669
670
    {
    return;
    }

671
672
  // Get the link information for this target.
  // It can provide the RPATH.
673
  cmComputeLinkInformation* cli = this->Target->GetLinkInformation(config);
674
675
676
677
678
679
680
681
682
683
684
  if(!cli)
    {
    return;
    }

  // Get the install RPATH from the link information.
  std::string newRpath = cli->GetChrpathString();

  // Write a rule to remove the installed file if its rpath is not the
  // new rpath.  This is needed for existing build/install trees when
  // the installed rpath changes but the file is not rebuilt.
685
  os << indent << "file(RPATH_CHECK\n"
686
687
688
689
     << indent << "     FILE \"" << toDestDirPath << "\"\n"
     << indent << "     RPATH \"" << newRpath << "\")\n";
}

690
691
692
693
//----------------------------------------------------------------------------
void
cmInstallTargetGenerator
::AddChrpathPatchRule(std::ostream& os, Indent const& indent,
694
695
                      const std::string& config,
                      std::string const& toDestDirPath)
696
{
697
  // Skip the chrpath if the target does not need it.
698
  if(this->ImportLibrary || !this->Target->IsChrpathUsed(config))
699
700
701
702
    {
    return;
    }

703
704
  // Get the link information for this target.
  // It can provide the RPATH.
705
  cmComputeLinkInformation* cli = this->Target->GetLinkInformation(config);
706
  if(!cli)
707
708
709
710
    {
    return;
    }

711
  cmMakefile* mf = this->Target->Target->GetMakefile();
712
713

  if(mf->IsOn("CMAKE_PLATFORM_HAS_INSTALLNAME"))
714
    {
715
716
    // If using install_name_tool, set up the rules to modify the rpaths.
    std::string installNameTool =
717
      mf->GetSafeDefinition("CMAKE_INSTALL_NAME_TOOL");
718
719
720
721
722

    std::vector<std::string> oldRuntimeDirs, newRuntimeDirs;
    cli->GetRPath(oldRuntimeDirs, false);
    cli->GetRPath(newRuntimeDirs, true);

723
724
    std::string darwin_major_version_s =
      mf->GetSafeDefinition("DARWIN_MAJOR_VERSION");
725

726
727
728
729
730
731
732
    std::stringstream ss(darwin_major_version_s);
    int darwin_major_version;
    ss >> darwin_major_version;
    if(!ss.fail() && darwin_major_version <= 9 &&
       (!oldRuntimeDirs.empty() || !newRuntimeDirs.empty())
      )
      {
733
      std::ostringstream msg;
734
735
736
737
738
739
740
      msg << "WARNING: Target \"" << this->Target->GetName()
        << "\" has runtime paths which cannot be changed during install.  "
        << "To change runtime paths, OS X version 10.6 or newer is required.  "
        << "Therefore, runtime paths will not be changed when installing.  "
        << "CMAKE_BUILD_WITH_INSTALL_RPATH may be used to work around"
           " this limitation.";
      mf->IssueMessage(cmake::WARNING, msg.str());
741
      }
742
    else
743
      {
744
745
746
747
748
749
750
      // Note: These paths are kept unique to avoid
      // install_name_tool corruption.
      std::set<std::string> runpaths;
      for(std::vector<std::string>::const_iterator i = oldRuntimeDirs.begin();
          i != oldRuntimeDirs.end(); ++i)
        {
        std::string runpath =
751
          mf->GetGlobalGenerator()->ExpandCFGIntDir(*i, config);
752
753
754
755
756
757
758
759
760

        if(runpaths.find(runpath) == runpaths.end())
          {
          runpaths.insert(runpath);
          os << indent << "execute_process(COMMAND " << installNameTool <<"\n";
          os << indent << "  -delete_rpath \"" << runpath << "\"\n";
          os << indent << "  \"" << toDestDirPath << "\")\n";
          }
        }
761

762
763
764
      runpaths.clear();
      for(std::vector<std::string>::const_iterator i = newRuntimeDirs.begin();
          i != newRuntimeDirs.end(); ++i)
765
        {
766
        std::string runpath =
767
          mf->GetGlobalGenerator()->ExpandCFGIntDir(*i, config);
768
769
770
771
772
773
774

        if(runpaths.find(runpath) == runpaths.end())
          {
          os << indent << "execute_process(COMMAND " << installNameTool <<"\n";
          os << indent << "  -add_rpath \"" << runpath << "\"\n";
          os << indent << "  \"" << toDestDirPath << "\")\n";
          }
775
        }
776
      }
777
778
779
    }
  else
    {
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
    // Construct the original rpath string to be replaced.
    std::string oldRpath = cli->GetRPathString(false);

    // Get the install RPATH from the link information.
    std::string newRpath = cli->GetChrpathString();

    // Skip the rule if the paths are identical
    if(oldRpath == newRpath)
      {
      return;
      }

    // Write a rule to run chrpath to set the install-tree RPATH
    if(newRpath.empty())
      {
795
      os << indent << "file(RPATH_REMOVE\n"
796
797
798
799
         << indent << "     FILE \"" << toDestDirPath << "\")\n";
      }
    else
      {
800
      os << indent << "file(RPATH_CHANGE\n"
801
802
803
804
         << indent << "     FILE \"" << toDestDirPath << "\"\n"
         << indent << "     OLD_RPATH \"" << oldRpath << "\"\n"
         << indent << "     NEW_RPATH \"" << newRpath << "\")\n";
      }
805
    }
806
807
}

808
809
810
//----------------------------------------------------------------------------
void
cmInstallTargetGenerator::AddStripRule(std::ostream& os,
811
                                       Indent const& indent,
812
                                       const std::string& toDestDirPath)
Alexander Neundorf's avatar
   
Alexander Neundorf committed
813
814
{

815
816
  // don't strip static and import libraries, because it removes the only
  // symbol table they have so you can't link to them anymore
817
  if(this->Target->GetType()==cmState::STATIC_LIBRARY || this->ImportLibrary)
Alexander Neundorf's avatar
   
Alexander Neundorf committed
818
819
820
821
    {
    return;
    }

Alexander Neundorf's avatar
   
Alexander Neundorf committed
822
  // Don't handle OSX Bundles.
823
  if(this->Target->Target->GetMakefile()->IsOn("APPLE") &&
824
     this->Target->GetPropertyAsBool("MACOSX_BUNDLE"))
Alexander Neundorf's avatar
   
Alexander Neundorf committed
825
826
827
828
    {
    return;
    }

829
  if(! this->Target->Target->GetMakefile()->IsSet("CMAKE_STRIP"))
Alexander Neundorf's avatar
   
Alexander Neundorf committed
830
831
832
833
    {
    return;
    }

834
835
  os << indent << "if(CMAKE_INSTALL_DO_STRIP)\n";
  os << indent << "  execute_process(COMMAND \""
836
     << this->Target->Target->GetMakefile()->GetDefinition("CMAKE_STRIP")
837
     << "\" \"" << toDestDirPath << "\")\n";
838
  os << indent << "endif()\n";
Alexander Neundorf's avatar
   
Alexander Neundorf committed
839
840
}

841
842
843
//----------------------------------------------------------------------------
void
cmInstallTargetGenerator::AddRanlibRule(std::ostream& os,
844
                                        Indent const& indent,
845
                                        const std::string& toDestDirPath)
Alexander Neundorf's avatar
   
Alexander Neundorf committed
846
847
{
  // Static libraries need ranlib on this platform.
848
  if(this->Target->GetType() != cmState::STATIC_LIBRARY)
Alexander Neundorf's avatar
   
Alexander Neundorf committed
849
850
851
852
853
854
    {
    return;
    }

  // Perform post-installation processing on the file depending
  // on its type.
855
  if(!this->Target->Target->GetMakefile()->IsOn("APPLE"))
Alexander Neundorf's avatar
   
Alexander Neundorf committed
856
857
858
859
    {
    return;
    }

860
  std::string ranlib =
861
    this->Target->Target->GetMakefile()->GetRequiredDefinition("CMAKE_RANLIB");
862
  if(ranlib.empty())
Alexander Neundorf's avatar
   
Alexander Neundorf committed
863
864
865
866
    {
    return;
    }

867
  os << indent << "execute_process(COMMAND \""
868
     << ranlib << "\" \"" << toDestDirPath << "\")\n";
Alexander Neundorf's avatar
   
Alexander Neundorf committed
869
}