[Mac/GN] Treat create_bundle as a leaf for `gn desc runtime_deps`.
BUG=611414
R=brettw@chromium.org,dpranke@chromium.org,sdefresne@chromium.org
Review-Url: https://codereview.chromium.org/1982463002
Cr-Original-Commit-Position: refs/heads/master@{#394840}
Cr-Mirrored-From: https://chromium.googlesource.com/chromium/src
Cr-Mirrored-Commit: 903e2b85c71675f83767ac9b1687087382b49f39
diff --git a/tools/gn/bundle_data.cc b/tools/gn/bundle_data.cc
index f211c1f..e182365 100644
--- a/tools/gn/bundle_data.cc
+++ b/tools/gn/bundle_data.cc
@@ -129,3 +129,8 @@
}
return SourceFile(root_dir().value());
}
+
+SourceDir BundleData::GetBundleRootDirOutputAsDir(
+ const Settings* settings) const {
+ return SourceDir(GetBundleRootDirOutput(settings).value());
+}
diff --git a/tools/gn/bundle_data.h b/tools/gn/bundle_data.h
index 9a2ea07..3a1ce95 100644
--- a/tools/gn/bundle_data.h
+++ b/tools/gn/bundle_data.h
@@ -77,6 +77,9 @@
// of its contents.
SourceFile GetBundleRootDirOutput(const Settings* settings) const;
+ // Performs GetBundleRootDirOutput but returns the result as a directory.
+ SourceDir GetBundleRootDirOutputAsDir(const Settings* settings) const;
+
// Returns the list of inputs for the compilation of the asset catalog.
SourceFiles& asset_catalog_sources() { return asset_catalog_sources_; }
const SourceFiles& asset_catalog_sources() const {
diff --git a/tools/gn/runtime_deps.cc b/tools/gn/runtime_deps.cc
index 17b9c07..5352de3 100644
--- a/tools/gn/runtime_deps.cc
+++ b/tools/gn/runtime_deps.cc
@@ -104,6 +104,15 @@
AddIfNew(output_file.value(), target, deps, found_files);
}
+ // Do not recurse into bundle targets. A bundle's dependencies should be
+ // copied into the bundle itself for run-time access.
+ if (target->output_type() == Target::CREATE_BUNDLE) {
+ SourceDir bundle_root_dir =
+ target->bundle_data().GetBundleRootDirOutputAsDir(target->settings());
+ AddIfNew(bundle_root_dir.value(), target, deps, found_files);
+ return;
+ }
+
// Non-data dependencies (both public and private).
for (const auto& dep_pair : target->GetDeps(Target::DEPS_LINKED)) {
if (dep_pair.ptr->output_type() == Target::EXECUTABLE)
diff --git a/tools/gn/runtime_deps_unittest.cc b/tools/gn/runtime_deps_unittest.cc
index 6c2013d..8b68bd8 100644
--- a/tools/gn/runtime_deps_unittest.cc
+++ b/tools/gn/runtime_deps_unittest.cc
@@ -258,6 +258,83 @@
EXPECT_TRUE(MakePair("../../dep.data", &dep) == result[0]);
}
+// Tests that the search for dependencies terminates at a bundle target,
+// ignoring any shared libraries or loadable modules that get copied into the
+// bundle.
+TEST(RuntimeDeps, CreateBundle) {
+ TestWithScope setup;
+ Err err;
+
+ // Dependency hierarchy:
+ // main(exe) -> dep(bundle) -> dep(shared_library) -> dep(source set)
+ // -> dep(bundle_data) -> dep(loadable_module)
+
+ const SourceDir source_dir("//");
+ const std::string& build_dir = setup.build_settings()->build_dir().value();
+
+ Target loadable_module(setup.settings(),
+ Label(source_dir, "loadable_module"));
+ InitTargetWithType(setup, &loadable_module, Target::LOADABLE_MODULE);
+ ASSERT_TRUE(loadable_module.OnResolved(&err));
+
+ Target module_data(setup.settings(), Label(source_dir, "module_data"));
+ InitTargetWithType(setup, &module_data, Target::BUNDLE_DATA);
+ module_data.private_deps().push_back(LabelTargetPair(&loadable_module));
+ module_data.bundle_data().file_rules().push_back(BundleFileRule(
+ std::vector<SourceFile>{SourceFile(build_dir + "loadable_module.so")},
+ SubstitutionPattern::MakeForTest("{{bundle_resources_dir}}")));
+ ASSERT_TRUE(module_data.OnResolved(&err));
+
+ Target source_set(setup.settings(), Label(source_dir, "sources"));
+ InitTargetWithType(setup, &source_set, Target::SOURCE_SET);
+ source_set.sources().push_back(SourceFile(source_dir.value() + "foo.cc"));
+ ASSERT_TRUE(source_set.OnResolved(&err));
+
+ Target dylib(setup.settings(), Label(source_dir, "dylib"));
+ dylib.set_output_prefix_override(true);
+ dylib.set_output_extension("");
+ dylib.set_output_name("Bundle");
+ InitTargetWithType(setup, &dylib, Target::SHARED_LIBRARY);
+ dylib.private_deps().push_back(LabelTargetPair(&source_set));
+ ASSERT_TRUE(dylib.OnResolved(&err));
+
+ Target dylib_data(setup.settings(), Label(source_dir, "dylib_data"));
+ InitTargetWithType(setup, &dylib_data, Target::BUNDLE_DATA);
+ dylib_data.private_deps().push_back(LabelTargetPair(&dylib));
+ dylib_data.bundle_data().file_rules().push_back(BundleFileRule(
+ std::vector<SourceFile>{SourceFile(build_dir + "dylib")},
+ SubstitutionPattern::MakeForTest("{{bundle_executable_dir}}")));
+ ASSERT_TRUE(dylib_data.OnResolved(&err));
+
+ Target bundle(setup.settings(), Label(source_dir, "bundle"));
+ InitTargetWithType(setup, &bundle, Target::CREATE_BUNDLE);
+ const std::string root_dir(build_dir + "Bundle.framework/Versions/A/");
+ bundle.bundle_data().root_dir() = SourceDir(root_dir);
+ bundle.bundle_data().resources_dir() = SourceDir(root_dir + "Resources");
+ bundle.bundle_data().executable_dir() = SourceDir(root_dir + "MacOS");
+ bundle.private_deps().push_back(LabelTargetPair(&dylib_data));
+ bundle.private_deps().push_back(LabelTargetPair(&module_data));
+ ASSERT_TRUE(bundle.OnResolved(&err));
+
+ Target main(setup.settings(), Label(source_dir, "main"));
+ InitTargetWithType(setup, &main, Target::EXECUTABLE);
+ main.data_deps().push_back(LabelTargetPair(&bundle));
+ ASSERT_TRUE(main.OnResolved(&err));
+
+ std::vector<std::pair<OutputFile, const Target*>> result =
+ ComputeRuntimeDeps(&main);
+
+ // The result should have deps of main, datadep, final_in.dat
+ ASSERT_EQ(2u, result.size()) << GetVectorDescription(result);
+
+ // The first one should always be the main exe.
+ EXPECT_EQ(MakePair("./main", &main), result[0]);
+
+ // The second one should be the framework bundle, not its included
+ // loadable_module or its intermediate shared_library.
+ EXPECT_EQ(MakePair("Bundle.framework/", &bundle), result[1]);
+}
+
// Tests that a dependency duplicated in regular and data deps is processed
// as a data dep.
TEST(RuntimeDeps, Dupe) {