cmMakefileLibraryTargetGenerator.cxx 27.4 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
14
#include "cmMakefileLibraryTargetGenerator.h"

#include "cmGeneratedFileStream.h"
15
#include "cmGlobalUnixMakefileGenerator3.h"
16
17
18
19
#include "cmLocalUnixMakefileGenerator3.h"
#include "cmMakefile.h"
#include "cmSourceFile.h"
#include "cmTarget.h"
20
#include "cmake.h"
21

22
//----------------------------------------------------------------------------
23
cmMakefileLibraryTargetGenerator
24
::cmMakefileLibraryTargetGenerator(cmGeneratorTarget* target):
25
  cmMakefileTargetGenerator(target)
26
{
27
  this->CustomCommandDriver = OnDepends;
28
29
30
31
32
33
  if (this->Target->GetType() != cmTarget::INTERFACE_LIBRARY)
    {
    this->Target->GetLibraryNames(
      this->TargetNameOut, this->TargetNameSO, this->TargetNameReal,
      this->TargetNameImport, this->TargetNamePDB, this->ConfigName);
    }
34

35
  this->OSXBundleGenerator = new cmOSXBundleGenerator(target,
36
37
38
39
40
41
42
43
44
                                                      this->ConfigName);
  this->OSXBundleGenerator->SetMacContentFolders(&this->MacContentFolders);
}

//----------------------------------------------------------------------------
cmMakefileLibraryTargetGenerator
::~cmMakefileLibraryTargetGenerator()
{
  delete this->OSXBundleGenerator;
45
46
}

47
48
49
50
51
52
//----------------------------------------------------------------------------
void cmMakefileLibraryTargetGenerator::WriteRuleFiles()
{
  // create the build.make file and directory, put in the common blocks
  this->CreateRuleFile();

53
  // write rules used to help build object files
54
  this->WriteCommonCodeRules();
55
56
57
58

  // write the per-target per-language flags
  this->WriteTargetLanguageFlags();

59
60
61
  // write in rules for object files and custom commands
  this->WriteTargetBuildRules();

62
63
64
65
66
67
68
69
  // write the link rules
  // Write the rule for this target type.
  switch(this->Target->GetType())
    {
    case cmTarget::STATIC_LIBRARY:
      this->WriteStaticLibraryRules();
      break;
    case cmTarget::SHARED_LIBRARY:
70
      this->WriteSharedLibraryRules(false);
71
      if(this->Target->NeedRelinkBeforeInstall(this->ConfigName))
72
73
74
75
        {
        // Write rules to link an installable version of the target.
        this->WriteSharedLibraryRules(true);
        }
76
77
      break;
    case cmTarget::MODULE_LIBRARY:
78
      this->WriteModuleLibraryRules(false);
79
      if(this->Target->NeedRelinkBeforeInstall(this->ConfigName))
80
81
82
83
        {
        // Write rules to link an installable version of the target.
        this->WriteModuleLibraryRules(true);
        }
84
      break;
85
86
87
    case cmTarget::OBJECT_LIBRARY:
      this->WriteObjectLibraryRules();
      break;
88
89
90
91
92
93
94
95
96
97
98
99
    default:
      // If language is not known, this is an error.
      cmSystemTools::Error("Unknown Library Type");
      break;
    }

  // Write the requires target.
  this->WriteTargetRequiresRules();

  // Write clean target
  this->WriteTargetCleanRules();

100
101
102
103
  // Write the dependency generation rule.  This must be done last so
  // that multiple output pair information is available.
  this->WriteTargetDependRules();

104
105
106
107
  // close the streams
  this->CloseFileStreams();
}

108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
//----------------------------------------------------------------------------
void cmMakefileLibraryTargetGenerator::WriteObjectLibraryRules()
{
  std::vector<std::string> commands;
  std::vector<std::string> depends;

  // Add post-build rules.
  this->LocalGenerator->
    AppendCustomCommands(commands, this->Target->GetPostBuildCommands(),
                         this->Target);

  // Depend on the object files.
  this->AppendObjectDepends(depends);

  // Write the rule.
  this->LocalGenerator->WriteMakeRule(*this->BuildFileStream, 0,
                                      this->Target->GetName(),
                                      depends, commands, true);

  // Write the main driver rule to build everything in this target.
Stephen Kelly's avatar
Stephen Kelly committed
128
  this->WriteTargetDriverRule(this->Target->GetName(), false);
129
130
}

131
132
133
//----------------------------------------------------------------------------
void cmMakefileLibraryTargetGenerator::WriteStaticLibraryRules()
{
134
  std::string linkLanguage =
135
    this->Target->GetLinkerLanguage(this->ConfigName);
136
  std::string linkRuleVar = "CMAKE_";
137
  linkRuleVar += linkLanguage;
138
139
  linkRuleVar += "_CREATE_STATIC_LIBRARY";

140
  if(this->GetFeatureAsBool("INTERPROCEDURAL_OPTIMIZATION") &&
Stephen Kelly's avatar
Stephen Kelly committed
141
     this->Makefile->GetDefinition(linkRuleVar+"_IPO"))
142
143
144
145
    {
    linkRuleVar += "_IPO";
    }

146
  std::string extraFlags;
147
148
  this->LocalGenerator->GetStaticLibraryFlags(extraFlags,
    cmSystemTools::UpperCase(this->ConfigName), this->Target);
Stephen Kelly's avatar
Stephen Kelly committed
149
  this->WriteLibraryRules(linkRuleVar, extraFlags, false);
150
151
152
}

//----------------------------------------------------------------------------
153
void cmMakefileLibraryTargetGenerator::WriteSharedLibraryRules(bool relink)
154
{
155
  if(this->Target->IsFrameworkOnApple())
156
157
158
159
    {
    this->WriteFrameworkRules(relink);
    return;
    }
160
  std::string linkLanguage =
161
    this->Target->GetLinkerLanguage(this->ConfigName);
162
  std::string linkRuleVar = "CMAKE_";
163
  linkRuleVar += linkLanguage;
164
165
166
  linkRuleVar += "_CREATE_SHARED_LIBRARY";

  std::string extraFlags;
Ken Martin's avatar
Ken Martin committed
167
168
  this->LocalGenerator->AppendFlags
    (extraFlags, this->Target->GetProperty("LINK_FLAGS"));
169
  std::string linkFlagsConfig = "LINK_FLAGS_";
170
  linkFlagsConfig += cmSystemTools::UpperCase(this->ConfigName);
Ken Martin's avatar
Ken Martin committed
171
  this->LocalGenerator->AppendFlags
Stephen Kelly's avatar
Stephen Kelly committed
172
    (extraFlags, this->Target->GetProperty(linkFlagsConfig));
173

Ken Martin's avatar
Ken Martin committed
174
  this->LocalGenerator->AddConfigVariableFlags
175
    (extraFlags, "CMAKE_SHARED_LINKER_FLAGS", this->ConfigName);
176
177
  this->AddModuleDefinitionFlag(extraFlags);

Stephen Kelly's avatar
Stephen Kelly committed
178
  this->WriteLibraryRules(linkRuleVar, extraFlags, relink);
179
180
181
}

//----------------------------------------------------------------------------
182
void cmMakefileLibraryTargetGenerator::WriteModuleLibraryRules(bool relink)
183
{
184
  std::string linkLanguage =
185
    this->Target->GetLinkerLanguage(this->ConfigName);
186
  std::string linkRuleVar = "CMAKE_";
187
  linkRuleVar += linkLanguage;
188
189
190
  linkRuleVar += "_CREATE_SHARED_MODULE";

  std::string extraFlags;
191
  this->LocalGenerator->AppendFlags(extraFlags,
Ken Martin's avatar
Ken Martin committed
192
193
                                    this->Target->GetProperty("LINK_FLAGS"));
  std::string linkFlagsConfig = "LINK_FLAGS_";
194
  linkFlagsConfig += cmSystemTools::UpperCase(this->ConfigName);
Ken Martin's avatar
Ken Martin committed
195
  this->LocalGenerator->AppendFlags
Stephen Kelly's avatar
Stephen Kelly committed
196
    (extraFlags, this->Target->GetProperty(linkFlagsConfig));
Ken Martin's avatar
Ken Martin committed
197
  this->LocalGenerator->AddConfigVariableFlags
198
    (extraFlags, "CMAKE_MODULE_LINKER_FLAGS", this->ConfigName);
199
  this->AddModuleDefinitionFlag(extraFlags);
Ken Martin's avatar
Ken Martin committed
200

Stephen Kelly's avatar
Stephen Kelly committed
201
  this->WriteLibraryRules(linkRuleVar, extraFlags, relink);
202
203
}

204
205
206
//----------------------------------------------------------------------------
void cmMakefileLibraryTargetGenerator::WriteFrameworkRules(bool relink)
{
207
  std::string linkLanguage =
208
    this->Target->GetLinkerLanguage(this->ConfigName);
209
  std::string linkRuleVar = "CMAKE_";
210
  linkRuleVar += linkLanguage;
211
212
213
  linkRuleVar += "_CREATE_MACOSX_FRAMEWORK";

  std::string extraFlags;
214
  this->LocalGenerator->AppendFlags(extraFlags,
215
216
                                    this->Target->GetProperty("LINK_FLAGS"));
  std::string linkFlagsConfig = "LINK_FLAGS_";
217
  linkFlagsConfig += cmSystemTools::UpperCase(this->ConfigName);
218
  this->LocalGenerator->AppendFlags
Stephen Kelly's avatar
Stephen Kelly committed
219
    (extraFlags, this->Target->GetProperty(linkFlagsConfig));
220
  this->LocalGenerator->AddConfigVariableFlags
221
    (extraFlags, "CMAKE_MACOSX_FRAMEWORK_LINKER_FLAGS", this->ConfigName);
222

Stephen Kelly's avatar
Stephen Kelly committed
223
  this->WriteLibraryRules(linkRuleVar, extraFlags, relink);
224
225
}

226
227
//----------------------------------------------------------------------------
void cmMakefileLibraryTargetGenerator::WriteLibraryRules
228
(const std::string& linkRuleVar, const std::string& extraFlags, bool relink)
229
230
231
232
233
234
235
{
  // TODO: Merge the methods that call this method to avoid
  // code duplication.
  std::vector<std::string> commands;

  // Build list of dependencies.
  std::vector<std::string> depends;
236
  this->AppendLinkDepends(depends);
237
238

  // Get the language to use for linking this library.
239
  std::string linkLanguage =
240
    this->Target->GetLinkerLanguage(this->ConfigName);
241
242

  // Make sure we have a link language.
243
  if(linkLanguage.empty())
244
245
    {
    cmSystemTools::Error("Cannot determine link language for target \"",
246
                         this->Target->GetName().c_str(), "\".");
247
248
249
250
251
    return;
    }

  // Create set of linking flags.
  std::string linkFlags;
252
  this->LocalGenerator->AppendFlags(linkFlags, extraFlags);
253

254
255
256
257
258
259
260
261
  // Add OSX version flags, if any.
  if(this->Target->GetType() == cmTarget::SHARED_LIBRARY ||
     this->Target->GetType() == cmTarget::MODULE_LIBRARY)
    {
    this->AppendOSXVerFlag(linkFlags, linkLanguage, "COMPATIBILITY", true);
    this->AppendOSXVerFlag(linkFlags, linkLanguage, "CURRENT", false);
    }

262
263
264
265
  // Construct the name of the library.
  std::string targetName;
  std::string targetNameSO;
  std::string targetNameReal;
266
  std::string targetNameImport;
267
  std::string targetNamePDB;
268
  this->Target->GetLibraryNames(
269
    targetName, targetNameSO, targetNameReal, targetNameImport, targetNamePDB,
270
    this->ConfigName);
271
272

  // Construct the full path version of the names.
273
  std::string outpath;
274
  std::string outpathImp;
275
276
  if(this->Target->IsFrameworkOnApple())
    {
277
278
279
    outpath = this->Target->GetDirectory(this->ConfigName);
    this->OSXBundleGenerator->CreateFramework(targetName, outpath);
    outpath += "/";
280
    }
281
282
283
  else if(this->Target->IsCFBundleOnApple())
    {
    outpath = this->Target->GetDirectory(this->ConfigName);
284
    this->OSXBundleGenerator->CreateCFBundle(targetName, outpath);
285
    outpath += "/";
286
    }
287
  else if(relink)
288
    {
289
    outpath = this->Makefile->GetCurrentBinaryDirectory();
290
291
    outpath += cmake::GetCMakeFilesDirectory();
    outpath += "/CMakeRelink.dir";
292
293
    cmSystemTools::MakeDirectory(outpath.c_str());
    outpath += "/";
294
295
296
297
    if(!targetNameImport.empty())
      {
      outpathImp = outpath;
      }
298
    }
299
300
  else
    {
301
    outpath = this->Target->GetDirectory(this->ConfigName);
302
    cmSystemTools::MakeDirectory(outpath.c_str());
303
    outpath += "/";
304
305
    if(!targetNameImport.empty())
      {
306
      outpathImp = this->Target->GetDirectory(this->ConfigName, true);
307
      cmSystemTools::MakeDirectory(outpathImp.c_str());
308
309
      outpathImp += "/";
      }
310
    }
311

312
313
314
315
  std::string compilePdbOutputPath =
    this->Target->GetCompilePDBDirectory(this->ConfigName);
  cmSystemTools::MakeDirectory(compilePdbOutputPath.c_str());

316
  std::string pdbOutputPath = this->Target->GetPDBDirectory(this->ConfigName);
317
318
319
  cmSystemTools::MakeDirectory(pdbOutputPath.c_str());
  pdbOutputPath += "/";

320
  std::string targetFullPath = outpath + targetName;
321
  std::string targetFullPathPDB = pdbOutputPath + targetNamePDB;
322
323
  std::string targetFullPathSO = outpath + targetNameSO;
  std::string targetFullPathReal = outpath + targetNameReal;
324
  std::string targetFullPathImport = outpathImp + targetNameImport;
325
326
327

  // Construct the output path version of the names for use in command
  // arguments.
328
  std::string targetOutPathPDB =
Stephen Kelly's avatar
Stephen Kelly committed
329
    this->Convert(targetFullPathPDB,cmLocalGenerator::NONE,
330
                  cmLocalGenerator::SHELL);
331
  std::string targetOutPath =
Stephen Kelly's avatar
Stephen Kelly committed
332
    this->Convert(targetFullPath,cmLocalGenerator::START_OUTPUT,
333
                  cmLocalGenerator::SHELL);
334
  std::string targetOutPathSO =
Stephen Kelly's avatar
Stephen Kelly committed
335
    this->Convert(targetFullPathSO,cmLocalGenerator::START_OUTPUT,
336
                  cmLocalGenerator::SHELL);
337
  std::string targetOutPathReal =
Stephen Kelly's avatar
Stephen Kelly committed
338
    this->Convert(targetFullPathReal,cmLocalGenerator::START_OUTPUT,
339
                  cmLocalGenerator::SHELL);
340
  std::string targetOutPathImport =
Stephen Kelly's avatar
Stephen Kelly committed
341
    this->Convert(targetFullPathImport,cmLocalGenerator::START_OUTPUT,
342
                  cmLocalGenerator::SHELL);
343

344
  this->NumberOfProgressActions++;
345
  if(!this->NoRuleMessages)
346
    {
347
348
    cmLocalUnixMakefileGenerator3::EchoProgress progress;
    this->MakeEchoProgress(progress);
349
350
351
352
353
354
355
356
357
358
359
360
    // Add the link message.
    std::string buildEcho = "Linking ";
    buildEcho += linkLanguage;
    switch(this->Target->GetType())
      {
      case cmTarget::STATIC_LIBRARY:
        buildEcho += " static library ";
        break;
      case cmTarget::SHARED_LIBRARY:
        buildEcho += " shared library ";
        break;
      case cmTarget::MODULE_LIBRARY:
361
362
        if (this->Target->IsCFBundleOnApple())
            buildEcho += " CFBundle";
363
364
365
366
367
368
369
370
        buildEcho += " shared module ";
        break;
      default:
        buildEcho += " library ";
        break;
      }
    buildEcho += targetOutPath.c_str();
    this->LocalGenerator->AppendEcho(commands, buildEcho.c_str(),
371
372
                                     cmLocalUnixMakefileGenerator3::EchoLink,
                                     &progress);
373
374
    }

Brad King's avatar
Brad King committed
375
376
377
378
379
380
381
382
383
384
385
386
  const char* forbiddenFlagVar = 0;
  switch(this->Target->GetType())
    {
    case cmTarget::SHARED_LIBRARY:
      forbiddenFlagVar = "_CREATE_SHARED_LIBRARY_FORBIDDEN_FLAGS";
      break;
    case cmTarget::MODULE_LIBRARY:
      forbiddenFlagVar = "_CREATE_SHARED_MODULE_FORBIDDEN_FLAGS";
      break;
    default: break;
    }

387
  // Clean files associated with this library.
388
  std::vector<std::string> libCleanFiles;
Stephen Kelly's avatar
Stephen Kelly committed
389
  libCleanFiles.push_back(this->Convert(targetFullPath,
390
391
392
        cmLocalGenerator::START_OUTPUT,
        cmLocalGenerator::UNCHANGED));
  if(targetNameReal != targetName)
393
    {
Stephen Kelly's avatar
Stephen Kelly committed
394
    libCleanFiles.push_back(this->Convert(targetFullPathReal,
395
396
        cmLocalGenerator::START_OUTPUT,
        cmLocalGenerator::UNCHANGED));
397
    }
398
399
  if(targetNameSO != targetName &&
     targetNameSO != targetNameReal)
400
    {
Stephen Kelly's avatar
Stephen Kelly committed
401
    libCleanFiles.push_back(this->Convert(targetFullPathSO,
402
403
        cmLocalGenerator::START_OUTPUT,
        cmLocalGenerator::UNCHANGED));
404
    }
405
406
  if(!targetNameImport.empty())
    {
Stephen Kelly's avatar
Stephen Kelly committed
407
    libCleanFiles.push_back(this->Convert(targetFullPathImport,
408
409
        cmLocalGenerator::START_OUTPUT,
        cmLocalGenerator::UNCHANGED));
410
411
412
    std::string implib;
    if(this->Target->GetImplibGNUtoMS(targetFullPathImport, implib))
      {
Stephen Kelly's avatar
Stephen Kelly committed
413
      libCleanFiles.push_back(this->Convert(implib,
414
415
416
                                            cmLocalGenerator::START_OUTPUT,
                                            cmLocalGenerator::UNCHANGED));
      }
417
418
419
420
421
422
    }

  // List the PDB for cleaning only when the whole target is
  // cleaned.  We do not want to delete the .pdb file just before
  // linking the target.
  this->CleanFiles.push_back
Stephen Kelly's avatar
Stephen Kelly committed
423
    (this->Convert(targetFullPathPDB,
424
425
                   cmLocalGenerator::START_OUTPUT,
                   cmLocalGenerator::UNCHANGED));
426
427
428
429
430
431
432
433
434
435
436
437
438

#ifdef _WIN32
  // There may be a manifest file for this target.  Add it to the
  // clean set just in case.
  if(this->Target->GetType() != cmTarget::STATIC_LIBRARY)
    {
    libCleanFiles.push_back(
      this->Convert((targetFullPath+".manifest").c_str(),
                    cmLocalGenerator::START_OUTPUT,
                    cmLocalGenerator::UNCHANGED));
    }
#endif

439
  std::vector<std::string> commands1;
440
  // Add a command to remove any existing files for this library.
441
  // for static libs only
442
443
444
445
446
447
  if(this->Target->GetType() == cmTarget::STATIC_LIBRARY)
    {
    this->LocalGenerator->AppendCleanCommand(commands1, libCleanFiles,
                                             *this->Target, "target");
    this->LocalGenerator->CreateCDCommand
      (commands1,
448
       this->Makefile->GetCurrentBinaryDirectory(),
449
       cmLocalGenerator::HOME_OUTPUT);
450
451
452
    commands.insert(commands.end(), commands1.begin(), commands1.end());
    commands1.clear();
    }
453
454
455
456
457

  // Add the pre-build and pre-link rules building but not when relinking.
  if(!relink)
    {
    this->LocalGenerator
458
459
      ->AppendCustomCommands(commands, this->Target->GetPreBuildCommands(),
                             this->Target);
460
    this->LocalGenerator
461
462
      ->AppendCustomCommands(commands, this->Target->GetPreLinkCommands(),
                             this->Target);
463
    }
464

465
466
  // Determine whether a link script will be used.
  bool useLinkScript = this->GlobalGenerator->GetUseLinkScript();
467

468
  // Select whether to use a response file for objects.
469
  bool useResponseFileForObjects = false;
470
471
472
473
  {
  std::string responseVar = "CMAKE_";
  responseVar += linkLanguage;
  responseVar += "_USE_RESPONSE_FILE_FOR_OBJECTS";
Stephen Kelly's avatar
Stephen Kelly committed
474
  if(this->Makefile->IsOn(responseVar))
475
    {
476
    useResponseFileForObjects = true;
477
478
479
    }
  }

480
481
482
483
484
485
  // Select whether to use a response file for libraries.
  bool useResponseFileForLibs = false;
  {
  std::string responseVar = "CMAKE_";
  responseVar += linkLanguage;
  responseVar += "_USE_RESPONSE_FILE_FOR_LIBRARIES";
Stephen Kelly's avatar
Stephen Kelly committed
486
  if(this->Makefile->IsOn(responseVar))
487
488
489
490
491
    {
    useResponseFileForLibs = true;
    }
  }

492
  // For static libraries there might be archiving rules.
493
  bool haveStaticLibraryRule = false;
494
495
496
497
  std::vector<std::string> archiveCreateCommands;
  std::vector<std::string> archiveAppendCommands;
  std::vector<std::string> archiveFinishCommands;
  std::string::size_type archiveCommandLimit = std::string::npos;
498
  if(this->Target->GetType() == cmTarget::STATIC_LIBRARY)
499
    {
500
501
    haveStaticLibraryRule =
      this->Makefile->GetDefinition(linkRuleVar)? true:false;
502
503
504
    std::string arCreateVar = "CMAKE_";
    arCreateVar += linkLanguage;
    arCreateVar += "_ARCHIVE_CREATE";
Stephen Kelly's avatar
Stephen Kelly committed
505
    if(const char* rule = this->Makefile->GetDefinition(arCreateVar))
506
507
508
509
510
511
      {
      cmSystemTools::ExpandListArgument(rule, archiveCreateCommands);
      }
    std::string arAppendVar = "CMAKE_";
    arAppendVar += linkLanguage;
    arAppendVar += "_ARCHIVE_APPEND";
Stephen Kelly's avatar
Stephen Kelly committed
512
    if(const char* rule = this->Makefile->GetDefinition(arAppendVar))
513
514
515
516
517
518
      {
      cmSystemTools::ExpandListArgument(rule, archiveAppendCommands);
      }
    std::string arFinishVar = "CMAKE_";
    arFinishVar += linkLanguage;
    arFinishVar += "_ARCHIVE_FINISH";
Stephen Kelly's avatar
Stephen Kelly committed
519
    if(const char* rule = this->Makefile->GetDefinition(arFinishVar))
520
521
522
      {
      cmSystemTools::ExpandListArgument(rule, archiveFinishCommands);
      }
523
524
525
526
    }

  // Decide whether to use archiving rules.
  bool useArchiveRules =
527
    !haveStaticLibraryRule &&
528
529
530
531
532
    !archiveCreateCommands.empty() && !archiveAppendCommands.empty();
  if(useArchiveRules)
    {
    // Archiving rules are always run with a link script.
    useLinkScript = true;
533

534
    // Archiving rules never use a response file.
535
    useResponseFileForObjects = false;
536

537
538
539
540
541
    // Limit the length of individual object lists to less than the
    // 32K command line length limit on Windows.  We could make this a
    // platform file variable but this should work everywhere.
    archiveCommandLimit = 30000;
    }
542

543
  // Expand the rule variables.
544
  std::vector<std::string> real_link_commands;
545
  {
546
547
  bool useWatcomQuote = this->Makefile->IsOn(linkRuleVar+"_USE_WATCOM_QUOTE");

548
549
550
  // Set path conversion for link script shells.
  this->LocalGenerator->SetLinkScriptShell(useLinkScript);

551
  // Collect up flags to link in needed libraries.
552
  std::string linkLibs;
553
554
  if(this->Target->GetType() != cmTarget::STATIC_LIBRARY)
    {
555
556
    this->CreateLinkLibs(linkLibs, relink, useResponseFileForLibs, depends,
                         useWatcomQuote);
557
    }
558
559
560

  // Construct object file lists that may be needed to expand the
  // rule.
561
  std::string buildObjs;
562
  this->CreateObjectLists(useLinkScript, useArchiveRules,
563
564
                          useResponseFileForObjects, buildObjs, depends,
                          useWatcomQuote);
565

566
  cmLocalGenerator::RuleVariables vars;
567
  vars.TargetPDB = targetOutPathPDB.c_str();
568
569
570
571
572

  // Setup the target version.
  std::string targetVersionMajor;
  std::string targetVersionMinor;
  {
573
574
  std::ostringstream majorStream;
  std::ostringstream minorStream;
575
576
577
578
579
580
581
582
583
584
585
  int major;
  int minor;
  this->Target->GetTargetVersion(major, minor);
  majorStream << major;
  minorStream << minor;
  targetVersionMajor = majorStream.str();
  targetVersionMinor = minorStream.str();
  }
  vars.TargetVersionMajor = targetVersionMajor.c_str();
  vars.TargetVersionMinor = targetVersionMinor.c_str();

586
587
  vars.RuleLauncher = "RULE_LAUNCH_LINK";
  vars.CMTarget = this->Target;
588
  vars.Language = linkLanguage.c_str();
589
  vars.Objects = buildObjs.c_str();
590
  std::string objectDir = this->Target->GetSupportDirectory();
Stephen Kelly's avatar
Stephen Kelly committed
591
  objectDir = this->Convert(objectDir,
592
593
594
                            cmLocalGenerator::START_OUTPUT,
                            cmLocalGenerator::SHELL);
  vars.ObjectDir = objectDir.c_str();
595
596
597
598
599
600
  cmLocalGenerator::OutputFormat output = (useWatcomQuote) ?
    cmLocalGenerator::WATCOMQUOTE : cmLocalGenerator::SHELL;
  std::string target = this->Convert(targetFullPathReal,
                                     cmLocalGenerator::START_OUTPUT,
                                     output);
  vars.Target = target.c_str();
601
  vars.LinkLibraries = linkLibs.c_str();
602
  vars.ObjectsQuoted = buildObjs.c_str();
603
604
605
606
607
  if (this->Target->HasSOName(this->ConfigName))
    {
    vars.SONameFlag = this->Makefile->GetSONameFlag(linkLanguage);
    vars.TargetSOName= targetNameSO.c_str();
    }
608
  vars.LinkFlags = linkFlags.c_str();
609
610
611
612
613

  // Compute the directory portion of the install_name setting.
  std::string install_name_dir;
  if(this->Target->GetType() == cmTarget::SHARED_LIBRARY)
    {
614
    // Get the install_name directory for the build tree.
615
616
    install_name_dir =
      this->Target->GetInstallNameDirForBuildTree(this->ConfigName);
617
618
619
620
621
622
623
624
625
626

    // Set the rule variable replacement value.
    if(install_name_dir.empty())
      {
      vars.TargetInstallNameDir = "";
      }
    else
      {
      // Convert to a path for the native build tool.
      install_name_dir =
Stephen Kelly's avatar
Stephen Kelly committed
627
        this->LocalGenerator->Convert(install_name_dir,
628
                                      cmLocalGenerator::NONE,
629
                                      cmLocalGenerator::SHELL);
630
631
632
      vars.TargetInstallNameDir = install_name_dir.c_str();
      }
    }
633
634

  // Add language feature flags.
635
  std::string langFlags;
636
637
  this->AddFeatureFlags(langFlags, linkLanguage);

638
  this->LocalGenerator->AddArchitectureFlags(langFlags, this->GeneratorTarget,
Brad King's avatar
Brad King committed
639
                                             linkLanguage, this->ConfigName);
640

641
642
643
644
645
646
647
  // remove any language flags that might not work with the
  // particular os
  if(forbiddenFlagVar)
    {
    this->RemoveForbiddenFlags(forbiddenFlagVar,
                               linkLanguage, langFlags);
    }
648
  vars.LanguageCompileFlags = langFlags.c_str();
649
650

  // Construct the main link rule and expand placeholders.
Ken Martin's avatar
Ken Martin committed
651
  this->LocalGenerator->TargetImplib = targetOutPathImport;
652
653
654
655
656
657
658
659
  if(useArchiveRules)
    {
    // Construct the individual object list strings.
    std::vector<std::string> object_strings;
    this->WriteObjectsStrings(object_strings, archiveCommandLimit);

    // Create the archive with the first set of objects.
    std::vector<std::string>::iterator osi = object_strings.begin();
660
    {
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
    vars.Objects = osi->c_str();
    for(std::vector<std::string>::const_iterator
          i = archiveCreateCommands.begin();
        i != archiveCreateCommands.end(); ++i)
      {
      std::string cmd = *i;
      this->LocalGenerator->ExpandRuleVariables(cmd, vars);
      real_link_commands.push_back(cmd);
      }
    }
    // Append to the archive with the other object sets.
    for(++osi; osi != object_strings.end(); ++osi)
      {
      vars.Objects = osi->c_str();
      for(std::vector<std::string>::const_iterator
            i = archiveAppendCommands.begin();
          i != archiveAppendCommands.end(); ++i)
        {
        std::string cmd = *i;
        this->LocalGenerator->ExpandRuleVariables(cmd, vars);
        real_link_commands.push_back(cmd);
        }
      }
    // Finish the archive.
    vars.Objects = "";
    for(std::vector<std::string>::const_iterator
          i = archiveFinishCommands.begin();
        i != archiveFinishCommands.end(); ++i)
      {
      std::string cmd = *i;
      this->LocalGenerator->ExpandRuleVariables(cmd, vars);
      real_link_commands.push_back(cmd);
      }
    }
  else
    {
    // Get the set of commands.
698
    std::string linkRule = this->GetLinkRule(linkRuleVar);
699
700
701
702
703
704
705
706
    cmSystemTools::ExpandListArgument(linkRule, real_link_commands);

    // Expand placeholders.
    for(std::vector<std::string>::iterator i = real_link_commands.begin();
        i != real_link_commands.end(); ++i)
      {
      this->LocalGenerator->ExpandRuleVariables(*i, vars);
      }
707
    }
Ken Martin's avatar
Ken Martin committed
708
  this->LocalGenerator->TargetImplib = "";
709
710
711

  // Restore path conversion to normal shells.
  this->LocalGenerator->SetLinkScriptShell(false);
712
  }
713

714
715
716
717
  // Optionally convert the build rule to use a script to avoid long
  // command lines in the make shell.
  if(useLinkScript)
    {
718
719
    // Use a link script.
    const char* name = (relink? "relink.txt" : "link.txt");
720
    this->CreateLinkScript(name, real_link_commands, commands1, depends);
721
722
723
724
725
726
727
728
    }
  else
    {
    // No link script.  Just use the link rule directly.
    commands1 = real_link_commands;
    }
  this->LocalGenerator->CreateCDCommand
    (commands1,
729
     this->Makefile->GetCurrentBinaryDirectory(),
730
     cmLocalGenerator::HOME_OUTPUT);
731
732
733
734
  commands.insert(commands.end(), commands1.begin(), commands1.end());
  commands1.clear();

  // Add a rule to create necessary symlinks for the library.
735
736
  // Frameworks are handled by cmOSXBundleGenerator.
  if(targetOutPath != targetOutPathReal && !this->Target->IsFrameworkOnApple())
737
738
739
740
741
742
743
744
745
    {
    std::string symlink = "$(CMAKE_COMMAND) -E cmake_symlink_library ";
    symlink += targetOutPathReal;
    symlink += " ";
    symlink += targetOutPathSO;
    symlink += " ";
    symlink += targetOutPath;
    commands1.push_back(symlink);
    this->LocalGenerator->CreateCDCommand(commands1,
746
                                  this->Makefile->GetCurrentBinaryDirectory(),
747
                                  cmLocalGenerator::HOME_OUTPUT);
748
749
750
751
752
753
754
    commands.insert(commands.end(), commands1.begin(), commands1.end());
    commands1.clear();
    }
  // Add the post-build rules when building but not when relinking.
  if(!relink)
    {
    this->LocalGenerator->
755
756
      AppendCustomCommands(commands, this->Target->GetPostBuildCommands(),
                           this->Target);
757
758
    }

759
760
  // Compute the list of outputs.
  std::vector<std::string> outputs(1, targetFullPathReal);
761
  if(targetNameSO != targetNameReal)
762
    {
763
    outputs.push_back(targetFullPathSO);
764
    }
765
766
  if(targetName != targetNameSO &&
     targetName != targetNameReal)
767
    {
768
    outputs.push_back(targetFullPath);
769
770
    }

771
  // Write the build rule.
772
773
  this->WriteMakeRule(*this->BuildFileStream, 0, outputs,
                      depends, commands, false);
774

775
  // Write the main driver rule to build everything in this target.
Stephen Kelly's avatar
Stephen Kelly committed
776
  this->WriteTargetDriverRule(targetFullPath, relink);
777

778
  // Clean all the possible library names and symlinks.
779
  this->CleanFiles.insert(this->CleanFiles.end(),
780
                          libCleanFiles.begin(),libCleanFiles.end());
781
}
782
783
784
785

//----------------------------------------------------------------------------
void
cmMakefileLibraryTargetGenerator
786
::AppendOSXVerFlag(std::string& flags, const std::string& lang,
787
788
789
790
791
792
793
794
                   const char* name, bool so)
{
  // Lookup the flag to specify the version.
  std::string fvar = "CMAKE_";
  fvar += lang;
  fvar += "_OSX_";
  fvar += name;
  fvar += "_VERSION_FLAG";
Stephen Kelly's avatar
Stephen Kelly committed
795
  const char* flag = this->Makefile->GetDefinition(fvar);
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810

  // Skip if no such flag.
  if(!flag)
    {
    return;
    }

  // Lookup the target version information.
  int major;
  int minor;
  int patch;
  this->Target->GetTargetVersion(so, major, minor, patch);
  if(major > 0 || minor > 0 || patch > 0)
    {
    // Append the flag since a non-zero version is specified.
811
    std::ostringstream vflag;
812
    vflag << flag << major << "." << minor << "." << patch;
813
    this->LocalGenerator->AppendFlags(flags, vflag.str());
814
815
    }
}