ENH: check in almost building VMS stuff with VMSBuild directory since the bootstrap...
[cmake.git] / Source / cmFileCommand.cxx
bloba3449109d88a2403773950941ea82b8856f2e723
1 /*=========================================================================
3 Program: CMake - Cross-Platform Makefile Generator
4 Module: $RCSfile: cmFileCommand.cxx,v $
5 Language: C++
6 Date: $Date: 2009-04-15 13:58:13 $
7 Version: $Revision: 1.119 $
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 "cmFileCommand.h"
18 #include "cmake.h"
19 #include "cmHexFileConverter.h"
20 #include "cmFileTimeComparison.h"
22 #if defined(CMAKE_BUILD_WITH_CMAKE)
23 #include "cm_curl.h"
24 #endif
26 #undef GetCurrentDirectory
27 #include <sys/types.h>
28 #include <sys/stat.h>
30 #include <cmsys/Directory.hxx>
31 #include <cmsys/Glob.hxx>
32 #include <cmsys/RegularExpression.hxx>
34 // Table of permissions flags.
35 #if defined(_WIN32) && !defined(__CYGWIN__)
36 static mode_t mode_owner_read = S_IREAD;
37 static mode_t mode_owner_write = S_IWRITE;
38 static mode_t mode_owner_execute = S_IEXEC;
39 static mode_t mode_group_read = 0;
40 static mode_t mode_group_write = 0;
41 static mode_t mode_group_execute = 0;
42 static mode_t mode_world_read = 0;
43 static mode_t mode_world_write = 0;
44 static mode_t mode_world_execute = 0;
45 static mode_t mode_setuid = 0;
46 static mode_t mode_setgid = 0;
47 #else
48 static mode_t mode_owner_read = S_IRUSR;
49 static mode_t mode_owner_write = S_IWUSR;
50 static mode_t mode_owner_execute = S_IXUSR;
51 static mode_t mode_group_read = S_IRGRP;
52 static mode_t mode_group_write = S_IWGRP;
53 static mode_t mode_group_execute = S_IXGRP;
54 static mode_t mode_world_read = S_IROTH;
55 static mode_t mode_world_write = S_IWOTH;
56 static mode_t mode_world_execute = S_IXOTH;
57 static mode_t mode_setuid = S_ISUID;
58 static mode_t mode_setgid = S_ISGID;
59 #endif
61 // cmLibraryCommand
62 bool cmFileCommand
63 ::InitialPass(std::vector<std::string> const& args, cmExecutionStatus &)
65 if(args.size() < 2 )
67 this->SetError("must be called with at least two arguments.");
68 return false;
70 std::string subCommand = args[0];
71 if ( subCommand == "WRITE" )
73 return this->HandleWriteCommand(args, false);
75 else if ( subCommand == "APPEND" )
77 return this->HandleWriteCommand(args, true);
79 else if ( subCommand == "DOWNLOAD" )
81 return this->HandleDownloadCommand(args);
83 else if ( subCommand == "READ" )
85 return this->HandleReadCommand(args);
87 else if ( subCommand == "STRINGS" )
89 return this->HandleStringsCommand(args);
91 else if ( subCommand == "GLOB" )
93 return this->HandleGlobCommand(args, false);
95 else if ( subCommand == "GLOB_RECURSE" )
97 return this->HandleGlobCommand(args, true);
99 else if ( subCommand == "MAKE_DIRECTORY" )
101 return this->HandleMakeDirectoryCommand(args);
103 else if ( subCommand == "RENAME" )
105 return this->HandleRename(args);
107 else if ( subCommand == "REMOVE" )
109 return this->HandleRemove(args, false);
111 else if ( subCommand == "REMOVE_RECURSE" )
113 return this->HandleRemove(args, true);
115 else if ( subCommand == "INSTALL" )
117 return this->HandleInstallCommand(args);
119 else if ( subCommand == "DIFFERENT" )
121 return this->HandleDifferentCommand(args);
123 else if ( subCommand == "RPATH_CHANGE" || subCommand == "CHRPATH" )
125 return this->HandleRPathChangeCommand(args);
127 else if ( subCommand == "RPATH_CHECK" )
129 return this->HandleRPathCheckCommand(args);
131 else if ( subCommand == "RPATH_REMOVE" )
133 return this->HandleRPathRemoveCommand(args);
135 else if ( subCommand == "RELATIVE_PATH" )
137 return this->HandleRelativePathCommand(args);
139 else if ( subCommand == "TO_CMAKE_PATH" )
141 return this->HandleCMakePathCommand(args, false);
143 else if ( subCommand == "TO_NATIVE_PATH" )
145 return this->HandleCMakePathCommand(args, true);
148 std::string e = "does not recognize sub-command "+subCommand;
149 this->SetError(e.c_str());
150 return false;
153 //----------------------------------------------------------------------------
154 bool cmFileCommand::HandleWriteCommand(std::vector<std::string> const& args,
155 bool append)
157 std::string message;
158 std::vector<std::string>::const_iterator i = args.begin();
160 i++; // Get rid of subcommand
162 std::string fileName = *i;
163 if ( !cmsys::SystemTools::FileIsFullPath(i->c_str()) )
165 fileName = this->Makefile->GetCurrentDirectory();
166 fileName += "/" + *i;
169 i++;
171 for(;i != args.end(); ++i)
173 message += *i;
175 if ( !this->Makefile->CanIWriteThisFile(fileName.c_str()) )
177 std::string e
178 = "attempted to write a file: " + fileName +
179 " into a source directory.";
180 this->SetError(e.c_str());
181 cmSystemTools::SetFatalErrorOccured();
182 return false;
184 std::string dir = cmSystemTools::GetFilenamePath(fileName);
185 cmSystemTools::MakeDirectory(dir.c_str());
187 mode_t mode =
188 #if defined( _MSC_VER ) || defined( __MINGW32__ )
189 S_IREAD | S_IWRITE
190 #elif defined( __BORLANDC__ )
191 S_IRUSR | S_IWUSR
192 #else
193 S_IRUSR | S_IWUSR |
194 S_IRGRP |
195 S_IROTH
196 #endif
199 // Set permissions to writable
200 if ( cmSystemTools::GetPermissions(fileName.c_str(), mode) )
202 cmSystemTools::SetPermissions(fileName.c_str(),
203 #if defined( _MSC_VER ) || defined( __MINGW32__ )
204 S_IREAD | S_IWRITE
205 #else
206 S_IRUSR | S_IWUSR
207 #endif
210 // If GetPermissions fails, pretend like it is ok. File open will fail if
211 // the file is not writable
212 std::ofstream file(fileName.c_str(), append?std::ios::app: std::ios::out);
213 if ( !file )
215 std::string error = "Internal CMake error when trying to open file: ";
216 error += fileName.c_str();
217 error += " for writing.";
218 this->SetError(error.c_str());
219 return false;
221 file << message;
222 file.close();
223 cmSystemTools::SetPermissions(fileName.c_str(), mode);
224 return true;
227 //----------------------------------------------------------------------------
228 bool cmFileCommand::HandleReadCommand(std::vector<std::string> const& args)
230 if ( args.size() < 3 )
232 this->SetError("READ must be called with at least two additional "
233 "arguments");
234 return false;
237 cmCommandArgumentsHelper argHelper;
238 cmCommandArgumentGroup group;
240 cmCAString readArg (&argHelper, "READ");
241 cmCAString fileNameArg (&argHelper, 0);
242 cmCAString resultArg (&argHelper, 0);
244 cmCAString offsetArg (&argHelper, "OFFSET", &group);
245 cmCAString limitArg (&argHelper, "LIMIT", &group);
246 cmCAEnabler hexOutputArg (&argHelper, "HEX", &group);
247 readArg.Follows(0);
248 fileNameArg.Follows(&readArg);
249 resultArg.Follows(&fileNameArg);
250 group.Follows(&resultArg);
251 argHelper.Parse(&args, 0);
253 std::string fileName = fileNameArg.GetString();
254 if ( !cmsys::SystemTools::FileIsFullPath(fileName.c_str()) )
256 fileName = this->Makefile->GetCurrentDirectory();
257 fileName += "/" + fileNameArg.GetString();
260 std::string variable = resultArg.GetString();
262 // Open the specified file.
263 #if defined(_WIN32) || defined(__CYGWIN__)
264 std::ifstream file(fileName.c_str(), std::ios::in |
265 (hexOutputArg.IsEnabled() ? std::ios::binary : std::ios::in));
266 #else
267 std::ifstream file(fileName.c_str(), std::ios::in);
268 #endif
270 if ( !file )
272 std::string error = "Internal CMake error when trying to open file: ";
273 error += fileName.c_str();
274 error += " for reading.";
275 this->SetError(error.c_str());
276 return false;
279 // is there a limit?
280 long sizeLimit = -1;
281 if (limitArg.GetString().size() > 0)
283 sizeLimit = atoi(limitArg.GetCString());
286 // is there an offset?
287 long offset = 0;
288 if (offsetArg.GetString().size() > 0)
290 offset = atoi(offsetArg.GetCString());
293 file.seekg(offset);
295 std::string output;
297 if (hexOutputArg.IsEnabled())
299 // Convert part of the file into hex code
300 int c;
301 while((sizeLimit != 0) && (c = file.get(), file))
303 char hex[4];
304 sprintf(hex, "%x", c&0xff);
305 output += hex;
306 if (sizeLimit > 0)
308 sizeLimit--;
312 else
314 std::string line;
315 bool has_newline = false;
316 while (sizeLimit != 0 &&
317 cmSystemTools::GetLineFromStream(file, line, &has_newline,
318 sizeLimit) )
320 if (sizeLimit > 0)
322 sizeLimit = sizeLimit - static_cast<long>(line.size());
323 if (has_newline)
325 sizeLimit--;
327 if (sizeLimit < 0)
329 sizeLimit = 0;
332 output += line;
333 if ( has_newline )
335 output += "\n";
339 this->Makefile->AddDefinition(variable.c_str(), output.c_str());
340 return true;
343 //----------------------------------------------------------------------------
344 bool cmFileCommand::HandleStringsCommand(std::vector<std::string> const& args)
346 if(args.size() < 3)
348 this->SetError("STRINGS requires a file name and output variable");
349 return false;
352 // Get the file to read.
353 std::string fileName = args[1];
354 if(!cmsys::SystemTools::FileIsFullPath(fileName.c_str()))
356 fileName = this->Makefile->GetCurrentDirectory();
357 fileName += "/" + args[1];
360 // Get the variable in which to store the results.
361 std::string outVar = args[2];
363 // Parse the options.
364 enum { arg_none,
365 arg_limit_input,
366 arg_limit_output,
367 arg_limit_count,
368 arg_length_minimum,
369 arg_length_maximum,
370 arg__maximum,
371 arg_regex };
372 unsigned int minlen = 0;
373 unsigned int maxlen = 0;
374 int limit_input = -1;
375 int limit_output = -1;
376 unsigned int limit_count = 0;
377 cmsys::RegularExpression regex;
378 bool have_regex = false;
379 bool newline_consume = false;
380 bool hex_conversion_enabled = true;
381 int arg_mode = arg_none;
382 for(unsigned int i=3; i < args.size(); ++i)
384 if(args[i] == "LIMIT_INPUT")
386 arg_mode = arg_limit_input;
388 else if(args[i] == "LIMIT_OUTPUT")
390 arg_mode = arg_limit_output;
392 else if(args[i] == "LIMIT_COUNT")
394 arg_mode = arg_limit_count;
396 else if(args[i] == "LENGTH_MINIMUM")
398 arg_mode = arg_length_minimum;
400 else if(args[i] == "LENGTH_MAXIMUM")
402 arg_mode = arg_length_maximum;
404 else if(args[i] == "REGEX")
406 arg_mode = arg_regex;
408 else if(args[i] == "NEWLINE_CONSUME")
410 newline_consume = true;
411 arg_mode = arg_none;
413 else if(args[i] == "NO_HEX_CONVERSION")
415 hex_conversion_enabled = false;
416 arg_mode = arg_none;
418 else if(arg_mode == arg_limit_input)
420 if(sscanf(args[i].c_str(), "%d", &limit_input) != 1 ||
421 limit_input < 0)
423 cmOStringStream e;
424 e << "STRINGS option LIMIT_INPUT value \""
425 << args[i] << "\" is not an unsigned integer.";
426 this->SetError(e.str().c_str());
427 return false;
429 arg_mode = arg_none;
431 else if(arg_mode == arg_limit_output)
433 if(sscanf(args[i].c_str(), "%d", &limit_output) != 1 ||
434 limit_output < 0)
436 cmOStringStream e;
437 e << "STRINGS option LIMIT_OUTPUT value \""
438 << args[i] << "\" is not an unsigned integer.";
439 this->SetError(e.str().c_str());
440 return false;
442 arg_mode = arg_none;
444 else if(arg_mode == arg_limit_count)
446 int count;
447 if(sscanf(args[i].c_str(), "%d", &count) != 1 || count < 0)
449 cmOStringStream e;
450 e << "STRINGS option LIMIT_COUNT value \""
451 << args[i] << "\" is not an unsigned integer.";
452 this->SetError(e.str().c_str());
453 return false;
455 limit_count = count;
456 arg_mode = arg_none;
458 else if(arg_mode == arg_length_minimum)
460 int len;
461 if(sscanf(args[i].c_str(), "%d", &len) != 1 || len < 0)
463 cmOStringStream e;
464 e << "STRINGS option LENGTH_MINIMUM value \""
465 << args[i] << "\" is not an unsigned integer.";
466 this->SetError(e.str().c_str());
467 return false;
469 minlen = len;
470 arg_mode = arg_none;
472 else if(arg_mode == arg_length_maximum)
474 int len;
475 if(sscanf(args[i].c_str(), "%d", &len) != 1 || len < 0)
477 cmOStringStream e;
478 e << "STRINGS option LENGTH_MAXIMUM value \""
479 << args[i] << "\" is not an unsigned integer.";
480 this->SetError(e.str().c_str());
481 return false;
483 maxlen = len;
484 arg_mode = arg_none;
486 else if(arg_mode == arg_regex)
488 if(!regex.compile(args[i].c_str()))
490 cmOStringStream e;
491 e << "STRINGS option REGEX value \""
492 << args[i] << "\" could not be compiled.";
493 this->SetError(e.str().c_str());
494 return false;
496 have_regex = true;
497 arg_mode = arg_none;
499 else
501 cmOStringStream e;
502 e << "STRINGS given unknown argument \""
503 << args[i] << "\"";
504 this->SetError(e.str().c_str());
505 return false;
509 if (hex_conversion_enabled)
511 // TODO: should work without temp file, but just on a memory buffer
512 std::string binaryFileName = this->Makefile->GetCurrentOutputDirectory();
513 binaryFileName += cmake::GetCMakeFilesDirectory();
514 binaryFileName += "/FileCommandStringsBinaryFile";
515 if(cmHexFileConverter::TryConvert(fileName.c_str(),binaryFileName.c_str()))
517 fileName = binaryFileName;
521 // Open the specified file.
522 #if defined(_WIN32) || defined(__CYGWIN__)
523 std::ifstream fin(fileName.c_str(), std::ios::in | std::ios::binary);
524 #else
525 std::ifstream fin(fileName.c_str(), std::ios::in);
526 #endif
527 if(!fin)
529 cmOStringStream e;
530 e << "STRINGS file \"" << fileName << "\" cannot be read.";
531 this->SetError(e.str().c_str());
532 return false;
535 // Parse strings out of the file.
536 int output_size = 0;
537 std::vector<std::string> strings;
538 std::string s;
539 int c;
540 while((!limit_count || strings.size() < limit_count) &&
541 (limit_input < 0 || static_cast<int>(fin.tellg()) < limit_input) &&
542 (c = fin.get(), fin))
544 if(c == '\0')
546 // A terminating null character has been found. Check if the
547 // current string matches the requirements. Since it was
548 // terminated by a null character, we require that the length be
549 // at least one no matter what the user specified.
550 if(s.length() >= minlen && s.length() >= 1 &&
551 (!have_regex || regex.find(s.c_str())))
553 output_size += static_cast<int>(s.size()) + 1;
554 if(limit_output >= 0 && output_size >= limit_output)
556 s = "";
557 break;
559 strings.push_back(s);
562 // Reset the string to empty.
563 s = "";
565 else if(c == '\n' && !newline_consume)
567 // The current line has been terminated. Check if the current
568 // string matches the requirements. The length may now be as
569 // low as zero since blank lines are allowed.
570 if(s.length() >= minlen &&
571 (!have_regex || regex.find(s.c_str())))
573 output_size += static_cast<int>(s.size()) + 1;
574 if(limit_output >= 0 && output_size >= limit_output)
576 s = "";
577 break;
579 strings.push_back(s);
582 // Reset the string to empty.
583 s = "";
585 else if(c == '\r')
587 // Ignore CR character to make output always have UNIX newlines.
589 else if(c >= 0x20 && c < 0x7F || c == '\t' || c == '\f' ||
590 (c == '\n' && newline_consume))
592 // This is an ASCII character that may be part of a string.
593 s += c;
595 else
597 // This is a non-string character. Reset the string to emtpy.
598 s = "";
601 // Terminate a string if the maximum length is reached.
602 if(maxlen > 0 && s.size() == maxlen)
604 if(s.length() >= minlen &&
605 (!have_regex || regex.find(s.c_str())))
607 output_size += static_cast<int>(s.size()) + 1;
608 if(limit_output >= 0 && output_size >= limit_output)
610 s = "";
611 break;
613 strings.push_back(s);
615 s = "";
619 // If there is a non-empty current string we have hit the end of the
620 // input file or the input size limit. Check if the current string
621 // matches the requirements.
622 if((!limit_count || strings.size() < limit_count) &&
623 !s.empty() && s.length() >= minlen &&
624 (!have_regex || regex.find(s.c_str())))
626 output_size += static_cast<int>(s.size()) + 1;
627 if(limit_output < 0 || output_size < limit_output)
629 strings.push_back(s);
633 // Encode the result in a CMake list.
634 const char* sep = "";
635 std::string output;
636 for(std::vector<std::string>::const_iterator si = strings.begin();
637 si != strings.end(); ++si)
639 // Separate the strings in the output to make it a list.
640 output += sep;
641 sep = ";";
643 // Store the string in the output, but escape semicolons to
644 // make sure it is a list.
645 std::string const& sr = *si;
646 for(unsigned int i=0; i < sr.size(); ++i)
648 if(sr[i] == ';')
650 output += '\\';
652 output += sr[i];
656 // Save the output in a makefile variable.
657 this->Makefile->AddDefinition(outVar.c_str(), output.c_str());
658 return true;
661 //----------------------------------------------------------------------------
662 bool cmFileCommand::HandleGlobCommand(std::vector<std::string> const& args,
663 bool recurse)
665 if ( args.size() < 2 )
667 this->SetError("GLOB requires at least a variable name");
668 return false;
671 std::vector<std::string>::const_iterator i = args.begin();
673 i++; // Get rid of subcommand
675 std::string variable = *i;
676 i++;
677 cmsys::Glob g;
678 g.SetRecurse(recurse);
680 bool explicitFollowSymlinks = false;
681 cmPolicies::PolicyStatus status =
682 this->Makefile->GetPolicyStatus(cmPolicies::CMP0009);
683 if(recurse)
685 switch(status)
687 case cmPolicies::NEW:
688 g.RecurseThroughSymlinksOff();
689 break;
690 case cmPolicies::OLD:
691 case cmPolicies::WARN:
692 case cmPolicies::REQUIRED_IF_USED:
693 case cmPolicies::REQUIRED_ALWAYS:
694 g.RecurseThroughSymlinksOn();
695 break;
699 std::string output = "";
700 bool first = true;
701 for ( ; i != args.end(); ++i )
703 if ( recurse && (*i == "FOLLOW_SYMLINKS") )
705 explicitFollowSymlinks = true;
706 g.RecurseThroughSymlinksOn();
707 ++i;
708 if ( i == args.end() )
710 this->SetError(
711 "GLOB_RECURSE requires a glob expression after FOLLOW_SYMLINKS");
712 return false;
716 if ( *i == "RELATIVE" )
718 ++i; // skip RELATIVE
719 if ( i == args.end() )
721 this->SetError("GLOB requires a directory after the RELATIVE tag");
722 return false;
724 g.SetRelative(i->c_str());
725 ++i;
726 if(i == args.end())
728 this->SetError("GLOB requires a glob expression after the directory");
729 return false;
733 if ( !cmsys::SystemTools::FileIsFullPath(i->c_str()) )
735 std::string expr = this->Makefile->GetCurrentDirectory();
736 // Handle script mode
737 if ( expr.size() > 0 )
739 expr += "/" + *i;
740 g.FindFiles(expr);
742 else
744 g.FindFiles(*i);
747 else
749 g.FindFiles(*i);
752 std::vector<std::string>::size_type cc;
753 std::vector<std::string>& files = g.GetFiles();
754 for ( cc = 0; cc < files.size(); cc ++ )
756 if ( !first )
758 output += ";";
760 output += files[cc];
761 first = false;
765 if(recurse && !explicitFollowSymlinks)
767 switch (status)
769 case cmPolicies::NEW:
770 // Correct behavior, yay!
771 break;
772 case cmPolicies::OLD:
773 // Probably not really the expected behavior, but the author explicitly
774 // asked for the old behavior... no warning.
775 case cmPolicies::WARN:
776 // Possibly unexpected old behavior *and* we actually traversed
777 // symlinks without being explicitly asked to: warn the author.
778 if(g.GetFollowedSymlinkCount() != 0)
780 this->Makefile->IssueMessage(cmake::AUTHOR_WARNING,
781 this->Makefile->GetPolicies()->
782 GetPolicyWarning(cmPolicies::CMP0009));
784 break;
785 case cmPolicies::REQUIRED_IF_USED:
786 case cmPolicies::REQUIRED_ALWAYS:
787 this->SetError("policy CMP0009 error");
788 this->Makefile->IssueMessage(cmake::FATAL_ERROR,
789 this->Makefile->GetPolicies()->
790 GetRequiredPolicyError(cmPolicies::CMP0009));
791 return false;
795 this->Makefile->AddDefinition(variable.c_str(), output.c_str());
796 return true;
799 //----------------------------------------------------------------------------
800 bool cmFileCommand::HandleMakeDirectoryCommand(
801 std::vector<std::string> const& args)
803 if(args.size() < 2 )
805 this->SetError("called with incorrect number of arguments");
806 return false;
809 std::vector<std::string>::const_iterator i = args.begin();
811 i++; // Get rid of subcommand
813 std::string expr;
814 for ( ; i != args.end(); ++i )
816 const std::string* cdir = &(*i);
817 if ( !cmsys::SystemTools::FileIsFullPath(i->c_str()) )
819 expr = this->Makefile->GetCurrentDirectory();
820 expr += "/" + *i;
821 cdir = &expr;
823 if ( !this->Makefile->CanIWriteThisFile(cdir->c_str()) )
825 std::string e = "attempted to create a directory: " + *cdir
826 + " into a source directory.";
827 this->SetError(e.c_str());
828 cmSystemTools::SetFatalErrorOccured();
829 return false;
831 if ( !cmSystemTools::MakeDirectory(cdir->c_str()) )
833 std::string error = "problem creating directory: " + *cdir;
834 this->SetError(error.c_str());
835 return false;
838 return true;
841 //----------------------------------------------------------------------------
842 bool
843 cmFileCommand::HandleDifferentCommand(std::vector<std::string> const& args)
846 FILE(DIFFERENT <variable> FILES <lhs> <rhs>)
849 // Evaluate arguments.
850 const char* file_lhs = 0;
851 const char* file_rhs = 0;
852 const char* var = 0;
853 enum Doing { DoingNone, DoingVar, DoingFileLHS, DoingFileRHS };
854 Doing doing = DoingVar;
855 for(unsigned int i=1; i < args.size(); ++i)
857 if(args[i] == "FILES")
859 doing = DoingFileLHS;
861 else if(doing == DoingVar)
863 var = args[i].c_str();
864 doing = DoingNone;
866 else if(doing == DoingFileLHS)
868 file_lhs = args[i].c_str();
869 doing = DoingFileRHS;
871 else if(doing == DoingFileRHS)
873 file_rhs = args[i].c_str();
874 doing = DoingNone;
876 else
878 cmOStringStream e;
879 e << "DIFFERENT given unknown argument " << args[i];
880 this->SetError(e.str().c_str());
881 return false;
884 if(!var)
886 this->SetError("DIFFERENT not given result variable name.");
887 return false;
889 if(!file_lhs || !file_rhs)
891 this->SetError("DIFFERENT not given FILES option with two file names.");
892 return false;
895 // Compare the files.
896 const char* result =
897 cmSystemTools::FilesDiffer(file_lhs, file_rhs)? "1" : "0";
898 this->Makefile->AddDefinition(var, result);
899 return true;
902 //----------------------------------------------------------------------------
903 // File installation helper class.
904 struct cmFileInstaller
906 // Methods to actually install files.
907 bool InstallFile(const char* fromFile, const char* toFile, bool always);
908 bool InstallDirectory(const char* source, const char* destination,
909 bool always);
911 // All instances need the file command and makefile using them.
912 cmFileInstaller(cmFileCommand* fc, cmMakefile* mf):
913 FileCommand(fc), Makefile(mf), DestDirLength(0), MatchlessFiles(true)
915 // Get the current manifest.
916 this->Manifest =
917 this->Makefile->GetSafeDefinition("CMAKE_INSTALL_MANIFEST_FILES");
919 ~cmFileInstaller()
921 // Save the updated install manifest.
922 this->Makefile->AddDefinition("CMAKE_INSTALL_MANIFEST_FILES",
923 this->Manifest.c_str());
926 private:
927 cmFileCommand* FileCommand;
928 cmMakefile* Makefile;
929 cmFileTimeComparison FileTimes;
930 public:
932 // The length of the destdir setting.
933 int DestDirLength;
935 // Whether to install a file not matching any expression.
936 bool MatchlessFiles;
938 // The current file manifest (semicolon separated list).
939 std::string Manifest;
941 // Permissions for files and directories installed by this object.
942 mode_t FilePermissions;
943 mode_t DirPermissions;
945 // Properties set by pattern and regex match rules.
946 struct MatchProperties
948 bool Exclude;
949 mode_t Permissions;
950 MatchProperties(): Exclude(false), Permissions(0) {}
952 struct MatchRule
954 cmsys::RegularExpression Regex;
955 MatchProperties Properties;
956 std::string RegexString;
957 MatchRule(std::string const& regex):
958 Regex(regex.c_str()), RegexString(regex) {}
960 std::vector<MatchRule> MatchRules;
962 // Get the properties from rules matching this input file.
963 MatchProperties CollectMatchProperties(const char* file,
964 bool isDirectory)
966 // Match rules are case-insensitive on some platforms.
967 #if defined(_WIN32) || defined(__APPLE__) || defined(__CYGWIN__)
968 std::string lower = cmSystemTools::LowerCase(file);
969 file = lower.c_str();
970 #endif
972 // Collect properties from all matching rules.
973 bool matched = false;
974 MatchProperties result;
975 for(std::vector<MatchRule>::iterator mr = this->MatchRules.begin();
976 mr != this->MatchRules.end(); ++mr)
978 if(mr->Regex.find(file))
980 matched = true;
981 result.Exclude |= mr->Properties.Exclude;
982 result.Permissions |= mr->Properties.Permissions;
985 if(!matched && !this->MatchlessFiles && !isDirectory)
987 result.Exclude = true;
989 return result;
992 // Append a file to the installation manifest.
993 void ManifestAppend(std::string const& file)
995 this->Manifest += ";";
996 this->Manifest += file.substr(this->DestDirLength);
999 // Translate an argument to a permissions bit.
1000 bool CheckPermissions(std::string const& arg, mode_t& permissions)
1002 if(arg == "OWNER_READ") { permissions |= mode_owner_read; }
1003 else if(arg == "OWNER_WRITE") { permissions |= mode_owner_write; }
1004 else if(arg == "OWNER_EXECUTE") { permissions |= mode_owner_execute; }
1005 else if(arg == "GROUP_READ") { permissions |= mode_group_read; }
1006 else if(arg == "GROUP_WRITE") { permissions |= mode_group_write; }
1007 else if(arg == "GROUP_EXECUTE") { permissions |= mode_group_execute; }
1008 else if(arg == "WORLD_READ") { permissions |= mode_world_read; }
1009 else if(arg == "WORLD_WRITE") { permissions |= mode_world_write; }
1010 else if(arg == "WORLD_EXECUTE") { permissions |= mode_world_execute; }
1011 else if(arg == "SETUID") { permissions |= mode_setuid; }
1012 else if(arg == "SETGID") { permissions |= mode_setgid; }
1013 else
1015 cmOStringStream e;
1016 e << "INSTALL given invalid permission \"" << arg << "\".";
1017 this->FileCommand->SetError(e.str().c_str());
1018 return false;
1020 return true;
1023 private:
1024 bool InstallSymlink(const char* fromFile, const char* toFile, bool always);
1027 //----------------------------------------------------------------------------
1028 bool cmFileInstaller::InstallSymlink(const char* fromFile, const char* toFile,
1029 bool always)
1031 // Read the original symlink.
1032 std::string symlinkTarget;
1033 if(!cmSystemTools::ReadSymlink(fromFile, symlinkTarget))
1035 cmOStringStream e;
1036 e << "INSTALL cannot read symlink \"" << fromFile
1037 << "\" to duplicate at \"" << toFile << "\".";
1038 this->FileCommand->SetError(e.str().c_str());
1039 return false;
1042 // Compare the symlink value to that at the destination if not
1043 // always installing.
1044 bool copy = true;
1045 if(!always)
1047 std::string oldSymlinkTarget;
1048 if(cmSystemTools::ReadSymlink(toFile, oldSymlinkTarget))
1050 if(symlinkTarget == oldSymlinkTarget)
1052 copy = false;
1057 // Inform the user about this file installation.
1058 std::string message = (copy? "Installing: " : "Up-to-date: ");
1059 message += toFile;
1060 this->Makefile->DisplayStatus(message.c_str(), -1);
1062 if(copy)
1064 // Remove the destination file so we can always create the symlink.
1065 cmSystemTools::RemoveFile(toFile);
1067 // Create the symlink.
1068 if(!cmSystemTools::CreateSymlink(symlinkTarget.c_str(), toFile))
1070 cmOStringStream e;
1071 e << "INSTALL cannot duplicate symlink \"" << fromFile
1072 << "\" at \"" << toFile << "\".";
1073 this->FileCommand->SetError(e.str().c_str());
1074 return false;
1078 // Add the file to the manifest.
1079 this->ManifestAppend(toFile);
1081 return true;
1084 //----------------------------------------------------------------------------
1085 bool cmFileInstaller::InstallFile(const char* fromFile, const char* toFile,
1086 bool always)
1088 // Collect any properties matching this file name.
1089 MatchProperties match_properties =
1090 this->CollectMatchProperties(fromFile, false);
1092 // Skip the file if it is excluded.
1093 if(match_properties.Exclude)
1095 return true;
1098 // Short-circuit for symbolic links.
1099 if(cmSystemTools::FileIsSymlink(fromFile))
1101 return this->InstallSymlink(fromFile, toFile, always);
1104 // Determine whether we will copy the file.
1105 bool copy = true;
1106 if(!always)
1108 // If both files exist with the same time do not copy.
1109 if(!this->FileTimes.FileTimesDiffer(fromFile, toFile))
1111 copy = false;
1115 // Inform the user about this file installation.
1116 std::string message = (copy? "Installing: " : "Up-to-date: ");
1117 message += toFile;
1118 this->Makefile->DisplayStatus(message.c_str(), -1);
1120 // Copy the file.
1121 if(copy && !cmSystemTools::CopyAFile(fromFile, toFile, true, false))
1123 cmOStringStream e;
1124 e << "INSTALL cannot copy file \"" << fromFile
1125 << "\" to \"" << toFile << "\".";
1126 this->FileCommand->SetError(e.str().c_str());
1127 return false;
1130 // Add the file to the manifest.
1131 this->ManifestAppend(toFile);
1133 // Set the file modification time of the destination file.
1134 if(copy && !always)
1136 if (!cmSystemTools::CopyFileTime(fromFile, toFile))
1138 cmOStringStream e;
1139 e << "Problem setting modification time on file \"" << toFile << "\"";
1140 this->FileCommand->SetError(e.str().c_str());
1141 return false;
1145 // Set permissions of the destination file.
1146 mode_t permissions = (match_properties.Permissions?
1147 match_properties.Permissions : this->FilePermissions);
1148 if(!permissions)
1150 // No permissions were explicitly provided but the user requested
1151 // that the source file permissions be used.
1152 cmSystemTools::GetPermissions(fromFile, permissions);
1154 if(permissions && !cmSystemTools::SetPermissions(toFile, permissions))
1156 cmOStringStream e;
1157 e << "Problem setting permissions on file \"" << toFile << "\"";
1158 this->FileCommand->SetError(e.str().c_str());
1159 return false;
1162 return true;
1165 //----------------------------------------------------------------------------
1166 bool cmFileInstaller::InstallDirectory(const char* source,
1167 const char* destination,
1168 bool always)
1170 // Collect any properties matching this directory name.
1171 MatchProperties match_properties =
1172 this->CollectMatchProperties(source, true);
1174 // Skip the directory if it is excluded.
1175 if(match_properties.Exclude)
1177 return true;
1180 // Short-circuit for symbolic links.
1181 if(cmSystemTools::FileIsSymlink(source))
1183 return this->InstallSymlink(source, destination, always);
1186 // Inform the user about this directory installation.
1187 std::string message = "Installing: ";
1188 message += destination;
1189 this->Makefile->DisplayStatus(message.c_str(), -1);
1191 // Make sure the destination directory exists.
1192 if(!cmSystemTools::MakeDirectory(destination))
1194 return false;
1197 // Compute the requested permissions for the destination directory.
1198 mode_t permissions = (match_properties.Permissions?
1199 match_properties.Permissions : this->DirPermissions);
1200 if(!permissions)
1202 // No permissions were explicitly provided but the user requested
1203 // that the source directory permissions be used.
1204 cmSystemTools::GetPermissions(source, permissions);
1207 // Compute the set of permissions required on this directory to
1208 // recursively install files and subdirectories safely.
1209 mode_t required_permissions =
1210 mode_owner_read | mode_owner_write | mode_owner_execute;
1212 // If the required permissions are specified it is safe to set the
1213 // final permissions now. Otherwise we must add the required
1214 // permissions temporarily during file installation.
1215 mode_t permissions_before = 0;
1216 mode_t permissions_after = 0;
1217 if(permissions & required_permissions)
1219 permissions_before = permissions;
1221 else
1223 permissions_before = permissions | required_permissions;
1224 permissions_after = permissions;
1227 // Set the required permissions of the destination directory.
1228 if(permissions_before &&
1229 !cmSystemTools::SetPermissions(destination, permissions_before))
1231 cmOStringStream e;
1232 e << "Problem setting permissions on directory \""
1233 << destination << "\"";
1234 this->FileCommand->SetError(e.str().c_str());
1235 return false;
1238 // Load the directory contents to traverse it recursively.
1239 cmsys::Directory dir;
1240 if(source && *source)
1242 dir.Load(source);
1244 unsigned long numFiles = static_cast<unsigned long>(dir.GetNumberOfFiles());
1245 for(unsigned long fileNum = 0; fileNum < numFiles; ++fileNum)
1247 if(!(strcmp(dir.GetFile(fileNum), ".") == 0 ||
1248 strcmp(dir.GetFile(fileNum), "..") == 0))
1250 cmsys_stl::string fromPath = source;
1251 fromPath += "/";
1252 fromPath += dir.GetFile(fileNum);
1253 if(cmSystemTools::FileIsDirectory(fromPath.c_str()))
1255 cmsys_stl::string toDir = destination;
1256 toDir += "/";
1257 toDir += dir.GetFile(fileNum);
1258 if(!this->InstallDirectory(fromPath.c_str(), toDir.c_str(), always))
1260 return false;
1263 else
1265 // Install this file.
1266 std::string toFile = destination;
1267 toFile += "/";
1268 toFile += dir.GetFile(fileNum);
1269 if(!this->InstallFile(fromPath.c_str(), toFile.c_str(), always))
1271 return false;
1277 // Set the requested permissions of the destination directory.
1278 if(permissions_after &&
1279 !cmSystemTools::SetPermissions(destination, permissions_after))
1281 cmOStringStream e;
1282 e << "Problem setting permissions on directory \"" << destination << "\"";
1283 this->FileCommand->SetError(e.str().c_str());
1284 return false;
1287 return true;
1290 //----------------------------------------------------------------------------
1291 void cmFileCommand::HandleInstallPermissions(cmFileInstaller& installer,
1292 mode_t& permissions_file,
1293 mode_t& permissions_dir,
1294 int itype,
1295 bool use_given_permissions_file,
1296 bool use_given_permissions_dir,
1297 bool use_source_permissions) const
1299 // Choose a default for shared library permissions.
1300 bool install_so_no_exe = this->Makefile->IsOn("CMAKE_INSTALL_SO_NO_EXE");
1301 // If file permissions were not specified set default permissions
1302 // for this target type.
1303 if(!use_given_permissions_file && !use_source_permissions)
1305 switch(itype)
1307 case cmTarget::SHARED_LIBRARY:
1308 case cmTarget::MODULE_LIBRARY:
1309 if(install_so_no_exe)
1311 // Use read/write permissions.
1312 permissions_file = 0;
1313 permissions_file |= mode_owner_read;
1314 permissions_file |= mode_owner_write;
1315 permissions_file |= mode_group_read;
1316 permissions_file |= mode_world_read;
1317 break;
1319 case cmTarget::EXECUTABLE:
1320 case cmTarget::INSTALL_PROGRAMS:
1321 // Use read/write/executable permissions.
1322 permissions_file = 0;
1323 permissions_file |= mode_owner_read;
1324 permissions_file |= mode_owner_write;
1325 permissions_file |= mode_owner_execute;
1326 permissions_file |= mode_group_read;
1327 permissions_file |= mode_group_execute;
1328 permissions_file |= mode_world_read;
1329 permissions_file |= mode_world_execute;
1330 break;
1331 default:
1332 // Use read/write permissions.
1333 permissions_file = 0;
1334 permissions_file |= mode_owner_read;
1335 permissions_file |= mode_owner_write;
1336 permissions_file |= mode_group_read;
1337 permissions_file |= mode_world_read;
1338 break;
1342 // If directory permissions were not specified set default permissions.
1343 if(!use_given_permissions_dir && !use_source_permissions)
1345 // Use read/write/executable permissions.
1346 permissions_dir = 0;
1347 permissions_dir |= mode_owner_read;
1348 permissions_dir |= mode_owner_write;
1349 permissions_dir |= mode_owner_execute;
1350 permissions_dir |= mode_group_read;
1351 permissions_dir |= mode_group_execute;
1352 permissions_dir |= mode_world_read;
1353 permissions_dir |= mode_world_execute;
1355 // Set the installer permissions.
1356 installer.FilePermissions = permissions_file;
1357 installer.DirPermissions = permissions_dir;
1360 //----------------------------------------------------------------------------
1361 void cmFileCommand
1362 ::GetTargetTypeFromString(const std::string& stype, int& itype) const
1364 if ( stype == "EXECUTABLE" )
1366 itype = cmTarget::EXECUTABLE;
1368 else if ( stype == "PROGRAM" )
1370 itype = cmTarget::INSTALL_PROGRAMS;
1372 else if ( stype == "STATIC_LIBRARY" )
1374 itype = cmTarget::STATIC_LIBRARY;
1376 else if ( stype == "SHARED_LIBRARY" )
1378 itype = cmTarget::SHARED_LIBRARY;
1380 else if ( stype == "MODULE" )
1382 itype = cmTarget::MODULE_LIBRARY;
1384 else if ( stype == "DIRECTORY" )
1386 itype = cmTarget::INSTALL_DIRECTORY;
1391 //----------------------------------------------------------------------------
1392 bool cmFileCommand::HandleInstallDestination(cmFileInstaller& installer,
1393 std::string& destination)
1395 // allow for / to be a valid destination
1396 if ( destination.size() < 2 && destination != "/" )
1398 this->SetError("called with inapropriate arguments. "
1399 "No DESTINATION provided or .");
1400 return false;
1403 const char* destdir = cmSystemTools::GetEnv("DESTDIR");
1404 if ( destdir && *destdir )
1406 std::string sdestdir = destdir;
1407 cmSystemTools::ConvertToUnixSlashes(sdestdir);
1408 char ch1 = destination[0];
1409 char ch2 = destination[1];
1410 char ch3 = 0;
1411 if ( destination.size() > 2 )
1413 ch3 = destination[2];
1415 int skip = 0;
1416 if ( ch1 != '/' )
1418 int relative = 0;
1419 if ( ( ch1 >= 'a' && ch1 <= 'z' || ch1 >= 'A' && ch1 <= 'Z' ) &&
1420 ch2 == ':' )
1422 // Assume windows
1423 // let's do some destdir magic:
1424 skip = 2;
1425 if ( ch3 != '/' )
1427 relative = 1;
1430 else
1432 relative = 1;
1434 if ( relative )
1436 // This is relative path on unix or windows. Since we are doing
1437 // destdir, this case does not make sense.
1438 this->SetError("called with relative DESTINATION. This "
1439 "does not make sense when using DESTDIR. Specify "
1440 "absolute path or remove DESTDIR environment variable.");
1441 return false;
1444 else
1446 if ( ch2 == '/' )
1448 // looks like a network path.
1449 std::string message = "called with network path DESTINATION. This "
1450 "does not make sense when using DESTDIR. Specify local "
1451 "absolute path or remove DESTDIR environment variable."
1452 "\nDESTINATION=\n";
1453 message += destination;
1454 this->SetError(message.c_str());
1455 return false;
1458 destination = sdestdir + (destination.c_str() + skip);
1459 installer.DestDirLength = int(sdestdir.size());
1462 if ( !cmSystemTools::FileExists(destination.c_str()) )
1464 if ( !cmSystemTools::MakeDirectory(destination.c_str()) )
1466 std::string errstring = "cannot create directory: " + destination +
1467 ". Maybe need administrative privileges.";
1468 this->SetError(errstring.c_str());
1469 return false;
1472 if ( !cmSystemTools::FileIsDirectory(destination.c_str()) )
1474 std::string errstring = "INSTALL destination: " + destination +
1475 " is not a directory.";
1476 this->SetError(errstring.c_str());
1477 return false;
1479 return true;
1482 //----------------------------------------------------------------------------
1483 bool
1484 cmFileCommand::HandleRPathChangeCommand(std::vector<std::string> const& args)
1486 // Evaluate arguments.
1487 const char* file = 0;
1488 const char* oldRPath = 0;
1489 const char* newRPath = 0;
1490 enum Doing { DoingNone, DoingFile, DoingOld, DoingNew };
1491 Doing doing = DoingNone;
1492 for(unsigned int i=1; i < args.size(); ++i)
1494 if(args[i] == "OLD_RPATH")
1496 doing = DoingOld;
1498 else if(args[i] == "NEW_RPATH")
1500 doing = DoingNew;
1502 else if(args[i] == "FILE")
1504 doing = DoingFile;
1506 else if(doing == DoingFile)
1508 file = args[i].c_str();
1509 doing = DoingNone;
1511 else if(doing == DoingOld)
1513 oldRPath = args[i].c_str();
1514 doing = DoingNone;
1516 else if(doing == DoingNew)
1518 newRPath = args[i].c_str();
1519 doing = DoingNone;
1521 else
1523 cmOStringStream e;
1524 e << "RPATH_CHANGE given unknown argument " << args[i];
1525 this->SetError(e.str().c_str());
1526 return false;
1529 if(!file)
1531 this->SetError("RPATH_CHANGE not given FILE option.");
1532 return false;
1534 if(!oldRPath)
1536 this->SetError("RPATH_CHANGE not given OLD_RPATH option.");
1537 return false;
1539 if(!newRPath)
1541 this->SetError("RPATH_CHANGE not given NEW_RPATH option.");
1542 return false;
1544 if(!cmSystemTools::FileExists(file, true))
1546 cmOStringStream e;
1547 e << "RPATH_CHANGE given FILE \"" << file << "\" that does not exist.";
1548 this->SetError(e.str().c_str());
1549 return false;
1551 bool success = true;
1552 cmSystemToolsFileTime* ft = cmSystemTools::FileTimeNew();
1553 bool have_ft = cmSystemTools::FileTimeGet(file, ft);
1554 std::string emsg;
1555 bool changed;
1556 if(!cmSystemTools::ChangeRPath(file, oldRPath, newRPath, &emsg, &changed))
1558 cmOStringStream e;
1559 e << "RPATH_CHANGE could not write new RPATH:\n"
1560 << " " << newRPath << "\n"
1561 << "to the file:\n"
1562 << " " << file << "\n"
1563 << emsg;
1564 this->SetError(e.str().c_str());
1565 success = false;
1567 if(success)
1569 if(changed)
1571 std::string message = "Set runtime path of \"";
1572 message += file;
1573 message += "\" to \"";
1574 message += newRPath;
1575 message += "\"";
1576 this->Makefile->DisplayStatus(message.c_str(), -1);
1578 if(have_ft)
1580 cmSystemTools::FileTimeSet(file, ft);
1583 cmSystemTools::FileTimeDelete(ft);
1584 return success;
1587 //----------------------------------------------------------------------------
1588 bool
1589 cmFileCommand::HandleRPathRemoveCommand(std::vector<std::string> const& args)
1591 // Evaluate arguments.
1592 const char* file = 0;
1593 enum Doing { DoingNone, DoingFile };
1594 Doing doing = DoingNone;
1595 for(unsigned int i=1; i < args.size(); ++i)
1597 if(args[i] == "FILE")
1599 doing = DoingFile;
1601 else if(doing == DoingFile)
1603 file = args[i].c_str();
1604 doing = DoingNone;
1606 else
1608 cmOStringStream e;
1609 e << "RPATH_REMOVE given unknown argument " << args[i];
1610 this->SetError(e.str().c_str());
1611 return false;
1614 if(!file)
1616 this->SetError("RPATH_REMOVE not given FILE option.");
1617 return false;
1619 if(!cmSystemTools::FileExists(file, true))
1621 cmOStringStream e;
1622 e << "RPATH_REMOVE given FILE \"" << file << "\" that does not exist.";
1623 this->SetError(e.str().c_str());
1624 return false;
1626 bool success = true;
1627 cmSystemToolsFileTime* ft = cmSystemTools::FileTimeNew();
1628 bool have_ft = cmSystemTools::FileTimeGet(file, ft);
1629 std::string emsg;
1630 bool removed;
1631 if(!cmSystemTools::RemoveRPath(file, &emsg, &removed))
1633 cmOStringStream e;
1634 e << "RPATH_REMOVE could not remove RPATH from file:\n"
1635 << " " << file << "\n"
1636 << emsg;
1637 this->SetError(e.str().c_str());
1638 success = false;
1640 if(success)
1642 if(removed)
1644 std::string message = "Removed runtime path from \"";
1645 message += file;
1646 message += "\"";
1647 this->Makefile->DisplayStatus(message.c_str(), -1);
1649 if(have_ft)
1651 cmSystemTools::FileTimeSet(file, ft);
1654 cmSystemTools::FileTimeDelete(ft);
1655 return success;
1658 //----------------------------------------------------------------------------
1659 bool
1660 cmFileCommand::HandleRPathCheckCommand(std::vector<std::string> const& args)
1662 // Evaluate arguments.
1663 const char* file = 0;
1664 const char* rpath = 0;
1665 enum Doing { DoingNone, DoingFile, DoingRPath };
1666 Doing doing = DoingNone;
1667 for(unsigned int i=1; i < args.size(); ++i)
1669 if(args[i] == "RPATH")
1671 doing = DoingRPath;
1673 else if(args[i] == "FILE")
1675 doing = DoingFile;
1677 else if(doing == DoingFile)
1679 file = args[i].c_str();
1680 doing = DoingNone;
1682 else if(doing == DoingRPath)
1684 rpath = args[i].c_str();
1685 doing = DoingNone;
1687 else
1689 cmOStringStream e;
1690 e << "RPATH_CHECK given unknown argument " << args[i];
1691 this->SetError(e.str().c_str());
1692 return false;
1695 if(!file)
1697 this->SetError("RPATH_CHECK not given FILE option.");
1698 return false;
1700 if(!rpath)
1702 this->SetError("RPATH_CHECK not given RPATH option.");
1703 return false;
1706 // If the file exists but does not have the desired RPath then
1707 // delete it. This is used during installation to re-install a file
1708 // if its RPath will change.
1709 if(cmSystemTools::FileExists(file, true) &&
1710 !cmSystemTools::CheckRPath(file, rpath))
1712 cmSystemTools::RemoveFile(file);
1715 return true;
1718 //----------------------------------------------------------------------------
1719 bool cmFileCommand::HandleInstallCommand(std::vector<std::string> const& args)
1721 if ( args.size() < 6 )
1723 this->SetError("called with incorrect number of arguments");
1724 return false;
1727 // Construct a file installer object.
1728 cmFileInstaller installer(this, this->Makefile);
1730 std::string rename = "";
1731 std::string destination = "";
1733 std::vector<std::string> files;
1734 int itype = cmTarget::INSTALL_FILES;
1736 std::map<cmStdString, const char*> properties;
1737 bool optional = false;
1738 bool result = this->ParseInstallArgs(args, installer, properties,
1739 itype, rename, destination, files,
1740 optional);
1741 if (result == true)
1743 result = this->DoInstall(installer,
1744 itype, rename, destination, files, optional);
1746 return result;
1749 //----------------------------------------------------------------------------
1750 bool cmFileCommand::ParseInstallArgs(std::vector<std::string> const& args,
1751 cmFileInstaller& installer,
1752 std::map<cmStdString, const char*>& properties,
1753 int& itype,
1754 std::string& rename,
1755 std::string& destination,
1756 std::vector<std::string>& files,
1757 bool& optional)
1759 std::string stype = "FILES";
1760 enum Doing { DoingNone, DoingFiles, DoingProperties,
1761 DoingPermissionsFile, DoingPermissionsDir,
1762 DoingPermissionsMatch, DoingSelf24 };
1763 Doing doing = DoingNone;
1764 bool use_given_permissions_file = false;
1765 bool use_given_permissions_dir = false;
1766 bool use_source_permissions = false;
1767 mode_t permissions_file = 0;
1768 mode_t permissions_dir = 0;
1770 cmFileInstaller::MatchRule* current_match_rule = 0;
1771 std::vector<std::string>::size_type i = 0;
1772 i++; // Get rid of subcommand
1773 for ( ; i != args.size(); ++i )
1775 const std::string* cstr = &args[i];
1776 if ( *cstr == "DESTINATION" && i < args.size()-1 )
1778 if(current_match_rule)
1780 cmOStringStream e;
1781 e << "INSTALL does not allow \"" << *cstr << "\" after REGEX.";
1782 this->SetError(e.str().c_str());
1783 return false;
1786 i++;
1787 destination = args[i];
1788 doing = DoingNone;
1790 else if ( *cstr == "TYPE" && i < args.size()-1 )
1792 if(current_match_rule)
1794 cmOStringStream e;
1795 e << "INSTALL does not allow \"" << *cstr << "\" after REGEX.";
1796 this->SetError(e.str().c_str());
1797 return false;
1800 i++;
1801 stype = args[i];
1802 if ( args[i+1] == "OPTIONAL" )
1804 i++;
1805 optional = true;
1807 doing = DoingNone;
1809 else if ( *cstr == "RENAME" && i < args.size()-1 )
1811 if(current_match_rule)
1813 cmOStringStream e;
1814 e << "INSTALL does not allow \"" << *cstr << "\" after REGEX.";
1815 this->SetError(e.str().c_str());
1816 return false;
1819 i++;
1820 rename = args[i];
1821 doing = DoingNone;
1823 else if ( *cstr == "REGEX" && i < args.size()-1 )
1825 i++;
1826 installer.MatchRules.push_back(cmFileInstaller::MatchRule(args[i]));
1827 current_match_rule = &*(installer.MatchRules.end()-1);
1828 if(!current_match_rule->Regex.is_valid())
1830 cmOStringStream e;
1831 e << "INSTALL could not compile REGEX \"" << args[i] << "\".";
1832 this->SetError(e.str().c_str());
1833 return false;
1835 doing = DoingNone;
1837 else if ( *cstr == "EXCLUDE" )
1839 // Add this property to the current match rule.
1840 if(!current_match_rule)
1842 cmOStringStream e;
1843 e << "INSTALL does not allow \""
1844 << *cstr << "\" before a REGEX is given.";
1845 this->SetError(e.str().c_str());
1846 return false;
1848 current_match_rule->Properties.Exclude = true;
1849 doing = DoingPermissionsMatch;
1851 else if ( *cstr == "PROPERTIES" )
1853 if(current_match_rule)
1855 cmOStringStream e;
1856 e << "INSTALL does not allow \"" << *cstr << "\" after REGEX.";
1857 this->SetError(e.str().c_str());
1858 return false;
1861 doing = DoingProperties;
1863 else if ( *cstr == "PERMISSIONS" )
1865 if(current_match_rule)
1867 doing = DoingPermissionsMatch;
1869 else
1871 doing = DoingPermissionsFile;
1872 use_given_permissions_file = true;
1875 else if ( *cstr == "DIR_PERMISSIONS" )
1877 if(current_match_rule)
1879 cmOStringStream e;
1880 e << "INSTALL does not allow \"" << *cstr << "\" after REGEX.";
1881 this->SetError(e.str().c_str());
1882 return false;
1885 use_given_permissions_dir = true;
1886 doing = DoingPermissionsDir;
1888 else if ( *cstr == "USE_SOURCE_PERMISSIONS" )
1890 if(current_match_rule)
1892 cmOStringStream e;
1893 e << "INSTALL does not allow \"" << *cstr << "\" after REGEX.";
1894 this->SetError(e.str().c_str());
1895 return false;
1898 doing = DoingNone;
1899 use_source_permissions = true;
1901 else if ( *cstr == "FILES_MATCHING" )
1903 if(current_match_rule)
1905 cmOStringStream e;
1906 e << "INSTALL does not allow \"" << *cstr << "\" after REGEX.";
1907 this->SetError(e.str().c_str());
1908 return false;
1911 doing = DoingNone;
1912 installer.MatchlessFiles = false;
1914 else if ( *cstr == "COMPONENTS" )
1916 if(this->Makefile->IsOn("CMAKE_INSTALL_SELF_2_4"))
1918 // When CMake 2.4 builds this CMake version we need to support
1919 // the install scripts it generates since it asks this CMake
1920 // to install itself using the rules it generated.
1921 doing = DoingSelf24;
1922 continue;
1924 cmOStringStream e;
1925 e << "INSTALL called with old-style COMPONENTS argument. "
1926 << "This script was generated with an older version of CMake. "
1927 << "Re-run this cmake version on your build tree.";
1928 this->SetError(e.str().c_str());
1929 return false;
1931 else if ( *cstr == "CONFIGURATIONS" )
1933 cmOStringStream e;
1934 e << "INSTALL called with old-style CONFIGURATIONS argument. "
1935 << "This script was generated with an older version of CMake. "
1936 << "Re-run this cmake version on your build tree.";
1937 this->SetError(e.str().c_str());
1938 return false;
1940 else if(*cstr == "FILES" && doing != DoingFiles)
1942 if(current_match_rule)
1944 cmOStringStream e;
1945 e << "INSTALL does not allow \"" << *cstr << "\" after REGEX.";
1946 this->SetError(e.str().c_str());
1947 return false;
1950 doing = DoingFiles;
1952 else if(doing == DoingProperties && i < args.size()-1)
1954 properties[args[i]] = args[i+1].c_str();
1955 i++;
1957 else if(doing == DoingFiles)
1959 files.push_back(*cstr);
1961 else if(doing == DoingPermissionsFile)
1963 if(!installer.CheckPermissions(args[i], permissions_file))
1965 return false;
1968 else if(doing == DoingPermissionsDir)
1970 if(!installer.CheckPermissions(args[i], permissions_dir))
1972 return false;
1975 else if(doing == DoingPermissionsMatch)
1977 if(!installer.CheckPermissions(
1978 args[i], current_match_rule->Properties.Permissions))
1980 return false;
1983 else if(doing == DoingSelf24)
1985 // Ignore these arguments for compatibility. This should be
1986 // reached only when CMake 2.4 is installing the current
1987 // CMake. It can be removed when CMake 2.6 or higher is
1988 // required to build CMake.
1990 else
1992 this->SetError("called with inappropriate arguments");
1993 return false;
1997 // now check and postprocess what has been parsed
1998 if ( files.size() == 0 )
2000 // nothing to do, no files were listed.
2001 // if this is handled as error, INSTALL_FILES() creates an invalid
2002 // cmake_install.cmake script with no FILES() arguments if no files were
2003 // given to INSTALL_FILES(). This was accepted with CMake 2.4.x.
2004 return true;
2007 // Check rename form.
2008 if(!rename.empty())
2010 if(itype != cmTarget::INSTALL_FILES &&
2011 itype != cmTarget::INSTALL_PROGRAMS)
2013 this->SetError("INSTALL option RENAME may be used only with "
2014 "FILES or PROGRAMS.");
2015 return false;
2017 if(files.size() > 1)
2019 this->SetError("INSTALL option RENAME may be used only with "
2020 "one file.");
2021 return false;
2025 if (this->HandleInstallDestination(installer, destination) == false)
2027 return false;
2030 if(properties.find("VERSION") != properties.end())
2032 cmOStringStream e;
2033 e << "INSTALL called with old-style VERSION property. "
2034 << "This script was generated with an older version of CMake. "
2035 << "Re-run this cmake version on your build tree.";
2036 this->SetError(e.str().c_str());
2037 return false;
2039 if(properties.find("SOVERSION") != properties.end())
2041 cmOStringStream e;
2042 e << "INSTALL called with old-style SOVERSION property. "
2043 << "This script was generated with an older version of CMake. "
2044 << "Re-run this cmake version on your build tree.";
2045 this->SetError(e.str().c_str());
2046 return false;
2049 this->GetTargetTypeFromString(stype, itype);
2051 this->HandleInstallPermissions(installer,
2052 permissions_file,
2053 permissions_dir,
2054 itype,
2055 use_given_permissions_file,
2056 use_given_permissions_dir,
2057 use_source_permissions);
2059 return true;
2062 //----------------------------------------------------------------------------
2063 bool cmFileCommand::DoInstall( cmFileInstaller& installer,
2064 const int itype,
2065 const std::string& rename,
2066 const std::string& destination,
2067 const std::vector<std::string>& files,
2068 const bool optional)
2070 typedef std::set<cmStdString>::const_iterator iter_type;
2072 // Check whether files should be copied always or only if they have
2073 // changed.
2074 bool copy_always =
2075 cmSystemTools::IsOn(cmSystemTools::GetEnv("CMAKE_INSTALL_ALWAYS"));
2077 // Handle each file listed.
2078 for (std::vector<std::string>::size_type i = 0; i < files.size(); i ++ )
2080 // Split the input file into its directory and name components.
2081 std::vector<std::string> fromPathComponents;
2082 cmSystemTools::SplitPath(files[i].c_str(), fromPathComponents);
2083 std::string fromName = *(fromPathComponents.end()-1);
2084 std::string fromDir = cmSystemTools::JoinPath(fromPathComponents.begin(),
2085 fromPathComponents.end()-1);
2087 // Compute the full path to the destination file.
2088 std::string toFile = destination;
2089 std::string const& toName = rename.empty()? fromName : rename;
2090 if(!toName.empty())
2092 toFile += "/";
2093 toFile += toName;
2096 // Construct the full path to the source file. The file name may
2097 // have been changed above.
2098 std::string fromFile = fromDir;
2099 if(!fromName.empty())
2101 fromFile += "/";
2102 fromFile += fromName;
2105 std::string message;
2106 if(!cmSystemTools::SameFile(fromFile.c_str(), toFile.c_str()))
2108 if(itype == cmTarget::INSTALL_DIRECTORY &&
2109 (fromFile.empty() ||
2110 cmSystemTools::FileIsDirectory(fromFile.c_str())))
2112 // Try installing this directory.
2113 if(!installer.InstallDirectory(fromFile.c_str(), toFile.c_str(),
2114 copy_always))
2116 return false;
2119 else if(cmSystemTools::FileExists(fromFile.c_str()))
2121 // Install this file.
2122 if(!installer.InstallFile(fromFile.c_str(), toFile.c_str(),
2123 copy_always))
2125 return false;
2128 else if(!optional)
2130 // The input file does not exist and installation is not optional.
2131 cmOStringStream e;
2132 e << "INSTALL cannot find file \"" << fromFile << "\" to install.";
2133 this->SetError(e.str().c_str());
2134 return false;
2139 return true;
2142 //----------------------------------------------------------------------------
2143 bool cmFileCommand::HandleRelativePathCommand(
2144 std::vector<std::string> const& args)
2146 if(args.size() != 4 )
2148 this->SetError("called with incorrect number of arguments");
2149 return false;
2152 const std::string& outVar = args[1];
2153 const std::string& directoryName = args[2];
2154 const std::string& fileName = args[3];
2156 if(!cmSystemTools::FileIsFullPath(directoryName.c_str()))
2158 std::string errstring =
2159 "RelativePath must be passed a full path to the directory: "
2160 + directoryName;
2161 this->SetError(errstring.c_str());
2162 return false;
2164 if(!cmSystemTools::FileIsFullPath(fileName.c_str()))
2166 std::string errstring =
2167 "RelativePath must be passed a full path to the file: "
2168 + fileName;
2169 this->SetError(errstring.c_str());
2170 return false;
2173 std::string res = cmSystemTools::RelativePath(directoryName.c_str(),
2174 fileName.c_str());
2175 this->Makefile->AddDefinition(outVar.c_str(),
2176 res.c_str());
2177 return true;
2181 //----------------------------------------------------------------------------
2182 bool cmFileCommand::HandleRename(std::vector<std::string> const& args)
2184 if(args.size() != 3)
2186 this->SetError("given incorrect number of arguments.");
2187 return false;
2190 // Compute full path for old and new names.
2191 std::string oldname = args[1];
2192 if(!cmsys::SystemTools::FileIsFullPath(oldname.c_str()))
2194 oldname = this->Makefile->GetCurrentDirectory();
2195 oldname += "/" + args[1];
2197 std::string newname = args[2];
2198 if(!cmsys::SystemTools::FileIsFullPath(newname.c_str()))
2200 newname = this->Makefile->GetCurrentDirectory();
2201 newname += "/" + args[2];
2204 if(!cmSystemTools::RenameFile(oldname.c_str(), newname.c_str()))
2206 std::string err = cmSystemTools::GetLastSystemError();
2207 cmOStringStream e;
2208 e << "RENAME failed to rename\n"
2209 << " " << oldname << "\n"
2210 << "to\n"
2211 << " " << newname << "\n"
2212 << "because: " << err << "\n";
2213 this->SetError(e.str().c_str());
2214 return false;
2216 return true;
2220 //----------------------------------------------------------------------------
2221 bool cmFileCommand::HandleRemove(std::vector<std::string> const& args,
2222 bool recurse)
2225 std::string message;
2226 std::vector<std::string>::const_iterator i = args.begin();
2228 i++; // Get rid of subcommand
2229 for(;i != args.end(); ++i)
2231 std::string fileName = *i;
2232 if(!cmsys::SystemTools::FileIsFullPath(fileName.c_str()))
2234 fileName = this->Makefile->GetCurrentDirectory();
2235 fileName += "/" + *i;
2238 if(cmSystemTools::FileIsDirectory(fileName.c_str()) && recurse)
2240 cmSystemTools::RemoveADirectory(fileName.c_str());
2242 else
2244 cmSystemTools::RemoveFile(fileName.c_str());
2247 return true;
2250 //----------------------------------------------------------------------------
2251 bool cmFileCommand::HandleCMakePathCommand(std::vector<std::string>
2252 const& args,
2253 bool nativePath)
2255 std::vector<std::string>::const_iterator i = args.begin();
2256 if(args.size() != 3)
2258 this->SetError("FILE(SYSTEM_PATH ENV result) must be called with "
2259 "only three arguments.");
2260 return false;
2262 i++; // Get rid of subcommand
2263 #if defined(_WIN32) && !defined(__CYGWIN__)
2264 char pathSep = ';';
2265 #else
2266 char pathSep = ':';
2267 #endif
2268 std::vector<cmsys::String> path = cmSystemTools::SplitString(i->c_str(),
2269 pathSep);
2270 i++;
2271 const char* var = i->c_str();
2272 std::string value;
2273 for(std::vector<cmsys::String>::iterator j = path.begin();
2274 j != path.end(); ++j)
2276 if(j != path.begin())
2278 value += ";";
2280 if(!nativePath)
2282 cmSystemTools::ConvertToUnixSlashes(*j);
2284 else
2286 *j = cmSystemTools::ConvertToOutputPath(j->c_str());
2287 // remove double quotes in the path
2288 cmsys::String& s = *j;
2290 if(s.size() > 1 && s[0] == '\"' && s[s.size()-1] == '\"')
2292 s = s.substr(1,s.size()-2);
2295 value += *j;
2297 this->Makefile->AddDefinition(var, value.c_str());
2298 return true;
2300 #if defined(CMAKE_BUILD_WITH_CMAKE)
2302 // Stuff for curl download
2303 typedef std::vector<char> cmFileCommandVectorOfChar;
2304 namespace{
2305 size_t
2306 cmFileCommandWriteMemoryCallback(void *ptr, size_t size, size_t nmemb,
2307 void *data)
2309 register int realsize = (int)(size * nmemb);
2310 std::ofstream* fout = static_cast<std::ofstream*>(data);
2311 const char* chPtr = static_cast<char*>(ptr);
2312 fout->write(chPtr, realsize);
2313 return realsize;
2316 static size_t
2317 cmFileCommandCurlDebugCallback(CURL *, curl_infotype, char *chPtr,
2318 size_t size, void *data)
2320 cmFileCommandVectorOfChar *vec
2321 = static_cast<cmFileCommandVectorOfChar*>(data);
2322 vec->insert(vec->end(), chPtr, chPtr + size);
2324 return size;
2330 #endif
2332 bool
2333 cmFileCommand::HandleDownloadCommand(std::vector<std::string>
2334 const& args)
2336 #if defined(CMAKE_BUILD_WITH_CMAKE)
2337 std::vector<std::string>::const_iterator i = args.begin();
2338 if(args.size() < 3)
2340 this->SetError("FILE(DOWNLOAD url file) must be called with "
2341 "at least three arguments.");
2342 return false;
2344 i++; // Get rid of subcommand
2345 std::string url = *i;
2346 i++;
2347 std::string file = *i;
2348 i++;
2349 double timeout = 0;
2350 std::string verboseLog;
2351 std::string statusVar;
2352 while(i != args.end())
2354 if(*i == "TIMEOUT")
2356 i++;
2357 if(i != args.end())
2359 timeout = atof(i->c_str());
2361 else
2363 this->SetError("FILE(DOWNLOAD url file TIMEOUT time) missing "
2364 "time for TIMEOUT.");
2365 return false;
2368 else if(*i == "LOG")
2370 i++;
2371 if( i == args.end())
2373 this->SetError("FILE(DOWNLOAD url file LOG VAR) missing "
2374 "VAR for LOG.");
2375 return false;
2377 verboseLog = *i;
2379 else if(*i == "STATUS")
2381 i++;
2382 if( i == args.end())
2384 this->SetError("FILE(DOWNLOAD url file STATUS VAR) missing "
2385 "VAR for STATUS.");
2386 return false;
2388 statusVar = *i;
2390 i++;
2393 std::string dir = cmSystemTools::GetFilenamePath(file.c_str());
2394 if(!cmSystemTools::FileExists(dir.c_str()) &&
2395 !cmSystemTools::MakeDirectory(dir.c_str()))
2397 std::string errstring = "FILE(DOWNLOAD ) error; cannot create directory: "
2398 + dir + ". Maybe need administrative privileges.";
2399 this->SetError(errstring.c_str());
2400 return false;
2403 std::ofstream fout(file.c_str(), std::ios::binary);
2404 if(!fout)
2406 this->SetError("FILE(DOWNLOAD url file TIMEOUT time) can not open "
2407 "file for write.");
2408 return false;
2410 CURL *curl;
2411 curl_global_init(CURL_GLOBAL_DEFAULT);
2412 curl = curl_easy_init();
2413 if(!curl)
2415 this->SetError("FILE(DOWNLOAD ) error "
2416 "initializing curl.");
2417 return false;
2420 curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
2421 curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION,
2422 cmFileCommandWriteMemoryCallback);
2423 curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION,
2424 cmFileCommandCurlDebugCallback);
2425 cmFileCommandVectorOfChar chunkDebug;
2426 ::curl_easy_setopt(curl, CURLOPT_FILE, (void *)&fout);
2427 ::curl_easy_setopt(curl, CURLOPT_DEBUGDATA, (void *)&chunkDebug);
2428 if(verboseLog.size())
2430 curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
2432 if(timeout > 0)
2434 curl_easy_setopt(curl, CURLOPT_TIMEOUT, timeout );
2436 CURLcode res = curl_easy_perform(curl);
2437 /* always cleanup */
2438 curl_easy_cleanup(curl);
2439 if(statusVar.size())
2441 cmOStringStream result;
2442 result << (int)res << ";\"" << curl_easy_strerror(res) << "\"";
2443 this->Makefile->AddDefinition(statusVar.c_str(),
2444 result.str().c_str());
2446 curl_global_cleanup();
2447 if(chunkDebug.size())
2449 chunkDebug.push_back(0);
2450 if(CURLE_OPERATION_TIMEOUTED == res)
2452 std::string output = &*chunkDebug.begin();
2454 if(verboseLog.size())
2456 this->Makefile->AddDefinition(verboseLog.c_str(),
2457 &*chunkDebug.begin());
2461 this->Makefile->AddDefinition(verboseLog.c_str(),
2462 &*chunkDebug.begin());
2464 return true;
2465 #else
2466 this->SetError("FILE(DOWNLOAD ) "
2467 "not supported in bootstrap cmake ");
2468 return false;
2469 #endif