Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
vcpkg-empty-featureful-port[a,b] = feature-fails
vcpkg-empty-featureful-port[b,c] = cascade

Check failure on line 2 in azure-pipelines/e2e-assets/ci-feature-baseline/conflicting-features.txt

View workflow job for this annotation

GitHub Actions / builds / build (windows-2022, windows-ci)

'b' was already declared as 'feature-fails'

Check failure on line 2 in azure-pipelines/e2e-assets/ci-feature-baseline/conflicting-features.txt

View workflow job for this annotation

GitHub Actions / builds / build (ubuntu-22.04, linux-ci)

'b' was already declared as 'feature-fails'

Check failure on line 2 in azure-pipelines/e2e-assets/ci-feature-baseline/conflicting-features.txt

View workflow job for this annotation

GitHub Actions / builds / build (ubuntu-24.04-arm, linux-arm64-ci)

'b' was already declared as 'feature-fails'

Check failure on line 2 in azure-pipelines/e2e-assets/ci-feature-baseline/conflicting-features.txt

View workflow job for this annotation

GitHub Actions / builds / build (macos-14, macos-ci)

'b' was already declared as 'feature-fails'
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
set(VCPKG_POLICY_EMPTY_PACKAGE enabled)
21 changes: 21 additions & 0 deletions azure-pipelines/e2e-ports/vcpkg-empty-featureful-port/vcpkg.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"name": "vcpkg-empty-featureful-port",
"version": "0",
"default-features": [
"a-default-feature"
],
"features": {
"a": {
"description": "a feature named a"
},
"a-default-feature": {
"description": "a default feature"
},
"b": {
"description": "a feature named b"
},
"c": {
"description": "a feature named c"
}
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
. $PSScriptRoot/../end-to-end-tests-prelude.ps1

$ciFeatureBaselines = (Get-Item "$PSScriptRoot/../e2e-assets/ci-feature-baseline").FullName
$ciFeatureBaselines = (Get-Item "$PSScriptRoot/../e2e-assets/format-feature-baseline").FullName
$testProjects = Get-ChildItem "$ciFeatureBaselines/*.txt" -File
$testProjects | % {
$asItem = Get-Item $_
Expand Down
15 changes: 15 additions & 0 deletions azure-pipelines/end-to-end-tests-dir/test-features.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
. $PSScriptRoot/../end-to-end-tests-prelude.ps1

$ciFeatureBaseline = "$PSScriptRoot/../e2e-assets/ci-feature-baseline/conflicting-features.txt"
$output = Run-VcpkgAndCaptureOutput x-test-features "--x-builtin-ports-root=$PSScriptRoot/../e2e-ports" vcpkg-empty-featureful-port --ci-feature-baseline $ciFeatureBaseline
Throw-IfNotFailed
$expected = @"
$($ciFeatureBaseline):2:29: error: 'b' was already declared as 'feature-fails'
on expression: vcpkg-empty-featureful-port[b,c] = cascade
^
$($ciFeatureBaseline):1:31: note: previous declaration was here
on expression: vcpkg-empty-featureful-port[a,b] = feature-fails
^
"@

Throw-IfNonContains -Expected $expected -Actual $output
24 changes: 16 additions & 8 deletions include/vcpkg/base/message-data.inc.h
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ DECLARE_MESSAGE(
"The version format of \"{package_name}\" uses \"version-string\", but the format is acceptable as a \"version\". "
"If the versions for this port are orderable using relaxed-version rules, change the format to \"version\", and "
"rerun this command. Relaxed-version rules order versions by each numeric component. Then, versions with dash "
"suffixes are sorted lexcographically before. Plus'd build tags are ignored. Examples:\n"
"suffixes are sorted lexicographically before. Plus'd build tags are ignored. Examples:\n"
"1.0 < 1.1-alpha < 1.1-b < 1.1 < 1.1.1 < 1.2+build = 1.2 < 2.0\n"
"Note in particular that dashed suffixes sort *before*, not after. 1.0-anything < 1.0\n"
"Note that this sort order is the same as chosen in Semantic Versioning (see https://semver.org), even though the "
Expand Down Expand Up @@ -510,6 +510,7 @@ DECLARE_MESSAGE(CISettingsOptCIBase,
DECLARE_MESSAGE(CISettingsOptExclude, (), "", "Comma separated list of ports to skip")
DECLARE_MESSAGE(CISettingsOptFailureLogs, (), "", "Directory to which failure logs will be copied")
DECLARE_MESSAGE(CISettingsOptHostExclude, (), "", "Comma separated list of ports to skip for the host triplet")
DECLARE_MESSAGE(CISettingsOptKnownFailuresFrom, (), "", "Path to the file of known package build failures")
DECLARE_MESSAGE(CISettingsOptOutputHashes, (), "", "File to output all determined package hashes")
DECLARE_MESSAGE(CISettingsOptParentHashes,
(),
Expand Down Expand Up @@ -1236,7 +1237,12 @@ DECLARE_MESSAGE(ExpectedCharacterHere,
DECLARE_MESSAGE(ExpectedDefaultFeaturesList, (), "", "expected ',' or end of text in default features list")
DECLARE_MESSAGE(ExpectedDependenciesList, (), "", "expected ',' or end of text in dependencies list")
DECLARE_MESSAGE(ExpectedDigitsAfterDecimal, (), "", "Expected digits after the decimal point")
DECLARE_MESSAGE(ExpectedFailOrSkip, (), "", "expected 'fail', 'skip', or 'pass' here")
DECLARE_MESSAGE(ExpectedFailSkipOrPass, (), "", "expected 'fail', 'skip', or 'pass' here")
DECLARE_MESSAGE(ExpectedFeatureBaselineState,
(),
"",
"expected 'fail', 'skip', 'pass', 'cascade', 'no-separate-feature-test', 'options', 'feature-fails', "
"or 'combination-fails' here")
DECLARE_MESSAGE(ExpectedFeatureListTerminal, (), "", "expected ',' or ']' in feature list")
DECLARE_MESSAGE(ExpectedFeatureName, (), "", "expected feature name (must be lowercase, digits, '-')")
DECLARE_MESSAGE(ExpectedExplicitTriplet, (), "", "expected an explicit triplet")
Expand Down Expand Up @@ -1351,13 +1357,14 @@ DECLARE_MESSAGE(FailedVendorAuthentication,
DECLARE_MESSAGE(FeatureBaselineEntryAlreadySpecified,
(msg::feature, msg::value),
"{value} is a keyword",
"Feature '{feature}' was already declared as '{value}'.")
"'{feature}' was already declared as '{value}'")
DECLARE_MESSAGE(FeatureBaselineExpectedFeatures,
(msg::value),
"{value} is a keyword",
"When using '{value}' a list of features must be specified.")
DECLARE_MESSAGE(FeatureBaselineFormatted, (), "", "Succeeded in formatting the feature baseline file.")
DECLARE_MESSAGE(FeatureBaselineNoFeaturesForFail, (), "", "When using '= fail' no list of features is allowed.")
DECLARE_MESSAGE(FeatureTestProblems, (), "", "There are some feature test problems!")
DECLARE_MESSAGE(FileIsNotExecutable, (), "", "this file does not appear to be executable")
DECLARE_MESSAGE(FilesRelativeToTheBuildDirectoryHere, (), "", "the files are relative to the build directory here")
DECLARE_MESSAGE(FilesRelativeToThePackageDirectoryHere,
Expand Down Expand Up @@ -2634,6 +2641,7 @@ DECLARE_MESSAGE(PortVersionMultipleSpecification,
DECLARE_MESSAGE(PortVersionControlMustBeANonNegativeInteger, (), "", "\"Port-Version\" must be a non-negative integer")
DECLARE_MESSAGE(PrebuiltPackages, (), "", "There are packages that have not been built. To build them run:")
DECLARE_MESSAGE(PrecheckBinaryCache, (), "", "Checking the binary cache...")
DECLARE_MESSAGE(PreviousDeclarationWasHere, (), "", "previous declaration was here")
DECLARE_MESSAGE(PreviousIntegrationFileRemains, (), "", "Previous integration file was not removed.")
DECLARE_MESSAGE(ProgramReturnedNonzeroExitCode,
(msg::tool_name, msg::exit_code),
Expand Down Expand Up @@ -2884,11 +2892,11 @@ DECLARE_MESSAGE(UnexpectedState,
(msg::feature_spec, msg::actual, msg::elapsed),
"{actual} is the actual state, e.g. 'pass', 'skip', ...",
"{feature_spec} resulted in the unexpected state {actual} after {elapsed}")
DECLARE_MESSAGE(UnexpectedStateCascade,
(msg::feature_spec, msg::actual),
"{actual} is the actual state, e.g. 'pass', 'skip', ...",
"{feature_spec} resulted in the unexpected state {actual} because the following "
"dependencies did not build:")
DECLARE_MESSAGE(
UnexpectedStateCascade,
(msg::feature_spec),
"",
"{feature_spec} was unexpectedly a cascading failure because the following dependencies are unavailable:")
DECLARE_MESSAGE(UnexpectedSwitch,
(msg::option),
"Switch is a command line switch like --switch",
Expand Down
17 changes: 9 additions & 8 deletions include/vcpkg/base/parse.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,12 @@

namespace vcpkg
{
struct SourceLoc
{
Unicode::Utf8Decoder it;
Unicode::Utf8Decoder start_of_line;
int row;
int column;
};

void append_caret_line(LocalizedString& res,
const Unicode::Utf8Decoder& it,
const Unicode::Utf8Decoder& start_of_line);

void append_caret_line(LocalizedString& res, const SourceLoc& loc);

struct ParseMessage
{
SourceLoc location = {};
Expand Down Expand Up @@ -101,8 +95,15 @@ namespace vcpkg
char32_t next();
bool at_eof() const { return m_it == m_it.end(); }

std::string format_file_prefix(int row, int column) const;

private:
LocalizedString& create_error_impl(LocalizedString&& message, const SourceLoc& loc);

public:
void add_error(LocalizedString&& message);
void add_error(LocalizedString&& message, const SourceLoc& loc);
void add_error(LocalizedString&& message, const SourceLoc& loc, const LocalizedString& additional_info);

void add_warning(LocalizedString&& message);
void add_warning(LocalizedString&& message, const SourceLoc& loc);
Expand Down
1 change: 0 additions & 1 deletion include/vcpkg/base/span.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
#include <cstddef>
#include <initializer_list>
#include <type_traits>
#include <vector>

namespace vcpkg
{
Expand Down
11 changes: 11 additions & 0 deletions include/vcpkg/base/unicode.h
Original file line number Diff line number Diff line change
Expand Up @@ -197,4 +197,15 @@ namespace vcpkg::Unicode
const char* next_;
const char* last_;
};
} // namespace vcpkg::Unicode

namespace vcpkg
{
struct SourceLoc
{
Unicode::Utf8Decoder it;
Unicode::Utf8Decoder start_of_line;
int row;
int column;
};
}
15 changes: 7 additions & 8 deletions include/vcpkg/ci-feature-baseline.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,19 +19,18 @@ namespace vcpkg
Fail,
Cascade,
Pass,
FirstFree // only a marker for the last enum entry
};

struct CiFeatureBaselineEntry
{
CiFeatureBaselineState state = CiFeatureBaselineState::Pass;
std::set<std::string, std::less<>> skip_features;
std::set<std::string, std::less<>> no_separate_feature_test;
std::set<std::string, std::less<>> cascade_features;
std::set<std::string, std::less<>> failing_features;
std::vector<std::vector<std::string>> fail_configurations;
// A list of sets of features of which excatly one must be selected
std::vector<std::vector<std::string>> options;
std::set<Located<std::string>, LocatedStringLess> skip_features;
std::set<Located<std::string>, LocatedStringLess> no_separate_feature_test;
std::set<Located<std::string>, LocatedStringLess> cascade_features;
std::set<Located<std::string>, LocatedStringLess> failing_features;
std::vector<Located<std::vector<std::string>>> fail_configurations;
// A list of sets of features of which exactly one must be selected
std::vector<Located<std::vector<std::string>>> options;
bool will_fail(const InternalFeatureSet& internal_feature_set) const;
};

Expand Down
55 changes: 50 additions & 5 deletions include/vcpkg/packagespec.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

#include <vcpkg/base/expected.h>
#include <vcpkg/base/optional.h>
#include <vcpkg/base/unicode.h>

#include <vcpkg/platform-expression.h>
#include <vcpkg/triplet.h>
Expand Down Expand Up @@ -98,6 +99,48 @@ namespace vcpkg

std::string format_name_only_feature_spec(StringView package_name, StringView feature_name);

template<class T>
struct Located
{
SourceLoc loc;
T value;

template<class... Args>
explicit Located(const SourceLoc& loc, Args&&... args) : loc(loc), value(std::forward<Args>(args)...)
{
}

friend bool operator==(const Located& lhs, const Located& rhs)
{
return lhs.loc.row == rhs.loc.row && rhs.loc.column == rhs.loc.column && lhs.value == rhs.value;
}
friend bool operator!=(const Located& lhs, const Located& rhs) { return !(lhs == rhs); }
};

struct LocatedStringLess
{
using is_transparent = void;

bool operator()(const Located<std::string>& lhs, const Located<std::string>& rhs) const
{
return lhs.value < rhs.value;
}

template<class Left>
bool operator()(const Left& lhs, const Located<std::string>& rhs) const
{
return lhs < rhs.value;
}

template<class Right>
bool operator()(const Located<std::string>& lhs, const Right& rhs) const
{
return lhs.value < rhs;
}
};

Located<std::vector<std::string>> hoist_locations(std::vector<Located<std::string>>&& values);

/// In an internal feature set, "default" represents default features and missing "core" has no semantic
struct InternalFeatureSet : std::vector<std::string>
{
Expand All @@ -106,7 +149,7 @@ namespace vcpkg
bool empty_or_only_core() const;
};

InternalFeatureSet internalize_feature_list(View<std::string> fs, ImplicitDefault id);
InternalFeatureSet internalize_feature_list(View<Located<std::string>> fs, ImplicitDefault id);

///
/// <summary>
Expand Down Expand Up @@ -139,10 +182,12 @@ namespace vcpkg

struct ParsedQualifiedSpecifier
{
std::string name;
Optional<std::vector<std::string>> features;
Optional<std::string> triplet;
Optional<PlatformExpression::Expr> platform;
Located<std::string> name;
Optional<std::vector<Located<std::string>>> features;
Optional<Located<std::string>> triplet;
Optional<Located<PlatformExpression::Expr>> platform;

const PlatformExpression::Expr& platform_or_always_true() const;

/// @param id add "default" if "core" is not present
// Assumes AllowPlatformSpec::No
Expand Down
2 changes: 2 additions & 0 deletions include/vcpkg/platform-expression.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@ namespace vcpkg::PlatformExpression

friend std::string to_string(const Expr& expr);

static const Expr always_true;

private:
std::unique_ptr<detail::ExprImpl> underlying_;
};
Expand Down
Loading
Loading