Merge topic 'genex-TARGET_OBJECTS-SOURCE_FILES'

987e0af366 GenEx: Add `$<TARGET_OBJECTS:...>` option to filter on source files

Acked-by: Kitware Robot <kwrobot@kitware.com>
Tested-by: buildbot <buildbot@kitware.com>
Merge-request: !11782
This commit is contained in:
Brad King
2026-03-11 13:17:00 -04:00
committed by Kitware Robot
37 changed files with 370 additions and 44 deletions
+11 -1
View File
@@ -3298,13 +3298,23 @@ In the following, the phrase "the ``tgt`` filename" means the name of the
Note that ``tgt`` is not added as a dependency of the target this
expression is evaluated on (see policy :policy:`CMP0112`).
.. genex:: $<TARGET_OBJECTS:tgt>
.. genex:: $<TARGET_OBJECTS:tgt[,SOURCE_FILES:source_file[;source_file]...]>
.. versionadded:: 3.1
List of objects resulting from building ``tgt``. This would typically be
used on :ref:`object library <Object Libraries>` targets.
Additional arguments:
``SOURCE_FILES:source_file[;source_file]...``
.. versionadded:: 4.4
An optional list of one or more source files for the target. Only the
object files built from those source files will be returned (but not
necessarily in the same order they were specified).
.. genex:: $<TARGET_RUNTIME_DLLS:tgt>
.. versionadded:: 3.21
@@ -0,0 +1,7 @@
genex-TARGET_OBJECTS-SOURCE_FILES
---------------------------------
* The :genex:`TARGET_OBJECTS` generator expression now has an optional
``SOURCE_FILES:...`` argument, which can take one or more source files as
arguments, and will filter its output to only include objects built from
those source files.
+56 -1
View File
@@ -4335,6 +4335,55 @@ static const struct TargetObjectsNode : public cmGeneratorExpressionNode
return std::string();
}
std::vector<std::string> sourceFilePaths;
for (auto const& arg : cmMakeRange(parameters).advance(1)) {
if (cmHasLiteralPrefix(arg, "SOURCE_FILES:")) {
cm::string_view listView{ arg.c_str() + cmStrLen("SOURCE_FILES:") };
std::size_t semicolon;
std::size_t start = 0;
do {
semicolon = listView.find(';', start);
sourceFilePaths.push_back(
std::string{ listView.substr(start, semicolon - start) });
start = semicolon + 1;
} while (semicolon != cm::string_view::npos);
} else {
reportError(eval, content->GetOriginalExpression(),
cmStrCat("Unrecognized argument:\n ", arg));
return std::string();
}
}
if (gt->IsImported() && !sourceFilePaths.empty()) {
reportError(
eval, content->GetOriginalExpression(),
cmStrCat("Cannot use SOURCE_FILES argument on imported target \"",
tgtName, '"'));
return std::string();
}
std::set<cmSourceFile const*> sourceFiles;
for (auto const& sf : gt->GetSourceFiles(eval->Context.Config)) {
sourceFiles.insert(sf.Value);
}
std::set<cmSourceFile const*> filteredSourceFiles;
for (auto const& path : sourceFilePaths) {
if (!cmSystemTools::FileIsFullPath(path)) {
reportError(
eval, content->GetOriginalExpression(),
cmStrCat("Source file:\n ", path, "\nis not an absolute path"));
return std::string();
}
auto const* sf = gt->Makefile->GetSource(path);
if (!sf || !sourceFiles.count(sf)) {
reportError(eval, content->GetOriginalExpression(),
cmStrCat("Source file:\n ", path,
"\ndoes not exist for target \"", tgtName, '"'));
return std::string();
}
filteredSourceFiles.insert(sf);
}
cmList objects;
if (gt->IsImported()) {
@@ -4347,7 +4396,11 @@ static const struct TargetObjectsNode : public cmGeneratorExpressionNode
}
eval->HadContextSensitiveCondition = true;
} else {
gt->GetTargetObjectNames(eval->Context.Config, objects);
auto const filter =
[&filteredSourceFiles](cmSourceFile const& sf) -> bool {
return filteredSourceFiles.empty() || filteredSourceFiles.count(&sf);
};
gt->GetTargetObjectNames(eval->Context.Config, filter, objects);
std::string obj_dir;
if (eval->EvaluateForBuildsystem && !gg->SupportsCrossConfigs()) {
@@ -4373,6 +4426,8 @@ static const struct TargetObjectsNode : public cmGeneratorExpressionNode
return objects.to_string();
}
int NumExpectedParameters() const override { return OneOrMoreParameters; }
} targetObjectsNode;
struct TargetRuntimeDllsBaseNode : public cmGeneratorExpressionNode
+43 -20
View File
@@ -4076,9 +4076,17 @@ std::string cmGeneratorTarget::GetObjectDirectory(
void cmGeneratorTarget::GetTargetObjectNames(
std::string const& config, std::vector<std::string>& objects) const
{
this->GetTargetObjectNames(
config, [](cmSourceFile const&) -> bool { return true; }, objects);
}
void cmGeneratorTarget::GetTargetObjectNames(
std::string const& config, std::function<bool(cmSourceFile const&)> filter,
std::vector<std::string>& objects) const
{
this->GetTargetObjectLocations(
config,
config, filter,
[&objects](cmObjectLocation const& buildLoc, cmObjectLocation const&) {
objects.push_back(buildLoc.GetPath());
});
@@ -4088,6 +4096,15 @@ void cmGeneratorTarget::GetTargetObjectLocations(
std::string const& config,
std::function<void(cmObjectLocation const&, cmObjectLocation const&)> cb)
const
{
this->GetTargetObjectLocations(
config, [](cmSourceFile const&) -> bool { return true; }, cb);
}
void cmGeneratorTarget::GetTargetObjectLocations(
std::string const& config, std::function<bool(cmSourceFile const&)> filter,
std::function<void(cmObjectLocation const&, cmObjectLocation const&)> cb)
const
{
std::vector<cmSourceFile const*> objectSources;
this->GetObjectSources(objectSources, config);
@@ -4105,15 +4122,17 @@ void cmGeneratorTarget::GetTargetObjectLocations(
auto const installUseShortPaths = this->GetUseShortObjectNamesForInstall();
for (cmSourceFile const* src : objectSources) {
// Find the object file name corresponding to this source file.
auto map_it = mapping.find(src);
auto const& buildLoc = map_it->second.GetLocation(buildUseShortPaths);
auto const& installLoc =
map_it->second.GetInstallLocation(installUseShortPaths, config);
// It must exist because we populated the mapping just above.
assert(!buildLoc.GetPath().empty());
assert(!installLoc.GetPath().empty());
cb(buildLoc, installLoc);
if (filter(*src)) {
// Find the object file name corresponding to this source file.
auto map_it = mapping.find(src);
auto const& buildLoc = map_it->second.GetLocation(buildUseShortPaths);
auto const& installLoc =
map_it->second.GetInstallLocation(installUseShortPaths, config);
// It must exist because we populated the mapping just above.
assert(!buildLoc.GetPath().empty());
assert(!installLoc.GetPath().empty());
cb(buildLoc, installLoc);
}
}
// We need to compute the relative path from the root of
@@ -4121,11 +4140,14 @@ void cmGeneratorTarget::GetTargetObjectLocations(
std::string rootObjectDir = this->GetObjectDirectory(config);
rootObjectDir = cmSystemTools::CollapseFullPath(rootObjectDir);
auto ispcObjects = this->GetGeneratedISPCObjects(config);
for (std::string const& output : ispcObjects) {
auto relativePathFromObjectDir = output.substr(rootObjectDir.size());
cmObjectLocation ispcLoc(relativePathFromObjectDir);
// FIXME: apply short path to this object if needed.
cb(ispcLoc, ispcLoc);
for (auto const& output : ispcObjects) {
if (filter(*output.first)) {
auto relativePathFromObjectDir =
output.second.substr(rootObjectDir.size());
cmObjectLocation ispcLoc(relativePathFromObjectDir);
// FIXME: apply short path to this object if needed.
cb(ispcLoc, ispcLoc);
}
}
}
@@ -4389,8 +4411,9 @@ std::vector<std::string> cmGeneratorTarget::GetGeneratedISPCHeaders(
return iter->second;
}
void cmGeneratorTarget::AddISPCGeneratedObject(std::vector<std::string>&& objs,
std::string const& config)
void cmGeneratorTarget::AddISPCGeneratedObject(
std::vector<std::pair<cmSourceFile const*, std::string>>&& objs,
std::string const& config)
{
std::string config_upper;
if (!config.empty()) {
@@ -4404,8 +4427,8 @@ void cmGeneratorTarget::AddISPCGeneratedObject(std::vector<std::string>&& objs,
}
}
std::vector<std::string> cmGeneratorTarget::GetGeneratedISPCObjects(
std::string const& config) const
std::vector<std::pair<cmSourceFile const*, std::string>>
cmGeneratorTarget::GetGeneratedISPCObjects(std::string const& config) const
{
std::string config_upper;
if (!config.empty()) {
@@ -4413,7 +4436,7 @@ std::vector<std::string> cmGeneratorTarget::GetGeneratedISPCObjects(
}
auto iter = this->ISPCGeneratedObjects.find(config_upper);
if (iter == this->ISPCGeneratedObjects.end()) {
return std::vector<std::string>{};
return std::vector<std::pair<cmSourceFile const*, std::string>>{};
}
return iter->second;
}
+14 -5
View File
@@ -313,11 +313,18 @@ public:
its object file directory for the build. */
void GetTargetObjectNames(std::string const& config,
std::vector<std::string>& objects) const;
void GetTargetObjectNames(std::string const& config,
std::function<bool(cmSourceFile const&)> filter,
std::vector<std::string>& objects) const;
/** Get the build and install locations of objects for a given context. */
void GetTargetObjectLocations(
std::string const& config,
std::function<void(cmObjectLocation const&, cmObjectLocation const&)> cb)
const;
void GetTargetObjectLocations(
std::string const& config, std::function<bool(cmSourceFile const&)> filter,
std::function<void(cmObjectLocation const&, cmObjectLocation const&)> cb)
const;
/** What hierarchy level should the reported directory contain */
enum BundleDirectoryLevel
@@ -1102,10 +1109,11 @@ public:
std::vector<std::string> GetGeneratedISPCHeaders(
std::string const& config) const;
void AddISPCGeneratedObject(std::vector<std::string>&& objs,
std::string const& config);
std::vector<std::string> GetGeneratedISPCObjects(
std::string const& config) const;
void AddISPCGeneratedObject(
std::vector<std::pair<cmSourceFile const*, std::string>>&& objs,
std::string const& config);
std::vector<std::pair<cmSourceFile const*, std::string>>
GetGeneratedISPCObjects(std::string const& config) const;
void AddSystemIncludeDirectory(std::string const& inc,
std::string const& lang);
@@ -1370,7 +1378,8 @@ private:
std::unordered_map<std::string, std::vector<std::string>>
ISPCGeneratedHeaders;
std::unordered_map<std::string, std::vector<std::string>>
std::unordered_map<std::string,
std::vector<std::pair<cmSourceFile const*, std::string>>>
ISPCGeneratedObjects;
enum class LinkInterfaceField
+7 -6
View File
@@ -1383,17 +1383,18 @@ void cmGlobalNinjaGenerator::AppendTargetDepends(
std::string const& targetConfig) {
if (depTarget->CanCompileSources()) {
auto headers = depTarget->GetGeneratedISPCHeaders(targetConfig);
auto const mapToNinjaPath = gg->MapToNinjaPath();
if (!headers.empty()) {
std::transform(headers.begin(), headers.end(), headers.begin(),
gg->MapToNinjaPath());
mapToNinjaPath);
outputDeps.insert(outputDeps.end(), headers.begin(), headers.end());
}
auto objs = depTarget->GetGeneratedISPCObjects(targetConfig);
if (!objs.empty()) {
std::transform(objs.begin(), objs.end(), objs.begin(),
gg->MapToNinjaPath());
outputDeps.insert(outputDeps.end(), objs.begin(), objs.end());
}
std::transform(
objs.begin(), objs.end(), std::back_inserter(outputDeps),
[&mapToNinjaPath](
std::pair<cmSourceFile const*, std::string> const& obj)
-> std::string { return mapToNinjaPath(obj.second); });
}
};
+5 -2
View File
@@ -2688,8 +2688,11 @@ void cmLocalGenerator::AddISPCDependencies(cmGeneratorTarget* target)
cmStrCat(headerDir, '/', ispcSource, *ispcHeaderSuffixProp);
target->AddISPCGeneratedHeader(headerPath, config);
if (extra_objects) {
std::vector<std::string> objs = detail::ComputeISPCExtraObjects(
objectName, rootObjectDir, ispcArchSuffixes);
std::vector<std::pair<cmSourceFile const*, std::string>> objs;
for (auto& obj : detail::ComputeISPCExtraObjects(
objectName, rootObjectDir, ispcArchSuffixes)) {
objs.push_back({ sf, std::move(obj) });
}
target->AddISPCGeneratedObject(std::move(objs), config);
}
}
+4 -4
View File
@@ -240,9 +240,9 @@ void cmMakefileTargetGenerator::WriteTargetBuildRules()
// Look for ISPC extra object files generated by this target
auto const ispcAdditionalObjs =
this->GeneratorTarget->GetGeneratedISPCObjects(this->GetConfigName());
for (std::string const& ispcObj : ispcAdditionalObjs) {
for (auto const& ispcObj : ispcAdditionalObjs) {
this->CleanFiles.insert(
this->LocalGenerator->MaybeRelativeToCurBinDir(ispcObj));
this->LocalGenerator->MaybeRelativeToCurBinDir(ispcObj.second));
}
// add custom commands to the clean rules?
@@ -1930,8 +1930,8 @@ void cmMakefileTargetGenerator::WriteObjectsStrings(
}
auto const ispcAdditionalObjs =
this->GeneratorTarget->GetGeneratedISPCObjects(this->GetConfigName());
for (std::string const& obj : ispcAdditionalObjs) {
helper.Feed(obj);
for (auto const& obj : ispcAdditionalObjs) {
helper.Feed(obj.second);
}
helper.Done();
}
+8 -5
View File
@@ -1319,11 +1319,14 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement(
linkBuild.ExplicitDeps = this->GetObjects(config);
}
std::vector<std::string> extraISPCObjects =
auto extraISPCObjects =
this->GetGeneratorTarget()->GetGeneratedISPCObjects(config);
std::transform(extraISPCObjects.begin(), extraISPCObjects.end(),
std::back_inserter(linkBuild.ExplicitDeps),
this->MapToNinjaPath());
auto const mapToNinjaPath = this->MapToNinjaPath();
std::transform(
extraISPCObjects.begin(), extraISPCObjects.end(),
std::back_inserter(linkBuild.ExplicitDeps),
[&mapToNinjaPath](std::pair<cmSourceFile const*, std::string> const& obj)
-> std::string { return mapToNinjaPath(obj.second); });
linkBuild.ImplicitDeps =
this->ComputeLinkDeps(this->TargetLinkLanguage(config), config);
@@ -1497,7 +1500,7 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement(
std::transform(
ccByproducts.begin(), ccByproducts.end(),
std::back_inserter(globalGen->GetByproductsForCleanTarget()),
this->MapToNinjaPath());
mapToNinjaPath);
}
}
}
+5
View File
@@ -536,6 +536,11 @@ add_RunCMake_test(GenEx-FILE_SET_EXISTS)
add_RunCMake_test(GenEx-FILE_SET_PROPERTY)
add_RunCMake_test(GenEx-TARGET_PROPERTY)
add_RunCMake_test(GenEx-TARGET_RUNTIME_DLLS)
list(LENGTH CMAKE_OSX_ARCHITECTURES _num_archs)
if(NOT (XCODE AND _num_archs GREATER 1))
add_RunCMake_test(GenEx-TARGET_OBJECTS -DCMake_TEST_CUDA=${CMake_TEST_CUDA})
set_property(TEST RunCMake.GenEx-TARGET_OBJECTS APPEND PROPERTY LABELS "CUDA")
endif()
add_RunCMake_test(GenEx-STRING)
add_RunCMake_test(GenEx-PATH)
add_RunCMake_test(GenEx-PATH_EQUAL)
@@ -0,0 +1,3 @@
cmake_minimum_required(VERSION 4.3)
project(${RunCMake_TEST} NONE)
include(${RunCMake_TEST}.cmake)
@@ -0,0 +1,18 @@
include(RunCMake)
function(run_cmake_and_build name)
set(RunCMake_TEST_BINARY_DIR "${RunCMake_BINARY_DIR}/${name}-build")
run_cmake_with_options(${name} -DCMake_TEST_CUDA=${CMake_TEST_CUDA})
set(RunCMake_TEST_NO_CLEAN 1)
run_cmake_command(${name}-build ${CMAKE_COMMAND} --build . --verbose)
endfunction()
run_cmake_and_build(all)
run_cmake_and_build(SOURCE_FILES)
run_cmake(SOURCE_FILES-noexist)
run_cmake(SOURCE_FILES-not-in-target)
run_cmake(SOURCE_FILES-imported)
run_cmake(SOURCE_FILES-relative)
run_cmake(invalid)
@@ -0,0 +1,7 @@
CMake Error at SOURCE_FILES-imported\.cmake:[0-9]+ \(add_custom_target\):
Error evaluating generator expression:
\$<TARGET_OBJECTS:c_objs,SOURCE_FILES:[^
]*/Tests/RunCMake/GenEx-TARGET_OBJECTS/empty4\.c>
Cannot use SOURCE_FILES argument on imported target "c_objs"
@@ -0,0 +1,8 @@
enable_language(C)
add_library(c_objs IMPORTED OBJECT)
add_custom_target(obj ALL
COMMAND ${CMAKE_COMMAND} -E echo $<TARGET_OBJECTS:c_objs,SOURCE_FILES:${CMAKE_CURRENT_SOURCE_DIR}/empty4.c>
VERBATIM
)
@@ -0,0 +1,12 @@
CMake Error at SOURCE_FILES-noexist\.cmake:[0-9]+ \(add_custom_target\):
Error evaluating generator expression:
\$<TARGET_OBJECTS:c_objs,SOURCE_FILES:[^
]*/Tests/RunCMake/GenEx-TARGET_OBJECTS/empty4\.c>
Source file:
[^
]*/Tests/RunCMake/GenEx-TARGET_OBJECTS/empty4\.c
does not exist for target "c_objs"
@@ -0,0 +1,8 @@
enable_language(C)
add_library(c_objs OBJECT empty1.c empty2.c empty3.c)
add_custom_target(obj ALL
COMMAND ${CMAKE_COMMAND} -E echo $<TARGET_OBJECTS:c_objs,SOURCE_FILES:${CMAKE_CURRENT_SOURCE_DIR}/empty4.c>
VERBATIM
)
@@ -0,0 +1,12 @@
CMake Error at SOURCE_FILES-not-in-target\.cmake:[0-9]+ \(add_custom_target\):
Error evaluating generator expression:
\$<TARGET_OBJECTS:c_objs,SOURCE_FILES:[^
]*/Tests/RunCMake/GenEx-TARGET_OBJECTS/empty3\.c>
Source file:
[^
]*/Tests/RunCMake/GenEx-TARGET_OBJECTS/empty3\.c
does not exist for target "c_objs"
@@ -0,0 +1,9 @@
enable_language(C)
add_library(c_objs OBJECT empty1.c empty2.c)
add_library(other OBJECT empty3.c)
add_custom_target(obj ALL
COMMAND ${CMAKE_COMMAND} -E echo $<TARGET_OBJECTS:c_objs,SOURCE_FILES:${CMAKE_CURRENT_SOURCE_DIR}/empty3.c>
VERBATIM
)
@@ -0,0 +1,10 @@
CMake Error at SOURCE_FILES-relative\.cmake:[0-9]+ \(add_custom_target\):
Error evaluating generator expression:
\$<TARGET_OBJECTS:c_objs,SOURCE_FILES:empty1\.c>
Source file:
empty1\.c
is not an absolute path
@@ -0,0 +1,8 @@
enable_language(C)
add_library(c_objs OBJECT empty1.c empty2.c empty3.c)
add_custom_target(obj ALL
COMMAND ${CMAKE_COMMAND} -E echo $<TARGET_OBJECTS:c_objs,SOURCE_FILES:empty1.c>
VERBATIM
)
@@ -0,0 +1,53 @@
enable_language(C)
include(common.cmake)
add_library(c_objs OBJECT EXCLUDE_FROM_ALL empty1.c empty2.c empty3.c)
check_target_objects(single_absolute
"$<TARGET_OBJECTS:c_objs,SOURCE_FILES:${CMAKE_CURRENT_SOURCE_DIR}/empty2.c>"
[[/Tests/RunCMake/GenEx-TARGET_OBJECTS/SOURCE_FILES-build((/CMakeFiles)?/c_objs\.dir(/(\.|[a-zA-Z]+))?|/build/c_objs\.build/.*)/empty2(\.c)?\.(o|obj)$]]
)
check_target_objects(multi
"$<TARGET_OBJECTS:c_objs,SOURCE_FILES:${CMAKE_CURRENT_SOURCE_DIR}/empty1.c;${CMAKE_CURRENT_SOURCE_DIR}/empty2.c>"
[[/Tests/RunCMake/GenEx-TARGET_OBJECTS/SOURCE_FILES-build((/CMakeFiles)?/c_objs\.dir(/(\.|[a-zA-Z]+))?|/build/c_objs\.build/.*)/empty1(\.c)?\.(o|obj)$]]
[[/Tests/RunCMake/GenEx-TARGET_OBJECTS/SOURCE_FILES-build((/CMakeFiles)?/c_objs\.dir(/(\.|[a-zA-Z]+))?|/build/c_objs\.build/.*)/empty2(\.c)?\.(o|obj)$]]
)
check_target_objects(multi_reordered
"$<TARGET_OBJECTS:c_objs,SOURCE_FILES:${CMAKE_CURRENT_SOURCE_DIR}/empty3.c;${CMAKE_CURRENT_SOURCE_DIR}/empty2.c>"
[[/Tests/RunCMake/GenEx-TARGET_OBJECTS/SOURCE_FILES-build((/CMakeFiles)?/c_objs\.dir(/(\.|[a-zA-Z]+))?|/build/c_objs\.build/.*)/empty2(\.c)?\.(o|obj)$]]
[[/Tests/RunCMake/GenEx-TARGET_OBJECTS/SOURCE_FILES-build((/CMakeFiles)?/c_objs\.dir(/(\.|[a-zA-Z]+))?|/build/c_objs\.build/.*)/empty3(\.c)?\.(o|obj)$]]
)
check_target_objects(multi_duplicate
"$<TARGET_OBJECTS:c_objs,SOURCE_FILES:${CMAKE_CURRENT_SOURCE_DIR}/empty1.c;${CMAKE_CURRENT_SOURCE_DIR}/empty3.c;${CMAKE_CURRENT_SOURCE_DIR}/empty1.c>"
[[/Tests/RunCMake/GenEx-TARGET_OBJECTS/SOURCE_FILES-build((/CMakeFiles)?/c_objs\.dir(/(\.|[a-zA-Z]+))?|/build/c_objs\.build/.*)/empty1(\.c)?\.(o|obj)$]]
[[/Tests/RunCMake/GenEx-TARGET_OBJECTS/SOURCE_FILES-build((/CMakeFiles)?/c_objs\.dir(/(\.|[a-zA-Z]+))?|/build/c_objs\.build/.*)/empty3(\.c)?\.(o|obj)$]]
)
add_subdirectory(SOURCE_FILES_subdir)
if(CMake_TEST_CUDA)
enable_language(CUDA)
include(CheckIPOSupported)
check_ipo_supported(RESULT ipo_supported LANGUAGES CUDA)
if(ipo_supported AND CMAKE_CUDA_COMPILER_ID STREQUAL "NVIDIA")
add_library(fatbin_objs OBJECT EXCLUDE_FROM_ALL empty1.cu empty2.cu)
set_target_properties(fatbin_objs PROPERTIES
CUDA_SEPARABLE_COMPILATION ON
CUDA_FATBIN_COMPILATION ON
POSITION_INDEPENDENT_CODE ON
INTERPROCEDURAL_OPTIMIZATION ON
)
check_target_objects(fatbin_1
"$<TARGET_OBJECTS:fatbin_objs,SOURCE_FILES:${CMAKE_CURRENT_SOURCE_DIR}/empty1.cu>"
[[/Tests/RunCMake/GenEx-TARGET_OBJECTS/SOURCE_FILES-build((/CMakeFiles)?/fatbin_objs\.dir(/(\.|[a-zA-Z]+))?|/build/fatbin_objs\.build/.*)/empty1(\.cu\.o)?\.fatbin$]]
)
check_target_objects(fatbin_2
"$<TARGET_OBJECTS:fatbin_objs,SOURCE_FILES:${CMAKE_CURRENT_SOURCE_DIR}/empty2.cu>"
[[/Tests/RunCMake/GenEx-TARGET_OBJECTS/SOURCE_FILES-build((/CMakeFiles)?/fatbin_objs\.dir(/(\.|[a-zA-Z]+))?|/build/fatbin_objs\.build/.*)/empty2(\.cu\.o)?\.fatbin$]]
)
endif()
endif()
@@ -0,0 +1,4 @@
check_target_objects(single_subdir_absolute
"$<TARGET_OBJECTS:c_objs,SOURCE_FILES:${CMAKE_SOURCE_DIR}/empty2.c>"
[[/Tests/RunCMake/GenEx-TARGET_OBJECTS/SOURCE_FILES-build((/CMakeFiles)?/c_objs\.dir(/(\.|[a-zA-Z]+))?|/build/c_objs\.build/.*)/empty2(\.c)?\.(o|obj)$]]
)
@@ -0,0 +1,12 @@
enable_language(C)
include(common.cmake)
add_library(c_objs OBJECT EXCLUDE_FROM_ALL empty1.c empty2.c empty3.c)
check_target_objects(all
$<TARGET_OBJECTS:c_objs>
[[/Tests/RunCMake/GenEx-TARGET_OBJECTS/all-build((/CMakeFiles)?/c_objs\.dir(/(\.|[a-zA-Z]+))?|/build/c_objs\.build/.*)/empty1(\.c)?\.(o|obj)$]]
[[/Tests/RunCMake/GenEx-TARGET_OBJECTS/all-build((/CMakeFiles)?/c_objs\.dir(/(\.|[a-zA-Z]+))?|/build/c_objs\.build/.*)/empty2(\.c)?\.(o|obj)$]]
[[/Tests/RunCMake/GenEx-TARGET_OBJECTS/all-build((/CMakeFiles)?/c_objs\.dir(/(\.|[a-zA-Z]+))?|/build/c_objs\.build/.*)/empty3(\.c)?\.(o|obj)$]]
)
@@ -0,0 +1,13 @@
include("${VARS_FILE}")
list(LENGTH ACTUAL al)
list(LENGTH EXPECTED el)
if(NOT al EQUAL el)
message(FATAL_ERROR "Got the wrong number of objects")
endif()
foreach(a e IN ZIP_LISTS ACTUAL EXPECTED)
if(NOT a MATCHES "${e}")
message(SEND_ERROR "Object \"${a}\" does not match expected regex \"${e}\"")
endif()
endforeach()
@@ -0,0 +1,12 @@
function(check_target_objects name genex)
file(GENERATE OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/${name}_vars_$<CONFIG>.cmake" CONTENT "
set(EXPECTED [==[${ARGN}]==])
set(ACTUAL [==[${genex}]==])
")
add_custom_target(${name}_check ALL
COMMAND ${CMAKE_COMMAND}
"-DVARS_FILE=${CMAKE_CURRENT_BINARY_DIR}/${name}_vars_$<CONFIG>.cmake"
-P "${CMAKE_SOURCE_DIR}/check_target_objects.cmake"
VERBATIM
)
endfunction()
@@ -0,0 +1 @@
1
@@ -0,0 +1,8 @@
CMake Error at invalid\.cmake:[0-9]+ \(add_custom_target\):
Error evaluating generator expression:
\$<TARGET_OBJECTS:c_objs,INVALID_ARGUMENT_1,INVALID_ARGUMENT_2>
Unrecognized argument:
INVALID_ARGUMENT_1
@@ -0,0 +1,8 @@
enable_language(C)
add_library(c_objs OBJECT empty1.c empty2.c empty3.c)
add_custom_target(obj ALL
COMMAND ${CMAKE_COMMAND} -E echo $<TARGET_OBJECTS:c_objs,INVALID_ARGUMENT_1,INVALID_ARGUMENT_2>
VERBATIM
)