Skip to content
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)...);
}
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>
{
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