diff options
82 files changed, 846 insertions, 113 deletions
diff --git a/Auxiliary/cmake-mode.el b/Auxiliary/cmake-mode.el index 6137ea9..52f2d41 100644 --- a/Auxiliary/cmake-mode.el +++ b/Auxiliary/cmake-mode.el @@ -28,6 +28,7 @@ ;; (require 'rst) +(require 'rx) (defcustom cmake-mode-cmake-executable "cmake" "*The name of the cmake executable. @@ -190,6 +191,61 @@ the indentation. Otherwise it retains the same position on the line" ) ) + +;------------------------------------------------------------------------------ + +;; +;; Navigation / marking by function or macro +;; + +(defconst cmake--regex-defun-start + (rx line-start + (zero-or-more space) + (or "function" "macro") + (zero-or-more space) + "(")) + +(defconst cmake--regex-defun-end + (rx line-start + (zero-or-more space) + "end" + (or "function" "macro") + (zero-or-more space) + "(" (zero-or-more (not ")")) ")")) + +(defun cmake-beginning-of-defun () + "Move backward to the beginning of a CMake function or macro. + +Return t unless search stops due to beginning of buffer." + (interactive) + (when (not (region-active-p)) + (push-mark)) + (let ((case-fold-search t)) + (when (re-search-backward cmake--regex-defun-start nil 'move) + t))) + +(defun cmake-end-of-defun () + "Move forward to the end of a CMake function or macro. + +Return t unless search stops due to end of buffer." + (interactive) + (when (not (region-active-p)) + (push-mark)) + (let ((case-fold-search t)) + (when (re-search-forward cmake--regex-defun-end nil 'move) + (forward-line) + t))) + +(defun cmake-mark-defun () + "Mark the current CMake function or macro. + +This puts the mark at the end, and point at the beginning." + (interactive) + (cmake-end-of-defun) + (push-mark nil :nomsg :activate) + (cmake-beginning-of-defun)) + + ;------------------------------------------------------------------------------ ;; @@ -242,6 +298,12 @@ the indentation. Otherwise it retains the same position on the line" ; Setup comment syntax. (set (make-local-variable 'comment-start) "#")) +;; Default cmake-mode key bindings +(define-key cmake-mode-map "\e\C-a" #'cmake-beginning-of-defun) +(define-key cmake-mode-map "\e\C-e" #'cmake-end-of-defun) +(define-key cmake-mode-map "\e\C-h" #'cmake-mark-defun) + + ; Help mode starts here diff --git a/Help/command/add_test.rst b/Help/command/add_test.rst index 832d8db..95cd037 100644 --- a/Help/command/add_test.rst +++ b/Help/command/add_test.rst @@ -57,7 +57,7 @@ Example usage: .. code-block:: cmake add_test(NAME mytest - COMMAND testDriver --config $<CONFIGURATION> + COMMAND testDriver --config $<CONFIG> --exe $<TARGET_FILE:myexe>) This creates a test ``mytest`` whose command runs a ``testDriver`` tool diff --git a/Help/command/file.rst b/Help/command/file.rst index 6837672..76a07f9 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/command/target_include_directories.rst b/Help/command/target_include_directories.rst index a8a5c83..3e53b2e 100644 --- a/Help/command/target_include_directories.rst +++ b/Help/command/target_include_directories.rst @@ -5,7 +5,7 @@ Add include directories to a target. .. code-block:: cmake - target_include_directories(<target> [SYSTEM] [BEFORE] + target_include_directories(<target> [SYSTEM] [AFTER|BEFORE] <INTERFACE|PUBLIC|PRIVATE> [items1...] [<INTERFACE|PUBLIC|PRIVATE> [items2...] ...]) @@ -14,8 +14,8 @@ The named ``<target>`` must have been created by a command such as :command:`add_executable` or :command:`add_library` and must not be an :ref:`ALIAS target <Alias Targets>`. -If ``BEFORE`` is specified, the content will be prepended to the property -instead of being appended. +By using ``AFTER`` or ``BEFORE`` explicitly, you can select between appending +and prepending, independent of the default. The ``INTERFACE``, ``PUBLIC`` and ``PRIVATE`` keywords are required to specify the scope of the following arguments. ``PRIVATE`` and ``PUBLIC`` items will diff --git a/Help/manual/cmake-qt.7.rst b/Help/manual/cmake-qt.7.rst index d8d6172..f156f95 100644 --- a/Help/manual/cmake-qt.7.rst +++ b/Help/manual/cmake-qt.7.rst @@ -48,6 +48,8 @@ and ``rcc`` for virtual file system content generation. These tools may be automatically invoked by :manual:`cmake(1)` if the appropriate conditions are met. The automatic tool invocation may be used with both Qt 4 and Qt 5. +.. _`Qt AUTOMOC`: + AUTOMOC ^^^^^^^ @@ -77,8 +79,9 @@ automatically added to the target's :prop_tgt:`INCLUDE_DIRECTORIES`. Not included ``moc_<basename>.cpp`` files will be generated in custom folders to avoid name collisions and included in a separate -``<AUTOGEN_BUILD_DIR>/mocs_compilation.cpp`` file which is compiled -into the target. +file which is compiled into the target, named either +``<AUTOGEN_BUILD_DIR>/mocs_compilation.cpp`` or +``<AUTOGEN_BUILD_DIR>/mocs_compilation_$<CONFIG>.cpp``. * See :prop_tgt:`AUTOGEN_BUILD_DIR`. diff --git a/Help/manual/ctest.1.rst b/Help/manual/ctest.1.rst index 00df24b..16afcec 100644 --- a/Help/manual/ctest.1.rst +++ b/Help/manual/ctest.1.rst @@ -324,6 +324,9 @@ Options ``--build-and-test`` See `Build and Test Mode`_. +``--test-dir <dir>`` +Specify the directory in which to look for tests. + ``--test-output-size-passed <size>`` Limit the output for passed tests to ``<size>`` bytes. diff --git a/Help/prop_tgt/AUTOMOC.rst b/Help/prop_tgt/AUTOMOC.rst index c18859b..52d96e0 100644 --- a/Help/prop_tgt/AUTOMOC.rst +++ b/Help/prop_tgt/AUTOMOC.rst @@ -137,7 +137,8 @@ parent directory path of the ``moc`` input file. This scheme allows to have All not included ``moc`` output files will be included automatically by the CMake generated file -- ``<AUTOGEN_BUILD_DIR>/mocs_compilation.cpp``, +- ``<AUTOGEN_BUILD_DIR>/mocs_compilation.cpp``, or +- ``<AUTOGEN_BUILD_DIR>/mocs_compilation_$<CONFIG>.cpp``, which is added to the target's sources. diff --git a/Help/prop_tgt/XCODE_LINK_BUILD_PHASE_MODE.rst b/Help/prop_tgt/XCODE_LINK_BUILD_PHASE_MODE.rst index 2a79bca..836cc6b 100644 --- a/Help/prop_tgt/XCODE_LINK_BUILD_PHASE_MODE.rst +++ b/Help/prop_tgt/XCODE_LINK_BUILD_PHASE_MODE.rst @@ -31,6 +31,7 @@ Possible values are: * ``KNOWN_LOCATION`` The "Link Binary With Libraries" build phase will be used to link to another target under the same conditions as with ``BUILT_ONLY`` and also: + - Imported library targets except those of type ``UNKNOWN``. - Any non-target library specified directly with a path. diff --git a/Help/release/dev/after-option-in-target_include-directories.rst b/Help/release/dev/after-option-in-target_include-directories.rst new file mode 100644 index 0000000..f61026c --- /dev/null +++ b/Help/release/dev/after-option-in-target_include-directories.rst @@ -0,0 +1,5 @@ +after-option-in-target_include-directories.rst +---------------------------------------------- + +* The :command:`target_include_directories` command gained a new option + ``AFTER``. diff --git a/Help/release/dev/ctest-test-dir.rst b/Help/release/dev/ctest-test-dir.rst new file mode 100644 index 0000000..ab8d618 --- /dev/null +++ b/Help/release/dev/ctest-test-dir.rst @@ -0,0 +1,5 @@ +ctest-test-dir.rst +------------------ + +* :manual:`ctest(1)` gained a ``--test-dir`` option to specify the directory + in which to look for tests. diff --git a/Help/release/dev/file-generate-permissions.rst b/Help/release/dev/file-generate-permissions.rst new file mode 100644 index 0000000..d1a4d42 --- /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/Help/release/dev/qt-autogen-per-config.rst b/Help/release/dev/qt-autogen-per-config.rst new file mode 100644 index 0000000..6ba929d --- /dev/null +++ b/Help/release/dev/qt-autogen-per-config.rst @@ -0,0 +1,4 @@ +qt-autogen-per-config +--------------------- + +* The :ref:`Qt AUTOMOC` feature now works with per-config sources. diff --git a/Modules/CMakeDetermineCompilerId.cmake b/Modules/CMakeDetermineCompilerId.cmake index 8cf161f..d07db70 100644 --- a/Modules/CMakeDetermineCompilerId.cmake +++ b/Modules/CMakeDetermineCompilerId.cmake @@ -911,12 +911,12 @@ function(CMAKE_DETERMINE_COMPILER_ID_CHECK lang file) # # COFF (.exe) files start with "MZ" # if("${CMAKE_EXECUTABLE_MAGIC}" MATCHES "4d5a....") -# set(CMAKE_EXECUTABLE_FORMAT "COFF" CACHE STRING "Executable file format") +# set(CMAKE_EXECUTABLE_FORMAT "COFF" CACHE INTERNAL "Executable file format") # endif() # # Mach-O files start with MH_MAGIC or MH_CIGAM if("${CMAKE_EXECUTABLE_MAGIC}" MATCHES "feedface|cefaedfe|feedfacf|cffaedfe") - set(CMAKE_EXECUTABLE_FORMAT "MACHO" CACHE STRING "Executable file format") + set(CMAKE_EXECUTABLE_FORMAT "MACHO" CACHE INTERNAL "Executable file format") endif() endif() diff --git a/Modules/FindOpenSSL.cmake b/Modules/FindOpenSSL.cmake index 03b699b..d574790 100644 --- a/Modules/FindOpenSSL.cmake +++ b/Modules/FindOpenSSL.cmake @@ -141,16 +141,30 @@ if (WIN32) "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\OpenSSL (64-bit)_is1;Inno Setup: App Path]" ENV OPENSSL_ROOT_DIR ) - file(TO_CMAKE_PATH "$ENV{PROGRAMFILES}" _programfiles) + + if("${CMAKE_SIZEOF_VOID_P}" STREQUAL "8") + set(_arch "Win64") + file(TO_CMAKE_PATH "$ENV{PROGRAMFILES}" _programfiles) + else() + set(_arch "Win32") + set(_progfiles_x86 "ProgramFiles(x86)") + if(NOT "$ENV{${_progfiles_x86}}" STREQUAL "") + # under windows 64 bit machine + file(TO_CMAKE_PATH "$ENV{${_progfiles_x86}}" _programfiles) + else() + # under windows 32 bit machine + file(TO_CMAKE_PATH "$ENV{ProgramFiles}" _programfiles) + endif() + endif() + set(_OPENSSL_ROOT_PATHS "${_programfiles}/OpenSSL" - "${_programfiles}/OpenSSL-Win32" - "${_programfiles}/OpenSSL-Win64" + "${_programfiles}/OpenSSL-${_arch}" "C:/OpenSSL/" - "C:/OpenSSL-Win32/" - "C:/OpenSSL-Win64/" + "C:/OpenSSL-${_arch}/" ) unset(_programfiles) + unset(_arch) else () set(_OPENSSL_ROOT_HINTS ${OPENSSL_ROOT_DIR} diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake index 61645f2..49c60e6 100644 --- a/Source/CMakeVersion.cmake +++ b/Source/CMakeVersion.cmake @@ -1,7 +1,7 @@ # CMake version number components. set(CMake_VERSION_MAJOR 3) set(CMake_VERSION_MINOR 19) -set(CMake_VERSION_PATCH 20201216) +set(CMake_VERSION_PATCH 20201222) #set(CMake_VERSION_RC 0) set(CMake_VERSION_IS_DIRTY 0) diff --git a/Source/cmCTest.cxx b/Source/cmCTest.cxx index 8479458..014ce4e 100644 --- a/Source/cmCTest.cxx +++ b/Source/cmCTest.cxx @@ -4,6 +4,7 @@ #include <algorithm> #include <cctype> +#include <cerrno> #include <chrono> #include <cstdio> #include <cstdlib> @@ -179,6 +180,7 @@ struct cmCTest::Private // information for the --build-and-test options std::string BinaryDir; + std::string TestDir; std::string NotesFiles; @@ -2059,6 +2061,13 @@ bool cmCTest::HandleCommandLineArguments(size_t& i, i++; this->SetNotesFiles(args[i]); return true; + } else if (this->CheckArgument(arg, "--test-dir"_s)) { + if (i >= args.size() - 1) { + errormsg = "'--test-dir' requires an argument"; + return false; + } + i++; + this->Impl->TestDir = std::string(args[i]); } cm::string_view noTestsPrefix = "--no-tests="; @@ -2467,8 +2476,26 @@ int cmCTest::ExecuteTests() handler->SetVerbose(this->Impl->Verbose); handler->SetSubmitIndex(this->Impl->SubmitIndex); } - std::string cwd = cmSystemTools::GetCurrentWorkingDirectory(); - if (!this->Initialize(cwd.c_str(), nullptr)) { + + const std::string currDir = cmSystemTools::GetCurrentWorkingDirectory(); + std::string workDir = currDir; + if (!this->Impl->TestDir.empty()) { + workDir = cmSystemTools::CollapseFullPath(this->Impl->TestDir); + } + + if (currDir != workDir) { + cmCTestLog(this, OUTPUT, + "Internal ctest changing into directory: " << workDir + << std::endl); + if (cmSystemTools::ChangeDirectory(workDir) != 0) { + auto msg = "Failed to change working directory to \"" + workDir + + "\" : " + std::strerror(errno) + "\n"; + cmCTestLog(this, ERROR_MESSAGE, msg); + return 1; + } + } + + if (!this->Initialize(workDir.c_str(), nullptr)) { res = 12; cmCTestLog(this, ERROR_MESSAGE, "Problem initializing the dashboard." << std::endl); @@ -2476,6 +2503,10 @@ int cmCTest::ExecuteTests() res = this->ProcessSteps(); } this->Finalize(); + + if (currDir != workDir) { + cmSystemTools::ChangeDirectory(currDir); + } } if (res != 0) { cmCTestLog(this, DEBUG, diff --git a/Source/cmComputeLinkInformation.cxx b/Source/cmComputeLinkInformation.cxx index 201a9d9..6e1fac0 100644 --- a/Source/cmComputeLinkInformation.cxx +++ b/Source/cmComputeLinkInformation.cxx @@ -699,9 +699,13 @@ void cmComputeLinkInformation::AddItem(BT<std::string> const& item, } else { // This is not a CMake target. Use the name given. if (cmSystemTools::FileIsFullPath(item.Value)) { - if (cmSystemTools::FileIsDirectory(item.Value)) { + if (cmSystemTools::IsPathToFramework(item.Value) && + this->Makefile->IsOn("APPLE")) { + // This is a framework. + this->AddFrameworkItem(item.Value); + } else if (cmSystemTools::FileIsDirectory(item.Value)) { // This is a directory. - this->AddDirectoryItem(item.Value); + this->DropDirectoryItem(item.Value); } else { // Use the full path given to the library file. this->Depends.push_back(item.Value); @@ -1306,16 +1310,6 @@ void cmComputeLinkInformation::AddFrameworkItem(std::string const& item) } } -void cmComputeLinkInformation::AddDirectoryItem(std::string const& item) -{ - if (this->Makefile->IsOn("APPLE") && - cmSystemTools::IsPathToFramework(item)) { - this->AddFrameworkItem(item); - } else { - this->DropDirectoryItem(item); - } -} - void cmComputeLinkInformation::DropDirectoryItem(std::string const& item) { // A full path to a directory was found as a link item. Warn the diff --git a/Source/cmComputeLinkInformation.h b/Source/cmComputeLinkInformation.h index 543b6d7..ec8d73c 100644 --- a/Source/cmComputeLinkInformation.h +++ b/Source/cmComputeLinkInformation.h @@ -155,7 +155,6 @@ private: void AddFullItem(BT<std::string> const& item); bool CheckImplicitDirItem(std::string const& item); void AddUserItem(BT<std::string> const& item, bool pathNotKnown); - void AddDirectoryItem(std::string const& item); void AddFrameworkItem(std::string const& item); void DropDirectoryItem(std::string const& item); bool CheckSharedLibNoSOName(std::string const& item); diff --git a/Source/cmCreateTestSourceList.cxx b/Source/cmCreateTestSourceList.cxx index 9d492ba..3001ae0 100644 --- a/Source/cmCreateTestSourceList.cxx +++ b/Source/cmCreateTestSourceList.cxx @@ -125,7 +125,7 @@ bool cmCreateTestSourceList(std::vector<std::string> const& args, mf.AddDefinition("CMAKE_TESTDRIVER_ARGVC_FUNCTION", function); } mf.AddDefinition("CMAKE_FORWARD_DECLARE_TESTS", forwardDeclareCode); - mf.AddDefinition("CMAKE_FUNCTION_TABLE_ENTIRES", functionMapCode); + mf.AddDefinition("CMAKE_FUNCTION_TABLE_ENTRIES", functionMapCode); bool res = true; if (!mf.ConfigureFile(configFile, driver, false, true, false)) { res = false; diff --git a/Source/cmFileCommand.cxx b/Source/cmFileCommand.cxx index 9467c03..9815d9d 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 3c17b54..af129d3 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 2cd35ae..5ad5e23 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/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx index dfeb029..e2943d6 100644 --- a/Source/cmGeneratorTarget.cxx +++ b/Source/cmGeneratorTarget.cxx @@ -7039,7 +7039,7 @@ const cmLinkImplementation* cmGeneratorTarget::GetLinkImplementation( return &impl; } -bool cmGeneratorTarget::GetConfigCommonSourceFiles( +bool cmGeneratorTarget::GetConfigCommonSourceFilesForXcode( std::vector<cmSourceFile*>& files) const { std::vector<std::string> const& configs = diff --git a/Source/cmGeneratorTarget.h b/Source/cmGeneratorTarget.h index cb312ad..51369c2 100644 --- a/Source/cmGeneratorTarget.h +++ b/Source/cmGeneratorTarget.h @@ -430,8 +430,9 @@ public: /** Get source files common to all configurations and diagnose cases with per-config sources. Excludes sources added by a TARGET_OBJECTS - generator expression. */ - bool GetConfigCommonSourceFiles(std::vector<cmSourceFile*>& files) const; + generator expression. Do not use outside the Xcode generator. */ + bool GetConfigCommonSourceFilesForXcode( + std::vector<cmSourceFile*>& files) const; bool HaveBuildTreeRPATH(const std::string& config) const; diff --git a/Source/cmGlobalXCodeGenerator.cxx b/Source/cmGlobalXCodeGenerator.cxx index 70aa052..b6fedaf 100644 --- a/Source/cmGlobalXCodeGenerator.cxx +++ b/Source/cmGlobalXCodeGenerator.cxx @@ -1384,7 +1384,7 @@ bool cmGlobalXCodeGenerator::CreateXCodeTarget( // organize the sources std::vector<cmSourceFile*> commonSourceFiles; - if (!gtgt->GetConfigCommonSourceFiles(commonSourceFiles)) { + if (!gtgt->GetConfigCommonSourceFilesForXcode(commonSourceFiles)) { return false; } @@ -1748,7 +1748,7 @@ void cmGlobalXCodeGenerator::CreateCustomCommands( this->CreateRunScriptBuildPhase("CMake PostBuild Rules", postbuild); } else { std::vector<cmSourceFile*> classes; - if (!gtgt->GetConfigCommonSourceFiles(classes)) { + if (!gtgt->GetConfigCommonSourceFilesForXcode(classes)) { return; } // add all the sources @@ -1821,7 +1821,7 @@ void cmGlobalXCodeGenerator::CreateRunScriptBuildPhases( cmXCodeObject* buildPhases, cmGeneratorTarget const* gt) { std::vector<cmSourceFile*> sources; - if (!gt->GetConfigCommonSourceFiles(sources)) { + if (!gt->GetConfigCommonSourceFilesForXcode(sources)) { return; } auto& visited = this->CommandsVisited[gt]; @@ -2964,7 +2964,7 @@ cmXCodeObject* cmGlobalXCodeGenerator::CreateUtilityTarget( if (gtgt->GetType() != cmStateEnums::GLOBAL_TARGET && gtgt->GetName() != CMAKE_CHECK_BUILD_SYSTEM_TARGET) { std::vector<cmSourceFile*> sources; - if (!gtgt->GetConfigCommonSourceFiles(sources)) { + if (!gtgt->GetConfigCommonSourceFilesForXcode(sources)) { return nullptr; } diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx index 028688d..9d37d61 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 f18f70c..1617793 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/Source/cmQtAutoGenInitializer.cxx b/Source/cmQtAutoGenInitializer.cxx index 67834f1..1f74578 100644 --- a/Source/cmQtAutoGenInitializer.cxx +++ b/Source/cmQtAutoGenInitializer.cxx @@ -17,6 +17,7 @@ #include <cm/iterator> #include <cm/memory> #include <cmext/algorithm> +#include <cmext/string_view> #include <cm3p/json/value.h> #include <cm3p/json/writer.h> @@ -564,8 +565,22 @@ bool cmQtAutoGenInitializer::InitCustomTargets() bool cmQtAutoGenInitializer::InitMoc() { // Mocs compilation file - this->Moc.CompilationFile = - cmStrCat(this->Dir.Build, "/mocs_compilation.cpp"); + if (this->GlobalGen->IsXcode()) { + // XXX(xcode-per-cfg-src): Drop this Xcode-specific code path + // when the Xcode generator supports per-config sources. + this->Moc.CompilationFile.Default = + cmStrCat(this->Dir.Build, "/mocs_compilation.cpp"); + this->Moc.CompilationFileGenex = this->Moc.CompilationFile.Default; + } else { + ConfigFileNames(this->Moc.CompilationFile, + cmStrCat(this->Dir.Build, "/mocs_compilation"), ".cpp"); + if (this->MultiConfig) { + this->Moc.CompilationFileGenex = + cmStrCat(this->Dir.Build, "/mocs_compilation_$<CONFIG>.cpp"_s); + } else { + this->Moc.CompilationFileGenex = this->Moc.CompilationFile.Default; + } + } // Moc predefs if (this->GenTarget->GetPropertyAsBool("AUTOMOC_COMPILER_PREDEFINES") && @@ -731,10 +746,14 @@ bool cmQtAutoGenInitializer::InitScanFiles() auto const& kw = this->GlobalInitializer->kw(); auto makeMUFile = [this, &kw](cmSourceFile* sf, std::string const& fullPath, + std::vector<size_t> const& configs, bool muIt) -> MUFileHandle { MUFileHandle muf = cm::make_unique<MUFile>(); muf->FullPath = fullPath; muf->SF = sf; + if (!configs.empty() && configs.size() != this->ConfigsList.size()) { + muf->Configs = configs; + } muf->Generated = sf->GetIsGenerated(); bool const skipAutogen = sf->GetPropertyAsBool(kw.SKIP_AUTOGEN); muf->SkipMoc = this->Moc.Enabled && @@ -773,42 +792,37 @@ bool cmQtAutoGenInitializer::InitScanFiles() // Scan through target files { // Scan through target files - std::vector<cmSourceFile*> srcFiles; - this->GenTarget->GetConfigCommonSourceFiles(srcFiles); - for (cmSourceFile* sf : srcFiles) { - // sf->GetExtension() is only valid after sf->ResolveFullPath() ... - // Since we're iterating over source files that might be not in the - // target we need to check for path errors (not existing files). - std::string pathError; - std::string const& fullPath = sf->ResolveFullPath(&pathError); - if (!pathError.empty() || fullPath.empty()) { - continue; - } + for (cmGeneratorTarget::AllConfigSource const& acs : + this->GenTarget->GetAllConfigSources()) { + std::string const& fullPath = acs.Source->GetFullPath(); std::string const& extLower = - cmSystemTools::LowerCase(sf->GetExtension()); + cmSystemTools::LowerCase(acs.Source->GetExtension()); // Register files that will be scanned by moc or uic if (this->MocOrUicEnabled()) { if (cm->IsAHeaderExtension(extLower)) { - addMUHeader(makeMUFile(sf, fullPath, true), extLower); + addMUHeader(makeMUFile(acs.Source, fullPath, acs.Configs, true), + extLower); } else if (cm->IsACLikeSourceExtension(extLower)) { - addMUSource(makeMUFile(sf, fullPath, true)); + addMUSource(makeMUFile(acs.Source, fullPath, acs.Configs, true)); } } // Register rcc enabled files if (this->Rcc.Enabled) { - if ((extLower == kw.qrc) && !sf->GetPropertyAsBool(kw.SKIP_AUTOGEN) && - !sf->GetPropertyAsBool(kw.SKIP_AUTORCC)) { + if ((extLower == kw.qrc) && + !acs.Source->GetPropertyAsBool(kw.SKIP_AUTOGEN) && + !acs.Source->GetPropertyAsBool(kw.SKIP_AUTORCC)) { // Register qrc file Qrc qrc; qrc.QrcFile = fullPath; qrc.QrcName = cmSystemTools::GetFilenameWithoutLastExtension(qrc.QrcFile); - qrc.Generated = sf->GetIsGenerated(); + qrc.Generated = acs.Source->GetIsGenerated(); // RCC options { - std::string const& opts = sf->GetSafeProperty(kw.AUTORCC_OPTIONS); + std::string const& opts = + acs.Source->GetSafeProperty(kw.AUTORCC_OPTIONS); if (!opts.empty()) { cmExpandList(opts, qrc.Options); } @@ -818,7 +832,7 @@ bool cmQtAutoGenInitializer::InitScanFiles() } } } - // cmGeneratorTarget::GetConfigCommonSourceFiles computes the target's + // cmGeneratorTarget::GetAllConfigSources computes the target's // sources meta data cache. Clear it so that OBJECT library targets that // are AUTOGEN initialized after this target get their added // mocs_compilation.cpp source acknowledged by this target. @@ -862,7 +876,7 @@ bool cmQtAutoGenInitializer::InitScanFiles() } if (sf != nullptr) { - auto eMuf = makeMUFile(sf, fullPath, true); + auto eMuf = makeMUFile(sf, fullPath, muf.Configs, true); // Only process moc/uic when the parent is processed as well if (!muf.MocIt) { eMuf->MocIt = false; @@ -897,14 +911,14 @@ bool cmQtAutoGenInitializer::InitScanFiles() if (cm->IsAHeaderExtension(extLower)) { if (!cm::contains(this->AutogenTarget.Headers, sf.get())) { - auto muf = makeMUFile(sf.get(), fullPath, false); + auto muf = makeMUFile(sf.get(), fullPath, {}, false); if (muf->SkipMoc || muf->SkipUic) { addMUHeader(std::move(muf), extLower); } } } else if (cm->IsACLikeSourceExtension(extLower)) { if (!cm::contains(this->AutogenTarget.Sources, sf.get())) { - auto muf = makeMUFile(sf.get(), fullPath, false); + auto muf = makeMUFile(sf.get(), fullPath, {}, false); if (muf->SkipMoc || muf->SkipUic) { addMUSource(std::move(muf)); } @@ -1067,10 +1081,10 @@ bool cmQtAutoGenInitializer::InitAutogenTarget() this->Makefile->AddCMakeOutputFile(this->AutogenTarget.InfoFile); // Files provided by the autogen target - std::vector<std::string> autogenProvides; + std::vector<std::string> autogenByproducts; if (this->Moc.Enabled) { this->AddGeneratedSource(this->Moc.CompilationFile, this->Moc, true); - autogenProvides.push_back(this->Moc.CompilationFile); + autogenByproducts.push_back(this->Moc.CompilationFileGenex); } // Compose target comment @@ -1091,8 +1105,8 @@ bool cmQtAutoGenInitializer::InitAutogenTarget() } // Compose command lines - // TODO: Refactor autogen to output a per-config mocs_compilation.cpp instead - // of fiddling with the include directories + // FIXME: Take advantage of our per-config mocs_compilation_$<CONFIG>.cpp + // instead of fiddling with the include directories std::vector<std::string> configs; this->GlobalGen->GetQtAutoGenConfigs(configs); bool stdPipesUTF8 = true; @@ -1138,7 +1152,7 @@ bool cmQtAutoGenInitializer::InitAutogenTarget() // PRE_BUILD does not support file dependencies! const std::vector<std::string> no_output; const std::vector<std::string> no_deps; - cmCustomCommand cc(no_output, autogenProvides, no_deps, commandLines, + cmCustomCommand cc(no_output, autogenByproducts, no_deps, commandLines, this->Makefile->GetBacktrace(), autogenComment.c_str(), this->Dir.Work.c_str(), stdPipesUTF8); cc.SetEscapeOldStyle(false); @@ -1283,7 +1297,7 @@ bool cmQtAutoGenInitializer::InitAutogenTarget() // Create autogen target cmTarget* autogenTarget = this->LocalGen->AddUtilityCommand( this->AutogenTarget.Name, true, this->Dir.Work.c_str(), - /*byproducts=*/autogenProvides, + /*byproducts=*/autogenByproducts, /*depends=*/dependencies, commandLines, false, autogenComment.c_str()); // Create autogen generator target this->LocalGen->AddGeneratorTarget( @@ -1533,18 +1547,31 @@ bool cmQtAutoGenInitializer::SetupWriteAutogenInfo() info.SetArray("CMAKE_LIST_FILES", this->Makefile->GetListFiles()); info.SetArray("HEADER_EXTENSIONS", this->Makefile->GetCMakeInstance()->GetHeaderExtensions()); + auto cfgArray = [this](std::vector<size_t> const& configs) -> Json::Value { + Json::Value value; + if (!configs.empty()) { + value = Json::arrayValue; + for (size_t ci : configs) { + value.append(this->ConfigsList[ci]); + } + } + return value; + }; + info.SetArrayArray("HEADERS", headers, + [this, &cfgArray](Json::Value& jval, MUFile const* muf) { + jval.resize(4u); + jval[0u] = muf->FullPath; + jval[1u] = cmStrCat(muf->MocIt ? 'M' : 'm', + muf->UicIt ? 'U' : 'u'); + jval[2u] = cfgArray(muf->Configs); + jval[3u] = this->GetMocBuildPath(*muf); + }); info.SetArrayArray( - "HEADERS", headers, [this](Json::Value& jval, MUFile const* muf) { + "SOURCES", sources, [&cfgArray](Json::Value& jval, MUFile const* muf) { jval.resize(3u); jval[0u] = muf->FullPath; jval[1u] = cmStrCat(muf->MocIt ? 'M' : 'm', muf->UicIt ? 'U' : 'u'); - jval[2u] = this->GetMocBuildPath(*muf); - }); - info.SetArrayArray( - "SOURCES", sources, [](Json::Value& jval, MUFile const* muf) { - jval.resize(2u); - jval[0u] = muf->FullPath; - jval[1u] = cmStrCat(muf->MocIt ? 'M' : 'm', muf->UicIt ? 'U' : 'u'); + jval[2u] = cfgArray(muf->Configs); }); // Write moc settings @@ -1563,7 +1590,7 @@ bool cmQtAutoGenInitializer::SetupWriteAutogenInfo() jval[0u] = pair.first; jval[1u] = pair.second; }); - info.Set("MOC_COMPILATION_FILE", this->Moc.CompilationFile); + info.SetConfig("MOC_COMPILATION_FILE", this->Moc.CompilationFile); info.SetArray("MOC_PREDEFS_CMD", this->Moc.PredefsCmd); info.SetConfig("MOC_PREDEFS_FILE", this->Moc.PredefsFile); } @@ -1656,6 +1683,28 @@ cmSourceFile* cmQtAutoGenInitializer::AddGeneratedSource( return gFile; } +void cmQtAutoGenInitializer::AddGeneratedSource(ConfigString const& filename, + GenVarsT const& genVars, + bool prepend) +{ + // XXX(xcode-per-cfg-src): Drop the Xcode-specific part of the condition + // when the Xcode generator supports per-config sources. + if (!this->MultiConfig || this->GlobalGen->IsXcode()) { + this->AddGeneratedSource(filename.Default, genVars, prepend); + return; + } + for (auto const& cfg : this->ConfigsList) { + std::string const& filenameCfg = filename.Config.at(cfg); + // Register source at makefile + this->RegisterGeneratedSource(filenameCfg); + // Add source file to target for this configuration. + this->GenTarget->AddSource( + cmStrCat("$<$<CONFIG:"_s, cfg, ">:"_s, filenameCfg, ">"_s), prepend); + // Add source file to source group + this->AddToSourceGroup(filenameCfg, genVars.GenNameUpper); + } +} + void cmQtAutoGenInitializer::AddToSourceGroup(std::string const& fileName, cm::string_view genNameUpper) { diff --git a/Source/cmQtAutoGenInitializer.h b/Source/cmQtAutoGenInitializer.h index 3ab303a..e0e66f1 100644 --- a/Source/cmQtAutoGenInitializer.h +++ b/Source/cmQtAutoGenInitializer.h @@ -4,6 +4,7 @@ #include "cmConfigure.h" // IWYU pragma: keep +#include <cstddef> #include <memory> #include <set> #include <string> @@ -70,6 +71,7 @@ public: { std::string FullPath; cmSourceFile* SF = nullptr; + std::vector<size_t> Configs; bool Generated = false; bool SkipMoc = false; bool SkipUic = false; @@ -132,6 +134,8 @@ private: cmSourceFile* AddGeneratedSource(std::string const& filename, GenVarsT const& genVars, bool prepend = false); + void AddGeneratedSource(ConfigString const& filename, + GenVarsT const& genVars, bool prepend = false); void AddToSourceGroup(std::string const& fileName, cm::string_view genNameUpper); void AddCleanFile(std::string const& fileName); @@ -207,7 +211,8 @@ private: bool RelaxedMode = false; bool PathPrefix = false; - std::string CompilationFile; + ConfigString CompilationFile; + std::string CompilationFileGenex; // Compiler implicit pre defines std::vector<std::string> PredefsCmd; ConfigString PredefsFile; diff --git a/Source/cmQtAutoMocUic.cxx b/Source/cmQtAutoMocUic.cxx index b27bb88..c9d4268 100644 --- a/Source/cmQtAutoMocUic.cxx +++ b/Source/cmQtAutoMocUic.cxx @@ -2452,17 +2452,20 @@ bool cmQtAutoMocUicT::InitFromInfo(InfoT const& info) Json::Value const& entry = val[ii]; if (testEntry(entry.isArray(), "JSON value is not an array.") || - testEntry(entry.size() == 3, "JSON array size invalid.")) { + testEntry(entry.size() == 4, "JSON array size invalid.")) { return false; } Json::Value const& entryName = entry[0u]; Json::Value const& entryFlags = entry[1u]; - Json::Value const& entryBuild = entry[2u]; + Json::Value const& entryConfigs = entry[2u]; + Json::Value const& entryBuild = entry[3u]; if (testEntry(entryName.isString(), "JSON value for name is not a string.") || testEntry(entryFlags.isString(), "JSON value for flags is not a string.") || + testEntry(entryConfigs.isNull() || entryConfigs.isArray(), + "JSON value for configs is not null or array.") || testEntry(entryBuild.isString(), "JSON value for build path is not a string.")) { return false; @@ -2475,6 +2478,22 @@ bool cmQtAutoMocUicT::InitFromInfo(InfoT const& info) return false; } + if (entryConfigs.isArray()) { + bool configFound = false; + Json::ArrayIndex const configArraySize = entryConfigs.size(); + for (Json::ArrayIndex ci = 0; ci != configArraySize; ++ci) { + Json::Value const& config = entryConfigs[ci]; + if (testEntry(config.isString(), + "JSON value in config array is not a string.")) { + return false; + } + configFound = configFound || config.asString() == this->InfoConfig(); + } + if (!configFound) { + continue; + } + } + cmFileTime fileTime; if (!fileTime.Load(name)) { return info.LogError(cmStrCat( @@ -2515,16 +2534,19 @@ bool cmQtAutoMocUicT::InitFromInfo(InfoT const& info) Json::Value const& entry = val[ii]; if (testEntry(entry.isArray(), "JSON value is not an array.") || - testEntry(entry.size() == 2, "JSON array size invalid.")) { + testEntry(entry.size() == 3, "JSON array size invalid.")) { return false; } Json::Value const& entryName = entry[0u]; Json::Value const& entryFlags = entry[1u]; + Json::Value const& entryConfigs = entry[2u]; if (testEntry(entryName.isString(), "JSON value for name is not a string.") || testEntry(entryFlags.isString(), - "JSON value for flags is not a string.")) { + "JSON value for flags is not a string.") || + testEntry(entryConfigs.isNull() || entryConfigs.isArray(), + "JSON value for configs is not null or array.")) { return false; } @@ -2534,6 +2556,22 @@ bool cmQtAutoMocUicT::InitFromInfo(InfoT const& info) return false; } + if (entryConfigs.isArray()) { + bool configFound = false; + Json::ArrayIndex const configArraySize = entryConfigs.size(); + for (Json::ArrayIndex ci = 0; ci != configArraySize; ++ci) { + Json::Value const& config = entryConfigs[ci]; + if (testEntry(config.isString(), + "JSON value in config array is not a string.")) { + return false; + } + configFound = configFound || config.asString() == this->InfoConfig(); + } + if (!configFound) { + continue; + } + } + cmFileTime fileTime; if (!fileTime.Load(name)) { return info.LogError(cmStrCat( diff --git a/Source/cmSystemTools.cxx b/Source/cmSystemTools.cxx index 97440d2..6a705f4 100644 --- a/Source/cmSystemTools.cxx +++ b/Source/cmSystemTools.cxx @@ -952,9 +952,8 @@ bool cmMoveFile(std::wstring const& oldname, std::wstring const& newname) SetLastError(0); // Use MOVEFILE_REPLACE_EXISTING to replace an existing destination file. - // Use MOVEFILE_WRITE_THROUGH to flush the change to disk before returning. return MoveFileExW(oldname.c_str(), newname.c_str(), - MOVEFILE_REPLACE_EXISTING | MOVEFILE_WRITE_THROUGH); + MOVEFILE_REPLACE_EXISTING); } } #endif diff --git a/Source/cmTargetIncludeDirectoriesCommand.cxx b/Source/cmTargetIncludeDirectoriesCommand.cxx index 35635b9..bf4cc09 100644 --- a/Source/cmTargetIncludeDirectoriesCommand.cxx +++ b/Source/cmTargetIncludeDirectoriesCommand.cxx @@ -101,5 +101,6 @@ bool cmTargetIncludeDirectoriesCommand(std::vector<std::string> const& args, args, "INCLUDE_DIRECTORIES", TargetIncludeDirectoriesImpl::ArgumentFlags( TargetIncludeDirectoriesImpl::PROCESS_BEFORE | + TargetIncludeDirectoriesImpl::PROCESS_AFTER | TargetIncludeDirectoriesImpl::PROCESS_SYSTEM)); } diff --git a/Source/cmTargetPropCommandBase.cxx b/Source/cmTargetPropCommandBase.cxx index b050a58..e41714a 100644 --- a/Source/cmTargetPropCommandBase.cxx +++ b/Source/cmTargetPropCommandBase.cxx @@ -87,6 +87,13 @@ bool cmTargetPropCommandBase::HandleArguments( } prepend = true; ++argIndex; + } else if ((flags & PROCESS_AFTER) && args[argIndex] == "AFTER") { + if (args.size() < 3) { + this->SetError("called with incorrect number of arguments"); + return false; + } + prepend = false; + ++argIndex; } if ((flags & PROCESS_REUSE_FROM) && args[argIndex] == "REUSE_FROM") { diff --git a/Source/cmTargetPropCommandBase.h b/Source/cmTargetPropCommandBase.h index 50ac1aa..fc24fe8 100644 --- a/Source/cmTargetPropCommandBase.h +++ b/Source/cmTargetPropCommandBase.h @@ -23,8 +23,9 @@ public: { NO_FLAGS = 0x0, PROCESS_BEFORE = 0x1, - PROCESS_SYSTEM = 0x2, - PROCESS_REUSE_FROM = 0x3 + PROCESS_AFTER = 0x2, + PROCESS_SYSTEM = 0x3, + PROCESS_REUSE_FROM = 0x4 }; bool HandleArguments(std::vector<std::string> const& args, diff --git a/Source/ctest.cxx b/Source/ctest.cxx index d0bc061..600df1d 100644 --- a/Source/ctest.cxx +++ b/Source/ctest.cxx @@ -111,6 +111,7 @@ static const char* cmDocumentationOptions[][2] = { { "--no-subproject-summary", "Disable timing summary information for " "subprojects." }, + { "--test-dir <dir>", "Specify the directory in which to look for tests." }, { "--build-and-test", "Configure, build and run a test." }, { "--build-target", "Specify a specific target to build." }, { "--build-nocmake", "Run the build without running cmake first." }, diff --git a/Templates/TestDriver.cxx.in b/Templates/TestDriver.cxx.in index 053f1ee..3e47d6a 100644 --- a/Templates/TestDriver.cxx.in +++ b/Templates/TestDriver.cxx.in @@ -34,7 +34,7 @@ typedef struct /* NOLINT */ } functionMapEntry; static functionMapEntry cmakeGeneratedFunctionMapEntries[] = { - @CMAKE_FUNCTION_TABLE_ENTIRES@ + @CMAKE_FUNCTION_TABLE_ENTRIES@ { CM_NULL, CM_NULL } /* NOLINT */ }; diff --git a/Tests/Framework/CMakeLists.txt b/Tests/Framework/CMakeLists.txt index a313c2c..f741ec2 100644 --- a/Tests/Framework/CMakeLists.txt +++ b/Tests/Framework/CMakeLists.txt @@ -84,3 +84,19 @@ if(NOT XCODE OR NOT XCODE_VERSION VERSION_LESS 5) endif() include(CPack) + +if(APPLE) + set(ExternalFramework_INSTALL_DIR "${CMAKE_CURRENT_BINARY_DIR}/External") + file(REMOVE_RECURSE "${ExternalFramework_INSTALL_DIR}") + + include(ExternalProject) + ExternalProject_Add(ExternalFramework + SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/External" + INSTALL_DIR "${ExternalFramework_INSTALL_DIR}" + CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=<INSTALL_DIR> + ) + + add_executable(useExternal useExternal.c) + target_link_libraries(useExternal PRIVATE "${ExternalFramework_INSTALL_DIR}/lib/External.framework") + add_dependencies(useExternal ExternalFramework) +endif() diff --git a/Tests/Framework/External/CMakeLists.txt b/Tests/Framework/External/CMakeLists.txt new file mode 100644 index 0000000..b9128fd --- /dev/null +++ b/Tests/Framework/External/CMakeLists.txt @@ -0,0 +1,5 @@ +cmake_minimum_required(VERSION 3.19) +project(ExternalFramework C) +add_library(External SHARED external.c) +set_property(TARGET External PROPERTY FRAMEWORK 1) +install(TARGETS External DESTINATION lib) diff --git a/Tests/Framework/External/external.c b/Tests/Framework/External/external.c new file mode 100644 index 0000000..8441e71 --- /dev/null +++ b/Tests/Framework/External/external.c @@ -0,0 +1,4 @@ +int external(void) +{ + return 0; +} diff --git a/Tests/Framework/useExternal.c b/Tests/Framework/useExternal.c new file mode 100644 index 0000000..8494b15 --- /dev/null +++ b/Tests/Framework/useExternal.c @@ -0,0 +1,6 @@ +extern int external(void); + +int main(void) +{ + return external(); +} diff --git a/Tests/QtAutogen/AutogenOriginDependsOff/CMakeLists.txt b/Tests/QtAutogen/AutogenOriginDependsOff/CMakeLists.txt index d9fc2b0..17855ff 100644 --- a/Tests/QtAutogen/AutogenOriginDependsOff/CMakeLists.txt +++ b/Tests/QtAutogen/AutogenOriginDependsOff/CMakeLists.txt @@ -2,6 +2,15 @@ cmake_minimum_required(VERSION 3.11) project(AutogenOriginDependsOff) include("../AutogenCoreTest.cmake") +get_property(_isMultiConfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) +# XXX(xcode-per-cfg-src): Enable multi-config code path for Xcode +# when the Xcode generator supports per-config sources. +if(_isMultiConfig AND NOT CMAKE_GENERATOR STREQUAL "Xcode") + set(mocs_compilation_cpp "mocs_compilation_$<CONFIG>.cpp") +else() + set(mocs_compilation_cpp "mocs_compilation.cpp") +endif() + set(CSD ${CMAKE_CURRENT_SOURCE_DIR}) set(CBD ${CMAKE_CURRENT_BINARY_DIR}) include_directories(${CSD}) @@ -19,7 +28,7 @@ add_custom_command ( add_custom_target ( a_mc COMMAND ${CMAKE_COMMAND} -E sleep 2 COMMAND ${CMAKE_COMMAND} - "-DMCF=${CBD}/a_qt_autogen/mocs_compilation.cpp" + "-DMCF=${CBD}/a_qt_autogen/${mocs_compilation_cpp}" "-DCF_IN=${CSD}/a_mc.hpp.in" "-DCF_OUT=${CBD}/a_mc.hpp" -P ${CSD}/configure_content.cmake @@ -51,7 +60,7 @@ add_custom_command ( DEPENDS b_qt_autogen COMMAND ${CMAKE_COMMAND} -E sleep 2 COMMAND ${CMAKE_COMMAND} - "-DMCF=${CBD}/b_qt_autogen/mocs_compilation.cpp" + "-DMCF=${CBD}/b_qt_autogen/${mocs_compilation_cpp}" "-DCF_IN=${CSD}/b_mc.cpp.in" "-DCF_OUT=${CBD}/b_mc.cpp" -P ${CSD}/configure_content.cmake diff --git a/Tests/QtAutogen/GlobalAutogenTarget/CMakeLists.txt b/Tests/QtAutogen/GlobalAutogenTarget/CMakeLists.txt index 81fd8db..e95c626 100644 --- a/Tests/QtAutogen/GlobalAutogenTarget/CMakeLists.txt +++ b/Tests/QtAutogen/GlobalAutogenTarget/CMakeLists.txt @@ -13,10 +13,10 @@ include("../AutogenCoreTest.cmake") set(GAT_SDIR "${CMAKE_CURRENT_SOURCE_DIR}/GAT") set(GAT_BDIR "${CMAKE_CURRENT_BINARY_DIR}/GAT") # Files -set(MCA "sda/sda_autogen/mocs_compilation.cpp") -set(MCB "sdb/sdb_autogen/mocs_compilation.cpp") -set(MCC "sdc/sdc_autogen/mocs_compilation.cpp") -set(MCG "gat_autogen/mocs_compilation.cpp") +set(MCA "sda/sda_autogen/mocs_compilation*.cpp") +set(MCB "sdb/sdb_autogen/mocs_compilation*.cpp") +set(MCC "sdc/sdc_autogen/mocs_compilation*.cpp") +set(MCG "gat_autogen/mocs_compilation*.cpp") set(DRA "sda/sda_autogen/*qrc_data.cpp") set(DRB "sdb/sdb_autogen/*qrc_data.cpp") diff --git a/Tests/QtAutogen/MocOnly/CMakeLists.txt b/Tests/QtAutogen/MocOnly/CMakeLists.txt index e109154..f4fde58 100644 --- a/Tests/QtAutogen/MocOnly/CMakeLists.txt +++ b/Tests/QtAutogen/MocOnly/CMakeLists.txt @@ -11,6 +11,18 @@ add_executable(mocOnly IncA.cpp IncB.cpp ) +# XXX(xcode-per-cfg-src): Drop the NO_PER_CONFIG_SOURCES exclusion +# when the Xcode generator supports per-config sources. +if(NOT NO_PER_CONFIG_SOURCES) + target_sources(mocOnly PRIVATE + "$<$<CONFIG:Debug>:${CMAKE_CURRENT_SOURCE_DIR}/CfgDebug.cpp>" + "$<$<NOT:$<CONFIG:Debug>>:${CMAKE_CURRENT_SOURCE_DIR}/CfgOther.cpp>" + ) + target_compile_definitions(mocOnly PRIVATE + "$<$<CONFIG:Debug>:HAVE_CFG_DEBUG>" + "$<$<NOT:$<CONFIG:Debug>>:HAVE_CFG_OTHER>" + ) +endif() set_property(TARGET mocOnly PROPERTY AUTOMOC ON) target_link_libraries(mocOnly ${QT_LIBRARIES}) # Add compile definitions with unusual characters diff --git a/Tests/QtAutogen/MocOnly/CfgDebug.cpp b/Tests/QtAutogen/MocOnly/CfgDebug.cpp new file mode 100644 index 0000000..07ca3fb --- /dev/null +++ b/Tests/QtAutogen/MocOnly/CfgDebug.cpp @@ -0,0 +1,5 @@ +#include "CfgDebug.hpp" + +CfgDebug::CfgDebug() +{ +} diff --git a/Tests/QtAutogen/MocOnly/CfgDebug.hpp b/Tests/QtAutogen/MocOnly/CfgDebug.hpp new file mode 100644 index 0000000..3cd90a4 --- /dev/null +++ b/Tests/QtAutogen/MocOnly/CfgDebug.hpp @@ -0,0 +1,15 @@ +#ifndef CFGDEBUG_HPP +#define CFGDEBUG_HPP + +#include <QObject> + +/* clang-format off */ +class CfgDebug : public QObject +{ + Q_OBJECT +public: + CfgDebug(); +}; +/* clang-format on */ + +#endif diff --git a/Tests/QtAutogen/MocOnly/CfgOther.cpp b/Tests/QtAutogen/MocOnly/CfgOther.cpp new file mode 100644 index 0000000..0ccd433 --- /dev/null +++ b/Tests/QtAutogen/MocOnly/CfgOther.cpp @@ -0,0 +1,5 @@ +#include "CfgOther.hpp" + +CfgOther::CfgOther() +{ +} diff --git a/Tests/QtAutogen/MocOnly/CfgOther.hpp b/Tests/QtAutogen/MocOnly/CfgOther.hpp new file mode 100644 index 0000000..7cacd52 --- /dev/null +++ b/Tests/QtAutogen/MocOnly/CfgOther.hpp @@ -0,0 +1,15 @@ +#ifndef CFGOTHER_HPP +#define CFGOTHER_HPP + +#include <QObject> + +/* clang-format off */ +class CfgOther : public QObject +{ + Q_OBJECT +public: + CfgOther(); +}; +/* clang-format on */ + +#endif diff --git a/Tests/QtAutogen/MocOnly/main.cpp b/Tests/QtAutogen/MocOnly/main.cpp index ec8da21..6c0f6f2 100644 --- a/Tests/QtAutogen/MocOnly/main.cpp +++ b/Tests/QtAutogen/MocOnly/main.cpp @@ -5,6 +5,14 @@ #include "StyleA.hpp" #include "StyleB.hpp" +#ifdef HAVE_CFG_DEBUG +# include "CfgDebug.hpp" +#endif + +#ifdef HAVE_CFG_OTHER +# include "CfgOther.hpp" +#endif + int main(int argv, char** args) { StyleA styleA; diff --git a/Tests/QtAutogen/TestMacros.cmake b/Tests/QtAutogen/TestMacros.cmake index 0e27188..1024996 100644 --- a/Tests/QtAutogen/TestMacros.cmake +++ b/Tests/QtAutogen/TestMacros.cmake @@ -1,12 +1,19 @@ # Autogen build options set(Autogen_BUILD_OPTIONS "-DQT_TEST_VERSION=${QT_TEST_VERSION}") -if(NOT _isMultiConfig) # Set in Tests/CMakeLists.txt +if(_isMultiConfig) # Set in Tests/CMakeLists.txt + list(APPEND Autogen_CTEST_OPTIONS --build-config $<CONFIGURATION>) +else() list(APPEND Autogen_BUILD_OPTIONS "-DCMAKE_BUILD_TYPE=$<CONFIGURATION>") endif() list(APPEND Autogen_BUILD_OPTIONS "-DCMAKE_AUTOGEN_VERBOSE=1" "-DQT_QMAKE_EXECUTABLE:FILEPATH=${QT_QMAKE_EXECUTABLE}" ) +# XXX(xcode-per-cfg-src): Drop the NO_PER_CONFIG_SOURCES exclusion +# when the Xcode generator supports per-config sources. +if(CMAKE_GENERATOR STREQUAL "Xcode") + list(APPEND Autogen_BUILD_OPTIONS -DNO_PER_CONFIG_SOURCES=1) +endif() # A macro to add a QtAutogen test macro(ADD_AUTOGEN_TEST NAME) @@ -30,6 +37,7 @@ macro(ADD_AUTOGEN_TEST NAME) "${_BuildDir}" ${build_generator_args} --build-project ${NAME} + ${Autogen_CTEST_OPTIONS} --build-exe-dir "${_BuildDir}" --force-new-ctest-process --build-options ${build_options} ${Autogen_BUILD_OPTIONS} diff --git a/Tests/RunCMake/CTestCommandLine/RunCMakeTest.cmake b/Tests/RunCMake/CTestCommandLine/RunCMakeTest.cmake index e05ad79..6cf1476 100644 --- a/Tests/RunCMake/CTestCommandLine/RunCMakeTest.cmake +++ b/Tests/RunCMake/CTestCommandLine/RunCMakeTest.cmake @@ -380,3 +380,20 @@ run_MemCheckSan(Leak "simulate_sanitizer=1:report_bugs=1:history_size=5:exitcode run_MemCheckSan(Memory "simulate_sanitizer=1:report_bugs=1:history_size=5:exitcode=55") run_MemCheckSan(Thread "report_bugs=1:history_size=5:exitcode=55") run_MemCheckSan(UndefinedBehavior "simulate_sanitizer=1") + +run_cmake_command(test-dir-invalid-arg ${CMAKE_CTEST_COMMAND} --test-dir) +run_cmake_command(test-dir-non-existing-dir ${CMAKE_CTEST_COMMAND} --test-dir non-existing-dir) + +function(run_testDir) + set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/testDir) + set(RunCMake_TEST_NO_CLEAN 1) + file(REMOVE_RECURSE "${RunCMake_TEST_BINARY_DIR}") + file(MAKE_DIRECTORY "${RunCMake_TEST_BINARY_DIR}") + file(MAKE_DIRECTORY "${RunCMake_TEST_BINARY_DIR}/sub") + file(WRITE "${RunCMake_TEST_BINARY_DIR}/sub/CTestTestfile.cmake" " + add_test(Test1 \"${CMAKE_COMMAND}\" -E true) + add_test(Test2 \"${CMAKE_COMMAND}\" -E true) + ") + run_cmake_command(testDir ${CMAKE_CTEST_COMMAND} --test-dir "${RunCMake_TEST_BINARY_DIR}/sub") +endfunction() +run_testDir() diff --git a/Tests/RunCMake/CTestCommandLine/test-dir-invalid-arg-result.txt b/Tests/RunCMake/CTestCommandLine/test-dir-invalid-arg-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/CTestCommandLine/test-dir-invalid-arg-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/CTestCommandLine/test-dir-invalid-arg-stderr.txt b/Tests/RunCMake/CTestCommandLine/test-dir-invalid-arg-stderr.txt new file mode 100644 index 0000000..15908a7 --- /dev/null +++ b/Tests/RunCMake/CTestCommandLine/test-dir-invalid-arg-stderr.txt @@ -0,0 +1 @@ +CMake Error: '--test-dir' requires an argument diff --git a/Tests/RunCMake/CTestCommandLine/test-dir-non-existing-dir-result.txt b/Tests/RunCMake/CTestCommandLine/test-dir-non-existing-dir-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/CTestCommandLine/test-dir-non-existing-dir-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/CTestCommandLine/test-dir-non-existing-dir-stderr.txt b/Tests/RunCMake/CTestCommandLine/test-dir-non-existing-dir-stderr.txt new file mode 100644 index 0000000..017ccb0 --- /dev/null +++ b/Tests/RunCMake/CTestCommandLine/test-dir-non-existing-dir-stderr.txt @@ -0,0 +1 @@ +Failed to change working directory to ".*/non-existing-dir" : No such file or directory diff --git a/Tests/RunCMake/CTestCommandLine/test-dir-non-existing-dir-stdout.txt b/Tests/RunCMake/CTestCommandLine/test-dir-non-existing-dir-stdout.txt new file mode 100644 index 0000000..ddcd238 --- /dev/null +++ b/Tests/RunCMake/CTestCommandLine/test-dir-non-existing-dir-stdout.txt @@ -0,0 +1 @@ +Internal ctest changing into directory: .*/non-existing-dir diff --git a/Tests/RunCMake/File_Generate/CustomFilePermissions.cmake b/Tests/RunCMake/File_Generate/CustomFilePermissions.cmake new file mode 100644 index 0000000..0000ef9 --- /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 0000000..a87e916 --- /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 0000000..868a045 --- /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 0000000..7981ccc --- /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 48fb71c..51491af 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 0000000..d00491f --- /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 0000000..730800d --- /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 0000000..d25e66a --- /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 0000000..d00491f --- /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 0000000..e8184cc --- /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 0000000..2a1e3ea --- /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 0000000..d00491f --- /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 0000000..1143c78 --- /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 0000000..97e0deb --- /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 0000000..d00491f --- /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 0000000..84368cd --- /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 0000000..f4127a6 --- /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 0000000..d00491f --- /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 0000000..d66d488 --- /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 0000000..4eb4c36 --- /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 0000000..7cca9bf --- /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 0000000..8b30f96 --- /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() diff --git a/Tests/RunCMake/NinjaMultiConfig/Qt5.cmake b/Tests/RunCMake/NinjaMultiConfig/Qt5.cmake index 3a1c7f5..578256a 100644 --- a/Tests/RunCMake/NinjaMultiConfig/Qt5.cmake +++ b/Tests/RunCMake/NinjaMultiConfig/Qt5.cmake @@ -16,12 +16,13 @@ if(Qt5Core_VERSION VERSION_GREATER_EQUAL "5.15.0") set(moc_writes_depfiles 1) endif() -set(autogen_files "${CMAKE_BINARY_DIR}/exe_autogen/mocs_compilation.cpp") +set(autogen_files) if(moc_writes_depfiles) list(APPEND autogen_files "${CMAKE_BINARY_DIR}/exe_autogen/deps") list(APPEND autogen_files "${CMAKE_BINARY_DIR}/exe_autogen/timestamp") endif() foreach(c IN LISTS CMAKE_CONFIGURATION_TYPES) + list(APPEND autogen_files "${CMAKE_BINARY_DIR}/exe_autogen/mocs_compilation_${c}.cpp") list(APPEND autogen_files "${CMAKE_BINARY_DIR}/exe_autogen/include_${c}/moc_qt5.cpp") if(moc_writes_depfiles) list(APPEND autogen_files "${CMAKE_BINARY_DIR}/exe_autogen/include_${c}/moc_qt5.cpp.d") diff --git a/Tests/RunCMake/target_include_directories/RunCMakeTest.cmake b/Tests/RunCMake/target_include_directories/RunCMakeTest.cmake index b67c598..48a750d 100644 --- a/Tests/RunCMake/target_include_directories/RunCMakeTest.cmake +++ b/Tests/RunCMake/target_include_directories/RunCMakeTest.cmake @@ -1,3 +1,6 @@ include(RunCMake) run_cmake(empty_keyword_args) +run_cmake(include_before) +run_cmake(include_after) +run_cmake(include_default) diff --git a/Tests/RunCMake/target_include_directories/include_after.cmake b/Tests/RunCMake/target_include_directories/include_after.cmake new file mode 100644 index 0000000..68a08a7 --- /dev/null +++ b/Tests/RunCMake/target_include_directories/include_after.cmake @@ -0,0 +1,18 @@ +enable_language(C) +file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/main.c" "int main() { return 0;}") + +set(include_dir "${CMAKE_CURRENT_BINARY_DIR}/dir") +set(after_include_dir "${CMAKE_CURRENT_BINARY_DIR}/dirAfter") +file(MAKE_DIRECTORY "${include_dir}") +file(MAKE_DIRECTORY "${after_include_dir}") + +add_executable(main "${CMAKE_CURRENT_BINARY_DIR}/main.c") +include_directories("${include_dir}") +target_include_directories(main AFTER PRIVATE "${after_include_dir}") + +get_target_property(actual_include_dirs main INCLUDE_DIRECTORIES) +set(desired_include_dirs "${include_dir}" "${after_include_dir}") + +if (NOT "${actual_include_dirs}" MATCHES "${desired_include_dirs}") + message(SEND_ERROR "include after does not work") +endif() diff --git a/Tests/RunCMake/target_include_directories/include_before.cmake b/Tests/RunCMake/target_include_directories/include_before.cmake new file mode 100644 index 0000000..9bebecd --- /dev/null +++ b/Tests/RunCMake/target_include_directories/include_before.cmake @@ -0,0 +1,18 @@ +enable_language(C) +file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/main.c" "int main() { return 0;}") + +set(include_dir "${CMAKE_CURRENT_BINARY_DIR}/dir") +set(before_include_dir "${CMAKE_CURRENT_BINARY_DIR}/dirBefore") +file(MAKE_DIRECTORY "${include_dir}") +file(MAKE_DIRECTORY "${before_include_dir}") + +add_executable(main "${CMAKE_CURRENT_BINARY_DIR}/main.c") +include_directories("${include_dir}") +target_include_directories(main BEFORE PRIVATE "${before_include_dir}") + +get_target_property(actual_include_dirs main INCLUDE_DIRECTORIES) +set(desired_include_dirs "${before_include_dir}" "${include_dir}") + +if (NOT "${actual_include_dirs}" MATCHES "${desired_include_dirs}") + message(SEND_ERROR "include before does not work") +endif() diff --git a/Tests/RunCMake/target_include_directories/include_default.cmake b/Tests/RunCMake/target_include_directories/include_default.cmake new file mode 100644 index 0000000..88b2502 --- /dev/null +++ b/Tests/RunCMake/target_include_directories/include_default.cmake @@ -0,0 +1,18 @@ +enable_language(C) +file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/main.c" "int main() { return 0;}") + +set(include_dir "${CMAKE_CURRENT_BINARY_DIR}/dir") +set(default_include_dir "${CMAKE_CURRENT_BINARY_DIR}/dirDefault") +file(MAKE_DIRECTORY "${include_dir}") +file(MAKE_DIRECTORY "${default_include_dir}") + +add_executable(main "${CMAKE_CURRENT_BINARY_DIR}/main.c") +include_directories("${include_dir}") +target_include_directories(main AFTER PRIVATE "${default_include_dir}") + +get_target_property(actual_include_dirs main INCLUDE_DIRECTORIES) +set(desired_include_dirs "${include_dir}" "${default_include_dir}") + +if (NOT "${actual_include_dirs}" MATCHES "${desired_include_dirs}") + message(SEND_ERROR "include default does not work") +endif() |