BUG: fix some bad changes in progress calc
[cmake.git] / Source / cmInstallCommand.cxx
blobf3102c9da60b5d0f85c4255c4b4581f31f8d8117
1 /*=========================================================================
3 Program: CMake - Cross-Platform Makefile Generator
4 Module: $RCSfile: cmInstallCommand.cxx,v $
5 Language: C++
6 Date: $Date: 2008-02-07 21:22:00 $
7 Version: $Revision: 1.45 $
9 Copyright (c) 2002 Kitware, Inc., Insight Consortium. All rights reserved.
10 See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.
12 This software is distributed WITHOUT ANY WARRANTY; without even
13 the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
14 PURPOSE. See the above copyright notices for more information.
16 =========================================================================*/
17 #include "cmInstallCommand.h"
19 #include "cmInstallDirectoryGenerator.h"
20 #include "cmInstallFilesGenerator.h"
21 #include "cmInstallScriptGenerator.h"
22 #include "cmInstallTargetGenerator.h"
23 #include "cmInstallExportGenerator.h"
24 #include "cmInstallCommandArguments.h"
26 #include <cmsys/Glob.hxx>
28 static cmInstallTargetGenerator* CreateInstallTargetGenerator(cmTarget& target,
29 const cmInstallCommandArguments& args, bool impLib, bool forceOpt = false)
31 return new cmInstallTargetGenerator(target, args.GetDestination().c_str(),
32 impLib, args.GetPermissions().c_str(),
33 args.GetConfigurations(), args.GetComponent().c_str(),
34 args.GetOptional() || forceOpt);
37 static cmInstallFilesGenerator* CreateInstallFilesGenerator(
38 const std::vector<std::string>& absFiles,
39 const cmInstallCommandArguments& args, bool programs)
41 return new cmInstallFilesGenerator(absFiles, args.GetDestination().c_str(),
42 programs, args.GetPermissions().c_str(),
43 args.GetConfigurations(), args.GetComponent().c_str(),
44 args.GetRename().c_str(), args.GetOptional());
48 // cmInstallCommand
49 bool cmInstallCommand::InitialPass(std::vector<std::string> const& args,
50 cmExecutionStatus &)
52 // Allow calling with no arguments so that arguments may be built up
53 // using a variable that may be left empty.
54 if(args.empty())
56 return true;
59 // Enable the install target.
60 this->Makefile->GetLocalGenerator()
61 ->GetGlobalGenerator()->EnableInstallTarget();
63 // Switch among the command modes.
64 if(args[0] == "SCRIPT")
66 return this->HandleScriptMode(args);
68 else if(args[0] == "CODE")
70 return this->HandleScriptMode(args);
72 else if(args[0] == "TARGETS")
74 return this->HandleTargetsMode(args);
76 else if(args[0] == "FILES")
78 return this->HandleFilesMode(args);
80 else if(args[0] == "PROGRAMS")
82 return this->HandleFilesMode(args);
84 else if(args[0] == "DIRECTORY")
86 return this->HandleDirectoryMode(args);
88 else if(args[0] == "EXPORT")
90 return this->HandleExportMode(args);
93 // Unknown mode.
94 cmStdString e = "called with unknown mode ";
95 e += args[0];
96 this->SetError(e.c_str());
97 return false;
100 //----------------------------------------------------------------------------
101 bool cmInstallCommand::HandleScriptMode(std::vector<std::string> const& args)
103 std::string component("Unspecified");
104 int componentCount = 0;
105 bool doing_script = false;
106 bool doing_code = false;
108 // Scan the args once for COMPONENT. Only allow one.
110 for(size_t i=0; i < args.size(); ++i)
112 if(args[i] == "COMPONENT" && i+1 < args.size())
114 ++componentCount;
115 ++i;
116 component = args[i];
120 if(componentCount>1)
122 this->SetError("given more than one COMPONENT for the SCRIPT or CODE "
123 "signature of the INSTALL command. "
124 "Use multiple INSTALL commands with one COMPONENT each.");
125 return false;
128 // Scan the args again, this time adding install generators each time we
129 // encounter a SCRIPT or CODE arg:
131 for(size_t i=0; i < args.size(); ++i)
133 if(args[i] == "SCRIPT")
135 doing_script = true;
136 doing_code = false;
138 else if(args[i] == "CODE")
140 doing_script = false;
141 doing_code = true;
143 else if(args[i] == "COMPONENT")
145 doing_script = false;
146 doing_code = false;
148 else if(doing_script)
150 doing_script = false;
151 std::string script = args[i];
152 if(!cmSystemTools::FileIsFullPath(script.c_str()))
154 script = this->Makefile->GetCurrentDirectory();
155 script += "/";
156 script += args[i];
158 if(cmSystemTools::FileIsDirectory(script.c_str()))
160 this->SetError("given a directory as value of SCRIPT argument.");
161 return false;
163 this->Makefile->AddInstallGenerator(
164 new cmInstallScriptGenerator(script.c_str(), false,
165 component.c_str()));
167 else if(doing_code)
169 doing_code = false;
170 std::string code = args[i];
171 this->Makefile->AddInstallGenerator(
172 new cmInstallScriptGenerator(code.c_str(), true,
173 component.c_str()));
177 if(doing_script)
179 this->SetError("given no value for SCRIPT argument.");
180 return false;
182 if(doing_code)
184 this->SetError("given no value for CODE argument.");
185 return false;
188 //Tell the global generator about any installation component names specified.
189 this->Makefile->GetLocalGenerator()->GetGlobalGenerator()
190 ->AddInstallComponent(component.c_str());
192 return true;
196 /*struct InstallPart
198 InstallPart(cmCommandArgumentsHelper* helper, const char* key,
199 cmCommandArgumentGroup* group);
200 cmCAStringVector argVector;
201 cmInstallCommandArguments args;
202 };*/
204 //----------------------------------------------------------------------------
205 bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args)
207 // This is the TARGETS mode.
208 std::vector<cmTarget*> targets;
210 cmCommandArgumentsHelper argHelper;
211 cmCommandArgumentGroup group;
212 cmCAStringVector genericArgVector (&argHelper,0);
213 cmCAStringVector archiveArgVector (&argHelper,"ARCHIVE",&group);
214 cmCAStringVector libraryArgVector (&argHelper,"LIBRARY",&group);
215 cmCAStringVector runtimeArgVector (&argHelper,"RUNTIME",&group);
216 cmCAStringVector frameworkArgVector (&argHelper,"FRAMEWORK",&group);
217 cmCAStringVector bundleArgVector (&argHelper,"BUNDLE",&group);
218 cmCAStringVector privateHeaderArgVector(&argHelper,"PRIVATE_HEADER",&group);
219 cmCAStringVector publicHeaderArgVector (&argHelper,"PUBLIC_HEADER",&group);
220 cmCAStringVector resourceArgVector (&argHelper,"RESOURCE",&group);
221 genericArgVector.Follows(0);
222 group.Follows(&genericArgVector);
224 argHelper.Parse(&args, 0);
226 // now parse the generic args (i.e. the ones not specialized on LIBRARY/
227 // ARCHIVE, RUNTIME etc. (see above)
228 // These generic args also contain the targets and the export stuff
229 std::vector<std::string> unknownArgs;
230 cmInstallCommandArguments genericArgs;
231 cmCAStringVector targetList(&genericArgs.Parser, "TARGETS");
232 cmCAString exports(&genericArgs.Parser,"EXPORT", &genericArgs.ArgumentGroup);
233 targetList.Follows(0);
234 genericArgs.ArgumentGroup.Follows(&targetList);
235 genericArgs.Parse(&genericArgVector.GetVector(), &unknownArgs);
236 bool success = genericArgs.Finalize();
238 cmInstallCommandArguments archiveArgs;
239 cmInstallCommandArguments libraryArgs;
240 cmInstallCommandArguments runtimeArgs;
241 cmInstallCommandArguments frameworkArgs;
242 cmInstallCommandArguments bundleArgs;
243 cmInstallCommandArguments privateHeaderArgs;
244 cmInstallCommandArguments publicHeaderArgs;
245 cmInstallCommandArguments resourceArgs;
247 // now parse the args for specific parts of the target (e.g. LIBRARY,
248 // RUNTIME, ARCHIVE etc.
249 archiveArgs.Parse (&archiveArgVector.GetVector(), &unknownArgs);
250 libraryArgs.Parse (&libraryArgVector.GetVector(), &unknownArgs);
251 runtimeArgs.Parse (&runtimeArgVector.GetVector(), &unknownArgs);
252 frameworkArgs.Parse (&frameworkArgVector.GetVector(), &unknownArgs);
253 bundleArgs.Parse (&bundleArgVector.GetVector(), &unknownArgs);
254 privateHeaderArgs.Parse(&privateHeaderArgVector.GetVector(), &unknownArgs);
255 publicHeaderArgs.Parse (&publicHeaderArgVector.GetVector(), &unknownArgs);
256 resourceArgs.Parse (&resourceArgVector.GetVector(), &unknownArgs);
258 if(!unknownArgs.empty())
260 // Unknown argument.
261 cmOStringStream e;
262 e << "TARGETS given unknown argument \"" << unknownArgs[0] << "\".";
263 this->SetError(e.str().c_str());
264 return false;
267 // apply generic args
268 archiveArgs.SetGenericArguments(&genericArgs);
269 libraryArgs.SetGenericArguments(&genericArgs);
270 runtimeArgs.SetGenericArguments(&genericArgs);
271 frameworkArgs.SetGenericArguments(&genericArgs);
272 bundleArgs.SetGenericArguments(&genericArgs);
273 privateHeaderArgs.SetGenericArguments(&genericArgs);
274 publicHeaderArgs.SetGenericArguments(&genericArgs);
275 resourceArgs.SetGenericArguments(&genericArgs);
277 success = success && archiveArgs.Finalize();
278 success = success && libraryArgs.Finalize();
279 success = success && runtimeArgs.Finalize();
280 success = success && frameworkArgs.Finalize();
281 success = success && bundleArgs.Finalize();
282 success = success && privateHeaderArgs.Finalize();
283 success = success && publicHeaderArgs.Finalize();
284 success = success && resourceArgs.Finalize();
286 if(!success)
288 return false;
291 // Enforce argument rules too complex to specify for the
292 // general-purpose parser.
293 if(archiveArgs.GetNamelinkOnly() ||
294 runtimeArgs.GetNamelinkOnly() ||
295 frameworkArgs.GetNamelinkOnly() ||
296 bundleArgs.GetNamelinkOnly() ||
297 privateHeaderArgs.GetNamelinkOnly() ||
298 publicHeaderArgs.GetNamelinkOnly() ||
299 resourceArgs.GetNamelinkOnly())
301 this->SetError(
302 "TARGETS given NAMELINK_ONLY option not in LIBRARY group. "
303 "The NAMELINK_ONLY option may be specified only following LIBRARY."
305 return false;
307 if(archiveArgs.GetNamelinkSkip() ||
308 runtimeArgs.GetNamelinkSkip() ||
309 frameworkArgs.GetNamelinkSkip() ||
310 bundleArgs.GetNamelinkSkip() ||
311 privateHeaderArgs.GetNamelinkSkip() ||
312 publicHeaderArgs.GetNamelinkSkip() ||
313 resourceArgs.GetNamelinkSkip())
315 this->SetError(
316 "TARGETS given NAMELINK_SKIP option not in LIBRARY group. "
317 "The NAMELINK_SKIP option may be specified only following LIBRARY."
319 return false;
321 if(libraryArgs.GetNamelinkOnly() && libraryArgs.GetNamelinkSkip())
323 this->SetError(
324 "TARGETS given NAMELINK_ONLY and NAMELINK_SKIP. "
325 "At most one of these two options may be specified."
327 return false;
330 // Select the mode for installing symlinks to versioned shared libraries.
331 cmInstallTargetGenerator::NamelinkModeType
332 namelinkMode = cmInstallTargetGenerator::NamelinkModeNone;
333 if(libraryArgs.GetNamelinkOnly())
335 namelinkMode = cmInstallTargetGenerator::NamelinkModeOnly;
337 else if(libraryArgs.GetNamelinkSkip())
339 namelinkMode = cmInstallTargetGenerator::NamelinkModeSkip;
342 // Check if there is something to do.
343 if(targetList.GetVector().empty())
345 return true;
348 // Check whether this is a DLL platform.
349 bool dll_platform = (this->Makefile->IsOn("WIN32") ||
350 this->Makefile->IsOn("CYGWIN") ||
351 this->Makefile->IsOn("MINGW"));
353 for(std::vector<std::string>::const_iterator
354 targetIt=targetList.GetVector().begin();
355 targetIt!=targetList.GetVector().end();
356 ++targetIt)
358 // Lookup this target in the current directory.
359 if(cmTarget* target=this->Makefile->FindTarget(targetIt->c_str()))
361 // Found the target. Check its type.
362 if(target->GetType() != cmTarget::EXECUTABLE &&
363 target->GetType() != cmTarget::STATIC_LIBRARY &&
364 target->GetType() != cmTarget::SHARED_LIBRARY &&
365 target->GetType() != cmTarget::MODULE_LIBRARY)
367 cmOStringStream e;
368 e << "TARGETS given target \"" << (*targetIt)
369 << "\" which is not an executable, library, or module.";
370 this->SetError(e.str().c_str());
371 return false;
373 // Store the target in the list to be installed.
374 targets.push_back(target);
376 else
378 // Did not find the target.
379 cmOStringStream e;
380 e << "TARGETS given target \"" << (*targetIt)
381 << "\" which does not exist in this directory.";
382 this->SetError(e.str().c_str());
383 return false;
387 // Generate install script code to install the given targets.
388 for(std::vector<cmTarget*>::iterator ti = targets.begin();
389 ti != targets.end(); ++ti)
391 // Handle each target type.
392 cmTarget& target = *(*ti);
393 cmInstallTargetGenerator* archiveGenerator = 0;
394 cmInstallTargetGenerator* libraryGenerator = 0;
395 cmInstallTargetGenerator* runtimeGenerator = 0;
396 cmInstallTargetGenerator* frameworkGenerator = 0;
397 cmInstallTargetGenerator* bundleGenerator = 0;
398 cmInstallFilesGenerator* privateHeaderGenerator = 0;
399 cmInstallFilesGenerator* publicHeaderGenerator = 0;
400 cmInstallFilesGenerator* resourceGenerator = 0;
402 // Track whether this is a namelink-only rule.
403 bool namelinkOnly = false;
405 switch(target.GetType())
407 case cmTarget::SHARED_LIBRARY:
409 // Shared libraries are handled differently on DLL and non-DLL
410 // platforms. All windows platforms are DLL platforms including
411 // cygwin. Currently no other platform is a DLL platform.
412 if(dll_platform)
414 // When in namelink only mode skip all libraries on Windows.
415 if(namelinkMode == cmInstallTargetGenerator::NamelinkModeOnly)
417 continue;
420 // This is a DLL platform.
421 if(!archiveArgs.GetDestination().empty())
423 // The import library uses the ARCHIVE properties.
424 archiveGenerator = CreateInstallTargetGenerator(target,
425 archiveArgs, true);
427 if(!runtimeArgs.GetDestination().empty())
429 // The DLL uses the RUNTIME properties.
430 runtimeGenerator = CreateInstallTargetGenerator(target,
431 runtimeArgs, false);
433 if ((archiveGenerator==0) && (runtimeGenerator==0))
435 this->SetError("Library TARGETS given no DESTINATION!");
436 return false;
439 else
441 // This is a non-DLL platform.
442 // If it is marked with FRAMEWORK property use the FRAMEWORK set of
443 // INSTALL properties. Otherwise, use the LIBRARY properties.
444 if(target.IsFrameworkOnApple())
446 // When in namelink only mode skip frameworks.
447 if(namelinkMode == cmInstallTargetGenerator::NamelinkModeOnly)
449 continue;
452 // Use the FRAMEWORK properties.
453 if (!frameworkArgs.GetDestination().empty())
455 frameworkGenerator = CreateInstallTargetGenerator(target,
456 frameworkArgs, false);
458 else
460 cmOStringStream e;
461 e << "TARGETS given no FRAMEWORK DESTINATION for shared library "
462 "FRAMEWORK target \"" << target.GetName() << "\".";
463 this->SetError(e.str().c_str());
464 return false;
467 else
469 // The shared library uses the LIBRARY properties.
470 if (!libraryArgs.GetDestination().empty())
472 libraryGenerator = CreateInstallTargetGenerator(target,
473 libraryArgs, false);
474 libraryGenerator->SetNamelinkMode(namelinkMode);
475 namelinkOnly =
476 (namelinkMode == cmInstallTargetGenerator::NamelinkModeOnly);
478 else
480 cmOStringStream e;
481 e << "TARGETS given no LIBRARY DESTINATION for shared library "
482 "target \"" << target.GetName() << "\".";
483 this->SetError(e.str().c_str());
484 return false;
489 break;
490 case cmTarget::STATIC_LIBRARY:
492 // Static libraries use ARCHIVE properties.
493 if (!archiveArgs.GetDestination().empty())
495 archiveGenerator = CreateInstallTargetGenerator(target, archiveArgs,
496 false);
498 else
500 cmOStringStream e;
501 e << "TARGETS given no ARCHIVE DESTINATION for static library "
502 "target \"" << target.GetName() << "\".";
503 this->SetError(e.str().c_str());
504 return false;
507 break;
508 case cmTarget::MODULE_LIBRARY:
510 // Modules use LIBRARY properties.
511 if (!libraryArgs.GetDestination().empty())
513 libraryGenerator = CreateInstallTargetGenerator(target, libraryArgs,
514 false);
515 libraryGenerator->SetNamelinkMode(namelinkMode);
516 namelinkOnly =
517 (namelinkMode == cmInstallTargetGenerator::NamelinkModeOnly);
519 else
521 cmOStringStream e;
522 e << "TARGETS given no LIBRARY DESTINATION for module target \""
523 << target.GetName() << "\".";
524 this->SetError(e.str().c_str());
525 return false;
528 break;
529 case cmTarget::EXECUTABLE:
531 if(target.IsAppBundleOnApple())
533 // Application bundles use the BUNDLE properties.
534 if (!bundleArgs.GetDestination().empty())
536 bundleGenerator = CreateInstallTargetGenerator(target, bundleArgs,
537 false);
539 else
541 cmOStringStream e;
542 e << "TARGETS given no BUNDLE DESTINATION for MACOSX_BUNDLE "
543 "executable target \"" << target.GetName() << "\".";
544 this->SetError(e.str().c_str());
545 return false;
548 else
550 // Executables use the RUNTIME properties.
551 if (!runtimeArgs.GetDestination().empty())
553 runtimeGenerator = CreateInstallTargetGenerator(target,
554 runtimeArgs, false);
556 else
558 cmOStringStream e;
559 e << "TARGETS given no RUNTIME DESTINATION for executable "
560 "target \"" << target.GetName() << "\".";
561 this->SetError(e.str().c_str());
562 return false;
566 // On DLL platforms an executable may also have an import
567 // library. Install it to the archive destination if it
568 // exists.
569 if(dll_platform && !archiveArgs.GetDestination().empty() &&
570 target.IsExecutableWithExports())
572 // The import library uses the ARCHIVE properties.
573 archiveGenerator = CreateInstallTargetGenerator(target,
574 archiveArgs, true, true);
577 break;
578 default:
579 // This should never happen due to the above type check.
580 // Ignore the case.
581 break;
584 // if(target.GetProperty("ASSOCIATED_FILES");
586 // These well-known sets of files are installed *automatically* for FRAMEWORK
587 // SHARED library targets on the Mac as part of installing the FRAMEWORK.
588 // For other target types or on other platforms, they are not installed
589 // automatically and so we need to create install files generators for them.
591 bool createInstallGeneratorsForTargetFileSets = true;
593 if(target.IsFrameworkOnApple())
595 createInstallGeneratorsForTargetFileSets = false;
598 if(createInstallGeneratorsForTargetFileSets && !namelinkOnly)
600 const char* files = target.GetProperty("PRIVATE_HEADER");
601 if ((files) && (*files))
603 std::vector<std::string> relFiles;
604 cmSystemTools::ExpandListArgument(files, relFiles);
605 std::vector<std::string> absFiles;
606 if (!this->MakeFilesFullPath("PRIVATE_HEADER", relFiles, absFiles))
608 return false;
611 // Create the files install generator.
612 if (!privateHeaderArgs.GetDestination().empty())
614 privateHeaderGenerator = CreateInstallFilesGenerator(absFiles,
615 privateHeaderArgs, false);
617 else
619 cmOStringStream e;
620 e << "INSTALL TARGETS - target " << target.GetName() << " has "
621 << "PRIVATE_HEADER files but no PRIVATE_HEADER DESTINATION.";
622 cmSystemTools::Message(e.str().c_str(), "Warning");
626 files = target.GetProperty("PUBLIC_HEADER");
627 if ((files) && (*files))
629 std::vector<std::string> relFiles;
630 cmSystemTools::ExpandListArgument(files, relFiles);
631 std::vector<std::string> absFiles;
632 if (!this->MakeFilesFullPath("PUBLIC_HEADER", relFiles, absFiles))
634 return false;
637 // Create the files install generator.
638 if (!publicHeaderArgs.GetDestination().empty())
640 publicHeaderGenerator = CreateInstallFilesGenerator(absFiles,
641 publicHeaderArgs, false);
643 else
645 cmOStringStream e;
646 e << "INSTALL TARGETS - target " << target.GetName() << " has "
647 << "PUBLIC_HEADER files but no PUBLIC_HEADER DESTINATION.";
648 cmSystemTools::Message(e.str().c_str(), "Warning");
652 files = target.GetProperty("RESOURCE");
653 if ((files) && (*files))
655 std::vector<std::string> relFiles;
656 cmSystemTools::ExpandListArgument(files, relFiles);
657 std::vector<std::string> absFiles;
658 if (!this->MakeFilesFullPath("RESOURCE", relFiles, absFiles))
660 return false;
663 // Create the files install generator.
664 if (!resourceArgs.GetDestination().empty())
666 resourceGenerator = CreateInstallFilesGenerator(absFiles,
667 resourceArgs, false);
669 else
671 cmOStringStream e;
672 e << "INSTALL TARGETS - target " << target.GetName() << " has "
673 << "RESOURCE files but no RESOURCE DESTINATION.";
674 cmSystemTools::Message(e.str().c_str(), "Warning");
679 this->Makefile->AddInstallGenerator(archiveGenerator);
680 this->Makefile->AddInstallGenerator(libraryGenerator);
681 this->Makefile->AddInstallGenerator(runtimeGenerator);
682 this->Makefile->AddInstallGenerator(frameworkGenerator);
683 this->Makefile->AddInstallGenerator(bundleGenerator);
684 this->Makefile->AddInstallGenerator(privateHeaderGenerator);
685 this->Makefile->AddInstallGenerator(publicHeaderGenerator);
686 this->Makefile->AddInstallGenerator(resourceGenerator);
688 // Add this install rule to an export if one was specified and
689 // this is not a namelink-only rule.
690 if(!exports.GetString().empty() && !namelinkOnly)
692 this->Makefile->GetLocalGenerator()->GetGlobalGenerator()
693 ->AddTargetToExports(exports.GetCString(), &target,
694 archiveGenerator, runtimeGenerator,
695 libraryGenerator, frameworkGenerator,
696 bundleGenerator, publicHeaderGenerator);
700 // Tell the global generator about any installation component names specified
701 this->Makefile->GetLocalGenerator()->GetGlobalGenerator()
702 ->AddInstallComponent(archiveArgs.GetComponent().c_str());
703 this->Makefile->GetLocalGenerator()->GetGlobalGenerator()
704 ->AddInstallComponent(libraryArgs.GetComponent().c_str());
705 this->Makefile->GetLocalGenerator()->GetGlobalGenerator()
706 ->AddInstallComponent(runtimeArgs.GetComponent().c_str());
707 this->Makefile->GetLocalGenerator()->GetGlobalGenerator()
708 ->AddInstallComponent(frameworkArgs.GetComponent().c_str());
709 this->Makefile->GetLocalGenerator()->GetGlobalGenerator()
710 ->AddInstallComponent(bundleArgs.GetComponent().c_str());
711 this->Makefile->GetLocalGenerator()->GetGlobalGenerator()
712 ->AddInstallComponent(privateHeaderArgs.GetComponent().c_str());
713 this->Makefile->GetLocalGenerator()->GetGlobalGenerator()
714 ->AddInstallComponent(publicHeaderArgs.GetComponent().c_str());
715 this->Makefile->GetLocalGenerator()->GetGlobalGenerator()
716 ->AddInstallComponent(resourceArgs.GetComponent().c_str());
718 return true;
721 //----------------------------------------------------------------------------
722 bool cmInstallCommand::HandleFilesMode(std::vector<std::string> const& args)
724 // This is the FILES mode.
725 bool programs = (args[0] == "PROGRAMS");
726 cmInstallCommandArguments ica;
727 cmCAStringVector files(&ica.Parser, programs ? "PROGRAMS" : "FILES");
728 files.Follows(0);
729 ica.ArgumentGroup.Follows(&files);
730 std::vector<std::string> unknownArgs;
731 ica.Parse(&args, &unknownArgs);
733 if(!unknownArgs.empty())
735 // Unknown argument.
736 cmOStringStream e;
737 e << args[0] << " given unknown argument \"" << unknownArgs[0] << "\".";
738 this->SetError(e.str().c_str());
739 return false;
742 // Check if there is something to do.
743 if(files.GetVector().empty())
745 return true;
748 if(!ica.GetRename().empty() && files.GetVector().size() > 1)
750 // The rename option works only with one file.
751 cmOStringStream e;
752 e << args[0] << " given RENAME option with more than one file.";
753 this->SetError(e.str().c_str());
754 return false;
757 std::vector<std::string> absFiles;
758 if (!this->MakeFilesFullPath(args[0].c_str(), files.GetVector(), absFiles))
760 return false;
763 if (!ica.Finalize())
765 return false;
768 if(ica.GetDestination().empty())
770 // A destination is required.
771 cmOStringStream e;
772 e << args[0] << " given no DESTINATION!";
773 this->SetError(e.str().c_str());
774 return false;
777 // Create the files install generator.
778 this->Makefile->AddInstallGenerator(
779 CreateInstallFilesGenerator(absFiles, ica, programs));
781 //Tell the global generator about any installation component names specified.
782 this->Makefile->GetLocalGenerator()->GetGlobalGenerator()
783 ->AddInstallComponent(ica.GetComponent().c_str());
785 return true;
788 //----------------------------------------------------------------------------
789 bool
790 cmInstallCommand::HandleDirectoryMode(std::vector<std::string> const& args)
792 bool doing_dirs = true;
793 bool doing_destination = false;
794 bool doing_pattern = false;
795 bool doing_regex = false;
796 bool doing_permissions_file = false;
797 bool doing_permissions_dir = false;
798 bool doing_permissions_match = false;
799 bool doing_configurations = false;
800 bool doing_component = false;
801 bool in_match_mode = false;
802 std::vector<std::string> dirs;
803 const char* destination = 0;
804 std::string permissions_file;
805 std::string permissions_dir;
806 std::vector<std::string> configurations;
807 std::string component = "Unspecified";
808 std::string literal_args;
809 for(unsigned int i=1; i < args.size(); ++i)
811 if(args[i] == "DESTINATION")
813 if(in_match_mode)
815 cmOStringStream e;
816 e << args[0] << " does not allow \""
817 << args[i] << "\" after PATTERN or REGEX.";
818 this->SetError(e.str().c_str());
819 return false;
822 // Switch to setting the destination property.
823 doing_dirs = false;
824 doing_destination = true;
825 doing_pattern = false;
826 doing_regex = false;
827 doing_permissions_file = false;
828 doing_permissions_dir = false;
829 doing_configurations = false;
830 doing_component = false;
832 else if(args[i] == "PATTERN")
834 // Switch to a new pattern match rule.
835 doing_dirs = false;
836 doing_destination = false;
837 doing_pattern = true;
838 doing_regex = false;
839 doing_permissions_file = false;
840 doing_permissions_dir = false;
841 doing_permissions_match = false;
842 doing_configurations = false;
843 doing_component = false;
844 in_match_mode = true;
846 else if(args[i] == "REGEX")
848 // Switch to a new regex match rule.
849 doing_dirs = false;
850 doing_destination = false;
851 doing_pattern = false;
852 doing_regex = true;
853 doing_permissions_file = false;
854 doing_permissions_dir = false;
855 doing_permissions_match = false;
856 doing_configurations = false;
857 doing_component = false;
858 in_match_mode = true;
860 else if(args[i] == "EXCLUDE")
862 // Add this property to the current match rule.
863 if(!in_match_mode || doing_pattern || doing_regex)
865 cmOStringStream e;
866 e << args[0] << " does not allow \""
867 << args[i] << "\" before a PATTERN or REGEX is given.";
868 this->SetError(e.str().c_str());
869 return false;
871 literal_args += " EXCLUDE";
872 doing_permissions_match = false;
874 else if(args[i] == "PERMISSIONS")
876 if(!in_match_mode)
878 cmOStringStream e;
879 e << args[0] << " does not allow \""
880 << args[i] << "\" before a PATTERN or REGEX is given.";
881 this->SetError(e.str().c_str());
882 return false;
885 // Switch to setting the current match permissions property.
886 literal_args += " PERMISSIONS";
887 doing_permissions_match = true;
889 else if(args[i] == "FILE_PERMISSIONS")
891 if(in_match_mode)
893 cmOStringStream e;
894 e << args[0] << " does not allow \""
895 << args[i] << "\" after PATTERN or REGEX.";
896 this->SetError(e.str().c_str());
897 return false;
900 // Switch to setting the file permissions property.
901 doing_dirs = false;
902 doing_destination = false;
903 doing_pattern = false;
904 doing_regex = false;
905 doing_permissions_file = true;
906 doing_permissions_dir = false;
907 doing_configurations = false;
908 doing_component = false;
910 else if(args[i] == "DIRECTORY_PERMISSIONS")
912 if(in_match_mode)
914 cmOStringStream e;
915 e << args[0] << " does not allow \""
916 << args[i] << "\" after PATTERN or REGEX.";
917 this->SetError(e.str().c_str());
918 return false;
921 // Switch to setting the directory permissions property.
922 doing_dirs = false;
923 doing_destination = false;
924 doing_pattern = false;
925 doing_regex = false;
926 doing_permissions_file = false;
927 doing_permissions_dir = true;
928 doing_configurations = false;
929 doing_component = false;
931 else if(args[i] == "USE_SOURCE_PERMISSIONS")
933 if(in_match_mode)
935 cmOStringStream e;
936 e << args[0] << " does not allow \""
937 << args[i] << "\" after PATTERN or REGEX.";
938 this->SetError(e.str().c_str());
939 return false;
942 // Add this option literally.
943 doing_dirs = false;
944 doing_destination = false;
945 doing_pattern = false;
946 doing_regex = false;
947 doing_permissions_file = false;
948 doing_permissions_dir = false;
949 doing_configurations = false;
950 doing_component = false;
951 literal_args += " USE_SOURCE_PERMISSIONS";
953 else if(args[i] == "FILES_MATCHING")
955 if(in_match_mode)
957 cmOStringStream e;
958 e << args[0] << " does not allow \""
959 << args[i] << "\" after PATTERN or REGEX.";
960 this->SetError(e.str().c_str());
961 return false;
964 // Add this option literally.
965 doing_dirs = false;
966 doing_destination = false;
967 doing_pattern = false;
968 doing_regex = false;
969 doing_permissions_file = false;
970 doing_permissions_dir = false;
971 doing_permissions_match = false;
972 doing_configurations = false;
973 doing_component = false;
974 literal_args += " FILES_MATCHING";
976 else if(args[i] == "CONFIGURATIONS")
978 if(in_match_mode)
980 cmOStringStream e;
981 e << args[0] << " does not allow \""
982 << args[i] << "\" after PATTERN or REGEX.";
983 this->SetError(e.str().c_str());
984 return false;
987 // Switch to setting the configurations property.
988 doing_dirs = false;
989 doing_destination = false;
990 doing_pattern = false;
991 doing_regex = false;
992 doing_permissions_file = false;
993 doing_permissions_dir = false;
994 doing_configurations = true;
995 doing_component = false;
997 else if(args[i] == "COMPONENT")
999 if(in_match_mode)
1001 cmOStringStream e;
1002 e << args[0] << " does not allow \""
1003 << args[i] << "\" after PATTERN or REGEX.";
1004 this->SetError(e.str().c_str());
1005 return false;
1008 // Switch to setting the component property.
1009 doing_dirs = false;
1010 doing_destination = false;
1011 doing_pattern = false;
1012 doing_regex = false;
1013 doing_permissions_file = false;
1014 doing_permissions_dir = false;
1015 doing_configurations = false;
1016 doing_component = true;
1018 else if(doing_dirs)
1020 // Convert this directory to a full path.
1021 std::string dir = args[i];
1022 if(!cmSystemTools::FileIsFullPath(dir.c_str()))
1024 dir = this->Makefile->GetCurrentDirectory();
1025 dir += "/";
1026 dir += args[i];
1029 // Make sure the name is a directory.
1030 if(cmSystemTools::FileExists(dir.c_str()) &&
1031 !cmSystemTools::FileIsDirectory(dir.c_str()))
1033 cmOStringStream e;
1034 e << args[0] << " given non-directory \""
1035 << args[i] << "\" to install.";
1036 this->SetError(e.str().c_str());
1037 return false;
1040 // Store the directory for installation.
1041 dirs.push_back(dir);
1043 else if(doing_configurations)
1045 configurations.push_back(args[i]);
1047 else if(doing_destination)
1049 destination = args[i].c_str();
1050 doing_destination = false;
1052 else if(doing_pattern)
1054 // Convert the pattern to a regular expression. Require a
1055 // leading slash and trailing end-of-string in the matched
1056 // string to make sure the pattern matches only whole file
1057 // names.
1058 literal_args += " REGEX \"/";
1059 std::string regex = cmsys::Glob::PatternToRegex(args[i], false);
1060 cmSystemTools::ReplaceString(regex, "\\", "\\\\");
1061 literal_args += regex;
1062 literal_args += "$\"";
1063 doing_pattern = false;
1065 else if(doing_regex)
1067 literal_args += " REGEX \"";
1068 // Match rules are case-insensitive on some platforms.
1069 #if defined(_WIN32) || defined(__APPLE__) || defined(__CYGWIN__)
1070 std::string regex = cmSystemTools::LowerCase(args[i]);
1071 #else
1072 std::string regex = args[i];
1073 #endif
1074 cmSystemTools::ReplaceString(regex, "\\", "\\\\");
1075 literal_args += regex;
1076 literal_args += "\"";
1077 doing_regex = false;
1079 else if(doing_component)
1081 component = args[i];
1082 doing_component = false;
1084 else if(doing_permissions_file)
1086 // Check the requested permission.
1087 if(!cmInstallCommandArguments::CheckPermissions(args[i],permissions_file))
1089 cmOStringStream e;
1090 e << args[0] << " given invalid file permission \""
1091 << args[i] << "\".";
1092 this->SetError(e.str().c_str());
1093 return false;
1096 else if(doing_permissions_dir)
1098 // Check the requested permission.
1099 if(!cmInstallCommandArguments::CheckPermissions(args[i],permissions_dir))
1101 cmOStringStream e;
1102 e << args[0] << " given invalid directory permission \""
1103 << args[i] << "\".";
1104 this->SetError(e.str().c_str());
1105 return false;
1108 else if(doing_permissions_match)
1110 // Check the requested permission.
1111 if(!cmInstallCommandArguments::CheckPermissions(args[i], literal_args))
1113 cmOStringStream e;
1114 e << args[0] << " given invalid permission \""
1115 << args[i] << "\".";
1116 this->SetError(e.str().c_str());
1117 return false;
1120 else
1122 // Unknown argument.
1123 cmOStringStream e;
1124 e << args[0] << " given unknown argument \"" << args[i] << "\".";
1125 this->SetError(e.str().c_str());
1126 return false;
1130 // Support installing an empty directory.
1131 if(dirs.empty() && destination)
1133 dirs.push_back("");
1136 // Check if there is something to do.
1137 if(dirs.empty())
1139 return true;
1141 if(!destination)
1143 // A destination is required.
1144 cmOStringStream e;
1145 e << args[0] << " given no DESTINATION!";
1146 this->SetError(e.str().c_str());
1147 return false;
1150 // Create the directory install generator.
1151 this->Makefile->AddInstallGenerator(
1152 new cmInstallDirectoryGenerator(dirs, destination,
1153 permissions_file.c_str(),
1154 permissions_dir.c_str(),
1155 configurations,
1156 component.c_str(),
1157 literal_args.c_str()));
1159 // Tell the global generator about any installation component names
1160 // specified.
1161 this->Makefile->GetLocalGenerator()->GetGlobalGenerator()
1162 ->AddInstallComponent(component.c_str());
1164 return true;
1167 //----------------------------------------------------------------------------
1168 bool cmInstallCommand::HandleExportMode(std::vector<std::string> const& args)
1170 // This is the EXPORT mode.
1171 cmInstallCommandArguments ica;
1172 cmCAString exp(&ica.Parser, "EXPORT");
1173 cmCAString name_space(&ica.Parser, "NAMESPACE", &ica.ArgumentGroup);
1174 cmCAString filename(&ica.Parser, "FILE", &ica.ArgumentGroup);
1175 exp.Follows(0);
1177 ica.ArgumentGroup.Follows(&exp);
1178 std::vector<std::string> unknownArgs;
1179 ica.Parse(&args, &unknownArgs);
1181 if (!unknownArgs.empty())
1183 // Unknown argument.
1184 cmOStringStream e;
1185 e << args[0] << " given unknown argument \"" << unknownArgs[0] << "\".";
1186 this->SetError(e.str().c_str());
1187 return false;
1190 if (!ica.Finalize())
1192 return false;
1195 // Make sure there is a destination.
1196 if(ica.GetDestination().empty())
1198 // A destination is required.
1199 cmOStringStream e;
1200 e << args[0] << " given no DESTINATION!";
1201 this->SetError(e.str().c_str());
1202 return false;
1205 // Check the file name.
1206 std::string fname = filename.GetString();
1207 if(fname.find_first_of(":/\\") != fname.npos)
1209 cmOStringStream e;
1210 e << args[0] << " given invalid export file name \"" << fname << "\". "
1211 << "The FILE argument may not contain a path. "
1212 << "Specify the path in the DESTINATION argument.";
1213 this->SetError(e.str().c_str());
1214 return false;
1217 // Check the file extension.
1218 if(!fname.empty() &&
1219 cmSystemTools::GetFilenameLastExtension(fname) != ".cmake")
1221 cmOStringStream e;
1222 e << args[0] << " given invalid export file name \"" << fname << "\". "
1223 << "The FILE argument must specify a name ending in \".cmake\".";
1224 this->SetError(e.str().c_str());
1225 return false;
1228 // Construct the file name.
1229 if(fname.empty())
1231 fname = exp.GetString();
1232 fname += ".cmake";
1234 if(fname.find_first_of(":/\\") != fname.npos)
1236 cmOStringStream e;
1237 e << args[0] << " given export name \"" << exp.GetString() << "\". "
1238 << "This name cannot be safely converted to a file name. "
1239 << "Specify a different export name or use the FILE option to set "
1240 << "a file name explicitly.";
1241 this->SetError(e.str().c_str());
1242 return false;
1246 // Create the export install generator.
1247 cmInstallExportGenerator* exportGenerator =
1248 new cmInstallExportGenerator(
1249 exp.GetCString(), ica.GetDestination().c_str(),
1250 ica.GetPermissions().c_str(), ica.GetConfigurations(),
1251 ica.GetComponent().c_str(), fname.c_str(),
1252 name_space.GetCString(), this->Makefile);
1253 this->Makefile->AddInstallGenerator(exportGenerator);
1255 return true;
1258 bool cmInstallCommand::MakeFilesFullPath(const char* modeName,
1259 const std::vector<std::string>& relFiles,
1260 std::vector<std::string>& absFiles)
1262 for(std::vector<std::string>::const_iterator fileIt = relFiles.begin();
1263 fileIt != relFiles.end();
1264 ++fileIt)
1266 std::string file = (*fileIt);
1267 if(!cmSystemTools::FileIsFullPath(file.c_str()))
1269 file = this->Makefile->GetCurrentDirectory();
1270 file += "/";
1271 file += *fileIt;
1274 // Make sure the file is not a directory.
1275 if(cmSystemTools::FileIsDirectory(file.c_str()))
1277 cmOStringStream e;
1278 e << modeName << " given directory \"" << (*fileIt) << "\" to install.";
1279 this->SetError(e.str().c_str());
1280 return false;
1282 // Store the file for installation.
1283 absFiles.push_back(file);
1285 return true;