1 /*=========================================================================
3 Program: CMake - Cross-Platform Makefile Generator
4 Module: $RCSfile: cmFileCommand.cxx,v $
6 Date: $Date: 2008/01/23 15:27:59 $
7 Version: $Revision: 1.96 $
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"
19 #include "cmHexFileConverter.h"
20 #include "cmFileTimeComparison.h"
22 #include <sys/types.h>
25 #include <cmsys/Directory.hxx>
26 #include <cmsys/Glob.hxx>
27 #include <cmsys/RegularExpression.hxx>
29 // Table of permissions flags.
30 #if defined(_WIN32) && !defined(__CYGWIN__)
31 static mode_t mode_owner_read
= S_IREAD
;
32 static mode_t mode_owner_write
= S_IWRITE
;
33 static mode_t mode_owner_execute
= S_IEXEC
;
34 static mode_t mode_group_read
= 0;
35 static mode_t mode_group_write
= 0;
36 static mode_t mode_group_execute
= 0;
37 static mode_t mode_world_read
= 0;
38 static mode_t mode_world_write
= 0;
39 static mode_t mode_world_execute
= 0;
40 static mode_t mode_setuid
= 0;
41 static mode_t mode_setgid
= 0;
43 static mode_t mode_owner_read
= S_IRUSR
;
44 static mode_t mode_owner_write
= S_IWUSR
;
45 static mode_t mode_owner_execute
= S_IXUSR
;
46 static mode_t mode_group_read
= S_IRGRP
;
47 static mode_t mode_group_write
= S_IWGRP
;
48 static mode_t mode_group_execute
= S_IXGRP
;
49 static mode_t mode_world_read
= S_IROTH
;
50 static mode_t mode_world_write
= S_IWOTH
;
51 static mode_t mode_world_execute
= S_IXOTH
;
52 static mode_t mode_setuid
= S_ISUID
;
53 static mode_t mode_setgid
= S_ISGID
;
58 ::InitialPass(std::vector
<std::string
> const& args
, cmExecutionStatus
&)
62 this->SetError("must be called with at least two arguments.");
65 std::string subCommand
= args
[0];
66 if ( subCommand
== "WRITE" )
68 return this->HandleWriteCommand(args
, false);
70 else if ( subCommand
== "APPEND" )
72 return this->HandleWriteCommand(args
, true);
74 else if ( subCommand
== "READ" )
76 return this->HandleReadCommand(args
);
78 else if ( subCommand
== "STRINGS" )
80 return this->HandleStringsCommand(args
);
82 else if ( subCommand
== "GLOB" )
84 return this->HandleGlobCommand(args
, false);
86 else if ( subCommand
== "GLOB_RECURSE" )
88 return this->HandleGlobCommand(args
, true);
90 else if ( subCommand
== "MAKE_DIRECTORY" )
92 return this->HandleMakeDirectoryCommand(args
);
94 else if ( subCommand
== "REMOVE" )
96 return this->HandleRemove(args
, false);
98 else if ( subCommand
== "REMOVE_RECURSE" )
100 return this->HandleRemove(args
, true);
102 else if ( subCommand
== "INSTALL" )
104 return this->HandleInstallCommand(args
);
106 else if ( subCommand
== "RELATIVE_PATH" )
108 return this->HandleRelativePathCommand(args
);
110 else if ( subCommand
== "TO_CMAKE_PATH" )
112 return this->HandleCMakePathCommand(args
, false);
114 else if ( subCommand
== "TO_NATIVE_PATH" )
116 return this->HandleCMakePathCommand(args
, true);
119 std::string e
= "does not recognize sub-command "+subCommand
;
120 this->SetError(e
.c_str());
124 //----------------------------------------------------------------------------
125 bool cmFileCommand::HandleWriteCommand(std::vector
<std::string
> const& args
,
129 std::vector
<std::string
>::const_iterator i
= args
.begin();
131 i
++; // Get rid of subcommand
133 std::string fileName
= *i
;
134 if ( !cmsys::SystemTools::FileIsFullPath(i
->c_str()) )
136 fileName
= this->Makefile
->GetCurrentDirectory();
137 fileName
+= "/" + *i
;
142 for(;i
!= args
.end(); ++i
)
146 if ( !this->Makefile
->CanIWriteThisFile(fileName
.c_str()) )
149 = "attempted to write a file: " + fileName
+
150 " into a source directory.";
151 this->SetError(e
.c_str());
152 cmSystemTools::SetFatalErrorOccured();
155 std::string dir
= cmSystemTools::GetFilenamePath(fileName
);
156 cmSystemTools::MakeDirectory(dir
.c_str());
159 #if defined( _MSC_VER ) || defined( __MINGW32__ )
161 #elif defined( __BORLANDC__ )
170 // Set permissions to writable
171 if ( cmSystemTools::GetPermissions(fileName
.c_str(), mode
) )
173 cmSystemTools::SetPermissions(fileName
.c_str(),
174 #if defined( _MSC_VER ) || defined( __MINGW32__ )
181 // If GetPermissions fails, pretend like it is ok. File open will fail if
182 // the file is not writable
183 std::ofstream
file(fileName
.c_str(), append
?std::ios::app
: std::ios::out
);
186 std::string error
= "Internal CMake error when trying to open file: ";
187 error
+= fileName
.c_str();
188 error
+= " for writing.";
189 this->SetError(error
.c_str());
194 cmSystemTools::SetPermissions(fileName
.c_str(), mode
);
195 this->Makefile
->AddWrittenFile(fileName
.c_str());
199 //----------------------------------------------------------------------------
200 bool cmFileCommand::HandleReadCommand(std::vector
<std::string
> const& args
)
202 if ( args
.size() < 3 )
204 this->SetError("READ must be called with at least two additional "
209 cmCommandArgumentsHelper argHelper
;
210 cmCommandArgumentGroup group
;
212 cmCAString
readArg (&argHelper
, "READ");
213 cmCAString
fileNameArg (&argHelper
, 0);
214 cmCAString
resultArg (&argHelper
, 0);
216 cmCAString
offsetArg (&argHelper
, "OFFSET", &group
);
217 cmCAString
limitArg (&argHelper
, "LIMIT", &group
);
218 cmCAEnabler
hexOutputArg (&argHelper
, "HEX", &group
);
220 fileNameArg
.Follows(&readArg
);
221 resultArg
.Follows(&fileNameArg
);
222 group
.Follows(&resultArg
);
223 argHelper
.Parse(&args
, 0);
225 std::string fileName
= fileNameArg
.GetString();
226 if ( !cmsys::SystemTools::FileIsFullPath(fileName
.c_str()) )
228 fileName
= this->Makefile
->GetCurrentDirectory();
229 fileName
+= "/" + fileNameArg
.GetString();
232 std::string variable
= resultArg
.GetString();
234 // Open the specified file.
235 #if defined(_WIN32) || defined(__CYGWIN__)
236 std::ifstream
file(fileName
.c_str(), std::ios::in
|
237 (hexOutputArg
.IsEnabled() ? std::ios::binary
: std::ios::in
));
239 std::ifstream
file(fileName
.c_str(), std::ios::in
);
244 std::string error
= "Internal CMake error when trying to open file: ";
245 error
+= fileName
.c_str();
246 error
+= " for reading.";
247 this->SetError(error
.c_str());
253 if (limitArg
.GetString().size() > 0)
255 sizeLimit
= atoi(limitArg
.GetCString());
258 // is there an offset?
260 if (offsetArg
.GetString().size() > 0)
262 offset
= atoi(offsetArg
.GetCString());
269 if (hexOutputArg
.IsEnabled())
271 // Convert part of the file into hex code
273 while((sizeLimit
!= 0) && (c
= file
.get(), file
))
276 sprintf(hex
, "%x", c
&0xff);
287 bool has_newline
= false;
288 while (sizeLimit
!= 0 &&
289 cmSystemTools::GetLineFromStream(file
, line
, &has_newline
,
294 sizeLimit
= sizeLimit
- static_cast<long>(line
.size());
311 this->Makefile
->AddDefinition(variable
.c_str(), output
.c_str());
315 //----------------------------------------------------------------------------
316 bool cmFileCommand::HandleStringsCommand(std::vector
<std::string
> const& args
)
320 this->SetError("STRINGS requires a file name and output variable");
324 // Get the file to read.
325 std::string fileName
= args
[1];
326 if(!cmsys::SystemTools::FileIsFullPath(fileName
.c_str()))
328 fileName
= this->Makefile
->GetCurrentDirectory();
329 fileName
+= "/" + args
[1];
332 // Get the variable in which to store the results.
333 std::string outVar
= args
[2];
335 // Parse the options.
344 unsigned int minlen
= 0;
345 unsigned int maxlen
= 0;
346 int limit_input
= -1;
347 int limit_output
= -1;
348 unsigned int limit_count
= 0;
349 cmsys::RegularExpression regex
;
350 bool have_regex
= false;
351 bool newline_consume
= false;
352 bool hex_conversion_enabled
= true;
353 int arg_mode
= arg_none
;
354 for(unsigned int i
=3; i
< args
.size(); ++i
)
356 if(args
[i
] == "LIMIT_INPUT")
358 arg_mode
= arg_limit_input
;
360 else if(args
[i
] == "LIMIT_OUTPUT")
362 arg_mode
= arg_limit_output
;
364 else if(args
[i
] == "LIMIT_COUNT")
366 arg_mode
= arg_limit_count
;
368 else if(args
[i
] == "LENGTH_MINIMUM")
370 arg_mode
= arg_length_minimum
;
372 else if(args
[i
] == "LENGTH_MAXIMUM")
374 arg_mode
= arg_length_maximum
;
376 else if(args
[i
] == "REGEX")
378 arg_mode
= arg_regex
;
380 else if(args
[i
] == "NEWLINE_CONSUME")
382 newline_consume
= true;
385 else if(args
[i
] == "NO_HEX_CONVERSION")
387 hex_conversion_enabled
= false;
390 else if(arg_mode
== arg_limit_input
)
392 if(sscanf(args
[i
].c_str(), "%d", &limit_input
) != 1 ||
396 e
<< "STRINGS option LIMIT_INPUT value \""
397 << args
[i
] << "\" is not an unsigned integer.";
398 this->SetError(e
.str().c_str());
403 else if(arg_mode
== arg_limit_output
)
405 if(sscanf(args
[i
].c_str(), "%d", &limit_output
) != 1 ||
409 e
<< "STRINGS option LIMIT_OUTPUT value \""
410 << args
[i
] << "\" is not an unsigned integer.";
411 this->SetError(e
.str().c_str());
416 else if(arg_mode
== arg_limit_count
)
419 if(sscanf(args
[i
].c_str(), "%d", &count
) != 1 || count
< 0)
422 e
<< "STRINGS option LIMIT_COUNT value \""
423 << args
[i
] << "\" is not an unsigned integer.";
424 this->SetError(e
.str().c_str());
430 else if(arg_mode
== arg_length_minimum
)
433 if(sscanf(args
[i
].c_str(), "%d", &len
) != 1 || len
< 0)
436 e
<< "STRINGS option LENGTH_MINIMUM value \""
437 << args
[i
] << "\" is not an unsigned integer.";
438 this->SetError(e
.str().c_str());
444 else if(arg_mode
== arg_length_maximum
)
447 if(sscanf(args
[i
].c_str(), "%d", &len
) != 1 || len
< 0)
450 e
<< "STRINGS option LENGTH_MAXIMUM value \""
451 << args
[i
] << "\" is not an unsigned integer.";
452 this->SetError(e
.str().c_str());
458 else if(arg_mode
== arg_regex
)
460 if(!regex
.compile(args
[i
].c_str()))
463 e
<< "STRINGS option REGEX value \""
464 << args
[i
] << "\" could not be compiled.";
465 this->SetError(e
.str().c_str());
474 e
<< "STRINGS given unknown argument \""
476 this->SetError(e
.str().c_str());
481 if (hex_conversion_enabled
)
483 // TODO: should work without temp file, but just on a memory buffer
484 std::string binaryFileName
= this->Makefile
->GetCurrentOutputDirectory();
485 binaryFileName
+= cmake::GetCMakeFilesDirectory();
486 binaryFileName
+= "/FileCommandStringsBinaryFile";
487 if(cmHexFileConverter::TryConvert(fileName
.c_str(),binaryFileName
.c_str()))
489 fileName
= binaryFileName
;
493 // Open the specified file.
494 #if defined(_WIN32) || defined(__CYGWIN__)
495 std::ifstream
fin(fileName
.c_str(), std::ios::in
| std::ios::binary
);
497 std::ifstream
fin(fileName
.c_str(), std::ios::in
);
502 e
<< "STRINGS file \"" << fileName
<< "\" cannot be read.";
503 this->SetError(e
.str().c_str());
507 // Parse strings out of the file.
509 std::vector
<std::string
> strings
;
512 while((!limit_count
|| strings
.size() < limit_count
) &&
513 (limit_input
< 0 || static_cast<int>(fin
.tellg()) < limit_input
) &&
514 (c
= fin
.get(), fin
))
518 // A terminating null character has been found. Check if the
519 // current string matches the requirements. Since it was
520 // terminated by a null character, we require that the length be
521 // at least one no matter what the user specified.
522 if(s
.length() >= minlen
&& s
.length() >= 1 &&
523 (!have_regex
|| regex
.find(s
.c_str())))
525 output_size
+= static_cast<int>(s
.size()) + 1;
526 if(limit_output
>= 0 && output_size
>= limit_output
)
531 strings
.push_back(s
);
534 // Reset the string to empty.
537 else if(c
== '\n' && !newline_consume
)
539 // The current line has been terminated. Check if the current
540 // string matches the requirements. The length may now be as
541 // low as zero since blank lines are allowed.
542 if(s
.length() >= minlen
&&
543 (!have_regex
|| regex
.find(s
.c_str())))
545 output_size
+= static_cast<int>(s
.size()) + 1;
546 if(limit_output
>= 0 && output_size
>= limit_output
)
551 strings
.push_back(s
);
554 // Reset the string to empty.
559 // Ignore CR character to make output always have UNIX newlines.
561 else if(c
>= 0x20 && c
< 0x7F || c
== '\t' ||
562 (c
== '\n' && newline_consume
))
564 // This is an ASCII character that may be part of a string.
569 // This is a non-string character. Reset the string to emtpy.
573 // Terminate a string if the maximum length is reached.
574 if(maxlen
> 0 && s
.size() == maxlen
)
576 if(s
.length() >= minlen
&&
577 (!have_regex
|| regex
.find(s
.c_str())))
579 output_size
+= static_cast<int>(s
.size()) + 1;
580 if(limit_output
>= 0 && output_size
>= limit_output
)
585 strings
.push_back(s
);
591 // If there is a non-empty current string we have hit the end of the
592 // input file or the input size limit. Check if the current string
593 // matches the requirements.
594 if((!limit_count
|| strings
.size() < limit_count
) &&
595 !s
.empty() && s
.length() >= minlen
&&
596 (!have_regex
|| regex
.find(s
.c_str())))
598 output_size
+= static_cast<int>(s
.size()) + 1;
599 if(limit_output
< 0 || output_size
< limit_output
)
601 strings
.push_back(s
);
605 // Encode the result in a CMake list.
606 const char* sep
= "";
608 for(std::vector
<std::string
>::const_iterator si
= strings
.begin();
609 si
!= strings
.end(); ++si
)
611 // Separate the strings in the output to make it a list.
615 // Store the string in the output, but escape semicolons to
616 // make sure it is a list.
617 std::string
const& sr
= *si
;
618 for(unsigned int i
=0; i
< sr
.size(); ++i
)
628 // Save the output in a makefile variable.
629 this->Makefile
->AddDefinition(outVar
.c_str(), output
.c_str());
633 //----------------------------------------------------------------------------
634 bool cmFileCommand::HandleGlobCommand(std::vector
<std::string
> const& args
,
637 if ( args
.size() < 2 )
639 this->SetError("GLOB requires at least a variable name");
643 std::vector
<std::string
>::const_iterator i
= args
.begin();
645 i
++; // Get rid of subcommand
647 std::string variable
= *i
;
650 g
.SetRecurse(recurse
);
651 std::string output
= "";
653 for ( ; i
!= args
.end(); ++i
)
655 if ( *i
== "RELATIVE" )
657 ++i
; // skip RELATIVE
658 if ( i
== args
.end() )
660 this->SetError("GLOB requires a directory after the RELATIVE tag");
663 g
.SetRelative(i
->c_str());
667 this->SetError("GLOB requires a glob expression after the directory");
671 if ( !cmsys::SystemTools::FileIsFullPath(i
->c_str()) )
673 std::string expr
= this->Makefile
->GetCurrentDirectory();
674 // Handle script mode
675 if ( expr
.size() > 0 )
689 std::vector
<std::string
>::size_type cc
;
690 std::vector
<std::string
>& files
= g
.GetFiles();
691 for ( cc
= 0; cc
< files
.size(); cc
++ )
701 this->Makefile
->AddDefinition(variable
.c_str(), output
.c_str());
705 //----------------------------------------------------------------------------
706 bool cmFileCommand::HandleMakeDirectoryCommand(
707 std::vector
<std::string
> const& args
)
711 this->SetError("called with incorrect number of arguments");
715 std::vector
<std::string
>::const_iterator i
= args
.begin();
717 i
++; // Get rid of subcommand
720 for ( ; i
!= args
.end(); ++i
)
722 const std::string
* cdir
= &(*i
);
723 if ( !cmsys::SystemTools::FileIsFullPath(i
->c_str()) )
725 expr
= this->Makefile
->GetCurrentDirectory();
729 if ( !this->Makefile
->CanIWriteThisFile(cdir
->c_str()) )
731 std::string e
= "attempted to create a directory: " + *cdir
732 + " into a source directory.";
733 this->SetError(e
.c_str());
734 cmSystemTools::SetFatalErrorOccured();
737 if ( !cmSystemTools::MakeDirectory(cdir
->c_str()) )
739 std::string error
= "problem creating directory: " + *cdir
;
740 this->SetError(error
.c_str());
747 //----------------------------------------------------------------------------
748 // File installation helper class.
749 struct cmFileInstaller
751 // Methods to actually install files.
752 bool InstallFile(const char* fromFile
, const char* toFile
, bool always
);
753 bool InstallDirectory(const char* source
, const char* destination
,
756 // All instances need the file command and makefile using them.
757 cmFileInstaller(cmFileCommand
* fc
, cmMakefile
* mf
):
758 FileCommand(fc
), Makefile(mf
), DestDirLength(0), MatchlessFiles(true)
760 // Get the current manifest.
762 this->Makefile
->GetSafeDefinition("CMAKE_INSTALL_MANIFEST_FILES");
766 // Save the updated install manifest.
767 this->Makefile
->AddDefinition("CMAKE_INSTALL_MANIFEST_FILES",
768 this->Manifest
.c_str());
772 cmFileCommand
* FileCommand
;
773 cmMakefile
* Makefile
;
774 cmFileTimeComparison FileTimes
;
777 // The length of the destdir setting.
780 // Whether to install a file not matching any expression.
783 // The current file manifest (semicolon separated list).
784 std::string Manifest
;
786 // Permissions for files and directories installed by this object.
787 mode_t FilePermissions
;
788 mode_t DirPermissions
;
790 // Properties set by pattern and regex match rules.
791 struct MatchProperties
795 MatchProperties(): Exclude(false), Permissions(0) {}
799 cmsys::RegularExpression Regex
;
800 MatchProperties Properties
;
801 std::string RegexString
;
802 MatchRule(std::string
const& regex
):
803 Regex(regex
.c_str()), RegexString(regex
) {}
805 std::vector
<MatchRule
> MatchRules
;
807 // Get the properties from rules matching this input file.
808 MatchProperties
CollectMatchProperties(const char* file
,
811 // Match rules are case-insensitive on some platforms.
812 #if defined(_WIN32) || defined(__APPLE__) || defined(__CYGWIN__)
813 std::string lower
= cmSystemTools::LowerCase(file
);
814 file
= lower
.c_str();
817 // Collect properties from all matching rules.
818 bool matched
= false;
819 MatchProperties result
;
820 for(std::vector
<MatchRule
>::iterator mr
= this->MatchRules
.begin();
821 mr
!= this->MatchRules
.end(); ++mr
)
823 if(mr
->Regex
.find(file
))
826 result
.Exclude
|= mr
->Properties
.Exclude
;
827 result
.Permissions
|= mr
->Properties
.Permissions
;
830 if(!matched
&& !this->MatchlessFiles
&& !isDirectory
)
832 result
.Exclude
= true;
837 // Append a file to the installation manifest.
838 void ManifestAppend(std::string
const& file
)
840 this->Manifest
+= ";";
841 this->Manifest
+= file
.substr(this->DestDirLength
);
844 // Translate an argument to a permissions bit.
845 bool CheckPermissions(std::string
const& arg
, mode_t
& permissions
)
847 if(arg
== "OWNER_READ") { permissions
|= mode_owner_read
; }
848 else if(arg
== "OWNER_WRITE") { permissions
|= mode_owner_write
; }
849 else if(arg
== "OWNER_EXECUTE") { permissions
|= mode_owner_execute
; }
850 else if(arg
== "GROUP_READ") { permissions
|= mode_group_read
; }
851 else if(arg
== "GROUP_WRITE") { permissions
|= mode_group_write
; }
852 else if(arg
== "GROUP_EXECUTE") { permissions
|= mode_group_execute
; }
853 else if(arg
== "WORLD_READ") { permissions
|= mode_world_read
; }
854 else if(arg
== "WORLD_WRITE") { permissions
|= mode_world_write
; }
855 else if(arg
== "WORLD_EXECUTE") { permissions
|= mode_world_execute
; }
856 else if(arg
== "SETUID") { permissions
|= mode_setuid
; }
857 else if(arg
== "SETGID") { permissions
|= mode_setgid
; }
861 e
<< "INSTALL given invalid permission \"" << arg
<< "\".";
862 this->FileCommand
->SetError(e
.str().c_str());
869 bool InstallSymlink(const char* fromFile
, const char* toFile
, bool always
);
872 //----------------------------------------------------------------------------
873 bool cmFileInstaller::InstallSymlink(const char* fromFile
, const char* toFile
,
876 // Read the original symlink.
877 std::string symlinkTarget
;
878 if(!cmSystemTools::ReadSymlink(fromFile
, symlinkTarget
))
881 e
<< "INSTALL cannot read symlink \"" << fromFile
882 << "\" to duplicate at \"" << toFile
<< "\".";
883 this->FileCommand
->SetError(e
.str().c_str());
887 // Compare the symlink value to that at the destination if not
888 // always installing.
892 std::string oldSymlinkTarget
;
893 if(cmSystemTools::ReadSymlink(toFile
, oldSymlinkTarget
))
895 if(symlinkTarget
== oldSymlinkTarget
)
902 // Inform the user about this file installation.
903 std::string message
= (copy
? "Installing: " : "Up-to-date: ");
905 this->Makefile
->DisplayStatus(message
.c_str(), -1);
909 // Remove the destination file so we can always create the symlink.
910 cmSystemTools::RemoveFile(toFile
);
912 // Create the symlink.
913 if(!cmSystemTools::CreateSymlink(symlinkTarget
.c_str(), toFile
))
916 e
<< "INSTALL cannot duplicate symlink \"" << fromFile
917 << "\" at \"" << toFile
<< "\".";
918 this->FileCommand
->SetError(e
.str().c_str());
923 // Add the file to the manifest.
924 this->ManifestAppend(toFile
);
929 //----------------------------------------------------------------------------
930 bool cmFileInstaller::InstallFile(const char* fromFile
, const char* toFile
,
933 // Collect any properties matching this file name.
934 MatchProperties match_properties
=
935 this->CollectMatchProperties(fromFile
, false);
937 // Skip the file if it is excluded.
938 if(match_properties
.Exclude
)
943 // Short-circuit for symbolic links.
944 if(cmSystemTools::FileIsSymlink(fromFile
))
946 return this->InstallSymlink(fromFile
, toFile
, always
);
949 // Determine whether we will copy the file.
953 // If both files exist with the same time do not copy.
954 if(!this->FileTimes
.FileTimesDiffer(fromFile
, toFile
))
960 // Inform the user about this file installation.
961 std::string message
= (copy
? "Installing: " : "Up-to-date: ");
963 this->Makefile
->DisplayStatus(message
.c_str(), -1);
966 if(copy
&& !cmSystemTools::CopyAFile(fromFile
, toFile
, true))
969 e
<< "INSTALL cannot copy file \"" << fromFile
970 << "\" to \"" << toFile
<< "\".";
971 this->FileCommand
->SetError(e
.str().c_str());
975 // Add the file to the manifest.
976 this->ManifestAppend(toFile
);
978 // Set the file modification time of the destination file.
981 cmSystemTools::CopyFileTime(fromFile
, toFile
);
984 // Set permissions of the destination file.
985 mode_t permissions
= (match_properties
.Permissions
?
986 match_properties
.Permissions
: this->FilePermissions
);
989 // No permissions were explicitly provided but the user requested
990 // that the source file permissions be used.
991 cmSystemTools::GetPermissions(fromFile
, permissions
);
993 if(permissions
&& !cmSystemTools::SetPermissions(toFile
, permissions
))
996 e
<< "Problem setting permissions on file \"" << toFile
<< "\"";
997 this->FileCommand
->SetError(e
.str().c_str());
1004 //----------------------------------------------------------------------------
1005 bool cmFileInstaller::InstallDirectory(const char* source
,
1006 const char* destination
,
1009 // Collect any properties matching this directory name.
1010 MatchProperties match_properties
=
1011 this->CollectMatchProperties(source
, true);
1013 // Skip the directory if it is excluded.
1014 if(match_properties
.Exclude
)
1019 // Short-circuit for symbolic links.
1020 if(cmSystemTools::FileIsSymlink(source
))
1022 return this->InstallSymlink(source
, destination
, always
);
1025 // Inform the user about this directory installation.
1026 std::string message
= "Installing: ";
1027 message
+= destination
;
1028 this->Makefile
->DisplayStatus(message
.c_str(), -1);
1030 // Make sure the destination directory exists.
1031 if(!cmSystemTools::MakeDirectory(destination
))
1036 // Compute the requested permissions for the destination directory.
1037 mode_t permissions
= (match_properties
.Permissions
?
1038 match_properties
.Permissions
: this->DirPermissions
);
1041 // No permissions were explicitly provided but the user requested
1042 // that the source directory permissions be used.
1043 cmSystemTools::GetPermissions(source
, permissions
);
1046 // Compute the set of permissions required on this directory to
1047 // recursively install files and subdirectories safely.
1048 mode_t required_permissions
=
1049 mode_owner_read
| mode_owner_write
| mode_owner_execute
;
1051 // If the required permissions are specified it is safe to set the
1052 // final permissions now. Otherwise we must add the required
1053 // permissions temporarily during file installation.
1054 mode_t permissions_before
= 0;
1055 mode_t permissions_after
= 0;
1056 if(permissions
& required_permissions
)
1058 permissions_before
= permissions
;
1062 permissions_before
= permissions
| required_permissions
;
1063 permissions_after
= permissions
;
1066 // Set the required permissions of the destination directory.
1067 if(permissions_before
&&
1068 !cmSystemTools::SetPermissions(destination
, permissions_before
))
1071 e
<< "Problem setting permissions on directory \""
1072 << destination
<< "\"";
1073 this->FileCommand
->SetError(e
.str().c_str());
1077 // Load the directory contents to traverse it recursively.
1078 cmsys::Directory dir
;
1079 if(source
&& *source
)
1083 unsigned long numFiles
= static_cast<unsigned long>(dir
.GetNumberOfFiles());
1084 for(unsigned long fileNum
= 0; fileNum
< numFiles
; ++fileNum
)
1086 if(!(strcmp(dir
.GetFile(fileNum
), ".") == 0 ||
1087 strcmp(dir
.GetFile(fileNum
), "..") == 0))
1089 cmsys_stl::string fromPath
= source
;
1091 fromPath
+= dir
.GetFile(fileNum
);
1092 if(cmSystemTools::FileIsDirectory(fromPath
.c_str()))
1094 cmsys_stl::string toDir
= destination
;
1096 toDir
+= dir
.GetFile(fileNum
);
1097 if(!this->InstallDirectory(fromPath
.c_str(), toDir
.c_str(), always
))
1104 // Install this file.
1105 std::string toFile
= destination
;
1107 toFile
+= dir
.GetFile(fileNum
);
1108 if(!this->InstallFile(fromPath
.c_str(), toFile
.c_str(), always
))
1116 // Set the requested permissions of the destination directory.
1117 if(permissions_after
&&
1118 !cmSystemTools::SetPermissions(destination
, permissions_after
))
1121 e
<< "Problem setting permissions on directory \"" << destination
<< "\"";
1122 this->FileCommand
->SetError(e
.str().c_str());
1129 //----------------------------------------------------------------------------
1130 void cmFileCommand::HandleInstallPermissions(cmFileInstaller
& installer
,
1131 mode_t
& permissions_file
,
1132 mode_t
& permissions_dir
,
1134 bool use_given_permissions_file
,
1135 bool use_given_permissions_dir
,
1136 bool use_source_permissions
) const
1138 // Choose a default for shared library permissions.
1139 bool install_so_no_exe
= this->Makefile
->IsOn("CMAKE_INSTALL_SO_NO_EXE");
1140 // If file permissions were not specified set default permissions
1141 // for this target type.
1142 if(!use_given_permissions_file
&& !use_source_permissions
)
1146 case cmTarget::SHARED_LIBRARY
:
1147 case cmTarget::MODULE_LIBRARY
:
1148 if(install_so_no_exe
)
1150 // Use read/write permissions.
1151 permissions_file
= 0;
1152 permissions_file
|= mode_owner_read
;
1153 permissions_file
|= mode_owner_write
;
1154 permissions_file
|= mode_group_read
;
1155 permissions_file
|= mode_world_read
;
1158 case cmTarget::EXECUTABLE
:
1159 case cmTarget::INSTALL_PROGRAMS
:
1160 // Use read/write/executable permissions.
1161 permissions_file
= 0;
1162 permissions_file
|= mode_owner_read
;
1163 permissions_file
|= mode_owner_write
;
1164 permissions_file
|= mode_owner_execute
;
1165 permissions_file
|= mode_group_read
;
1166 permissions_file
|= mode_group_execute
;
1167 permissions_file
|= mode_world_read
;
1168 permissions_file
|= mode_world_execute
;
1171 // Use read/write permissions.
1172 permissions_file
= 0;
1173 permissions_file
|= mode_owner_read
;
1174 permissions_file
|= mode_owner_write
;
1175 permissions_file
|= mode_group_read
;
1176 permissions_file
|= mode_world_read
;
1181 // If directory permissions were not specified set default permissions.
1182 if(!use_given_permissions_dir
&& !use_source_permissions
)
1184 // Use read/write/executable permissions.
1185 permissions_dir
= 0;
1186 permissions_dir
|= mode_owner_read
;
1187 permissions_dir
|= mode_owner_write
;
1188 permissions_dir
|= mode_owner_execute
;
1189 permissions_dir
|= mode_group_read
;
1190 permissions_dir
|= mode_group_execute
;
1191 permissions_dir
|= mode_world_read
;
1192 permissions_dir
|= mode_world_execute
;
1194 // Set the installer permissions.
1195 installer
.FilePermissions
= permissions_file
;
1196 installer
.DirPermissions
= permissions_dir
;
1199 //----------------------------------------------------------------------------
1201 ::GetTargetTypeFromString(const std::string
& stype
, int& itype
) const
1203 if ( stype
== "EXECUTABLE" )
1205 itype
= cmTarget::EXECUTABLE
;
1207 else if ( stype
== "PROGRAM" )
1209 itype
= cmTarget::INSTALL_PROGRAMS
;
1211 else if ( stype
== "STATIC_LIBRARY" )
1213 itype
= cmTarget::STATIC_LIBRARY
;
1215 else if ( stype
== "SHARED_LIBRARY" )
1217 itype
= cmTarget::SHARED_LIBRARY
;
1219 else if ( stype
== "MODULE" )
1221 itype
= cmTarget::MODULE_LIBRARY
;
1223 else if ( stype
== "DIRECTORY" )
1225 itype
= cmTarget::INSTALL_DIRECTORY
;
1230 //----------------------------------------------------------------------------
1231 bool cmFileCommand::HandleInstallDestination(cmFileInstaller
& installer
,
1232 std::string
& destination
)
1234 if ( destination
.size() < 2 )
1236 this->SetError("called with inapropriate arguments. "
1237 "No DESTINATION provided or .");
1241 const char* destdir
= cmSystemTools::GetEnv("DESTDIR");
1242 if ( destdir
&& *destdir
)
1244 std::string sdestdir
= destdir
;
1245 cmSystemTools::ConvertToUnixSlashes(sdestdir
);
1247 char ch1
= destination
[0];
1248 char ch2
= destination
[1];
1250 if ( destination
.size() > 2 )
1252 ch3
= destination
[2];
1258 if ( ( ch1
>= 'a' && ch1
<= 'z' || ch1
>= 'A' && ch1
<= 'Z' ) &&
1262 // let's do some destdir magic:
1275 // This is relative path on unix or windows. Since we are doing
1276 // destdir, this case does not make sense.
1277 this->SetError("called with relative DESTINATION. This "
1278 "does not make sense when using DESTDIR. Specify "
1279 "absolute path or remove DESTDIR environment variable.");
1287 // looks like a network path.
1288 this->SetError("called with network path DESTINATION. This "
1289 "does not make sense when using DESTDIR. Specify local "
1290 "absolute path or remove DESTDIR environment variable.");
1294 destination
= sdestdir
+ (destination
.c_str() + skip
);
1295 installer
.DestDirLength
= int(sdestdir
.size());
1298 if ( !cmSystemTools::FileExists(destination
.c_str()) )
1300 if ( !cmSystemTools::MakeDirectory(destination
.c_str()) )
1302 std::string errstring
= "cannot create directory: " + destination
+
1303 ". Maybe need administrative privileges.";
1304 this->SetError(errstring
.c_str());
1308 if ( !cmSystemTools::FileIsDirectory(destination
.c_str()) )
1310 std::string errstring
= "INSTALL destination: " + destination
+
1311 " is not a directory.";
1312 this->SetError(errstring
.c_str());
1318 //----------------------------------------------------------------------------
1319 bool cmFileCommand::HandleInstallCommand(std::vector
<std::string
> const& args
)
1321 if ( args
.size() < 6 )
1323 this->SetError("called with incorrect number of arguments");
1327 // Construct a file installer object.
1328 cmFileInstaller
installer(this, this->Makefile
);
1330 std::string rename
= "";
1331 std::string destination
= "";
1333 std::vector
<std::string
> files
;
1334 int itype
= cmTarget::INSTALL_FILES
;
1336 std::map
<cmStdString
, const char*> properties
;
1337 bool optional
= false;
1338 bool result
= this->ParseInstallArgs(args
, installer
, properties
,
1339 itype
, rename
, destination
, files
,
1343 result
= this->DoInstall(installer
,
1344 itype
, rename
, destination
, files
, optional
);
1349 //----------------------------------------------------------------------------
1350 bool cmFileCommand::ParseInstallArgs(std::vector
<std::string
> const& args
,
1351 cmFileInstaller
& installer
,
1352 std::map
<cmStdString
, const char*>& properties
,
1354 std::string
& rename
,
1355 std::string
& destination
,
1356 std::vector
<std::string
>& files
,
1359 std::string stype
= "FILES";
1360 bool doing_files
= false;
1361 bool doing_properties
= false;
1362 bool doing_permissions_file
= false;
1363 bool doing_permissions_dir
= false;
1364 bool doing_permissions_match
= false;
1365 bool use_given_permissions_file
= false;
1366 bool use_given_permissions_dir
= false;
1367 bool use_source_permissions
= false;
1368 mode_t permissions_file
= 0;
1369 mode_t permissions_dir
= 0;
1371 cmFileInstaller::MatchRule
* current_match_rule
= 0;
1372 std::vector
<std::string
>::size_type i
= 0;
1373 i
++; // Get rid of subcommand
1374 for ( ; i
!= args
.size(); ++i
)
1376 const std::string
* cstr
= &args
[i
];
1377 if ( *cstr
== "DESTINATION" && i
< args
.size()-1 )
1379 if(current_match_rule
)
1382 e
<< "INSTALL does not allow \"" << *cstr
<< "\" after REGEX.";
1383 this->SetError(e
.str().c_str());
1388 destination
= args
[i
];
1389 doing_files
= false;
1390 doing_properties
= false;
1391 doing_permissions_file
= false;
1392 doing_permissions_dir
= false;
1394 else if ( *cstr
== "TYPE" && i
< args
.size()-1 )
1396 if(current_match_rule
)
1399 e
<< "INSTALL does not allow \"" << *cstr
<< "\" after REGEX.";
1400 this->SetError(e
.str().c_str());
1406 if ( args
[i
+1] == "OPTIONAL" )
1411 doing_properties
= false;
1412 doing_files
= false;
1413 doing_permissions_file
= false;
1414 doing_permissions_dir
= false;
1416 else if ( *cstr
== "RENAME" && i
< args
.size()-1 )
1418 if(current_match_rule
)
1421 e
<< "INSTALL does not allow \"" << *cstr
<< "\" after REGEX.";
1422 this->SetError(e
.str().c_str());
1428 doing_properties
= false;
1429 doing_files
= false;
1430 doing_permissions_file
= false;
1431 doing_permissions_dir
= false;
1433 else if ( *cstr
== "REGEX" && i
< args
.size()-1 )
1436 installer
.MatchRules
.push_back(cmFileInstaller::MatchRule(args
[i
]));
1437 current_match_rule
= &*(installer
.MatchRules
.end()-1);
1438 if(!current_match_rule
->Regex
.is_valid())
1441 e
<< "INSTALL could not compile REGEX \"" << args
[i
] << "\".";
1442 this->SetError(e
.str().c_str());
1445 doing_properties
= false;
1446 doing_files
= false;
1447 doing_permissions_file
= false;
1448 doing_permissions_dir
= false;
1450 else if ( *cstr
== "EXCLUDE" )
1452 // Add this property to the current match rule.
1453 if(!current_match_rule
)
1456 e
<< "INSTALL does not allow \""
1457 << *cstr
<< "\" before a REGEX is given.";
1458 this->SetError(e
.str().c_str());
1461 current_match_rule
->Properties
.Exclude
= true;
1462 doing_permissions_match
= true;
1464 else if ( *cstr
== "PROPERTIES" )
1466 if(current_match_rule
)
1469 e
<< "INSTALL does not allow \"" << *cstr
<< "\" after REGEX.";
1470 this->SetError(e
.str().c_str());
1474 doing_properties
= true;
1475 doing_files
= false;
1476 doing_permissions_file
= false;
1477 doing_permissions_dir
= false;
1479 else if ( *cstr
== "PERMISSIONS" )
1481 if(current_match_rule
)
1483 doing_permissions_match
= true;
1484 doing_permissions_file
= false;
1488 doing_permissions_match
= false;
1489 doing_permissions_file
= true;
1490 use_given_permissions_file
= true;
1492 doing_properties
= false;
1493 doing_files
= false;
1494 doing_permissions_dir
= false;
1496 else if ( *cstr
== "DIR_PERMISSIONS" )
1498 if(current_match_rule
)
1501 e
<< "INSTALL does not allow \"" << *cstr
<< "\" after REGEX.";
1502 this->SetError(e
.str().c_str());
1506 use_given_permissions_dir
= true;
1507 doing_properties
= false;
1508 doing_files
= false;
1509 doing_permissions_file
= false;
1510 doing_permissions_dir
= true;
1512 else if ( *cstr
== "USE_SOURCE_PERMISSIONS" )
1514 if(current_match_rule
)
1517 e
<< "INSTALL does not allow \"" << *cstr
<< "\" after REGEX.";
1518 this->SetError(e
.str().c_str());
1522 doing_properties
= false;
1523 doing_files
= false;
1524 doing_permissions_file
= false;
1525 doing_permissions_dir
= false;
1526 use_source_permissions
= true;
1528 else if ( *cstr
== "FILES_MATCHING" )
1530 if(current_match_rule
)
1533 e
<< "INSTALL does not allow \"" << *cstr
<< "\" after REGEX.";
1534 this->SetError(e
.str().c_str());
1538 doing_properties
= false;
1539 doing_files
= false;
1540 doing_permissions_file
= false;
1541 doing_permissions_dir
= false;
1542 installer
.MatchlessFiles
= false;
1544 else if ( *cstr
== "COMPONENTS" )
1547 e
<< "INSTALL called with old-style COMPONENTS argument. "
1548 << "This script was generated with an older version of CMake. "
1549 << "Re-run this cmake version on your build tree.";
1550 this->SetError(e
.str().c_str());
1553 else if ( *cstr
== "CONFIGURATIONS" )
1556 e
<< "INSTALL called with old-style CONFIGURATIONS argument. "
1557 << "This script was generated with an older version of CMake. "
1558 << "Re-run this cmake version on your build tree.";
1559 this->SetError(e
.str().c_str());
1562 else if ( *cstr
== "FILES" && !doing_files
)
1564 if(current_match_rule
)
1567 e
<< "INSTALL does not allow \"" << *cstr
<< "\" after REGEX.";
1568 this->SetError(e
.str().c_str());
1573 doing_properties
= false;
1574 doing_permissions_file
= false;
1575 doing_permissions_dir
= false;
1577 else if ( doing_properties
&& i
< args
.size()-1 )
1579 properties
[args
[i
]] = args
[i
+1].c_str();
1582 else if ( doing_files
)
1584 files
.push_back(*cstr
);
1586 else if(doing_permissions_file
)
1588 if(!installer
.CheckPermissions(args
[i
], permissions_file
))
1593 else if(doing_permissions_dir
)
1595 if(!installer
.CheckPermissions(args
[i
], permissions_dir
))
1600 else if(doing_permissions_match
)
1602 if(!installer
.CheckPermissions(
1603 args
[i
], current_match_rule
->Properties
.Permissions
))
1610 this->SetError("called with inappropriate arguments");
1615 // now check and postprocess what has been parsed
1616 if ( files
.size() == 0 )
1618 // nothing to do, no files were listed.
1619 // if this is handled as error, INSTALL_FILES() creates an invalid
1620 // cmake_install.cmake script with no FILES() arguments if no files were
1621 // given to INSTALL_FILES(). This was accepted with CMake 2.4.x.
1625 // Check rename form.
1628 if(itype
!= cmTarget::INSTALL_FILES
&&
1629 itype
!= cmTarget::INSTALL_PROGRAMS
)
1631 this->SetError("INSTALL option RENAME may be used only with "
1632 "FILES or PROGRAMS.");
1635 if(files
.size() > 1)
1637 this->SetError("INSTALL option RENAME may be used only with "
1643 if (this->HandleInstallDestination(installer
, destination
) == false)
1648 if(properties
.find("VERSION") != properties
.end())
1651 e
<< "INSTALL called with old-style VERSION property. "
1652 << "This script was generated with an older version of CMake. "
1653 << "Re-run this cmake version on your build tree.";
1654 this->SetError(e
.str().c_str());
1657 if(properties
.find("SOVERSION") != properties
.end())
1660 e
<< "INSTALL called with old-style SOVERSION property. "
1661 << "This script was generated with an older version of CMake. "
1662 << "Re-run this cmake version on your build tree.";
1663 this->SetError(e
.str().c_str());
1667 this->GetTargetTypeFromString(stype
, itype
);
1669 this->HandleInstallPermissions(installer
,
1673 use_given_permissions_file
,
1674 use_given_permissions_dir
,
1675 use_source_permissions
);
1680 //----------------------------------------------------------------------------
1681 bool cmFileCommand::DoInstall( cmFileInstaller
& installer
,
1683 const std::string
& rename
,
1684 const std::string
& destination
,
1685 const std::vector
<std::string
>& files
,
1686 const bool optional
)
1688 typedef std::set
<cmStdString
>::const_iterator iter_type
;
1690 // Check whether files should be copied always or only if they have
1693 cmSystemTools::IsOn(cmSystemTools::GetEnv("CMAKE_INSTALL_ALWAYS"));
1695 // Handle each file listed.
1696 for (std::vector
<std::string
>::size_type i
= 0; i
< files
.size(); i
++ )
1698 // Split the input file into its directory and name components.
1699 std::vector
<std::string
> fromPathComponents
;
1700 cmSystemTools::SplitPath(files
[i
].c_str(), fromPathComponents
);
1701 std::string fromName
= *(fromPathComponents
.end()-1);
1702 std::string fromDir
= cmSystemTools::JoinPath(fromPathComponents
.begin(),
1703 fromPathComponents
.end()-1);
1705 // Compute the full path to the destination file.
1706 std::string toFile
= destination
;
1707 std::string
const& toName
= rename
.empty()? fromName
: rename
;
1714 // Construct the full path to the source file. The file name may
1715 // have been changed above.
1716 std::string fromFile
= fromDir
;
1717 if(!fromName
.empty())
1720 fromFile
+= fromName
;
1723 std::string message
;
1724 if(!cmSystemTools::SameFile(fromFile
.c_str(), toFile
.c_str()))
1726 if(itype
== cmTarget::INSTALL_DIRECTORY
&&
1727 (fromFile
.empty() ||
1728 cmSystemTools::FileIsDirectory(fromFile
.c_str())))
1730 // Try installing this directory.
1731 if(!installer
.InstallDirectory(fromFile
.c_str(), toFile
.c_str(),
1737 else if(cmSystemTools::FileExists(fromFile
.c_str()))
1739 // Install this file.
1740 if(!installer
.InstallFile(fromFile
.c_str(), toFile
.c_str(),
1748 // The input file does not exist and installation is not optional.
1750 e
<< "INSTALL cannot find file \"" << fromFile
<< "\" to install.";
1751 this->SetError(e
.str().c_str());
1760 //----------------------------------------------------------------------------
1761 bool cmFileCommand::HandleRelativePathCommand(
1762 std::vector
<std::string
> const& args
)
1764 if(args
.size() != 4 )
1766 this->SetError("called with incorrect number of arguments");
1770 const std::string
& outVar
= args
[1];
1771 const std::string
& directoryName
= args
[2];
1772 const std::string
& fileName
= args
[3];
1774 if(!cmSystemTools::FileIsFullPath(directoryName
.c_str()))
1776 std::string errstring
=
1777 "RelativePath must be passed a full path to the directory: "
1779 this->SetError(errstring
.c_str());
1782 if(!cmSystemTools::FileIsFullPath(fileName
.c_str()))
1784 std::string errstring
=
1785 "RelativePath must be passed a full path to the file: "
1787 this->SetError(errstring
.c_str());
1791 std::string res
= cmSystemTools::RelativePath(directoryName
.c_str(),
1793 this->Makefile
->AddDefinition(outVar
.c_str(),
1799 //----------------------------------------------------------------------------
1800 bool cmFileCommand::HandleRemove(std::vector
<std::string
> const& args
,
1804 std::string message
;
1805 std::vector
<std::string
>::const_iterator i
= args
.begin();
1807 i
++; // Get rid of subcommand
1808 for(;i
!= args
.end(); ++i
)
1810 if(cmSystemTools::FileIsDirectory(i
->c_str()) && recurse
)
1812 cmSystemTools::RemoveADirectory(i
->c_str());
1816 cmSystemTools::RemoveFile(i
->c_str());
1822 //----------------------------------------------------------------------------
1823 bool cmFileCommand::HandleCMakePathCommand(std::vector
<std::string
>
1827 std::vector
<std::string
>::const_iterator i
= args
.begin();
1828 if(args
.size() != 3)
1830 this->SetError("FILE(SYSTEM_PATH ENV result) must be called with "
1831 "only three arguments.");
1834 i
++; // Get rid of subcommand
1835 #if defined(_WIN32) && !defined(__CYGWIN__)
1840 std::vector
<cmsys::String
> path
= cmSystemTools::SplitString(i
->c_str(),
1843 const char* var
= i
->c_str();
1845 for(std::vector
<cmsys::String
>::iterator j
= path
.begin();
1846 j
!= path
.end(); ++j
)
1848 if(j
!= path
.begin())
1854 cmSystemTools::ConvertToUnixSlashes(*j
);
1858 *j
= cmSystemTools::ConvertToOutputPath(j
->c_str());
1859 // remove double quotes in the path
1860 cmsys::String
& s
= *j
;
1862 if(s
.size() > 1 && s
[0] == '\"' && s
[s
.size()-1] == '\"')
1864 s
= s
.substr(1,s
.size()-2);
1869 this->Makefile
->AddDefinition(var
, value
.c_str());