summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Help/command/file.rst15
-rw-r--r--Help/release/dev/file-generate-permissions.rst6
-rw-r--r--Source/cmFileCommand.cxx82
-rw-r--r--Source/cmGeneratorExpressionEvaluationFile.cxx12
-rw-r--r--Source/cmGeneratorExpressionEvaluationFile.h4
-rw-r--r--Source/cmMakefile.cxx5
-rw-r--r--Source/cmMakefile.h2
-rw-r--r--Tests/RunCMake/File_Generate/CustomFilePermissions.cmake15
-rw-r--r--Tests/RunCMake/File_Generate/CustomFilePermissionsVerify.cmake36
-rw-r--r--Tests/RunCMake/File_Generate/NoSourcePermissions.cmake10
-rw-r--r--Tests/RunCMake/File_Generate/NoSourcePermissionsVerify.cmake36
-rw-r--r--Tests/RunCMake/File_Generate/RunCMakeTest.cmake21
-rw-r--r--Tests/RunCMake/File_Generate/SourcePermissions1-result.txt1
-rw-r--r--Tests/RunCMake/File_Generate/SourcePermissions1-stderr.txt5
-rw-r--r--Tests/RunCMake/File_Generate/SourcePermissions1.cmake5
-rw-r--r--Tests/RunCMake/File_Generate/SourcePermissions2-result.txt1
-rw-r--r--Tests/RunCMake/File_Generate/SourcePermissions2-stderr.txt5
-rw-r--r--Tests/RunCMake/File_Generate/SourcePermissions2.cmake5
-rw-r--r--Tests/RunCMake/File_Generate/SourcePermissions3-result.txt1
-rw-r--r--Tests/RunCMake/File_Generate/SourcePermissions3-stderr.txt5
-rw-r--r--Tests/RunCMake/File_Generate/SourcePermissions3.cmake5
-rw-r--r--Tests/RunCMake/File_Generate/SourcePermissions4-result.txt1
-rw-r--r--Tests/RunCMake/File_Generate/SourcePermissions4-stderr.txt4
-rw-r--r--Tests/RunCMake/File_Generate/SourcePermissions4.cmake4
-rw-r--r--Tests/RunCMake/File_Generate/SourcePermissions5-result.txt1
-rw-r--r--Tests/RunCMake/File_Generate/SourcePermissions5-stderr.txt4
-rw-r--r--Tests/RunCMake/File_Generate/SourcePermissions5.cmake4
-rw-r--r--Tests/RunCMake/File_Generate/UseSourcePermissions.cmake11
-rw-r--r--Tests/RunCMake/File_Generate/UseSourcePermissionsVerify.cmake51
29 files changed, 339 insertions, 18 deletions
diff --git a/Help/command/file.rst b/Help/command/file.rst
index 6837672576..76a07f9599 100644
--- a/Help/command/file.rst
+++ b/Help/command/file.rst
@@ -479,7 +479,9 @@ modified.
file(GENERATE OUTPUT output-file
<INPUT input-file|CONTENT content>
- [CONDITION expression] [TARGET target])
+ [CONDITION expression] [TARGET target]
+ [FILE_PERMISSIONS <permissions>...]
+ [NO_SOURCE_PERMISSIONS] [USE_SOURCE_PERMISSIONS])
Generate an output file for each build configuration supported by the current
:manual:`CMake Generator <cmake-generators(7)>`. Evaluate
@@ -520,6 +522,17 @@ from the input content to produce the output content. The options are:
require a target for evaluation (e.g. ``$<COMPILE_FEATURES:...>``,
``$<TARGET_PROPERTY:prop>``).
+``FILE_PERMISSIONS <permissions>...``
+ Use user provided permissions for the generated file.
+
+``NO_SOURCE_PERMISSIONS``
+ The generated file permissions default to the standard 644 value
+ (-rw-r--r--).
+
+``USE_SOURCE_PERMISSIONS``
+ Transfer the file permissions of the original file to the generated file.
+ This option expects INPUT option.
+
Exactly one ``CONTENT`` or ``INPUT`` option must be given. A specific
``OUTPUT`` file may be named by at most one invocation of ``file(GENERATE)``.
Generated files are modified and their timestamp updated on subsequent cmake
diff --git a/Help/release/dev/file-generate-permissions.rst b/Help/release/dev/file-generate-permissions.rst
new file mode 100644
index 0000000000..d1a4d4211b
--- /dev/null
+++ b/Help/release/dev/file-generate-permissions.rst
@@ -0,0 +1,6 @@
+file-generate-permissions
+-------------------------
+
+* The :command:`file(GENERATE)` command gained ``NO_SOURCE_PERMISSIONS``,
+ ``USE_SOURCE_PERMISSIONS``, and ``FILE_PERMISSIONS`` options to support
+ permissions of the generated file.
diff --git a/Source/cmFileCommand.cxx b/Source/cmFileCommand.cxx
index 9467c03dcb..9815d9d182 100644
--- a/Source/cmFileCommand.cxx
+++ b/Source/cmFileCommand.cxx
@@ -2291,7 +2291,7 @@ void AddEvaluationFile(const std::string& inputName,
const std::string& targetName,
const std::string& outputExpr,
const std::string& condition, bool inputIsContent,
- cmExecutionStatus& status)
+ mode_t permissions, cmExecutionStatus& status)
{
cmListFileBacktrace lfbt = status.GetMakefile().GetBacktrace();
@@ -2305,7 +2305,7 @@ void AddEvaluationFile(const std::string& inputName,
status.GetMakefile().AddEvaluationFile(
inputName, targetName, std::move(outputCge), std::move(conditionCge),
- inputIsContent);
+ permissions, inputIsContent);
}
bool HandleGenerateCommand(std::vector<std::string> const& args,
@@ -2323,14 +2323,21 @@ bool HandleGenerateCommand(std::vector<std::string> const& args,
std::string Content;
std::string Condition;
std::string Target;
+ bool NoSourcePermissions = false;
+ bool UseSourcePermissions = false;
+ std::vector<std::string> FilePermissions;
};
- static auto const parser = cmArgumentParser<Arguments>{}
- .Bind("OUTPUT"_s, &Arguments::Output)
- .Bind("INPUT"_s, &Arguments::Input)
- .Bind("CONTENT"_s, &Arguments::Content)
- .Bind("CONDITION"_s, &Arguments::Condition)
- .Bind("TARGET"_s, &Arguments::Target);
+ static auto const parser =
+ cmArgumentParser<Arguments>{}
+ .Bind("OUTPUT"_s, &Arguments::Output)
+ .Bind("INPUT"_s, &Arguments::Input)
+ .Bind("CONTENT"_s, &Arguments::Content)
+ .Bind("CONDITION"_s, &Arguments::Condition)
+ .Bind("TARGET"_s, &Arguments::Target)
+ .Bind("NO_SOURCE_PERMISSIONS"_s, &Arguments::NoSourcePermissions)
+ .Bind("USE_SOURCE_PERMISSIONS"_s, &Arguments::UseSourcePermissions)
+ .Bind("FILE_PERMISSIONS"_s, &Arguments::FilePermissions);
std::vector<std::string> unparsedArguments;
std::vector<std::string> keywordsMissingValues;
@@ -2399,8 +2406,65 @@ bool HandleGenerateCommand(std::vector<std::string> const& args,
input = arguments.Content;
}
+ if (arguments.NoSourcePermissions && arguments.UseSourcePermissions) {
+ status.SetError("given both NO_SOURCE_PERMISSIONS and "
+ "USE_SOURCE_PERMISSIONS. Only one option allowed.");
+ return false;
+ }
+
+ if (!arguments.FilePermissions.empty()) {
+ if (arguments.NoSourcePermissions) {
+ status.SetError("given both NO_SOURCE_PERMISSIONS and "
+ "FILE_PERMISSIONS. Only one option allowed.");
+ return false;
+ }
+ if (arguments.UseSourcePermissions) {
+ status.SetError("given both USE_SOURCE_PERMISSIONS and "
+ "FILE_PERMISSIONS. Only one option allowed.");
+ return false;
+ }
+ }
+
+ if (arguments.UseSourcePermissions) {
+ if (inputIsContent) {
+ status.SetError("given USE_SOURCE_PERMISSIONS without a file INPUT.");
+ return false;
+ }
+ }
+
+ mode_t permisiions = 0;
+ if (arguments.NoSourcePermissions) {
+ permisiions |= cmFSPermissions::mode_owner_read;
+ permisiions |= cmFSPermissions::mode_owner_write;
+ permisiions |= cmFSPermissions::mode_group_read;
+ permisiions |= cmFSPermissions::mode_world_read;
+ }
+
+ if (!arguments.FilePermissions.empty()) {
+ std::vector<std::string> invalidOptions;
+ for (auto const& e : arguments.FilePermissions) {
+ if (!cmFSPermissions::stringToModeT(e, permisiions)) {
+ invalidOptions.push_back(e);
+ }
+ }
+ if (!invalidOptions.empty()) {
+ std::ostringstream oss;
+ oss << "given invalid permission ";
+ for (auto i = 0u; i < invalidOptions.size(); i++) {
+ if (i == 0u) {
+ oss << "\"" << invalidOptions[i] << "\"";
+ } else {
+ oss << ",\"" << invalidOptions[i] << "\"";
+ }
+ }
+ oss << ".";
+ status.SetError(oss.str());
+ return false;
+ }
+ }
+
AddEvaluationFile(input, arguments.Target, arguments.Output,
- arguments.Condition, inputIsContent, status);
+ arguments.Condition, inputIsContent, permisiions, status);
return true;
}
diff --git a/Source/cmGeneratorExpressionEvaluationFile.cxx b/Source/cmGeneratorExpressionEvaluationFile.cxx
index 3c17b54db5..af129d3ca2 100644
--- a/Source/cmGeneratorExpressionEvaluationFile.cxx
+++ b/Source/cmGeneratorExpressionEvaluationFile.cxx
@@ -21,13 +21,15 @@ cmGeneratorExpressionEvaluationFile::cmGeneratorExpressionEvaluationFile(
std::string input, std::string target,
std::unique_ptr<cmCompiledGeneratorExpression> outputFileExpr,
std::unique_ptr<cmCompiledGeneratorExpression> condition,
- bool inputIsContent, cmPolicies::PolicyStatus policyStatusCMP0070)
+ bool inputIsContent, mode_t permissions,
+ cmPolicies::PolicyStatus policyStatusCMP0070)
: Input(std::move(input))
, Target(std::move(target))
, OutputFileExpr(std::move(outputFileExpr))
, Condition(std::move(condition))
, InputIsContent(inputIsContent)
, PolicyStatusCMP0070(policyStatusCMP0070)
+ , Permissions(permissions)
{
}
@@ -111,14 +113,15 @@ void cmGeneratorExpressionEvaluationFile::CreateOutputFile(
void cmGeneratorExpressionEvaluationFile::Generate(cmLocalGenerator* lg)
{
- mode_t perm = 0;
std::string inputContent;
if (this->InputIsContent) {
inputContent = this->Input;
} else {
const std::string inputFileName = this->GetInputFileName(lg);
lg->GetMakefile()->AddCMakeDependFile(inputFileName);
- cmSystemTools::GetPermissions(inputFileName.c_str(), perm);
+ if (!this->Permissions) {
+ cmSystemTools::GetPermissions(inputFileName.c_str(), this->Permissions);
+ }
cmsys::ifstream fin(inputFileName.c_str());
if (!fin) {
std::ostringstream e;
@@ -152,7 +155,8 @@ void cmGeneratorExpressionEvaluationFile::Generate(cmLocalGenerator* lg)
for (std::string const& le : enabledLanguages) {
for (std::string const& li : allConfigs) {
- this->Generate(lg, li, le, inputExpression.get(), outputFiles, perm);
+ this->Generate(lg, li, le, inputExpression.get(), outputFiles,
+ this->Permissions);
if (cmSystemTools::GetFatalErrorOccured()) {
return;
}
diff --git a/Source/cmGeneratorExpressionEvaluationFile.h b/Source/cmGeneratorExpressionEvaluationFile.h
index 2cd35ae945..5ad5e234f9 100644
--- a/Source/cmGeneratorExpressionEvaluationFile.h
+++ b/Source/cmGeneratorExpressionEvaluationFile.h
@@ -24,7 +24,8 @@ public:
std::string input, std::string target,
std::unique_ptr<cmCompiledGeneratorExpression> outputFileExpr,
std::unique_ptr<cmCompiledGeneratorExpression> condition,
- bool inputIsContent, cmPolicies::PolicyStatus policyStatusCMP0070);
+ bool inputIsContent, mode_t permissions,
+ cmPolicies::PolicyStatus policyStatusCMP0070);
void Generate(cmLocalGenerator* lg);
@@ -59,4 +60,5 @@ private:
std::vector<std::string> Files;
const bool InputIsContent;
cmPolicies::PolicyStatus PolicyStatusCMP0070;
+ mode_t Permissions;
};
diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx
index 028688dc8b..9d37d61645 100644
--- a/Source/cmMakefile.cxx
+++ b/Source/cmMakefile.cxx
@@ -865,13 +865,14 @@ void cmMakefile::EnforceDirectoryLevelRules() const
void cmMakefile::AddEvaluationFile(
const std::string& inputFile, const std::string& targetName,
std::unique_ptr<cmCompiledGeneratorExpression> outputName,
- std::unique_ptr<cmCompiledGeneratorExpression> condition,
+ std::unique_ptr<cmCompiledGeneratorExpression> condition, mode_t permissions,
bool inputIsContent)
{
this->EvaluationFiles.push_back(
cm::make_unique<cmGeneratorExpressionEvaluationFile>(
inputFile, targetName, std::move(outputName), std::move(condition),
- inputIsContent, this->GetPolicyStatus(cmPolicies::CMP0070)));
+ inputIsContent, permissions,
+ this->GetPolicyStatus(cmPolicies::CMP0070)));
}
const std::vector<std::unique_ptr<cmGeneratorExpressionEvaluationFile>>&
diff --git a/Source/cmMakefile.h b/Source/cmMakefile.h
index f18f70cb71..1617793b21 100644
--- a/Source/cmMakefile.h
+++ b/Source/cmMakefile.h
@@ -899,7 +899,7 @@ public:
const std::string& inputFile, const std::string& targetName,
std::unique_ptr<cmCompiledGeneratorExpression> outputName,
std::unique_ptr<cmCompiledGeneratorExpression> condition,
- bool inputIsContent);
+ mode_t permissions, bool inputIsContent);
const std::vector<std::unique_ptr<cmGeneratorExpressionEvaluationFile>>&
GetEvaluationFiles() const;
diff --git a/Tests/RunCMake/File_Generate/CustomFilePermissions.cmake b/Tests/RunCMake/File_Generate/CustomFilePermissions.cmake
new file mode 100644
index 0000000000..0000ef971f
--- /dev/null
+++ b/Tests/RunCMake/File_Generate/CustomFilePermissions.cmake
@@ -0,0 +1,15 @@
+file(REMOVE "${CMAKE_CURRENT_BINARY_DIR}/customfilepermissions.txt")
+
+file(GENERATE OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/$<LOWER_CASE:$<CONFIG>>/customfilepermissions.txt"
+ INPUT "${CMAKE_CURRENT_SOURCE_DIR}/input.txt"
+ FILE_PERMISSIONS
+ OWNER_READ OWNER_WRITE OWNER_EXECUTE
+ GROUP_EXECUTE
+ WORLD_EXECUTE
+ )
+
+add_custom_target(checkCustomFilePermissions ALL
+ COMMAND ${CMAKE_COMMAND}
+ -DgeneratedFile=${CMAKE_CURRENT_BINARY_DIR}/$<LOWER_CASE:$<CONFIG>>/customfilepermissions.txt
+ -P "${CMAKE_CURRENT_SOURCE_DIR}/CustomFilePermissionsVerify.cmake"
+ )
diff --git a/Tests/RunCMake/File_Generate/CustomFilePermissionsVerify.cmake b/Tests/RunCMake/File_Generate/CustomFilePermissionsVerify.cmake
new file mode 100644
index 0000000000..a87e916d50
--- /dev/null
+++ b/Tests/RunCMake/File_Generate/CustomFilePermissionsVerify.cmake
@@ -0,0 +1,36 @@
+if(NOT EXISTS "${generatedFile}")
+ message(SEND_ERROR "Missing file:\n ${generatedFile}")
+endif()
+
+if (UNIX)
+ find_program(STAT_EXECUTABLE NAMES stat)
+ if(NOT STAT_EXECUTABLE)
+ return()
+ endif()
+
+ if (CMAKE_HOST_SYSTEM_NAME MATCHES "FreeBSD")
+ execute_process(COMMAND "${STAT_EXECUTABLE}" -f %Lp "${generatedFile}"
+ OUTPUT_VARIABLE output
+ OUTPUT_STRIP_TRAILING_WHITESPACE
+ COMMAND_ERROR_IS_FATAL ANY
+ )
+ elseif (CMAKE_HOST_SYSTEM_NAME MATCHES "Darwin")
+ execute_process(COMMAND "${STAT_EXECUTABLE}" -f %A "${generatedFile}"
+ OUTPUT_VARIABLE output
+ OUTPUT_STRIP_TRAILING_WHITESPACE
+ COMMAND_ERROR_IS_FATAL ANY
+ )
+ else()
+ execute_process(COMMAND "${STAT_EXECUTABLE}" -c %a "${generatedFile}"
+ OUTPUT_VARIABLE output
+ OUTPUT_STRIP_TRAILING_WHITESPACE
+ COMMAND_ERROR_IS_FATAL ANY
+ )
+ endif()
+
+ if (NOT output EQUAL "711")
+ message(SEND_ERROR "file generate has different permissions source "
+ "permissions: \"${output}\" desired permissions: \"711\"")
+ endif()
+
+endif()
diff --git a/Tests/RunCMake/File_Generate/NoSourcePermissions.cmake b/Tests/RunCMake/File_Generate/NoSourcePermissions.cmake
new file mode 100644
index 0000000000..868a0459c9
--- /dev/null
+++ b/Tests/RunCMake/File_Generate/NoSourcePermissions.cmake
@@ -0,0 +1,10 @@
+file(GENERATE OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/$<LOWER_CASE:$<CONFIG>>/nosourcepermissions.txt"
+ INPUT "${CMAKE_CURRENT_SOURCE_DIR}/input.txt"
+ NO_SOURCE_PERMISSIONS
+ )
+
+add_custom_target(checkNoSourcePermission ALL
+ COMMAND ${CMAKE_COMMAND}
+ -DgeneratedFile=${CMAKE_CURRENT_BINARY_DIR}/$<LOWER_CASE:$<CONFIG>>/nosourcepermissions.txt
+ -P "${CMAKE_CURRENT_SOURCE_DIR}/NoSourcePermissionsVerify.cmake"
+ )
diff --git a/Tests/RunCMake/File_Generate/NoSourcePermissionsVerify.cmake b/Tests/RunCMake/File_Generate/NoSourcePermissionsVerify.cmake
new file mode 100644
index 0000000000..7981ccce1e
--- /dev/null
+++ b/Tests/RunCMake/File_Generate/NoSourcePermissionsVerify.cmake
@@ -0,0 +1,36 @@
+if(NOT EXISTS "${generatedFile}")
+ message(SEND_ERROR "Missing generated file:\n ${generatedFile}")
+endif()
+
+if (UNIX)
+ find_program(STAT_EXECUTABLE NAMES stat)
+ if(NOT STAT_EXECUTABLE)
+ return()
+ endif()
+
+ if (CMAKE_HOST_SYSTEM_NAME MATCHES "FreeBSD")
+ execute_process(COMMAND "${STAT_EXECUTABLE}" -f %Lp "${generatedFile}"
+ OUTPUT_VARIABLE output
+ OUTPUT_STRIP_TRAILING_WHITESPACE
+ COMMAND_ERROR_IS_FATAL ANY
+ )
+ elseif(CMAKE_HOST_SYSTEM_NAME MATCHES "Darwin")
+ execute_process(COMMAND "${STAT_EXECUTABLE}" -f %A "${generatedFile}"
+ OUTPUT_VARIABLE output
+ OUTPUT_STRIP_TRAILING_WHITESPACE
+ COMMAND_ERROR_IS_FATAL ANY
+ )
+ else()
+ execute_process(COMMAND "${STAT_EXECUTABLE}" -c %a "${generatedFile}"
+ OUTPUT_VARIABLE output
+ OUTPUT_STRIP_TRAILING_WHITESPACE
+ COMMAND_ERROR_IS_FATAL ANY
+ )
+ endif()
+
+ if (NOT output EQUAL "644")
+ message(SEND_ERROR "generated file has different permissions than "
+ "desired, generated permissions: \"${output}\"")
+ endif()
+
+endif()
diff --git a/Tests/RunCMake/File_Generate/RunCMakeTest.cmake b/Tests/RunCMake/File_Generate/RunCMakeTest.cmake
index 48fb71c7c1..51491af5f0 100644
--- a/Tests/RunCMake/File_Generate/RunCMakeTest.cmake
+++ b/Tests/RunCMake/File_Generate/RunCMakeTest.cmake
@@ -123,3 +123,24 @@ set(RunCMake_TEST_NO_CLEAN 1)
run_cmake_command(AdjacentInOut-nowork ${CMAKE_COMMAND} --build .)
unset(RunCMake_TEST_BINARY_DIR)
unset(RunCMake_TEST_NO_CLEAN)
+
+run_cmake(SourcePermissions1)
+run_cmake(SourcePermissions2)
+run_cmake(SourcePermissions3)
+run_cmake(SourcePermissions4)
+run_cmake(SourcePermissions5)
+
+function(run_cmake_and_verify_after_build case)
+ set(RunCMake_TEST_BINARY_DIR "${RunCMake_BINARY_DIR}/${case}-build")
+ file(REMOVE_RECURSE "${RunCMake_TEST_BINARY_DIR}")
+ file(MAKE_DIRECTORY "${RunCMake_TEST_BINARY_DIR}")
+ set(RunCMake_TEST_NO_CLEAN 1)
+ run_cmake(${case})
+ run_cmake_command("${case}-build" ${CMAKE_COMMAND} --build .)
+ unset(RunCMake_TEST_NO_CLEAN)
+ unset(RunCMake_TEST_BINARY_DIR)
+endfunction()
+
+run_cmake_and_verify_after_build(NoSourcePermissions)
+run_cmake_and_verify_after_build(UseSourcePermissions)
+run_cmake_and_verify_after_build(CustomFilePermissions)
diff --git a/Tests/RunCMake/File_Generate/SourcePermissions1-result.txt b/Tests/RunCMake/File_Generate/SourcePermissions1-result.txt
new file mode 100644
index 0000000000..d00491fd7e
--- /dev/null
+++ b/Tests/RunCMake/File_Generate/SourcePermissions1-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/File_Generate/SourcePermissions1-stderr.txt b/Tests/RunCMake/File_Generate/SourcePermissions1-stderr.txt
new file mode 100644
index 0000000000..730800d81b
--- /dev/null
+++ b/Tests/RunCMake/File_Generate/SourcePermissions1-stderr.txt
@@ -0,0 +1,5 @@
+CMake Error at SourcePermissions1.cmake:[0-9]+ \(file\):
+ file given both NO_SOURCE_PERMISSIONS and USE_SOURCE_PERMISSIONS. Only one
+ option allowed.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/File_Generate/SourcePermissions1.cmake b/Tests/RunCMake/File_Generate/SourcePermissions1.cmake
new file mode 100644
index 0000000000..d25e66a009
--- /dev/null
+++ b/Tests/RunCMake/File_Generate/SourcePermissions1.cmake
@@ -0,0 +1,5 @@
+file(GENERATE OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/output-sourcepermission1.txt"
+ INPUT "${CMAKE_CURRENT_SOURCE_DIR}/input.txt"
+ NO_SOURCE_PERMISSIONS
+ USE_SOURCE_PERMISSIONS
+ )
diff --git a/Tests/RunCMake/File_Generate/SourcePermissions2-result.txt b/Tests/RunCMake/File_Generate/SourcePermissions2-result.txt
new file mode 100644
index 0000000000..d00491fd7e
--- /dev/null
+++ b/Tests/RunCMake/File_Generate/SourcePermissions2-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/File_Generate/SourcePermissions2-stderr.txt b/Tests/RunCMake/File_Generate/SourcePermissions2-stderr.txt
new file mode 100644
index 0000000000..e8184cc520
--- /dev/null
+++ b/Tests/RunCMake/File_Generate/SourcePermissions2-stderr.txt
@@ -0,0 +1,5 @@
+CMake Error at SourcePermissions2.cmake:[0-9]+ \(file\):
+ file given both NO_SOURCE_PERMISSIONS and FILE_PERMISSIONS. Only one
+ option allowed.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/File_Generate/SourcePermissions2.cmake b/Tests/RunCMake/File_Generate/SourcePermissions2.cmake
new file mode 100644
index 0000000000..2a1e3ea029
--- /dev/null
+++ b/Tests/RunCMake/File_Generate/SourcePermissions2.cmake
@@ -0,0 +1,5 @@
+file(GENERATE OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/output-sourcepermission2.txt"
+ INPUT "${CMAKE_CURRENT_SOURCE_DIR}/input.txt"
+ NO_SOURCE_PERMISSIONS
+ FILE_PERMISSIONS OWNER_READ
+ )
diff --git a/Tests/RunCMake/File_Generate/SourcePermissions3-result.txt b/Tests/RunCMake/File_Generate/SourcePermissions3-result.txt
new file mode 100644
index 0000000000..d00491fd7e
--- /dev/null
+++ b/Tests/RunCMake/File_Generate/SourcePermissions3-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/File_Generate/SourcePermissions3-stderr.txt b/Tests/RunCMake/File_Generate/SourcePermissions3-stderr.txt
new file mode 100644
index 0000000000..1143c7871a
--- /dev/null
+++ b/Tests/RunCMake/File_Generate/SourcePermissions3-stderr.txt
@@ -0,0 +1,5 @@
+CMake Error at SourcePermissions3.cmake:[0-9]+ \(file\):
+ file given both USE_SOURCE_PERMISSIONS and FILE_PERMISSIONS. Only one
+ option allowed.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/File_Generate/SourcePermissions3.cmake b/Tests/RunCMake/File_Generate/SourcePermissions3.cmake
new file mode 100644
index 0000000000..97e0deb4e3
--- /dev/null
+++ b/Tests/RunCMake/File_Generate/SourcePermissions3.cmake
@@ -0,0 +1,5 @@
+file(GENERATE OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/output-sourcepermission3.txt"
+ INPUT "${CMAKE_CURRENT_SOURCE_DIR}/input.txt"
+ USE_SOURCE_PERMISSIONS
+ FILE_PERMISSIONS OWNER_READ
+ )
diff --git a/Tests/RunCMake/File_Generate/SourcePermissions4-result.txt b/Tests/RunCMake/File_Generate/SourcePermissions4-result.txt
new file mode 100644
index 0000000000..d00491fd7e
--- /dev/null
+++ b/Tests/RunCMake/File_Generate/SourcePermissions4-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/File_Generate/SourcePermissions4-stderr.txt b/Tests/RunCMake/File_Generate/SourcePermissions4-stderr.txt
new file mode 100644
index 0000000000..84368cde88
--- /dev/null
+++ b/Tests/RunCMake/File_Generate/SourcePermissions4-stderr.txt
@@ -0,0 +1,4 @@
+CMake Error at SourcePermissions4.cmake:[0-9]+ \(file\):
+ file given USE_SOURCE_PERMISSIONS without a file INPUT.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/File_Generate/SourcePermissions4.cmake b/Tests/RunCMake/File_Generate/SourcePermissions4.cmake
new file mode 100644
index 0000000000..f4127a6a90
--- /dev/null
+++ b/Tests/RunCMake/File_Generate/SourcePermissions4.cmake
@@ -0,0 +1,4 @@
+file(GENERATE OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/output-sourcepermission4.txt"
+ CONTENT "Input is content"
+ USE_SOURCE_PERMISSIONS
+ )
diff --git a/Tests/RunCMake/File_Generate/SourcePermissions5-result.txt b/Tests/RunCMake/File_Generate/SourcePermissions5-result.txt
new file mode 100644
index 0000000000..d00491fd7e
--- /dev/null
+++ b/Tests/RunCMake/File_Generate/SourcePermissions5-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/File_Generate/SourcePermissions5-stderr.txt b/Tests/RunCMake/File_Generate/SourcePermissions5-stderr.txt
new file mode 100644
index 0000000000..d66d488347
--- /dev/null
+++ b/Tests/RunCMake/File_Generate/SourcePermissions5-stderr.txt
@@ -0,0 +1,4 @@
+CMake Error at SourcePermissions5.cmake:[0-9]+ \(file\):
+ file given invalid permission "GROUP_RWX","USER_ALL".
+Call Stack \(most recent call first\):
+ CMakeLists.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/File_Generate/SourcePermissions5.cmake b/Tests/RunCMake/File_Generate/SourcePermissions5.cmake
new file mode 100644
index 0000000000..4eb4c3629a
--- /dev/null
+++ b/Tests/RunCMake/File_Generate/SourcePermissions5.cmake
@@ -0,0 +1,4 @@
+file(GENERATE OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/output-sourcepermission5.txt"
+ INPUT "${CMAKE_CURRENT_SOURCE_DIR}/input.txt"
+ FILE_PERMISSIONS OWNER_READ GROUP_RWX USER_ALL
+ )
diff --git a/Tests/RunCMake/File_Generate/UseSourcePermissions.cmake b/Tests/RunCMake/File_Generate/UseSourcePermissions.cmake
new file mode 100644
index 0000000000..7cca9bf8f4
--- /dev/null
+++ b/Tests/RunCMake/File_Generate/UseSourcePermissions.cmake
@@ -0,0 +1,11 @@
+file(GENERATE OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/$<LOWER_CASE:$<CONFIG>>/usesourcepermissions.txt"
+ INPUT "${CMAKE_CURRENT_SOURCE_DIR}/input.txt"
+ USE_SOURCE_PERMISSIONS
+ )
+
+add_custom_target(checkUseSourcePermissions ALL
+ COMMAND ${CMAKE_COMMAND}
+ -DsourceFile=${CMAKE_CURRENT_SOURCE_DIR}/input.txt
+ -DgeneratedFile=${CMAKE_CURRENT_BINARY_DIR}/$<LOWER_CASE:$<CONFIG>>/usesourcepermissions.txt
+ -P "${CMAKE_CURRENT_SOURCE_DIR}/UseSourcePermissionsVerify.cmake"
+ )
diff --git a/Tests/RunCMake/File_Generate/UseSourcePermissionsVerify.cmake b/Tests/RunCMake/File_Generate/UseSourcePermissionsVerify.cmake
new file mode 100644
index 0000000000..8b30f9679c
--- /dev/null
+++ b/Tests/RunCMake/File_Generate/UseSourcePermissionsVerify.cmake
@@ -0,0 +1,51 @@
+if(NOT EXISTS "${generatedFile}")
+ message(SEND_ERROR "Missing generated file:\n ${generatedFile}")
+endif()
+
+if (UNIX)
+ find_program(STAT_EXECUTABLE NAMES stat)
+ if(NOT STAT_EXECUTABLE)
+ return()
+ endif()
+
+ if (CMAKE_HOST_SYSTEM_NAME MATCHES "FreeBSD")
+ execute_process(COMMAND "${STAT_EXECUTABLE}" -f %Lp "${sourceFile}"
+ OUTPUT_VARIABLE output1
+ OUTPUT_STRIP_TRAILING_WHITESPACE
+ COMMAND_ERROR_IS_FATAL ANY
+ )
+ execute_process(COMMAND "${STAT_EXECUTABLE}" -f %Lp "${generatedFile}"
+ OUTPUT_VARIABLE output2
+ OUTPUT_STRIP_TRAILING_WHITESPACE
+ COMMAND_ERROR_IS_FATAL ANY
+ )
+ elseif (CMAKE_HOST_SYSTEM_NAME MATCHES "Darwin")
+ execute_process(COMMAND "${STAT_EXECUTABLE}" -f %A "${sourceFile}"
+ OUTPUT_VARIABLE output1
+ OUTPUT_STRIP_TRAILING_WHITESPACE
+ COMMAND_ERROR_IS_FATAL ANY
+ )
+ execute_process(COMMAND "${STAT_EXECUTABLE}" -f %A "${generatedFile}"
+ OUTPUT_VARIABLE output2
+ OUTPUT_STRIP_TRAILING_WHITESPACE
+ COMMAND_ERROR_IS_FATAL ANY
+ )
+ else()
+ execute_process(COMMAND "${STAT_EXECUTABLE}" -c %a "${sourceFile}"
+ OUTPUT_VARIABLE output1
+ OUTPUT_STRIP_TRAILING_WHITESPACE
+ COMMAND_ERROR_IS_FATAL ANY
+ )
+ execute_process(COMMAND "${STAT_EXECUTABLE}" -c %a "${generatedFile}"
+ OUTPUT_VARIABLE output2
+ OUTPUT_STRIP_TRAILING_WHITESPACE
+ COMMAND_ERROR_IS_FATAL ANY
+ )
+ endif()
+
+ if (NOT output1 EQUAL output2)
+ message(SEND_ERROR "generated file has a different permissions source "
+ "permissions: \"${output1}\" generated permissions: \"${output2}\"")
+ endif()
+
+endif()