From 064c3244da08acecb313d0076eecb4eba30f1932 Mon Sep 17 00:00:00 2001 From: Alexander Neundorf Date: Wed, 22 Feb 2023 23:12:49 +0100 Subject: TARGET_RUNTIME_DLLS: fix test for this genex In a95cbf38 multiple files were renamed, and check.cmake slipped through, and the test did actually not work correctly since then. This patch renames check.cmake to its correct name shared-check.cmake. --- Tests/RunCMake/GenEx-TARGET_RUNTIME_DLLS/check.cmake | 15 --------------- .../RunCMake/GenEx-TARGET_RUNTIME_DLLS/shared-check.cmake | 15 +++++++++++++++ 2 files changed, 15 insertions(+), 15 deletions(-) delete mode 100644 Tests/RunCMake/GenEx-TARGET_RUNTIME_DLLS/check.cmake create mode 100644 Tests/RunCMake/GenEx-TARGET_RUNTIME_DLLS/shared-check.cmake diff --git a/Tests/RunCMake/GenEx-TARGET_RUNTIME_DLLS/check.cmake b/Tests/RunCMake/GenEx-TARGET_RUNTIME_DLLS/check.cmake deleted file mode 100644 index e19598e..0000000 --- a/Tests/RunCMake/GenEx-TARGET_RUNTIME_DLLS/check.cmake +++ /dev/null @@ -1,15 +0,0 @@ -function(check_genex expected actual) - if(NOT expected STREQUAL actual) - string(APPEND RunCMake_TEST_FAILED "Expected DLLs:\n") - foreach(dll IN LISTS expected) - string(APPEND RunCMake_TEST_FAILED " ${dll}\n") - endforeach() - string(APPEND RunCMake_TEST_FAILED "Actual DLLs:\n") - foreach(dll IN LISTS actual) - string(APPEND RunCMake_TEST_FAILED " ${dll}\n") - endforeach() - endif() - set(RunCMake_TEST_FAILED "${RunCMake_TEST_FAILED}" PARENT_SCOPE) -endfunction() - -include("${RunCMake_TEST_BINARY_DIR}/dlls.cmake") diff --git a/Tests/RunCMake/GenEx-TARGET_RUNTIME_DLLS/shared-check.cmake b/Tests/RunCMake/GenEx-TARGET_RUNTIME_DLLS/shared-check.cmake new file mode 100644 index 0000000..e19598e --- /dev/null +++ b/Tests/RunCMake/GenEx-TARGET_RUNTIME_DLLS/shared-check.cmake @@ -0,0 +1,15 @@ +function(check_genex expected actual) + if(NOT expected STREQUAL actual) + string(APPEND RunCMake_TEST_FAILED "Expected DLLs:\n") + foreach(dll IN LISTS expected) + string(APPEND RunCMake_TEST_FAILED " ${dll}\n") + endforeach() + string(APPEND RunCMake_TEST_FAILED "Actual DLLs:\n") + foreach(dll IN LISTS actual) + string(APPEND RunCMake_TEST_FAILED " ${dll}\n") + endforeach() + endif() + set(RunCMake_TEST_FAILED "${RunCMake_TEST_FAILED}" PARENT_SCOPE) +endfunction() + +include("${RunCMake_TEST_BINARY_DIR}/dlls.cmake") -- cgit v0.12 From c351dcd967379644db65e62534e73f874b16b4a3 Mon Sep 17 00:00:00 2001 From: Alexander Neundorf Date: Sun, 26 Feb 2023 16:33:16 +0100 Subject: TARGET_RUNTIME_DLL_DIRS: add the new genex to cmGeneratorExpressionNode This commit adds handling for a new genex TARGET_RUNTIME_DLL_DIRS to cmGeneratorExpressionNode. It refactors the code for TARGET_RUNTIME_DLLS a bit, so that both TARGET_RUNTIME_DLL_DIRS and TARGET_RUNTIME_DLLS share the implementation to collect all dlls. The new genex collects the dlls and in a final step puts all the directories into the result variable (and makes sure there are no duplicates). --- Source/cmGeneratorExpressionNode.cxx | 56 +++++++++++++++++++++++++++++------- 1 file changed, 46 insertions(+), 10 deletions(-) diff --git a/Source/cmGeneratorExpressionNode.cxx b/Source/cmGeneratorExpressionNode.cxx index 5d761ac..44205b5 100644 --- a/Source/cmGeneratorExpressionNode.cxx +++ b/Source/cmGeneratorExpressionNode.cxx @@ -2337,15 +2337,12 @@ static const struct TargetObjectsNode : public cmGeneratorExpressionNode } } targetObjectsNode; -static const struct TargetRuntimeDllsNode : public cmGeneratorExpressionNode +struct TargetRuntimeDllsBaseNode : public cmGeneratorExpressionNode { - TargetRuntimeDllsNode() {} // NOLINT(modernize-use-equals-default) - - std::string Evaluate( + std::vector CollectDlls( const std::vector& parameters, cmGeneratorExpressionContext* context, - const GeneratorExpressionContent* content, - cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override + const GeneratorExpressionContent* content) const { std::string const& tgtName = parameters.front(); cmGeneratorTarget* gt = context->LG->FindGeneratorTargetToUse(tgtName); @@ -2354,7 +2351,7 @@ static const struct TargetRuntimeDllsNode : public cmGeneratorExpressionNode e << "Objects of target \"" << tgtName << "\" referenced but no such target exists."; reportError(context, content->GetOriginalExpression(), e.str()); - return std::string(); + return std::vector(); } cmStateEnums::TargetType type = gt->GetType(); if (type != cmStateEnums::EXECUTABLE && @@ -2365,7 +2362,7 @@ static const struct TargetRuntimeDllsNode : public cmGeneratorExpressionNode << "\" referenced but is not one of the allowed target types " << "(EXECUTABLE, SHARED, MODULE)."; reportError(context, content->GetOriginalExpression(), e.str()); - return std::string(); + return std::vector(); } if (auto* cli = gt->GetLinkInformation(context->Config)) { @@ -2378,13 +2375,51 @@ static const struct TargetRuntimeDllsNode : public cmGeneratorExpressionNode } } - return cmJoin(dllPaths, ";"); + return dllPaths; } - return ""; + return std::vector(); + } +}; + +static const struct TargetRuntimeDllsNode : public TargetRuntimeDllsBaseNode +{ + TargetRuntimeDllsNode() {} // NOLINT(modernize-use-equals-default) + + std::string Evaluate( + const std::vector& parameters, + cmGeneratorExpressionContext* context, + const GeneratorExpressionContent* content, + cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override + { + std::vector dlls = CollectDlls(parameters, context, content); + return cmJoin(dlls, ";"); } } targetRuntimeDllsNode; +static const struct TargetRuntimeDllDirsNode : public TargetRuntimeDllsBaseNode +{ + TargetRuntimeDllDirsNode() {} // NOLINT(modernize-use-equals-default) + + std::string Evaluate( + const std::vector& parameters, + cmGeneratorExpressionContext* context, + const GeneratorExpressionContent* content, + cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override + { + std::vector dlls = CollectDlls(parameters, context, content); + std::vector dllDirs; + for (const std::string& dll : dlls) { + std::string directory = cmSystemTools::GetFilenamePath(dll); + if (std::find(dllDirs.begin(), dllDirs.end(), directory) == + dllDirs.end()) { + dllDirs.push_back(directory); + } + } + return cmJoin(dllDirs, ";"); + } +} targetRuntimeDllDirsNode; + static const struct CompileFeaturesNode : public cmGeneratorExpressionNode { CompileFeaturesNode() {} // NOLINT(modernize-use-equals-default) @@ -3355,6 +3390,7 @@ const cmGeneratorExpressionNode* cmGeneratorExpressionNode::GetNode( { "TARGET_NAME_IF_EXISTS", &targetNameIfExistsNode }, { "TARGET_GENEX_EVAL", &targetGenexEvalNode }, { "TARGET_RUNTIME_DLLS", &targetRuntimeDllsNode }, + { "TARGET_RUNTIME_DLL_DIRS", &targetRuntimeDllDirsNode }, { "GENEX_EVAL", &genexEvalNode }, { "BUILD_INTERFACE", &buildInterfaceNode }, { "INSTALL_INTERFACE", &installInterfaceNode }, -- cgit v0.12 From 2ce3d62ffb5cf75cad23f7aeac59b4acc586c22f Mon Sep 17 00:00:00 2001 From: Alexander Neundorf Date: Sun, 26 Feb 2023 16:36:57 +0100 Subject: Help: add documentation for the new TARGET_RUNTIME_DLL_DIRS genex --- Help/manual/cmake-generator-expressions.7.rst | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/Help/manual/cmake-generator-expressions.7.rst b/Help/manual/cmake-generator-expressions.7.rst index c3e87d7..b642557 100644 --- a/Help/manual/cmake-generator-expressions.7.rst +++ b/Help/manual/cmake-generator-expressions.7.rst @@ -1668,7 +1668,9 @@ In the following, the phrase "the ``tgt`` filename" means the name of the List of DLLs that the target depends on at runtime. This is determined by the locations of all the ``SHARED`` targets in the target's transitive - dependencies. Using this generator expression on targets other than + dependencies. If only the directories of the DLLs are needed, see the + :genex:`TARGET_RUNTIME_DLL_DIRS` generator expression. + Using this generator expression on targets other than executables, ``SHARED`` libraries, and ``MODULE`` libraries is an error. **On non-DLL platforms, this expression always evaluates to an empty string**. @@ -1700,6 +1702,20 @@ On platforms that support runtime paths (``RPATH``), refer to the :prop_tgt:`INSTALL_RPATH` target property. On Apple platforms, refer to the :prop_tgt:`INSTALL_NAME_DIR` target property. +.. genex:: $ + + .. versionadded:: 3.27 + + List of the directories which contain the DLLs that the target depends on at + runtime (see :genex:`TARGET_RUNTIME_DLLS`). This is determined by + the locations of all the ``SHARED`` targets in the target's transitive + dependencies. Using this generator expression on targets other than + executables, ``SHARED`` libraries, and ``MODULE`` libraries is an error. + **On non-DLL platforms, this expression always evaluates to an empty string**. + + This generator expression can e.g. be used to create a batch file using + :command:`file(GENERATE)` which sets the PATH environment variable accordingly. + Export And Install Expressions ------------------------------ -- cgit v0.12 From aa68de0a27ef19f95f542535a46cabb3765da4da Mon Sep 17 00:00:00 2001 From: Alexander Neundorf Date: Wed, 22 Feb 2023 23:34:01 +0100 Subject: TARGET_RUNTIME_DLLS: minor refactoring of shared-check.cmake Renamed variables and text which mentions dlls to items, since we can use this check also for testing the directories. --- Tests/RunCMake/GenEx-TARGET_RUNTIME_DLLS/shared-check.cmake | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Tests/RunCMake/GenEx-TARGET_RUNTIME_DLLS/shared-check.cmake b/Tests/RunCMake/GenEx-TARGET_RUNTIME_DLLS/shared-check.cmake index e19598e..6b05b4e 100644 --- a/Tests/RunCMake/GenEx-TARGET_RUNTIME_DLLS/shared-check.cmake +++ b/Tests/RunCMake/GenEx-TARGET_RUNTIME_DLLS/shared-check.cmake @@ -1,12 +1,12 @@ function(check_genex expected actual) if(NOT expected STREQUAL actual) - string(APPEND RunCMake_TEST_FAILED "Expected DLLs:\n") - foreach(dll IN LISTS expected) - string(APPEND RunCMake_TEST_FAILED " ${dll}\n") + string(APPEND RunCMake_TEST_FAILED "Expected items:\n") + foreach(item IN LISTS expected) + string(APPEND RunCMake_TEST_FAILED " ${item}\n") endforeach() - string(APPEND RunCMake_TEST_FAILED "Actual DLLs:\n") - foreach(dll IN LISTS actual) - string(APPEND RunCMake_TEST_FAILED " ${dll}\n") + string(APPEND RunCMake_TEST_FAILED "Actual items:\n") + foreach(item IN LISTS actual) + string(APPEND RunCMake_TEST_FAILED " ${item}\n") endforeach() endif() set(RunCMake_TEST_FAILED "${RunCMake_TEST_FAILED}" PARENT_SCOPE) -- cgit v0.12 From a2c9c4f202d1bfb104ddebf5db11f7b74824337f Mon Sep 17 00:00:00 2001 From: Alexander Neundorf Date: Wed, 22 Feb 2023 23:55:53 +0100 Subject: Add test for the new TARGET_RUNTIME_DLL_PATHS genex For one of the shared libraries the RUNTIME_OUTPUT_PATH is set to a subdir and the test is supposed to check that those directories appear in TARGET_RUNTIME_DLL_PATHS genex --- Tests/RunCMake/GenEx-TARGET_RUNTIME_DLLS/shared.cmake | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/Tests/RunCMake/GenEx-TARGET_RUNTIME_DLLS/shared.cmake b/Tests/RunCMake/GenEx-TARGET_RUNTIME_DLLS/shared.cmake index 806f0b6..c38fa39 100644 --- a/Tests/RunCMake/GenEx-TARGET_RUNTIME_DLLS/shared.cmake +++ b/Tests/RunCMake/GenEx-TARGET_RUNTIME_DLLS/shared.cmake @@ -4,6 +4,10 @@ add_executable(exe main.c) add_library(lib1 SHARED lib1.c) add_library(lib2 SHARED lib2.c) add_library(lib3 SHARED lib3.c) +if(WIN32 OR CYGWIN) + set_property(TARGET lib3 PROPERTY RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/SomeSubDir/") +endif() + add_library(static STATIC static.c) add_library(imported SHARED IMPORTED) set_property(TARGET imported PROPERTY IMPORTED_LOCATION "${CMAKE_SOURCE_DIR}/imported.dll") @@ -26,9 +30,16 @@ if(WIN32 OR CYGWIN) "$" "$" ) + set(expected_dll_dirs + "$>" + "$>" + "$>" + ) endif() -set(content "check_genex(\"${expected_dlls}\" \"$\")\n") +set(content "check_genex(\"${expected_dlls}\" \"$\") +check_genex(\"${expected_dll_dirs}\" \"$\")\n") + set(condition) get_property(multi_config GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) if(multi_config) -- cgit v0.12