Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Clarify "default" feature #298

Merged
merged 10 commits into from
Jan 10, 2022
22 changes: 22 additions & 0 deletions include/vcpkg-test/util.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,15 @@ namespace Catch
}
};

template<>
struct StringMaker<vcpkg::FeatureSpec>
{
static std::string convert(vcpkg::FeatureSpec const& value)
{
return vcpkg::Strings::concat(value.spec().name(), '[', value.feature(), "]:", value.spec().triplet());
}
};

template<>
struct StringMaker<vcpkg::Triplet>
{
Expand Down Expand Up @@ -107,6 +116,19 @@ namespace vcpkg::Test
return std::move(*opt.get());
}

inline std::vector<FullPackageSpec> parse_test_fspecs(StringView sv, Triplet t = X86_WINDOWS)
{
std::vector<FullPackageSpec> ret;
Parse::ParserBase parser(sv, "test");
while (!parser.at_eof())
{
auto opt = parse_qualified_specifier(parser);
REQUIRE(opt.has_value());
ret.push_back(unwrap(opt.get()->to_full_spec(t, ImplicitDefault::YES)));
}
return ret;
}

template<class R1, class R2>
void check_ranges(const R1& r1, const R2& r2)
{
Expand Down
36 changes: 22 additions & 14 deletions include/vcpkg/base/expected.h
Original file line number Diff line number Diff line change
Expand Up @@ -165,66 +165,74 @@ namespace vcpkg
return this->m_t.get();
}

using const_ref_type = decltype(*std::declval<typename ExpectedHolder<T>::const_pointer>());
using move_ref_type = decltype(std::move(*std::declval<typename ExpectedHolder<T>::pointer>()));
template<class F>
using map_t = decltype(std::declval<F&>()(*std::declval<typename ExpectedHolder<T>::const_pointer>()));

template<class F, class U = map_t<F>>
ExpectedT<U, S> map(F f) const&
template<class F>
ExpectedT<map_t<F>, S> map(F f) const&
{
if (has_value())
{
return {f(*m_t.get()), expected_left_tag};
}
else
{
return {error(), expected_right_tag};
return ExpectedT<map_t<F>, S>{m_s};
}
}

template<class F>
using move_map_t =
decltype(std::declval<F&>()(std::move(*std::declval<typename ExpectedHolder<T>::pointer>())));

template<class F, class U = move_map_t<F>>
ExpectedT<U, S> map(F f) &&
template<class F>
ExpectedT<move_map_t<F>, S> map(F f) &&
{
if (has_value())
{
return {f(std::move(*m_t.get())), expected_left_tag};
}
else
{
return {std::move(*this).error(), expected_right_tag};
return ExpectedT<move_map_t<F>, S>{std::move(m_s)};
}
}

template<class F, class U = map_t<F>>
U then(F f) const&
template<class F, class... Args>
std::invoke_result_t<F, const_ref_type, Args&&...> then(F f, Args&&... args) const&
{
if (has_value())
{
return f(*m_t.get());
return std::invoke(f, *m_t.get(), static_cast<Args&&>(args)...);
ras0219-msft marked this conversation as resolved.
Show resolved Hide resolved
}
else
{
return U{error(), expected_right_tag};
return std::invoke_result_t<F, const_ref_type, Args&&...>{m_s};
}
}

template<class F, class U = move_map_t<F>>
U then(F f) &&
template<class F, class... Args>
std::invoke_result_t<F, move_ref_type, Args&&...> then(F f, Args&&... args) &&
{
if (has_value())
{
return f(std::move(*m_t.get()));
return std::invoke(f, std::move(*m_t.get()), static_cast<Args&&>(args)...);
}
else
{
return U{std::move(*this).error(), expected_right_tag};
return std::invoke_result_t<F, move_ref_type, Args&&...>{std::move(m_s)};
}
}

private:
template<class, class>
friend struct ExpectedT;

explicit ExpectedT(const ErrorHolder<S>& err) : m_s(err) { }
explicit ExpectedT(ErrorHolder<S>&& err) : m_s(static_cast<ErrorHolder<S>&&>(err)) { }

void exit_if_error(const LineInfo& line_info) const
{
if (m_s.has_error())
Expand Down
9 changes: 1 addition & 8 deletions include/vcpkg/dependencies.h
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ namespace vcpkg::Dependencies

std::map<std::string, std::vector<FeatureSpec>> feature_dependencies;
std::vector<PackageSpec> package_dependencies;
std::vector<std::string> feature_list;
InternalFeatureSet feature_list;
Triplet host_triplet;

Optional<Build::AbiInfo> abi_info;
Expand Down Expand Up @@ -196,13 +196,6 @@ namespace vcpkg::Dependencies
const StatusParagraphs& status_db,
const CreateInstallPlanOptions& options = {Triplet{}});

// `features` should have "default" instead of missing "core". This is only exposed for testing purposes.
std::vector<FullPackageSpec> resolve_deps_as_top_level(const SourceControlFile& scf,
Triplet triplet,
Triplet host_triplet,
std::vector<std::string> features,
CMakeVars::CMakeVarProvider& var_provider);

ExpectedS<ActionPlan> create_versioned_install_plan(const PortFileProvider::IVersionedPortfileProvider& vprovider,
const PortFileProvider::IBaselineProvider& bprovider,
const PortFileProvider::IOverlayProvider& oprovider,
Expand Down
7 changes: 5 additions & 2 deletions include/vcpkg/input.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,13 @@ namespace vcpkg::Input
{
PackageSpec check_and_get_package_spec(std::string&& spec_string,
Triplet default_triplet,
CStringView example_text);
CStringView example_text,
const VcpkgPaths& paths);

FullPackageSpec check_and_get_full_package_spec(std::string&& spec_string,
Triplet default_triplet,
CStringView example_text);
CStringView example_text,
const VcpkgPaths& paths);

void check_triplet(Triplet t, const VcpkgPaths& paths);
}
51 changes: 29 additions & 22 deletions include/vcpkg/packagespec.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include <vcpkg/base/expected.h>
#include <vcpkg/base/json.h>
#include <vcpkg/base/optional.h>
#include <vcpkg/base/view.h>

#include <vcpkg/platform-expression.h>
#include <vcpkg/triplet.h>
Expand Down Expand Up @@ -92,6 +93,12 @@ namespace vcpkg
std::string m_feature;
};

/// In an internal feature set, "default" represents default features and missing "core" has no semantic
struct InternalFeatureSet : std::vector<std::string>
ras0219-msft marked this conversation as resolved.
Show resolved Hide resolved
{
using std::vector<std::string>::vector;
};

///
/// <summary>
/// Full specification of a package. Contains all information to reference
Expand All @@ -101,37 +108,22 @@ namespace vcpkg
struct FullPackageSpec
{
PackageSpec package_spec;
std::vector<std::string> features;
InternalFeatureSet features;

FullPackageSpec() = default;
explicit FullPackageSpec(PackageSpec spec, std::vector<std::string> features = {})
explicit FullPackageSpec(PackageSpec spec, InternalFeatureSet features)
: package_spec(std::move(spec)), features(std::move(features))
{
}

std::vector<FeatureSpec> to_feature_specs(const std::vector<std::string>& default_features,
const std::vector<std::string>& all_features) const;

static ExpectedS<FullPackageSpec> from_string(const std::string& spec_as_string, Triplet default_triplet);
/// Splats into individual FeatureSpec's
void expand_fspecs_to(std::vector<FeatureSpec>& oFut) const;

bool operator==(const FullPackageSpec& o) const
friend bool operator==(const FullPackageSpec& l, const FullPackageSpec& r)
{
return package_spec == o.package_spec && features == o.features;
return l.package_spec == r.package_spec && l.features == r.features;
}
bool operator!=(const FullPackageSpec& o) const { return !(*this == o); }
};

///
/// <summary>
/// Contains all information to reference a collection of features in a single package by their names.
/// </summary>
///
struct Features
{
std::string name;
std::vector<std::string> features;

static ExpectedS<Features> from_string(const std::string& input);
friend bool operator!=(const FullPackageSpec& l, const FullPackageSpec& r) { return !(l == r); }
};

struct DependencyConstraint
Expand All @@ -147,6 +139,12 @@ namespace vcpkg
}
};

enum class ImplicitDefault : bool
{
NO,
YES,
};

struct Dependency
{
std::string name;
Expand All @@ -157,6 +155,9 @@ namespace vcpkg

Json::Object extra_info;

/// @param id adds "default" if "core" not present.
FullPackageSpec to_full_spec(Triplet target, Triplet host, ImplicitDefault id) const;

friend bool operator==(const Dependency& lhs, const Dependency& rhs);
friend bool operator!=(const Dependency& lhs, const Dependency& rhs) { return !(lhs == rhs); }
};
Expand All @@ -180,6 +181,12 @@ namespace vcpkg
Optional<std::vector<std::string>> features;
Optional<std::string> triplet;
Optional<PlatformExpression::Expr> platform;

/// @param id add "default" if "core" is not present
/// @return nullopt on success. On failure, caller should supplement returned string with more context.
ExpectedS<FullPackageSpec> to_full_spec(Triplet default_triplet, ImplicitDefault id) const;

ExpectedS<PackageSpec> to_package_spec(Triplet default_triplet) const;
};

Optional<std::string> parse_feature_name(Parse::ParserBase& parser);
Expand Down
3 changes: 2 additions & 1 deletion include/vcpkg/sourceparagraph.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ namespace vcpkg
std::vector<FullPackageSpec> filter_dependencies(const std::vector<Dependency>& deps,
Triplet t,
Triplet host,
const std::unordered_map<std::string, std::string>& cmake_vars);
const std::unordered_map<std::string, std::string>& cmake_vars,
ImplicitDefault id);

struct Type
{
Expand Down
2 changes: 1 addition & 1 deletion include/vcpkg/triplet.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ namespace vcpkg
public:
constexpr Triplet() noexcept : m_instance(&DEFAULT_INSTANCE) { }

static Triplet from_canonical_name(std::string&& triplet_as_string);
static Triplet from_canonical_name(std::string triplet_as_string);

const std::string& canonical_name() const;
const std::string& to_string() const;
Expand Down
2 changes: 2 additions & 0 deletions locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
"ErrorRequirePackagesToInstall": "Error: No packages were listed for installation and no manifest was found.",
"ErrorVcvarsUnsupported": "Error: in triplet {triplet}: Use of Visual Studio's Developer Prompt is unsupported on non-Windows hosts.\nDefine 'VCPKG_CMAKE_SYSTEM_NAME' or 'VCPKG_CHAINLOAD_TOOLCHAIN_FILE' in the triplet file.",
"ForceSystemBinariesOnWeirdPlatforms": "Environment variable VCPKG_FORCE_SYSTEM_BINARIES must be set on arm, s390x, and ppc64le platforms.",
"IllegalFeatures": "Error: List of features is not allowed in this contect",
"IllegalPlatformSpec": "Error: Platform qualifier is not allowed in this context",
"NoLocalizationForMessages": "No localization for the following messages:",
"SeeURL": "See {url} for more information.",
"UnsupportedSystemName": "Error: Could not map VCPKG_CMAKE_SYSTEM_NAME '{value}' to a vcvarsall platform. Supported system names are '', 'Windows' and 'WindowsStore'.",
Expand Down
Loading