From bb3a9ddb6ec917f549e991f6bd344ce77054bb67 Mon Sep 17 00:00:00 2001 From: Curtis J Bezault Date: Thu, 18 Jul 2019 09:02:21 -0700 Subject: [PATCH] [vcpkg] Environment Variable Passthrough (#7290) * use additional env param * remove partials * remove change to linux triplet * Fix some issues that vicroms pointed out * whitespace change --- scripts/get_triplet_environment.cmake | 1 + toolsrc/include/vcpkg/build.h | 24 ++ toolsrc/include/vcpkg/sourceparagraph.h | 2 + toolsrc/src/vcpkg/build.cpp | 423 +++++++++++++----------- toolsrc/src/vcpkg/sourceparagraph.cpp | 22 ++ 5 files changed, 280 insertions(+), 192 deletions(-) diff --git a/scripts/get_triplet_environment.cmake b/scripts/get_triplet_environment.cmake index bc79b16ced..24ff409058 100644 --- a/scripts/get_triplet_environment.cmake +++ b/scripts/get_triplet_environment.cmake @@ -9,3 +9,4 @@ message("VCPKG_PLATFORM_TOOLSET=${VCPKG_PLATFORM_TOOLSET}") message("VCPKG_VISUAL_STUDIO_PATH=${VCPKG_VISUAL_STUDIO_PATH}") message("VCPKG_CHAINLOAD_TOOLCHAIN_FILE=${VCPKG_CHAINLOAD_TOOLCHAIN_FILE}") message("VCPKG_BUILD_TYPE=${VCPKG_BUILD_TYPE}") +message("VCPKG_ENV_PASSTHROUGH=${VCPKG_ENV_PASSTHROUGH}") diff --git a/toolsrc/include/vcpkg/build.h b/toolsrc/include/vcpkg/build.h index 04cd7cf873..e26597376f 100644 --- a/toolsrc/include/vcpkg/build.h +++ b/toolsrc/include/vcpkg/build.h @@ -117,6 +117,29 @@ namespace vcpkg::Build std::string create_error_message(const BuildResult build_result, const PackageSpec& spec); std::string create_user_troubleshooting_message(const PackageSpec& spec); + enum class VcpkgTripletVar + { + TARGET_ARCHITECTURE = 0, + CMAKE_SYSTEM_NAME, + CMAKE_SYSTEM_VERSION, + PLATFORM_TOOLSET, + VISUAL_STUDIO_PATH, + CHAINLOAD_TOOLCHAIN_FILE, + BUILD_TYPE, + ENV_PASSTHROUGH, + }; + + const std::unordered_map VCPKG_OPTIONS = { + {"VCPKG_TARGET_ARCHITECTURE", VcpkgTripletVar::TARGET_ARCHITECTURE}, + {"VCPKG_CMAKE_SYSTEM_NAME", VcpkgTripletVar::CMAKE_SYSTEM_NAME}, + {"VCPKG_CMAKE_SYSTEM_VERSION", VcpkgTripletVar::CMAKE_SYSTEM_VERSION}, + {"VCPKG_PLATFORM_TOOLSET", VcpkgTripletVar::PLATFORM_TOOLSET}, + {"VCPKG_VISUAL_STUDIO_PATH", VcpkgTripletVar::VISUAL_STUDIO_PATH}, + {"VCPKG_CHAINLOAD_TOOLCHAIN_FILE", VcpkgTripletVar::CHAINLOAD_TOOLCHAIN_FILE}, + {"VCPKG_BUILD_TYPE", VcpkgTripletVar::BUILD_TYPE}, + {"VCPKG_ENV_PASSTHROUGH", VcpkgTripletVar::ENV_PASSTHROUGH}, + }; + /// /// Settings from the triplet file which impact the build environment and post-build checks /// @@ -135,6 +158,7 @@ namespace vcpkg::Build Optional visual_studio_path; Optional external_toolchain_file; Optional build_type; + std::vector passthrough_env_vars; }; std::string make_build_env_cmd(const PreBuildInfo& pre_build_info, const Toolset& toolset); diff --git a/toolsrc/include/vcpkg/sourceparagraph.h b/toolsrc/include/vcpkg/sourceparagraph.h index 6232a3fd29..9fbd83475d 100644 --- a/toolsrc/include/vcpkg/sourceparagraph.h +++ b/toolsrc/include/vcpkg/sourceparagraph.h @@ -23,6 +23,8 @@ namespace vcpkg std::vector filter_dependencies(const std::vector& deps, const Triplet& t); std::vector filter_dependencies_to_specs(const std::vector& deps, const Triplet& t); + std::vector filter_dependencies_to_features(const std::vector& deps, + const Triplet& t); // zlib[uwp] becomes Dependency{"zlib", "uwp"} std::vector expand_qualified_dependencies(const std::vector& depends); diff --git a/toolsrc/src/vcpkg/build.cpp b/toolsrc/src/vcpkg/build.cpp index 68df1f965a..2f58a33418 100644 --- a/toolsrc/src/vcpkg/build.cpp +++ b/toolsrc/src/vcpkg/build.cpp @@ -32,24 +32,16 @@ namespace vcpkg::Build::Command using Dependencies::InstallPlanAction; using Dependencies::InstallPlanType; - static constexpr StringLiteral OPTION_CHECKS_ONLY = "--checks-only"; - void perform_and_exit_ex(const FullPackageSpec& full_spec, const SourceControlFileLocation& scfl, const ParsedArguments& options, const VcpkgPaths& paths) { + vcpkg::Util::unused(options); + + const StatusParagraphs status_db = database_load_check(paths); const PackageSpec& spec = full_spec.package_spec; - const auto& scf = *scfl.source_control_file; - if (Util::Sets::contains(options.switches, OPTION_CHECKS_ONLY)) - { - const auto pre_build_info = Build::PreBuildInfo::from_triplet_file(paths, spec.triplet()); - const auto build_info = Build::read_build_info(paths.get_filesystem(), paths.build_info_file_path(spec)); - const size_t error_count = - PostBuildLint::perform_all_checks(spec, paths, pre_build_info, build_info, scfl.source_location); - Checks::check_exit(VCPKG_LINE_INFO, error_count == 0); - Checks::exit_success(VCPKG_LINE_INFO); - } + const SourceControlFile& scf = *scfl.source_control_file; Checks::check_exit(VCPKG_LINE_INFO, spec.name() == scf.core_paragraph->name, @@ -57,7 +49,6 @@ namespace vcpkg::Build::Command scf.core_paragraph->name, spec.name()); - const StatusParagraphs status_db = database_load_check(paths); const Build::BuildPackageOptions build_package_options{ Build::UseHeadVersion::NO, Build::AllowDownloads::YES, @@ -104,15 +95,11 @@ namespace vcpkg::Build::Command Checks::exit_success(VCPKG_LINE_INFO); } - static constexpr std::array BUILD_SWITCHES = {{ - {OPTION_CHECKS_ONLY, "Only run checks, do not rebuild package"}, - }}; - const CommandStructure COMMAND_STRUCTURE = { Help::create_example_string("build zlib:x64-windows"), 1, 1, - {BUILD_SWITCHES, {}}, + {{}, {}}, nullptr, }; @@ -230,6 +217,23 @@ namespace vcpkg::Build })); } + std::unordered_map make_env_passthrough(const PreBuildInfo& pre_build_info) + { + std::unordered_map env; + + for (auto&& env_var : pre_build_info.passthrough_env_vars) + { + auto env_val = System::get_environment_variable(env_var); + + if (env_val) + { + env[env_var] = env_val.value_or_exit(VCPKG_LINE_INFO); + } + } + + return env; + } + std::string make_build_env_cmd(const PreBuildInfo& pre_build_info, const Toolset& toolset) { if (pre_build_info.external_toolchain_file.has_value()) return ""; @@ -274,7 +278,7 @@ namespace vcpkg::Build return bcf; } - static void write_binary_control_file(const VcpkgPaths& paths, BinaryControlFile bcf) + static void write_binary_control_file(const VcpkgPaths& paths, const BinaryControlFile& bcf) { std::string start = Strings::serialize(bcf.core_paragraph); for (auto&& feature : bcf.features) @@ -285,23 +289,43 @@ namespace vcpkg::Build paths.get_filesystem().write_contents(binary_control_file, start, VCPKG_LINE_INFO); } + static std::vector get_dependencies(const SourceControlFile& scf, + const std::set& feature_list, + const Triplet& triplet) + { + return Util::fmap_flatten( + feature_list, + [&](std::string const& feature) -> std::vector { + if (feature == "core") + { + return filter_dependencies_to_features(scf.core_paragraph->depends, triplet); + } + + auto maybe_feature = scf.find_feature(feature); + Checks::check_exit(VCPKG_LINE_INFO, maybe_feature.has_value()); + + return filter_dependencies_to_features(maybe_feature.get()->depends, triplet); + }); + } + + static std::vector get_dependency_names(const SourceControlFile& scf, + const std::set& feature_list, + const Triplet& triplet) + { + return Util::fmap(get_dependencies(scf, feature_list, triplet), + [&](const Features& feat) { + return feat.name; + } + ); + } + static std::vector compute_required_feature_specs(const BuildPackageConfig& config, const StatusParagraphs& status_db) { const Triplet& triplet = config.triplet; const std::vector dep_strings = - Util::fmap_flatten(config.feature_list, [&](std::string const& feature) -> std::vector { - if (feature == "core") - { - return filter_dependencies(config.scf.core_paragraph->depends, triplet); - } - - auto maybe_feature = config.scf.find_feature(feature); - Checks::check_exit(VCPKG_LINE_INFO, maybe_feature.has_value()); - - return filter_dependencies(maybe_feature.get()->depends, triplet); - }); + get_dependency_names(config.scf, config.feature_list, triplet); auto dep_fspecs = FeatureSpec::from_strings_and_triplet(dep_strings, triplet); Util::sort_unique_erase(dep_fspecs); @@ -353,6 +377,128 @@ namespace vcpkg::Build return concurrency; } + static std::vector get_cmake_vars(const VcpkgPaths& paths, + const BuildPackageConfig& config, + const Triplet& triplet, + const Toolset& toolset) + { +#if !defined(_WIN32) + // TODO: remove when vcpkg.exe is in charge for acquiring tools. Change introduced in vcpkg v0.0.107. + // bootstrap should have already downloaded ninja, but making sure it is present in case it was deleted. + vcpkg::Util::unused(paths.get_tool_exe(Tools::NINJA)); +#endif + + const fs::path& git_exe_path = paths.get_tool_exe(Tools::GIT); + + std::string all_features; + for (auto& feature : config.scf.feature_paragraphs) + { + all_features.append(feature->name + ";"); + } + + std::vector variables{ + {"CMD", "BUILD"}, + {"PORT", config.scf.core_paragraph->name}, + {"CURRENT_PORT_DIR", config.port_dir}, + {"TARGET_TRIPLET", triplet.canonical_name()}, + {"TARGET_TRIPLET_FILE", paths.get_triplet_file_path(triplet).u8string()}, + {"VCPKG_PLATFORM_TOOLSET", toolset.version.c_str()}, + {"VCPKG_USE_HEAD_VERSION", Util::Enum::to_bool(config.build_package_options.use_head_version) ? "1" : "0"}, + {"DOWNLOADS", paths.downloads}, + {"_VCPKG_NO_DOWNLOADS", !Util::Enum::to_bool(config.build_package_options.allow_downloads) ? "1" : "0"}, + {"_VCPKG_DOWNLOAD_TOOL", to_string(config.build_package_options.download_tool)}, + {"FEATURES", Strings::join(";", config.feature_list)}, + {"ALL_FEATURES", all_features}, + {"VCPKG_CONCURRENCY", std::to_string(get_concurrency())}, + }; + + if (!System::get_environment_variable("VCPKG_FORCE_SYSTEM_BINARIES").has_value()) + { + variables.push_back({"GIT", git_exe_path}); + } + + return variables; + } + + static std::string make_build_cmd(const VcpkgPaths& paths, + const PreBuildInfo& pre_build_info, + const BuildPackageConfig& config, + const Triplet& triplet) + { + const Toolset& toolset = paths.get_toolset(pre_build_info); + const fs::path& cmake_exe_path = paths.get_tool_exe(Tools::CMAKE); + std::vector variables = + get_cmake_vars(paths, config, triplet, toolset); + + const std::string cmd_launch_cmake = System::make_cmake_cmd(cmake_exe_path, paths.ports_cmake, variables); + + std::string command = make_build_env_cmd(pre_build_info, toolset); + if (!command.empty()) + { +#ifdef _WIN32 + command.append(" & "); +#else + command.append(" && "); +#endif + } + + command.append(cmd_launch_cmake); + + return command; + } + + static std::string get_triplet_abi(const VcpkgPaths& paths, + const PreBuildInfo& pre_build_info, + const Triplet& triplet) + { + static std::map s_hash_cache; + + const fs::path triplet_file_path = paths.get_triplet_file_path(triplet); + const auto& fs = paths.get_filesystem(); + + std::string hash; + + auto it_hash = s_hash_cache.find(triplet_file_path); + if (it_hash != s_hash_cache.end()) + { + hash = it_hash->second; + } + else + { + hash = Hash::get_file_hash(fs, triplet_file_path, "SHA1"); + + if (auto p = pre_build_info.external_toolchain_file.get()) + { + hash += "-"; + hash += Hash::get_file_hash(fs, *p, "SHA1"); + } + else if (pre_build_info.cmake_system_name == "Linux") + { + hash += "-"; + hash += Hash::get_file_hash(fs, paths.scripts / "toolchains" / "linux.cmake", "SHA1"); + } + else if (pre_build_info.cmake_system_name == "Darwin") + { + hash += "-"; + hash += Hash::get_file_hash(fs, paths.scripts / "toolchains" / "osx.cmake", "SHA1"); + } + else if (pre_build_info.cmake_system_name == "FreeBSD") + { + hash += "-"; + hash += Hash::get_file_hash(fs, paths.scripts / "toolchains" / "freebsd.cmake", "SHA1"); + } + else if (pre_build_info.cmake_system_name == "Android") + { + hash += "-"; + hash += Hash::get_file_hash(fs, paths.scripts / "toolchains" / "android.cmake", "SHA1"); + } + + s_hash_cache.emplace(triplet_file_path, hash); + } + + return hash; + } + static ExtendedBuildResult do_build_package(const VcpkgPaths& paths, const PreBuildInfo& pre_build_info, const PackageSpec& spec, @@ -372,72 +518,16 @@ namespace vcpkg::Build System::printf("-- Installing port from location: %s\n", config.port_dir.u8string()); } -#if !defined(_WIN32) - // TODO: remove when vcpkg.exe is in charge for acquiring tools. Change introduced in vcpkg v0.0.107. - // bootstrap should have already downloaded ninja, but making sure it is present in case it was deleted. - vcpkg::Util::unused(paths.get_tool_exe(Tools::NINJA)); -#endif - - const fs::path& cmake_exe_path = paths.get_tool_exe(Tools::CMAKE); - const fs::path& git_exe_path = paths.get_tool_exe(Tools::GIT); -#if defined(_WIN32) - const fs::path& powershell_exe_path = paths.get_tool_exe("powershell-core"); - if (!fs.exists(powershell_exe_path.parent_path() / "powershell.exe")) - { - fs.copy(powershell_exe_path, powershell_exe_path.parent_path() / "powershell.exe", fs::copy_options::none); - } -#endif - - std::string all_features; - for (auto& feature : config.scf.feature_paragraphs) - { - all_features.append(feature->name + ";"); - } - - const Toolset& toolset = paths.get_toolset(pre_build_info); - - std::vector variables{ - {"CMD", "BUILD"}, - {"PORT", config.scf.core_paragraph->name}, - {"CURRENT_PORT_DIR", config.port_dir}, - {"TARGET_TRIPLET", spec.triplet().canonical_name()}, - {"TARGET_TRIPLET_FILE", triplet_file_path}, - {"VCPKG_PLATFORM_TOOLSET", toolset.version.c_str()}, - {"VCPKG_USE_HEAD_VERSION", Util::Enum::to_bool(config.build_package_options.use_head_version) ? "1" : "0"}, - {"DOWNLOADS", paths.downloads}, - {"_VCPKG_NO_DOWNLOADS", !Util::Enum::to_bool(config.build_package_options.allow_downloads) ? "1" : "0"}, - {"_VCPKG_DOWNLOAD_TOOL", to_string(config.build_package_options.download_tool)}, - {"FEATURES", Strings::join(";", config.feature_list)}, - {"ALL_FEATURES", all_features}, - {"VCPKG_CONCURRENCY", std::to_string(get_concurrency())}, - }; - - if (!System::get_environment_variable("VCPKG_FORCE_SYSTEM_BINARIES").has_value()) - { - variables.push_back({"GIT", git_exe_path}); - } - - const std::string cmd_launch_cmake = System::make_cmake_cmd(cmake_exe_path, paths.ports_cmake, variables); - - auto command = make_build_env_cmd(pre_build_info, toolset); - if (!command.empty()) - { -#ifdef _WIN32 - command.append(" & "); -#else - command.append(" && "); -#endif - } - command.append(cmd_launch_cmake); const auto timer = Chrono::ElapsedTimer::create_started(); - const int return_code = System::cmd_execute_clean( - command, - {} -#ifdef _WIN32 - , - powershell_exe_path.parent_path().u8string() + ";" -#endif - ); + + std::string command = + make_build_cmd(paths, pre_build_info, config, triplet); + std::unordered_map env = + make_env_passthrough(pre_build_info); + + const int return_code = + System::cmd_execute_clean(command, env); + const auto buildtimeus = timer.microseconds(); const auto spec_string = spec.to_string(); @@ -711,7 +801,7 @@ namespace vcpkg::Build { System::print2("Using cached binary package: ", archive_path.u8string(), "\n"); - auto archive_result = decompress_archive(paths, spec, archive_path); + int archive_result = decompress_archive(paths, spec, archive_path); if (archive_result != 0) { @@ -946,111 +1036,60 @@ namespace vcpkg::Build const std::string variable_name = s.at(0); const std::string variable_value = variable_with_no_value ? "" : s.at(1); - if (variable_name == "VCPKG_TARGET_ARCHITECTURE") + auto maybe_option = VCPKG_OPTIONS.find(variable_name); + if (maybe_option != VCPKG_OPTIONS.end()) { - pre_build_info.target_architecture = variable_value; - continue; + switch (maybe_option->second) + { + case VcpkgTripletVar::TARGET_ARCHITECTURE : + pre_build_info.target_architecture = variable_value; + break; + case VcpkgTripletVar::CMAKE_SYSTEM_NAME : + pre_build_info.cmake_system_name = variable_value; + break; + case VcpkgTripletVar::CMAKE_SYSTEM_VERSION : + pre_build_info.cmake_system_version = variable_value; + break; + case VcpkgTripletVar::PLATFORM_TOOLSET : + pre_build_info.platform_toolset = + variable_value.empty() ? nullopt : Optional{variable_value}; + break; + case VcpkgTripletVar::VISUAL_STUDIO_PATH : + pre_build_info.visual_studio_path = + variable_value.empty() ? nullopt : Optional{variable_value}; + break; + case VcpkgTripletVar::CHAINLOAD_TOOLCHAIN_FILE : + pre_build_info.external_toolchain_file = + variable_value.empty() ? nullopt : Optional{variable_value}; + break; + case VcpkgTripletVar::BUILD_TYPE : + if (variable_value.empty()) + pre_build_info.build_type = nullopt; + else if (Strings::case_insensitive_ascii_equals(variable_value, "debug")) + pre_build_info.build_type = ConfigurationType::DEBUG; + else if (Strings::case_insensitive_ascii_equals(variable_value, "release")) + pre_build_info.build_type = ConfigurationType::RELEASE; + else + Checks::exit_with_message( + VCPKG_LINE_INFO, "Unknown setting for VCPKG_BUILD_TYPE: %s", variable_value); + break; + case VcpkgTripletVar::ENV_PASSTHROUGH : + pre_build_info.passthrough_env_vars = Strings::split(variable_value, ";"); + break; + } } - - if (variable_name == "VCPKG_CMAKE_SYSTEM_NAME") + else { - pre_build_info.cmake_system_name = variable_value; - continue; + Checks::exit_with_message(VCPKG_LINE_INFO, "Unknown variable name %s", line); } - - if (variable_name == "VCPKG_CMAKE_SYSTEM_VERSION") - { - pre_build_info.cmake_system_version = variable_value; - continue; - } - - if (variable_name == "VCPKG_PLATFORM_TOOLSET") - { - pre_build_info.platform_toolset = - variable_value.empty() ? nullopt : Optional{variable_value}; - continue; - } - - if (variable_name == "VCPKG_VISUAL_STUDIO_PATH") - { - pre_build_info.visual_studio_path = - variable_value.empty() ? nullopt : Optional{variable_value}; - continue; - } - - if (variable_name == "VCPKG_CHAINLOAD_TOOLCHAIN_FILE") - { - pre_build_info.external_toolchain_file = - variable_value.empty() ? nullopt : Optional{variable_value}; - continue; - } - - if (variable_name == "VCPKG_BUILD_TYPE") - { - if (variable_value.empty()) - pre_build_info.build_type = nullopt; - else if (Strings::case_insensitive_ascii_equals(variable_value, "debug")) - pre_build_info.build_type = ConfigurationType::DEBUG; - else if (Strings::case_insensitive_ascii_equals(variable_value, "release")) - pre_build_info.build_type = ConfigurationType::RELEASE; - else - Checks::exit_with_message( - VCPKG_LINE_INFO, "Unknown setting for VCPKG_BUILD_TYPE: %s", variable_value); - continue; - } - - Checks::exit_with_message(VCPKG_LINE_INFO, "Unknown variable name %s", line); } - pre_build_info.triplet_abi_tag = [&]() { - const auto& fs = paths.get_filesystem(); - static std::map s_hash_cache; - - auto it_hash = s_hash_cache.find(triplet_file_path); - if (it_hash != s_hash_cache.end()) - { - return it_hash->second; - } - auto hash = Hash::get_file_hash(fs, triplet_file_path, "SHA1"); - - if (auto p = pre_build_info.external_toolchain_file.get()) - { - hash += "-"; - hash += Hash::get_file_hash(fs, *p, "SHA1"); - } - else if (pre_build_info.cmake_system_name.empty() || - pre_build_info.cmake_system_name == "WindowsStore") - { - hash += "-"; - hash += Hash::get_file_hash(fs, paths.scripts / "toolchains" / "windows.cmake", "SHA1"); - } - else if (pre_build_info.cmake_system_name == "Linux") - { - hash += "-"; - hash += Hash::get_file_hash(fs, paths.scripts / "toolchains" / "linux.cmake", "SHA1"); - } - else if (pre_build_info.cmake_system_name == "Darwin") - { - hash += "-"; - hash += Hash::get_file_hash(fs, paths.scripts / "toolchains" / "osx.cmake", "SHA1"); - } - else if (pre_build_info.cmake_system_name == "FreeBSD") - { - hash += "-"; - hash += Hash::get_file_hash(fs, paths.scripts / "toolchains" / "freebsd.cmake", "SHA1"); - } - else if (pre_build_info.cmake_system_name == "Android") - { - hash += "-"; - hash += Hash::get_file_hash(fs, paths.scripts / "toolchains" / "android.cmake", "SHA1"); - } - - s_hash_cache.emplace(triplet_file_path, hash); - return hash; - }(); + pre_build_info.triplet_abi_tag = + get_triplet_abi(paths, pre_build_info, triplet); return pre_build_info; } + ExtendedBuildResult::ExtendedBuildResult(BuildResult code) : code(code) {} ExtendedBuildResult::ExtendedBuildResult(BuildResult code, std::unique_ptr&& bcf) : code(code), binary_control_file(std::move(bcf)) diff --git a/toolsrc/src/vcpkg/sourceparagraph.cpp b/toolsrc/src/vcpkg/sourceparagraph.cpp index 9bc59cbe71..1a52bd05f4 100644 --- a/toolsrc/src/vcpkg/sourceparagraph.cpp +++ b/toolsrc/src/vcpkg/sourceparagraph.cpp @@ -238,6 +238,28 @@ namespace vcpkg return ret; } + std::vector filter_dependencies_to_features(const std::vector& deps, + const Triplet& t) + { + std::vector ret; + for (auto&& dep : deps) + { + auto qualifiers = Strings::split(dep.qualifier, "&"); + if (std::all_of(qualifiers.begin(), qualifiers.end(), [&](const std::string& qualifier) { + if (qualifier.empty()) return true; + if (qualifier[0] == '!') + { + return t.canonical_name().find(qualifier.substr(1)) == std::string::npos; + } + return t.canonical_name().find(qualifier) != std::string::npos; + })) + { + ret.emplace_back(dep.depend); + } + } + return ret; + } + std::vector filter_dependencies_to_specs(const std::vector& deps, const Triplet& t) { return FeatureSpec::from_strings_and_triplet(filter_dependencies(deps, t), t);