mirror of
https://github.com/microsoft/vcpkg.git
synced 2024-11-27 19:59:06 +08:00
[vcpkg manifest] Manifest Implementation (#11757)
==== Changes Related to manifests ==== * Add the `manifests` feature flag * This only says whether we look for a `vcpkg.json` in the cwd, not whether we support parsing manifests (for ports, for example) * Changes to the manifests RFC * `"authors"` -> `"maintainers"` * `--x-classic-mode` -> `-manifests` \in `vcpkg_feature_flags` * reserve `"core"` in addition to `"default"`, since that's already reserved for features * Add a small helper note about what identifiers must look like * `<license-string>`: SPDX v3.8 -> v3.9 * `"feature"."description"` is allowed to be an array of strings as well * `"version"` -> `"version-string"` for forward-compat with versions RFC * Add the `--feature-flags` option * Add the ability to turn off feature flags via passing `-<feature-flag>` to `VCPKG_FEATURE_FLAGS` or `--feature-flags` * Add CMake toolchain support for manifests * Requires either: * a feature flag of `manifests` in either `Env{VCPKG_FEATURE_FLAGS}` or `VCPKG_FEATURE_FLAGS` * Passing the `VCPKG_ENABLE_MANIFESTS` option * The toolchain will install your packages to `${VCPKG_MANIFEST_DIR}/vcpkg_installed`. * Add MSBuild `vcpkg integrate install` support for manifests * Requires `VcpkgEnableManifest` to be true * `vcpkg create` creates a port that has a `vcpkg.json` instead of a `CONTROL` * argparse, abseil, 3fd, and avisynthplus ports switched to manifest from CONTROL * Add support for `--x-manifest-root`, as well as code for finding it if not passed * Add support for parsing manifests! * Add a filesystem lock! ==== Important Changes which are somewhat unrelated to manifests ==== * Rename `logicexpression.{h,cpp}` to `platform-expression.{h,cpp}` * Add `PlatformExpression` type which takes the place of the old logic expression * Split the parsing of platform expressions from checking whether they're true or not * Eagerly parse PlatformExpressions as opposed to leaving them as strings * Add checking for feature flag consistency * i.e., if `-binarycaching` is passed, you shouldn't be passing `--binarysource` * Add the `Json::Reader` type which, with the help of user-defined visitors, converts JSON to your internal type * VcpkgArgParser: place the switch names into a constant as opposed to using magic constants * In general update the parsing code so that this ^ works * Add `Port-Version` fields to CONTROL files * This replaces the existing practice of `Version: <my-version>-<port-version>` ==== Smaller changes ==== * small drive-by cleanups to some CMake * `${_VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}` -> `${CURRENT_INSTALLED_DIR}` * Remove `-analyze` when compiling with clang-cl, since that's not a supported flag (vcpkg's build system) * Add a message about which compiler is detected by vcpkg's build system machinery * Fix `Expected::then` * Convert `""` to `{}` for `std::string` and `fs::path`, to avoid a `strlen` (additionally, `.empty()` instead of `== ""`, and `.clear()`) * Add `Strings::strto` which converts strings to numeric types * Support built-in arrays and `StringView` for `Strings::join` * Add `operator<` and friends to `StringView` * Add `substr` to `StringView` * SourceParagraphParser gets some new errors
This commit is contained in:
parent
67ab6130b6
commit
1d8f0acc9c
4
.gitignore
vendored
4
.gitignore
vendored
@ -13,6 +13,8 @@
|
||||
|
||||
toolsrc/out*
|
||||
toolsrc/CMakeSettings.json
|
||||
# fuzzing
|
||||
sync_dir*
|
||||
|
||||
# User-specific files (MonoDevelop/Xamarin Studio)
|
||||
*.userprefs
|
||||
@ -331,4 +333,4 @@ __pycache__/
|
||||
############################################################
|
||||
archives
|
||||
.DS_Store
|
||||
prefab/
|
||||
prefab/
|
||||
|
@ -41,7 +41,8 @@ We collect various telemetry events such as the command line used, the time of i
|
||||
|
||||
You can see the telemetry events any command by appending `--printmetrics` after the vcpkg command line.
|
||||
|
||||
In the source code (included in `toolsrc\`), you can search for calls to the functions `track_property()` and `track_metric()` to see every specific data point we collect.
|
||||
In the source code (included in `toolsrc\`), you can search for calls to the functions `track_property()`, `track_feature()`, `track_metric()`, and `track_buildtime()`
|
||||
to see every specific data point we collect.
|
||||
|
||||
## Avoid inadvertent disclosure information
|
||||
|
||||
|
@ -34,12 +34,6 @@ rather than JSON5 or JSON with comments because JSON is the everywhere-supported
|
||||
standard. That is not necessarily true of JSON with comments. Additionally, if one needs
|
||||
to write a comment, they can do so via `"$reason"` or `"$comment"` fields.
|
||||
|
||||
### Why are `<platform-specification>`s so verbose?
|
||||
|
||||
In the initial implementation, we didn't want to do more parsing than is strictly necessary,
|
||||
especially parsing languages which aren't defined anywhere. We may add a shorter way of
|
||||
defining platform specifications in the future (more similar to those in control files).
|
||||
|
||||
## Specification
|
||||
|
||||
A manifest file shall have the name `vcpkg.json`, and shall be in the root directory of a package.
|
||||
@ -54,26 +48,28 @@ to specify the shape of a value. Note that any object may contain any directives
|
||||
a field key that starts with a `$`; these directive shall be ignored by `vcpkg`. Common
|
||||
directives may include `"$schema"`, `"$comment"`, `"$reason"`.
|
||||
|
||||
A manifest must be a top-level object, and must have at least the following properties:
|
||||
A manifest must be a top-level object, and must have at least:
|
||||
|
||||
* `"name"`: a `<package-name>`
|
||||
* `"version"`: A `string`. This will be defined further later.
|
||||
* [Semver](https://semver.org) is recommended but not required.
|
||||
* One (and only one) of the following version fields:
|
||||
* `"version-string"`: A `string`. Has no semantic meaning.
|
||||
Equivalent to `CONTROL`'s `Version:` field.
|
||||
* Other version fields will be defined by the Versions RFC
|
||||
|
||||
The simplest vcpkg.json looks like this:
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "mypackage",
|
||||
"version": "0.1.0-dev"
|
||||
"version-string": "0.1.0-dev"
|
||||
}
|
||||
```
|
||||
|
||||
Additionally, it may contain the following properties:
|
||||
* `"port-version"`: A non-negative integer. If this field doesn't exist, it's assumed to be `0`.
|
||||
* Note that this is a change from existing CONTROL files, where versions were a part of the version string
|
||||
* `"authors"`: An array of `string`s which contain the authors of a package
|
||||
* `"authors": [ "Nicole Mazzuca <nicole@example.com>", "שלום עליכם <shalom@example.com>" ]`
|
||||
* `"maintainers"`: An array of `string`s which contain the authors of a package
|
||||
* `"maintainers": [ "Nicole Mazzuca <nicole@example.com>", "שלום עליכם <shalom@example.com>" ]`
|
||||
* `"description"`: A string or array of strings containing the description of a package
|
||||
* `"description": "mypackage is a package of mine"`
|
||||
* `"homepage"`: A url which points to the homepage of a package
|
||||
@ -86,8 +82,8 @@ Additionally, it may contain the following properties:
|
||||
* `"dev-dependencies"`: An array of `<dependency>`s which are required only for developers (testing and the like)
|
||||
* `"features"`: An array of `<feature>`s that the package supports
|
||||
* `"default-features"`: An array of `<identifier>`s that correspond to features, which will be used by default.
|
||||
* `"supports"`: A `<platform-specification>`
|
||||
* `"supports": { "and": [ "win", { "not": "arm" } ] }`
|
||||
* `"supports"`: A `<platform-expression>`
|
||||
* `"supports": "windows & !arm"`
|
||||
|
||||
Any properties which are not listed, and which do not start with a `$`,
|
||||
will be warned against and are reserved for future use.
|
||||
@ -105,7 +101,7 @@ Build-Depends: glib, gettext, cairo, fontconfig, freetype, harfbuzz[glib] (!(win
|
||||
```json
|
||||
{
|
||||
"name": "pango",
|
||||
"version": "1.40.11",
|
||||
"version-string": "1.40.11",
|
||||
"port-version": 6,
|
||||
"homepage": "https://ftp.gnome.org/pub/GNOME/sources/pango/",
|
||||
"description": "Text and font handling library.",
|
||||
@ -118,22 +114,15 @@ Build-Depends: glib, gettext, cairo, fontconfig, freetype, harfbuzz[glib] (!(win
|
||||
{
|
||||
"name": "harfbuzz",
|
||||
"features": [ "glib" ],
|
||||
"platform": {
|
||||
"and": [
|
||||
{ "not": { "and": [ "windows", "static" ] } },
|
||||
{ "not": "osx" }
|
||||
]
|
||||
}
|
||||
"platform": "!(windows & static) & !osx"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
You may notice that the platform specification is fairly wordy. See [reasoning](#why-are-platform-specifications-so-verbose) for why.
|
||||
|
||||
## Behavior of the Tool
|
||||
|
||||
There will be two "modes" for vcpkg from this point forward: "classic", and "modern".
|
||||
There will be two "modes" for vcpkg from this point forward: "classic", and "manifest".
|
||||
The former will act exactly like the existing vcpkg workflow, so as to avoid breaking
|
||||
anyone. The latter will be the mode only when the user either:
|
||||
|
||||
@ -146,11 +135,10 @@ anyone. The latter will be the mode only when the user either:
|
||||
* The environment variable `VCPKG_FEATURE_FLAGS`
|
||||
* The option `--feature-flags`
|
||||
* (e.g., `--feature-flags=binarycaching,manifests`)
|
||||
* If someone wants to use classic mode and silence the warning, they can add the
|
||||
`-manifests` feature flag to disable the mode.
|
||||
|
||||
Additionally, we'll add the `--x-classic-mode` flag to allow someone to force classic
|
||||
mode.
|
||||
|
||||
When in "modern" mode, the `installed` directory will be changed to
|
||||
When in "manifest" mode, the `installed` directory will be changed to
|
||||
`<manifest-root>/vcpkg_installed` (name up for bikeshedding).
|
||||
The following commands will change behavior:
|
||||
|
||||
@ -158,49 +146,38 @@ The following commands will change behavior:
|
||||
the manifest file, and will remove any dependencies
|
||||
which are no longer in the dependency tree implied by the manifest file.
|
||||
* `vcpkg install` with port arguments will give an error.
|
||||
* `vcpkg x-clean` will be added, and will delete your `vcpkg_installed` directory.
|
||||
|
||||
The following commands will not work in modern mode, at least initially:
|
||||
The following commands will not work in manifest mode, at least initially:
|
||||
|
||||
* `vcpkg x-set-installed`: `vcpkg install` serves the same function
|
||||
* `vcpkg remove`
|
||||
* `vcpkg export`
|
||||
* `vcpkg import`
|
||||
* `vcpkg create`
|
||||
|
||||
We may add these features back for modern mode once we understand how best to
|
||||
We may add these features back for manifest mode once we understand how best to
|
||||
implement them.
|
||||
|
||||
### Behavior of the Toolchain
|
||||
|
||||
Mostly, the toolchain file stays the same; however, we shall add one public cache variable:
|
||||
Mostly, the toolchain file stays the same; however, we shall add
|
||||
two public options:
|
||||
|
||||
```cmake
|
||||
VCPKG_MANIFEST_ROOT:PATH=<path to the directory containing the vcpkg.json file>
|
||||
VCPKG_MANIFEST_MODE:BOOL=<we found a manifest>
|
||||
VCPKG_MANIFEST_INSTALL:BOOL=ON
|
||||
```
|
||||
|
||||
and one function:
|
||||
The first option either explicitly turns on, or off, manifest mode;
|
||||
otherwise, we default to looking for a manifest file in the directory
|
||||
tree upwards from the source directory.
|
||||
|
||||
```cmake
|
||||
vcpkg_acquire_dependencies(
|
||||
[TRIPLET <triplet>]
|
||||
[MANIFEST <path to manifest>]
|
||||
[INSTALL_DIRECTORY <install directory>])
|
||||
```
|
||||
The `VCPKG_MANIFEST_INSTALL` option tells the toolchain whether to
|
||||
install the packages or not -- if you wish to install the manifest
|
||||
dependencies manually, you can set this to off, and we also turn it
|
||||
off for packages installed by vcpkg.
|
||||
|
||||
which installs the dependencies required by the manifest file.
|
||||
|
||||
The default for `TRIPLET` is `VCPKG_TARGET_TRIPLET`
|
||||
(which is the default triplet for the configured system).
|
||||
For example, on x64 Windows, it defaults to `x64-windows`.
|
||||
|
||||
The default for `INSTALL_DIRECTORY` is `${CMAKE_BINARY_DIR}/vcpkg_installed`.
|
||||
|
||||
Additionally, in the course of implementation, we would like to
|
||||
look at adding the following function, but may not be able to:
|
||||
|
||||
It is almost certain that one should guard any use of this function
|
||||
by `if(EXISTS CACHE{VCPKG_MANIFEST_FILE})`.
|
||||
Additionally, if `-manifests` is set in the feature flags environment
|
||||
variable, we turn off manifest mode in the toolchain, and we act like
|
||||
the classic toolchain.
|
||||
|
||||
### Example - CMake Integration
|
||||
|
||||
@ -232,7 +209,7 @@ Therefore, in `vcpkg.json`, we'll need to depend on `fmt`:
|
||||
```json
|
||||
{
|
||||
"name": "example",
|
||||
"version": "0.0.1",
|
||||
"version-string": "0.0.1",
|
||||
"dependencies": [
|
||||
"fmt"
|
||||
]
|
||||
@ -246,11 +223,6 @@ cmake_minimum_required(VERSION 3.14)
|
||||
|
||||
project(example CXX)
|
||||
|
||||
if(EXISTS CACHE{VCPKG_MANIFEST_FILE})
|
||||
vcpkg_acquire_dependencies()
|
||||
endif()
|
||||
|
||||
|
||||
add_executable(example src/main.cxx)
|
||||
|
||||
find_package(fmt REQUIRED)
|
||||
@ -285,7 +257,9 @@ Hello, world!
|
||||
* Does not have multiple consecutive hyphens
|
||||
* Does not begin nor end with a hyphen
|
||||
* Is not a Windows filesystem reserved name
|
||||
* Is not a vcpkg reserved name: "default".
|
||||
* Is not a vcpkg reserved name: "default" or "core".
|
||||
* In other words, it must follow the regex `[a-z0-9]+(-[a-z0-9]+)*`, and must not be any of:
|
||||
* `{ prn, aux, nul, con, lpt[1-9], com[1-9], core, default }`
|
||||
* `<package-name>`: A `string` consisting of a non-zero number of `<identifier>`s, separated by `.`.
|
||||
* `a.b.c` is valid
|
||||
* `a` is valid
|
||||
@ -296,15 +270,29 @@ Hello, world!
|
||||
* `"name"`: A `<package-name>`
|
||||
* Optionally, `"features"`: an array of `<identifier>`s corresponding to features in the package.
|
||||
* Optionally, `"default-features"`: a `boolean`. If this is false, then don't use the default features of the package; equivalent to core in existing CONTROL files. If this is true, do the default thing of including the default features.
|
||||
* Optionally, `"platform"`: a `<platform-specification>`
|
||||
* Optionally, `"platform"`: a `<platform-expression>`
|
||||
* `<dependency.port>`: No extra fields are required.
|
||||
* `<license-string>`: An SPDX license expression at version 3.8.
|
||||
* `<platform-specification>`: A specification of a set of platforms; used in platform-specific dependencies and supports fields. One of:
|
||||
* `<platform-specification.exact>`: A string denoting a triplet tag like “windows”, “osx”, etc.
|
||||
* `<platform-specification.not>`: An object containing a member with key "not" and value `<platform-specification>`.
|
||||
* `<platform-specification.and>`: An object containing a member with key "and" and value array of `<platform-specification>`s.
|
||||
* `<platform-specification.or>`: An object containing a member with key "or" and value array of `<platform-specification>`s.
|
||||
* `<license-string>`: An SPDX license expression at version 3.9.
|
||||
* `<platform-expression>`: A specification of a set of platforms; used in platform-specific dependencies and supports fields. A string that is parsed as follows:
|
||||
* `<platform-expression>`:
|
||||
* `<platform-expression.not>`
|
||||
* `<platform-expression.and>`
|
||||
* `<platform-expression.or>`
|
||||
* `<platform-expression.simple>`:
|
||||
* `( <platform-expression> )`
|
||||
* `<platform-expression.identifier>`
|
||||
* `<platform-expression.identifier>`:
|
||||
* regex: `/^[a-z0-9]+$/`
|
||||
* `<platform-expression.not>`:
|
||||
* `<platform-expression.simple>`
|
||||
* `! <platform-expression.simple>`
|
||||
* `<platform-expression.and>`
|
||||
* `<platform-expression.not>`
|
||||
* `<platform-expression.and> & <platform-expression.not>`
|
||||
* `<platform-expression.or>`
|
||||
* `<platform-expression.not>`
|
||||
* `<platform-expression.or> | <platform-expression.not>`
|
||||
* `<feature>`: An object containing the following:
|
||||
* `"name"`: An `<identifier>`, the name of the feature
|
||||
* `"description"`: A `string`, the description of the feature
|
||||
* `"description"`: A `string` or array of `string`s, the description of the feature
|
||||
* Optionally, `"dependencies"`: An array of `<dependency>`s, the dependencies used by this feature
|
||||
|
@ -15,6 +15,7 @@ subject to change without notice and should be considered highly unstable.
|
||||
Non-exhaustive list of off-by-default features:
|
||||
|
||||
- `binarycaching`
|
||||
- `manifest`
|
||||
|
||||
#### EDITOR
|
||||
|
||||
|
@ -1,4 +0,0 @@
|
||||
Source: 3fd
|
||||
Version: 2.6.2-3
|
||||
Description: C++ Framework For Fast Development
|
||||
Build-Depends: boost-lockfree (windows), boost-regex (windows), poco (windows), sqlite3, rapidxml
|
22
ports/3fd/vcpkg.json
Normal file
22
ports/3fd/vcpkg.json
Normal file
@ -0,0 +1,22 @@
|
||||
{
|
||||
"name": "3fd",
|
||||
"version-string": "2.6.2",
|
||||
"port-version": 3,
|
||||
"description": "C++ Framework For Fast Development",
|
||||
"dependencies": [
|
||||
{
|
||||
"name": "boost-lockfree",
|
||||
"platform": "windows"
|
||||
},
|
||||
{
|
||||
"name": "boost-regex",
|
||||
"platform": "windows"
|
||||
},
|
||||
{
|
||||
"name": "poco",
|
||||
"platform": "windows"
|
||||
},
|
||||
"sqlite3",
|
||||
"rapidxml"
|
||||
]
|
||||
}
|
@ -1,10 +0,0 @@
|
||||
Source: abseil
|
||||
Version: 2020-03-03-7
|
||||
Homepage: https://github.com/abseil/abseil-cpp
|
||||
Description: an open-source collection designed to augment the C++ standard library.
|
||||
Abseil is an open-source collection of C++ library code designed to augment the C++ standard library. The Abseil library code is collected from Google's own C++ code base, has been extensively tested and used in production, and is the same code we depend on in our daily coding lives.
|
||||
In some cases, Abseil provides pieces missing from the C++ standard; in others, Abseil provides alternatives to the standard for special needs we've found through usage in the Google code base. We denote those cases clearly within the library code we provide you.
|
||||
Abseil is not meant to be a competitor to the standard library; we've just found that many of these utilities serve a purpose within our code base, and we now want to provide those resources to the C++ community as a whole.
|
||||
|
||||
Feature: cxx17
|
||||
Description: Enable compiler C++17.
|
18
ports/abseil/vcpkg.json
Normal file
18
ports/abseil/vcpkg.json
Normal file
@ -0,0 +1,18 @@
|
||||
{
|
||||
"name": "abseil",
|
||||
"version-string": "2020-03-03",
|
||||
"port-version": 7,
|
||||
"homepage": "https://github.com/abseil/abseil-cpp",
|
||||
"description": [
|
||||
"an open-source collection designed to augment the C++ standard library.",
|
||||
"Abseil is an open-source collection of C++ library code designed to augment the C++ standard library. The Abseil library code is collected from Google's own C++ code base, has been extensively tested and used in production, and is the same code we depend on in our daily coding lives.",
|
||||
"In some cases, Abseil provides pieces missing from the C++ standard; in others, Abseil provides alternatives to the standard for special needs we've found through usage in the Google code base. We denote those cases clearly within the library code we provide you.",
|
||||
"Abseil is not meant to be a competitor to the standard library; we've just found that many of these utilities serve a purpose within our code base, and we now want to provide those resources to the C++ community as a whole."
|
||||
],
|
||||
"features": [
|
||||
{
|
||||
"name": "cxx17",
|
||||
"description": "Enable compiler C++17."
|
||||
}
|
||||
]
|
||||
}
|
@ -1,4 +0,0 @@
|
||||
Source: argparse
|
||||
Version: 2.1
|
||||
Description: Argument parser for modern C++
|
||||
Homepage: https://github.com/p-ranav/argparse
|
7
ports/argparse/vcpkg.json
Normal file
7
ports/argparse/vcpkg.json
Normal file
@ -0,0 +1,7 @@
|
||||
{
|
||||
"name": "argparse",
|
||||
"version-string": "2.1",
|
||||
"description": "Argument parser for modern C++",
|
||||
"license": "MIT",
|
||||
"homepage": "https://github.com/p-ranav/argparse"
|
||||
}
|
@ -1,5 +0,0 @@
|
||||
Source: avisynthplus
|
||||
Version: 3.6.0
|
||||
Homepage: http://avs-plus.net/
|
||||
Description: An improved version of the AviSynth frameserver, with improved features and developer friendliness
|
||||
Supports: !(uwp|arm|static)
|
7
ports/avisynthplus/vcpkg.json
Normal file
7
ports/avisynthplus/vcpkg.json
Normal file
@ -0,0 +1,7 @@
|
||||
{
|
||||
"name": "avisynthplus",
|
||||
"version-string": "3.6.0",
|
||||
"homepage": "http://avs-plus.net/",
|
||||
"description": "An improved version of the AviSynth frameserver, with improved features and developer friendliness",
|
||||
"supports": "!(uwp | arm | static)"
|
||||
}
|
@ -1,3 +1,4 @@
|
||||
Source: cmocka
|
||||
Version: 1.1.5-1
|
||||
Version: 1.1.5
|
||||
Port-Version: 2
|
||||
Description: An elegant unit testing framework for C with support for mock objects
|
||||
|
@ -3,8 +3,8 @@ _find_package(${ARGS})
|
||||
get_filename_component(_cmocka_lib_name ${CMOCKA_LIBRARY} NAME)
|
||||
|
||||
set(CMOCKA_LIBRARY
|
||||
debug ${_VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}/debug/lib/${_cmocka_lib_name}
|
||||
optimized ${_VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}/lib/${_cmocka_lib_name}
|
||||
debug ${CURRENT_INSTALLED_DIR}/debug/lib/${_cmocka_lib_name}
|
||||
optimized ${CURRENT_INSTALLED_DIR}/lib/${_cmocka_lib_name}
|
||||
)
|
||||
|
||||
set(CMOCKA_LIBRARIES ${CMOCKA_LIBRARY})
|
||||
|
@ -1,5 +1,6 @@
|
||||
Source: libarchive
|
||||
Version: 3.4.1-3
|
||||
Version: 3.4.1
|
||||
Port-Version: 4
|
||||
Homepage: https://github.com/libarchive/libarchive
|
||||
Description: Library for reading and writing streaming archives
|
||||
Build-Depends: zlib
|
||||
|
@ -22,8 +22,8 @@ if("@VCPKG_LIBRARY_LINKAGE@" STREQUAL "static")
|
||||
list(APPEND LibArchive_LIBRARIES LibLZMA::LibLZMA)
|
||||
endif()
|
||||
if(@ENABLE_LZO@)
|
||||
find_library(LZO_LIBRARY_DEBUG NAMES lzo2d lzo2 NAMES_PER_DIR PATH_SUFFIXES lib PATHS "${_VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}/debug" NO_DEFAULT_PATH)
|
||||
find_library(LZO_LIBRARY_RELEASE NAMES lzo2 NAMES_PER_DIR PATH_SUFFIXES lib PATHS "${_VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}" NO_DEFAULT_PATH)
|
||||
find_library(LZO_LIBRARY_DEBUG NAMES lzo2d lzo2 NAMES_PER_DIR PATH_SUFFIXES lib PATHS "${CURRENT_INSTALLED_DIR}/debug" NO_DEFAULT_PATH)
|
||||
find_library(LZO_LIBRARY_RELEASE NAMES lzo2 NAMES_PER_DIR PATH_SUFFIXES lib PATHS "${CURRENT_INSTALLED_DIR}" NO_DEFAULT_PATH)
|
||||
if(LZO_LIBRARY_RELEASE)
|
||||
list(APPEND LibArchive_LIBRARIES optimized ${LZO_LIBRARY_RELEASE})
|
||||
endif()
|
||||
@ -32,8 +32,8 @@ if("@VCPKG_LIBRARY_LINKAGE@" STREQUAL "static")
|
||||
endif()
|
||||
endif()
|
||||
if(@ENABLE_ZSTD@)
|
||||
find_library(ZSTD_LIBRARY_DEBUG NAMES zstdd zstd NAMES_PER_DIR PATH_SUFFIXES lib PATHS "${_VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}/debug" NO_DEFAULT_PATH)
|
||||
find_library(ZSTD_LIBRARY_RELEASE NAMES zstd NAMES_PER_DIR PATH_SUFFIXES lib PATHS "${_VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}" NO_DEFAULT_PATH)
|
||||
find_library(ZSTD_LIBRARY_DEBUG NAMES zstdd zstd NAMES_PER_DIR PATH_SUFFIXES lib PATHS "${CURRENT_INSTALLED_DIR}/debug" NO_DEFAULT_PATH)
|
||||
find_library(ZSTD_LIBRARY_RELEASE NAMES zstd NAMES_PER_DIR PATH_SUFFIXES lib PATHS "${CURRENT_INSTALLED_DIR}" NO_DEFAULT_PATH)
|
||||
if(ZSTD_LIBRARY_RELEASE)
|
||||
list(APPEND LibArchive_LIBRARIES optimized ${ZSTD_LIBRARY_RELEASE})
|
||||
endif()
|
||||
|
@ -1,4 +1,5 @@
|
||||
Source: libiconv
|
||||
Version: 1.16-3
|
||||
Version: 1.16
|
||||
Port-Version: 4
|
||||
Homepage: https://www.gnu.org/software/libiconv/
|
||||
Description: GNU Unicode text conversion
|
||||
|
@ -2,8 +2,8 @@ include(SelectLibraryConfigurations)
|
||||
|
||||
_find_package(${ARGS})
|
||||
if(Iconv_FOUND)
|
||||
find_library(CHARSET_LIBRARY_DEBUG NAMES charsetd libcharsetd charset libcharset NAMES_PER_DIR PATH_SUFFIXES lib PATHS "${_VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}/debug" NO_DEFAULT_PATH)
|
||||
find_library(CHARSET_LIBRARY_RELEASE NAMES charset libcharset NAMES_PER_DIR PATH_SUFFIXES lib PATHS "${_VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}" NO_DEFAULT_PATH)
|
||||
find_library(CHARSET_LIBRARY_DEBUG NAMES charsetd libcharsetd charset libcharset NAMES_PER_DIR PATH_SUFFIXES lib PATHS "${CURRENT_INSTALLED_DIR}/debug" NO_DEFAULT_PATH)
|
||||
find_library(CHARSET_LIBRARY_RELEASE NAMES charset libcharset NAMES_PER_DIR PATH_SUFFIXES lib PATHS "${CURRENT_INSTALLED_DIR}" NO_DEFAULT_PATH)
|
||||
find_library(CHARSET_LIBRARY_RELEASE NAMES charset libcharset NAMES_PER_DIR PATH_SUFFIXES lib)
|
||||
select_library_configurations(CHARSET)
|
||||
list(APPEND Iconv_LIBRARIES ${CHARSET_LIBRARIES})
|
||||
|
@ -2,7 +2,7 @@
|
||||
find_library(PostgreSQL_LIBRARY_DEBUG
|
||||
NAMES pq
|
||||
PATHS
|
||||
"${_VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}/debug/lib"
|
||||
"${CURRENT_INSTALLED_DIR}/debug/lib"
|
||||
NO_DEFAULT_PATH
|
||||
)
|
||||
_find_package(${ARGS})
|
||||
|
@ -1,5 +1,6 @@
|
||||
Source: libxml2
|
||||
Version: 2.9.9-6
|
||||
Version: 2.9.9
|
||||
Port-Version: 7
|
||||
Homepage: https://xmlsoft.org/
|
||||
Description: Libxml2 is the XML C parser and toolkit developed for the Gnome project (but usable outside of the Gnome platform)
|
||||
Build-Depends: zlib, libiconv, liblzma
|
||||
|
@ -3,11 +3,11 @@ if(LibXml2_FOUND)
|
||||
find_package(LibLZMA)
|
||||
find_package(ZLIB)
|
||||
include(SelectLibraryConfigurations)
|
||||
find_library(ICONV_LIBRARY_DEBUG NAMES iconvd libiconvd iconv libiconv NAMES_PER_DIR PATH_SUFFIXES lib PATHS "${_VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}/debug" NO_DEFAULT_PATH)
|
||||
find_library(ICONV_LIBRARY_RELEASE NAMES iconv libiconv NAMES_PER_DIR PATH_SUFFIXES lib PATHS "${_VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}" NO_DEFAULT_PATH)
|
||||
find_library(ICONV_LIBRARY_DEBUG NAMES iconvd libiconvd iconv libiconv NAMES_PER_DIR PATH_SUFFIXES lib PATHS "${CURRENT_INSTALLED_DIR}/debug" NO_DEFAULT_PATH)
|
||||
find_library(ICONV_LIBRARY_RELEASE NAMES iconv libiconv NAMES_PER_DIR PATH_SUFFIXES lib PATHS "${CURRENT_INSTALLED_DIR}" NO_DEFAULT_PATH)
|
||||
find_library(ICONV_LIBRARY_RELEASE NAMES iconv libiconv NAMES_PER_DIR PATH_SUFFIXES lib)
|
||||
find_library(CHARSET_LIBRARY_DEBUG NAMES charsetd libcharsetd charset libcharset NAMES_PER_DIR PATH_SUFFIXES lib PATHS "${_VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}/debug" NO_DEFAULT_PATH)
|
||||
find_library(CHARSET_LIBRARY_RELEASE NAMES charset libcharset NAMES_PER_DIR PATH_SUFFIXES lib PATHS "${_VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}" NO_DEFAULT_PATH)
|
||||
find_library(CHARSET_LIBRARY_DEBUG NAMES charsetd libcharsetd charset libcharset NAMES_PER_DIR PATH_SUFFIXES lib PATHS "${CURRENT_INSTALLED_DIR}/debug" NO_DEFAULT_PATH)
|
||||
find_library(CHARSET_LIBRARY_RELEASE NAMES charset libcharset NAMES_PER_DIR PATH_SUFFIXES lib PATHS "${CURRENT_INSTALLED_DIR}" NO_DEFAULT_PATH)
|
||||
find_library(CHARSET_LIBRARY_RELEASE NAMES charset libcharset NAMES_PER_DIR PATH_SUFFIXES lib)
|
||||
select_library_configurations(ICONV)
|
||||
select_library_configurations(CHARSET)
|
||||
|
@ -77,10 +77,10 @@ function(find_qt_mkspec TARGET_PLATFORM_MKSPEC_OUT HOST_PLATFORM_MKSPEC_OUT EXT_
|
||||
else()
|
||||
endif()
|
||||
foreach(_triplet ${_test_triplets})
|
||||
find_program(QMAKE_PATH qmake PATHS ${_VCPKG_INSTALLED_DIR}/${_triplet}/tools/qt5/bin NO_DEFAULT_PATHS)
|
||||
message(STATUS "Checking: ${_VCPKG_INSTALLED_DIR}/${_triplet}/tools/qt5/bin. ${QMAKE_PATH}")
|
||||
find_program(QMAKE_PATH qmake PATHS ${VCPKG_INSTALLED_DIR}/${_triplet}/tools/qt5/bin NO_DEFAULT_PATHS)
|
||||
message(STATUS "Checking: ${VCPKG_INSTALLED_DIR}/${_triplet}/tools/qt5/bin. ${QMAKE_PATH}")
|
||||
if(QMAKE_PATH)
|
||||
set(_tmp_host_root "${_VCPKG_INSTALLED_DIR}/${_triplet}/tools/qt5")
|
||||
set(_tmp_host_root "${VCPKG_INSTALLED_DIR}/${_triplet}/tools/qt5")
|
||||
set(_tmp_host_qmake ${QMAKE_PATH} PARENT_SCOPE)
|
||||
message(STATUS "Qt host tools root dir within vcpkg: ${_tmp_host_root}")
|
||||
break()
|
||||
@ -98,4 +98,4 @@ function(find_qt_mkspec TARGET_PLATFORM_MKSPEC_OUT HOST_PLATFORM_MKSPEC_OUT EXT_
|
||||
set(${EXT_HOST_TOOLS_OUT} ${_tmp_host_root} PARENT_SCOPE)
|
||||
endif()
|
||||
|
||||
endfunction()
|
||||
endfunction()
|
||||
|
@ -1,5 +1,6 @@
|
||||
Source: raylib
|
||||
Version: 3.0.0
|
||||
Port-Version: 1
|
||||
Description: A simple and easy-to-use library to enjoy videogames programming
|
||||
Homepage: https://github.com/raysan5/raylib
|
||||
Supports: !(arm|uwp)
|
||||
|
@ -6,8 +6,8 @@ if(raylib_FOUND)
|
||||
get_filename_component(_raylib_lib_name ${raylib_LIBRARY} NAME)
|
||||
|
||||
set(raylib_LIBRARY
|
||||
debug ${_VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}/debug/lib/${_raylib_lib_name}
|
||||
optimized ${_VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}/lib/${_raylib_lib_name}
|
||||
debug ${CURRENT_INSTALLED_DIR}/debug/lib/${_raylib_lib_name}
|
||||
optimized ${CURRENT_INSTALLED_DIR}/lib/${_raylib_lib_name}
|
||||
)
|
||||
|
||||
set(raylib_LIBRARIES ${raylib_LIBRARY})
|
||||
|
@ -1,5 +1,6 @@
|
||||
Source: spdk
|
||||
Version: 19.01.1
|
||||
Port-Version: 1
|
||||
Description: Storage Performance Development Kit
|
||||
Build-Depends: spdk-dpdk, spdk-ipsec, spdk-isal
|
||||
Supports: linux
|
||||
Supports: linux
|
||||
|
@ -7,7 +7,7 @@ Add following to build examples/nvme/perf/perf.c
|
||||
|
||||
ADD_EXECUTABLE(SPDKTest perf.c)
|
||||
|
||||
TARGET_LINK_DIRECTORIES(SPDKTest PRIVATE ${_VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}/lib/spdk)
|
||||
TARGET_LINK_DIRECTORIES(SPDKTest PRIVATE ${VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}/lib/spdk)
|
||||
TARGET_LINK_LIBRARIES(SPDKTest PRIVATE
|
||||
SPDK::spdk_app_rpc
|
||||
SPDK::spdk_bdev
|
||||
|
63
scripts/Generate-SpdxLicenseList.ps1
Normal file
63
scripts/Generate-SpdxLicenseList.ps1
Normal file
@ -0,0 +1,63 @@
|
||||
<#
|
||||
#>
|
||||
[CmdletBinding(PositionalBinding=$False)]
|
||||
Param(
|
||||
[Parameter(Mandatory=$True)]
|
||||
[string]$Commit,
|
||||
|
||||
[Parameter()]
|
||||
[string]$GithubRepository = "spdx/license-list-data",
|
||||
|
||||
[Parameter()]
|
||||
[string]$LicensesOutFile = "$PSScriptRoot/../toolsrc/src/vcpkg/spdx-licenses.inc",
|
||||
|
||||
[Parameter()]
|
||||
[string]$ExceptionsOutFile = "$PSScriptRoot/../toolsrc/src/vcpkg/spdx-exceptions.inc"
|
||||
)
|
||||
|
||||
function Transform-JsonFile {
|
||||
[CmdletBinding()]
|
||||
Param(
|
||||
[string]$Uri,
|
||||
[string]$OutFile,
|
||||
[string]$OuterName,
|
||||
[string]$Id
|
||||
)
|
||||
|
||||
$req = Invoke-WebRequest -Uri $Uri
|
||||
|
||||
if ($req.StatusCode -ne 200)
|
||||
{
|
||||
Write-Error "Failed to GET $Uri"
|
||||
return
|
||||
}
|
||||
|
||||
$json = $req.Content | ConvertFrom-Json -Depth 10
|
||||
Write-Verbose "Writing output to $OutFile"
|
||||
|
||||
$fileContent = @(
|
||||
"// Data downloaded from $Uri",
|
||||
"// Generated by scripts/Generate-SpdxLicenseList.ps1",
|
||||
"{")
|
||||
$json.$OuterName | ForEach-Object {
|
||||
$fileContent += " `"$($_.$Id)`","
|
||||
}
|
||||
$fileContent += "}"
|
||||
|
||||
$fileContent -join "`n" | Out-File -FilePath $OutFile -Encoding 'utf8'
|
||||
}
|
||||
|
||||
$baseUrl = "https://raw.githubusercontent.com/$GithubRepository/$Commit/json"
|
||||
Write-Verbose "Getting json files from $baseUrl"
|
||||
|
||||
Transform-JsonFile `
|
||||
-Uri "$baseUrl/licenses.json" `
|
||||
-OutFile $LicensesOutFile `
|
||||
-OuterName 'licenses' `
|
||||
-Id 'licenseId'
|
||||
|
||||
Transform-JsonFile `
|
||||
-Uri "$baseUrl/exceptions.json" `
|
||||
-OutFile $ExceptionsOutFile `
|
||||
-OuterName 'exceptions' `
|
||||
-Id 'licenseExceptionId'
|
@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Rule
|
||||
Name="VcpkgGeneral"
|
||||
Name="VcpkgOptions"
|
||||
DisplayName="Vcpkg"
|
||||
PageTemplate="generic"
|
||||
Description="Vcpkg"
|
||||
@ -11,16 +11,28 @@
|
||||
<Rule.DataSource>
|
||||
<DataSource Persistence="ProjectFile" Label="Vcpkg" HasConfigurationCondition="true" />
|
||||
</Rule.DataSource>
|
||||
<BoolProperty Name="VcpkgEnabled"
|
||||
DisplayName="Use Vcpkg"
|
||||
Description="Use Vcpkg for includes and libraries."
|
||||
Category="General"
|
||||
<BoolProperty Name="VcpkgEnabled"
|
||||
DisplayName="Use Vcpkg"
|
||||
Description="Use Vcpkg for includes and libraries."
|
||||
Category="General"
|
||||
Default="true">
|
||||
</BoolProperty>
|
||||
<BoolProperty Name="VcpkgUseStatic"
|
||||
DisplayName="Use static libraries"
|
||||
Description="Vcpkg can build static libraries (e.g. x64-windows-static). This options changes the default triplet to use these static libraries by appending -static to $(VcpkgTriplet). This will not be shown in the evaluation of the Triplet within the UI."
|
||||
Category="General"
|
||||
<BoolProperty Name="VcpkgEnableManifest"
|
||||
DisplayName="Use Vcpkg Manifest"
|
||||
Description="Use the vcpkg manifest file to define your dependencies."
|
||||
Category="General"
|
||||
Default="false">
|
||||
</BoolProperty>
|
||||
<BoolProperty Name="VcpkgManifestInstall"
|
||||
DisplayName="Install vcpkg dependencies"
|
||||
Description="Install dependencies from the vcpkg manifest."
|
||||
Category="General"
|
||||
Default="true">
|
||||
</BoolProperty>
|
||||
<BoolProperty Name="VcpkgUseStatic"
|
||||
DisplayName="Use static libraries"
|
||||
Description="Vcpkg can build static libraries (e.g. x64-windows-static). This options changes the default triplet to use these static libraries by appending -static to $(VcpkgTriplet). This will not be shown in the evaluation of the Triplet within the UI."
|
||||
Category="General"
|
||||
Default="false">
|
||||
</BoolProperty>
|
||||
<BoolProperty Name="VcpkgAutoLink"
|
||||
@ -42,11 +54,19 @@
|
||||
Subtype="folder"
|
||||
Visible="false">
|
||||
</StringProperty>
|
||||
<StringProperty Name="VcpkgManifestRoot"
|
||||
DisplayName="Vcpkg Manifest Root"
|
||||
Description="The path to the directory which contains the manifest file, and the vcpkg_installed directory."
|
||||
Category="General"
|
||||
Subtype="folder"
|
||||
Visible="false">
|
||||
</StringProperty>
|
||||
<StringProperty Name="VcpkgCurrentInstalledDir"
|
||||
DisplayName="Package install directory"
|
||||
Description="Defines the direct path to the installed Vcpkg packages. Only change this if you know what you are doing!"
|
||||
Category="General"
|
||||
Subtype="folder">
|
||||
Subtype="folder"
|
||||
Visible="false">
|
||||
</StringProperty>
|
||||
<EnumProperty Name="VcpkgConfiguration" DisplayName="Vcpkg Configuration" Description="Specifies if release or debug libraries build with vcpkg should be used." Category="General">
|
||||
<EnumValue Name="Release" Switch="Release" DisplayName="Release" Description="Uses release libraries">
|
||||
@ -54,4 +74,4 @@
|
||||
<EnumValue Name="Debug" Switch="Debug" DisplayName="Debug" Description="Uses debug libraries">
|
||||
</EnumValue>
|
||||
</EnumProperty>
|
||||
</Rule>
|
||||
</Rule>
|
||||
|
@ -25,11 +25,17 @@
|
||||
<VcpkgPlatformTarget Condition="'$(VcpkgPlatformTarget)' == ''">$(Platform)</VcpkgPlatformTarget>
|
||||
</PropertyGroup>
|
||||
|
||||
<!-- Manifest files -->
|
||||
<PropertyGroup>
|
||||
<VcpkgEnableManifest Condition="'$(VcpkgEnableManifest)' == ''">false</VcpkgEnableManifest>
|
||||
<VcpkgManifestInstall Condition="'$(VcpkgManifestInstall)' == ''">true</VcpkgManifestInstall>
|
||||
<VcpkgManifestRoot>$([MSbuild]::GetDirectoryNameOfFileAbove($(MSBuildProjectDirectory), vcpkg.json))</VcpkgManifestRoot>
|
||||
</PropertyGroup>
|
||||
|
||||
<!-- Set other defaults-->
|
||||
<PropertyGroup>
|
||||
<VcpkgUserTriplet Condition="'$(VcpkgUserTriplet)' == ''">$(VcpkgPlatformTarget)-$(VcpkgOSTarget)</VcpkgUserTriplet>
|
||||
<VcpkgTriplet Condition="'$(VcpkgTriplet)' == ''">$(VcpkgUserTriplet)</VcpkgTriplet>
|
||||
<VcpkgCurrentInstalledDir Condition="'$(VcpkgCurrentInstalledDir)' == ''">$(VcpkgRoot)\installed\$(VcpkgTriplet)\</VcpkgCurrentInstalledDir>
|
||||
<VcpkgPageSchema>$(VcpkgRoot)\scripts\buildsystems\msbuild\vcpkg-general.xml</VcpkgPageSchema>
|
||||
</PropertyGroup>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
|
@ -7,6 +7,9 @@
|
||||
<VcpkgRoot Condition="'$(VcpkgRoot)' == ''">$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), .vcpkg-root))</VcpkgRoot>
|
||||
<VcpkgConfiguration Condition="'$(VcpkgConfiguration)' == ''">$(Configuration)</VcpkgConfiguration>
|
||||
<VcpkgPageSchema Condition="'$(VcpkgPageSchema)' == ''">$(VcpkgRoot)\scripts\buildsystems\msbuild\vcpkg-general.xml</VcpkgPageSchema>
|
||||
<VcpkgEnableManifest Condition="'$(VcpkgEnableManifest)' == ''">false</VcpkgEnableManifest>
|
||||
<VcpkgManifestInstall Condition="'$(VcpkgManifestInstall)' == ''">true</VcpkgManifestInstall>
|
||||
<VcpkgManifestRoot>$([MSbuild]::GetDirectoryNameOfFileAbove($(MSBuildProjectDirectory), vcpkg.json))</VcpkgManifestRoot>
|
||||
</PropertyGroup>
|
||||
|
||||
<!-- Set default OS Target-->
|
||||
@ -22,7 +25,7 @@
|
||||
<VcpkgUserTriplet Condition="'$(VcpkgUserTriplet)' == ''">$(PlatformTarget)-$(VcpkgOSTarget)</VcpkgUserTriplet>
|
||||
<VcpkgTriplet Condition="'$(VcpkgTriplet)' == ''">$(VcpkgUserTriplet)</VcpkgTriplet>
|
||||
<VcpkgCurrentInstalledDir Condition="'$(VcpkgCurrentInstalledDir)' == ''">$(VcpkgRoot)\installed\$(VcpkgTriplet)\</VcpkgCurrentInstalledDir>
|
||||
</PropertyGroup>
|
||||
</PropertyGroup>
|
||||
|
||||
<!--Import property page for vcpkg -->
|
||||
<ItemGroup Condition="'$(VcpkgPageSchema)' != '' ">
|
||||
@ -31,19 +34,24 @@
|
||||
</PropertyPageSchema>
|
||||
</ItemGroup>
|
||||
|
||||
<!-- Update properties if using static libs-->
|
||||
<PropertyGroup Condition="'$(VcpkgUseStatic)' == 'true'">
|
||||
<VcpkgTripletTmp>$(VcpkgUserTriplet)</VcpkgTripletTmp>
|
||||
<VcpkgTriplet>$(VcpkgTripletTmp)-static</VcpkgTriplet>
|
||||
<VcpkgCurrentInstalledDir Condition="'$(VcpkgCurrentInstalledDir)' == '$(VcpkgRoot)\installed\$(VcpkgTripletTmp)\'">$(VcpkgRoot)\installed\$(VcpkgTriplet)\</VcpkgCurrentInstalledDir>
|
||||
<VcpkgTripletTmp />
|
||||
<!-- Update properties if manifests are enabled or disabled -->
|
||||
<PropertyGroup Condition="'$(VcpkgEnableManifest)' == 'true'">
|
||||
<VcpkgInstalledDir>$(VcpkgManifestRoot)\vcpkg_installed\</VcpkgInstalledDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(VcpkgEnableManifest)' != 'true'">
|
||||
<VcpkgInstalledDir>$(VcpkgRoot)\installed\</VcpkgInstalledDir>
|
||||
</PropertyGroup>
|
||||
|
||||
<!-- Update properties if using static libs-->
|
||||
<PropertyGroup Condition="'$(VcpkgUseStatic)' == 'true'">
|
||||
<VcpkgTriplet>$(VcpkgUserTriplet)-static</VcpkgTriplet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(VcpkgUseStatic)' != 'true'">
|
||||
<VcpkgTripletTmp>$(VcpkgTriplet)</VcpkgTripletTmp>
|
||||
<VcpkgTriplet Condition="'$(VcpkgTriplet)'!='$(VcpkgUserTriplet)'">$(VcpkgUserTriplet)</VcpkgTriplet>
|
||||
<VcpkgCurrentInstalledDir Condition="'$(VcpkgCurrentInstalledDir)' == '$(VcpkgRoot)\installed\$(VcpkgTripletTmp)\'">$(VcpkgRoot)\installed\$(VcpkgUserTriplet)\</VcpkgCurrentInstalledDir>
|
||||
<VcpkgTripletTmp />
|
||||
<VcpkgTriplet>$(VcpkgUserTriplet)</VcpkgTriplet>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(VcpkgCurrentInstalledDir)' == ''">
|
||||
<VcpkgCurrentInstalledDir>$(VcpkgInstalledDir)$(VcpkgTriplet)</VcpkgCurrentInstalledDir>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(VcpkgEnabled)' == 'true'">
|
||||
@ -51,8 +59,9 @@
|
||||
<VcpkgNormalizedConfiguration Condition="$(VcpkgConfiguration.StartsWith('Release')) or '$(VcpkgConfiguration)' == 'RelWithDebInfo' or '$(VcpkgConfiguration)' == 'MinSizeRel'">Release</VcpkgNormalizedConfiguration>
|
||||
<VcpkgRoot Condition="!$(VcpkgRoot.EndsWith('\'))">$(VcpkgRoot)\</VcpkgRoot>
|
||||
<VcpkgCurrentInstalledDir Condition="!$(VcpkgCurrentInstalledDir.EndsWith('\'))">$(VcpkgCurrentInstalledDir)\</VcpkgCurrentInstalledDir>
|
||||
<VcpkgManifestRoot Condition="!$(VcpkgManifestRoot.EndsWith('\'))">$(VcpkgManifestRoot)\</VcpkgManifestRoot>
|
||||
<VcpkgApplocalDeps Condition="'$(VcpkgApplocalDeps)' == ''">true</VcpkgApplocalDeps>
|
||||
<!-- Deactivate Autolinking if lld is used as a linker. (Until a better way to solve the problem is found!).
|
||||
<!-- Deactivate Autolinking if lld is used as a linker. (Until a better way to solve the problem is found!).
|
||||
Tried to add /lib as a parameter to the linker call but was unable to find a way to pass it as the first parameter. -->
|
||||
<VcpkgAutoLink Condition="'$(UseLldLink)' == 'true' and '$(VcpkgAutoLink)' == ''">false</VcpkgAutoLink>
|
||||
</PropertyGroup>
|
||||
@ -72,12 +81,22 @@
|
||||
</ResourceCompile>
|
||||
</ItemDefinitionGroup>
|
||||
|
||||
<Target Name="VcpkgCheckManifestRoot" Condition="'$(VcpkgEnabled)' == 'true'" BeforeTargets="VcpkgInstallManifestDependencies">
|
||||
<Error Text="The Vcpkg manifest was enabled, but we couldn't find a manifest file (vcpkg.json) in any directories above $(MSBuildProjectDirectory). Please add a manifest, disable manifests in your properties page, or pass /p:VcpkgEnableManifest=false." Condition="'$(VcpkgEnableManifest)' == 'true' and '$(VcpkgManifestRoot)' == ''" />
|
||||
<Message Text="The Vcpkg manifest was disabled, but we found a manifest file in $(VcpkgManifestRoot). You may want to enable vcpkg manifests in your properties page or pass /p:VcpkgEnableManifest=true to the msbuild invocation." Importance="High" Condition="'$(VcpkgEnableManifest)' != 'true' and '$(VcpkgManifestRoot)' != ''" />
|
||||
</Target>
|
||||
|
||||
<Target Name="VcpkgTripletSelection" BeforeTargets="ClCompile">
|
||||
<Message Text="Using triplet "$(VcpkgTriplet)" from "$(VcpkgCurrentInstalledDir)"" Importance="High" Condition="'$(VcpkgEnabled)' == 'true'"/>
|
||||
<Message Text="Not using Vcpkg because VcpkgEnabled is "$(VcpkgEnabled)"" Importance="High" Condition="'$(VcpkgEnabled)' != 'true'"/>
|
||||
<Message Text="Vcpkg is unable to link because we cannot decide between Release and Debug libraries. Please define the property VcpkgConfiguration to be 'Release' or 'Debug' (currently '$(VcpkgConfiguration)')." Importance="High" Condition="'$(VcpkgEnabled)' == 'true' and '$(VcpkgNormalizedConfiguration)' == ''"/>
|
||||
</Target>
|
||||
|
||||
<Target Name="VcpkgInstallManifestDependencies" Condition="'$(VcpkgEnabled)' == 'true' and '$(VcpkgEnableManifest)' == 'true' and '$(VcpkgManifestInstall)' == 'true'" BeforeTargets="ClCompile">
|
||||
<Message Text="Installing vcpkg dependencies" Importance="High" />
|
||||
<Exec Command="%22$(VcpkgRoot)vcpkg.exe%22 install --triplet %22$(VcpkgTriplet)%22 --vcpkg-root %22$(VcpkgRoot)\%22 %22--x-manifest-root=$(VcpkgManifestRoot)\%22 %22--x-install-root=$(VcpkgInstalledDir)\%22 --binarycaching" StandardOutputImportance="High" />
|
||||
</Target>
|
||||
|
||||
<Target Name="AppLocalFromInstalled" AfterTargets="CopyFilesToOutputDirectory" BeforeTargets="CopyLocalFilesOutputGroup;RegisterOutput" Condition="'$(VcpkgEnabled)' == 'true' and '$(VcpkgApplocalDeps)' == 'true'">
|
||||
<WriteLinesToFile
|
||||
File="$(TLogLocation)$(ProjectName).write.1u.tlog"
|
||||
@ -98,4 +117,4 @@
|
||||
<ReferenceCopyLocalPaths Include="@(VcpkgAppLocalDLLs)" />
|
||||
</ItemGroup>
|
||||
</Target>
|
||||
</Project>
|
||||
</Project>
|
||||
|
@ -5,6 +5,46 @@ mark_as_advanced(CMAKE_TOOLCHAIN_FILE)
|
||||
option(VCPKG_VERBOSE "Enables messages from the VCPKG toolchain for debugging purposes." OFF)
|
||||
mark_as_advanced(VCPKG_VERBOSE)
|
||||
|
||||
function(_vcpkg_get_directory_name_of_file_above OUT DIRECTORY FILENAME)
|
||||
if(DEFINED ${OUT})
|
||||
return()
|
||||
endif()
|
||||
|
||||
set(_vcpkg_get_dir_candidate ${DIRECTORY})
|
||||
while(IS_DIRECTORY ${_vcpkg_get_dir_candidate} AND NOT DEFINED _vcpkg_get_dir_out)
|
||||
if(EXISTS ${_vcpkg_get_dir_candidate}/${FILENAME})
|
||||
set(_vcpkg_get_dir_out ${_vcpkg_get_dir_candidate})
|
||||
else()
|
||||
get_filename_component(_vcpkg_get_dir_candidate_tmp ${_vcpkg_get_dir_candidate} DIRECTORY)
|
||||
if(_vcpkg_get_dir_candidate STREQUAL _vcpkg_get_dir_candidate_tmp) # we've reached the root
|
||||
set(_vcpkg_get_dir_out "${OUT}-NOTFOUND")
|
||||
else()
|
||||
set(_vcpkg_get_dir_candidate ${_vcpkg_get_dir_candidate_tmp})
|
||||
endif()
|
||||
endif()
|
||||
endwhile()
|
||||
|
||||
set(${OUT} ${_vcpkg_get_dir_out} CACHE INTERNAL "_vcpkg_get_directory_name_of_file_above: ${OUT}")
|
||||
endfunction()
|
||||
|
||||
_vcpkg_get_directory_name_of_file_above(_VCPKG_MANIFEST_DIR ${CMAKE_CURRENT_SOURCE_DIR} "vcpkg.json")
|
||||
if(_VCPKG_MANIFEST_DIR)
|
||||
set(_VCPKG_MANIFEST_MODE_DEFAULT ON)
|
||||
else()
|
||||
set(_VCPKG_MANIFEST_MODE_DEFAULT OFF)
|
||||
endif()
|
||||
|
||||
option(VCPKG_MANIFEST_MODE "Set vcpkg to manifest mode" ${_VCPKG_MANIFEST_MODE_DEFAULT})
|
||||
|
||||
if(NOT _VCPKG_MANIFEST_DIR AND VCPKG_MANIFEST_MODE)
|
||||
message(FATAL_ERROR
|
||||
"vcpkg manifest mode was enabled, but we couldn't find a manifest file (vcpkg.json) "
|
||||
"in any directories above ${CMAKE_CURRENT_SOURCE_DIR}. Please add a manifest, or "
|
||||
"disable manifests by turning off VCPKG_MANIFEST_MODE.")
|
||||
endif()
|
||||
|
||||
option(VCPKG_MANIFEST_INSTALL "Install packages from the manifest" ON)
|
||||
|
||||
# Determine whether the toolchain is loaded during a try-compile configuration
|
||||
get_property(_CMAKE_IN_TRY_COMPILE GLOBAL PROPERTY IN_TRY_COMPILE)
|
||||
|
||||
@ -144,19 +184,28 @@ if(NOT DEFINED _VCPKG_ROOT_DIR)
|
||||
while(IS_DIRECTORY ${_VCPKG_ROOT_DIR_CANDIDATE} AND NOT EXISTS "${_VCPKG_ROOT_DIR_CANDIDATE}/.vcpkg-root")
|
||||
get_filename_component(_VCPKG_ROOT_DIR_TEMP ${_VCPKG_ROOT_DIR_CANDIDATE} DIRECTORY)
|
||||
if (_VCPKG_ROOT_DIR_TEMP STREQUAL _VCPKG_ROOT_DIR_CANDIDATE) # If unchanged, we have reached the root of the drive
|
||||
message(FATAL_ERROR "Could not find .vcpkg-root")
|
||||
else()
|
||||
SET(_VCPKG_ROOT_DIR_CANDIDATE ${_VCPKG_ROOT_DIR_TEMP})
|
||||
endif()
|
||||
endwhile()
|
||||
set(_VCPKG_ROOT_DIR ${_VCPKG_ROOT_DIR_CANDIDATE} CACHE INTERNAL "Vcpkg root directory")
|
||||
endif()
|
||||
if (NOT DEFINED _VCPKG_INSTALLED_DIR)
|
||||
set(_VCPKG_INSTALLED_DIR ${_VCPKG_ROOT_DIR}/installed)
|
||||
|
||||
_vcpkg_get_directory_name_of_file_above(_VCPKG_ROOT_DIR ${CMAKE_CURRENT_LIST_DIR} ".vcpkg-root")
|
||||
if(NOT _VCPKG_ROOT_DIR)
|
||||
message(FATAL_ERROR "Could not find .vcpkg-root")
|
||||
endif()
|
||||
|
||||
if(NOT EXISTS "${_VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}" AND NOT _CMAKE_IN_TRY_COMPILE AND NOT VCPKG_SUPPRESS_INSTALLED_LIBRARIES_WARNING)
|
||||
message(WARNING "There are no libraries installed for the Vcpkg triplet ${VCPKG_TARGET_TRIPLET}.")
|
||||
if (NOT DEFINED _VCPKG_INSTALLED_DIR)
|
||||
if(_VCPKG_MANIFEST_DIR)
|
||||
set(_VCPKG_INSTALLED_DIR ${_VCPKG_MANIFEST_DIR}/vcpkg_installed)
|
||||
else()
|
||||
set(_VCPKG_INSTALLED_DIR ${_VCPKG_ROOT_DIR}/installed)
|
||||
endif()
|
||||
|
||||
set(_VCPKG_INSTALLED_DIR ${_VCPKG_INSTALLED_DIR}
|
||||
CACHE PATH
|
||||
"The directory which contains the installed libraries for each triplet")
|
||||
endif()
|
||||
|
||||
if(CMAKE_BUILD_TYPE MATCHES "^[Dd][Ee][Bb][Uu][Gg]$" OR NOT DEFINED CMAKE_BUILD_TYPE) #Debug build: Put Debug paths before Release paths.
|
||||
@ -218,6 +267,31 @@ foreach(_VCPKG_TOOLS_DIR ${_VCPKG_TOOLS_DIRS})
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
|
||||
# CMAKE_EXECUTABLE_SUFFIX is not yet defined
|
||||
if (CMAKE_HOST_SYSTEM_NAME STREQUAL "Windows")
|
||||
set(_VCPKG_EXECUTABLE_SUFFIX ".exe")
|
||||
else()
|
||||
set(_VCPKG_EXECUTABLE_SUFFIX "")
|
||||
endif()
|
||||
|
||||
if(VCPKG_MANIFEST_MODE AND VCPKG_MANIFEST_INSTALL AND NOT _CMAKE_IN_TRY_COMPILE)
|
||||
execute_process(
|
||||
COMMAND "${_VCPKG_ROOT_DIR}/vcpkg${_VCPKG_EXECUTABLE_SUFFIX}" install
|
||||
--triplet ${VCPKG_TARGET_TRIPLET}
|
||||
--vcpkg-root ${_VCPKG_ROOT_DIR}
|
||||
--x-manifest-root=${_VCPKG_MANIFEST_DIR}
|
||||
--x-install-root=${_VCPKG_INSTALLED_DIR}
|
||||
--binarycaching
|
||||
RESULT_VARIABLE _VCPKG_INSTALL_RESULT)
|
||||
if (NOT _VCPKG_INSTALL_RESULT EQUAL 0)
|
||||
message(FATAL_ERROR "vcpkg install failed")
|
||||
endif()
|
||||
set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS
|
||||
"${_VCPKG_MANIFEST_DIR}/vcpkg.json"
|
||||
"${_VCPKG_INSTALLED_DIR}/vcpkg/status")
|
||||
endif()
|
||||
|
||||
option(VCPKG_APPLOCAL_DEPS "Automatically copy dependencies into the output directory for executables." ON)
|
||||
function(add_executable name)
|
||||
_add_executable(${ARGV})
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -96,6 +96,7 @@ function(vcpkg_build_msbuild)
|
||||
/p:VCPkgLocalAppDataDisabled=true
|
||||
/p:UseIntelMKL=No
|
||||
/p:WindowsTargetPlatformVersion=${_csc_TARGET_PLATFORM_VERSION}
|
||||
/p:VcpkgManifestInstall=false
|
||||
/m
|
||||
)
|
||||
|
||||
|
@ -238,6 +238,7 @@ function(vcpkg_configure_cmake)
|
||||
"-DCMAKE_INSTALL_BINDIR:STRING=bin"
|
||||
"-D_VCPKG_ROOT_DIR=${VCPKG_ROOT_DIR}"
|
||||
"-D_VCPKG_INSTALLED_DIR=${_VCPKG_INSTALLED_DIR}"
|
||||
"-DVCPKG_MANIFEST_INSTALL=OFF"
|
||||
)
|
||||
|
||||
if(DEFINED ARCH)
|
||||
|
@ -13,7 +13,7 @@
|
||||
##
|
||||
## ## Parameters
|
||||
## ### RELEASE_FILES
|
||||
## Specifies a list of files to apply the fixes for release paths.
|
||||
## Specifies a list of files to apply the fixes for release paths.
|
||||
## Defaults to every *.pc file in the folder ${CURRENT_PACKAGES_DIR} without ${CURRENT_PACKAGES_DIR}/debug/
|
||||
##
|
||||
## ### DEBUG_FILES
|
||||
@ -22,11 +22,11 @@
|
||||
##
|
||||
## ### SYSTEM_PACKAGES
|
||||
## If the *.pc file contains system packages outside vcpkg these need to be listed here.
|
||||
## Since vcpkg checks the existence of all required packages within vcpkg.
|
||||
## Since vcpkg checks the existence of all required packages within vcpkg.
|
||||
##
|
||||
## ### SYSTEM_LIBRARIES
|
||||
## If the *.pc file contains system libraries outside vcpkg these need to be listed here.
|
||||
## VCPKG checks every -l flag for the existence of the required library within vcpkg.
|
||||
## VCPKG checks every -l flag for the existence of the required library within vcpkg.
|
||||
##
|
||||
## ### IGNORE_FLAGS
|
||||
## If the *.pc file contains flags in the lib field which are not libraries. These can be listed here
|
||||
@ -36,7 +36,7 @@
|
||||
##
|
||||
## ## Examples
|
||||
##
|
||||
## Just call vcpkg_fixup_pkgconfig() after any install step which installs *.pc files.
|
||||
## Just call vcpkg_fixup_pkgconfig() after any install step which installs *.pc files.
|
||||
function(vcpkg_fixup_pkgconfig_check_libraries _config _contents_var _system_libs _system_packages _ignore_flags)
|
||||
set(CMAKE_FIND_LIBRARY_SUFFIXES_BACKUP ${CMAKE_FIND_LIBRARY_SUFFIXES})
|
||||
list(APPEND CMAKE_FIND_LIBRARY_SUFFIXES ".lib;.dll.a;.a")
|
||||
@ -64,7 +64,7 @@ function(vcpkg_fixup_pkgconfig_check_libraries _config _contents_var _system_lib
|
||||
string(REPLACE "-l" "" _system_lib "${_system_lib}")
|
||||
list(APPEND _system_lib_normalized "${_system_lib}")
|
||||
endforeach()
|
||||
|
||||
|
||||
## Extra libraries:
|
||||
string(REGEX MATCH "Libs:[^\n#]+" _libs "${_contents}")
|
||||
#message(STATUS "LIB LINE: ${_libs}")
|
||||
@ -133,9 +133,9 @@ function(vcpkg_fixup_pkgconfig_check_libraries _config _contents_var _system_lib
|
||||
endif()
|
||||
else()
|
||||
#handle special cases
|
||||
if(_lib STREQUAL "-pthread" OR _lib STREQUAL "-pthreads")
|
||||
if(_lib STREQUAL "-pthread" OR _lib STREQUAL "-pthreads")
|
||||
# Replace with VCPKG version?
|
||||
#VCPKG should probably rename one of the pthread versions to avoid linking against system pthread?
|
||||
#VCPKG should probably rename one of the pthread versions to avoid linking against system pthread?
|
||||
# set(PTHREAD_SUFFIX )
|
||||
# if("${_config}" STREQUAL "DEBUG")
|
||||
# file(GLOB PTHREAD_LIB "${CURRENT_INSTALLED_DIR}/debug/lib/${VCPKG_TARGET_STATIC_LIBRARY_PREFIX}pthread*C3d.*")
|
||||
@ -165,18 +165,18 @@ function(vcpkg_fixup_pkgconfig_check_libraries _config _contents_var _system_lib
|
||||
string(REGEX REPLACE "[\t ]*,[\t ]*" ";" _pkg_private_list_tmp "${_pkg_private_list_tmp}")
|
||||
string(REGEX REPLACE "[\t ]*(>|=)+[\t ]*([0-9]+|\\.)+" " " _pkg_private_list_tmp "${_pkg_private_list_tmp}")
|
||||
string(REGEX REPLACE "[\t ]+" ";" _pkg_private_list_tmp "${_pkg_private_list_tmp}")
|
||||
|
||||
|
||||
debug_message("Required packages: ${_pkg_list_tmp}")
|
||||
debug_message("Required private packages: ${_pkg_private_list_tmp}")
|
||||
|
||||
|
||||
#message(STATUS "System packages: ${_system_packages}")
|
||||
foreach(_package ${_pkg_list_tmp} ${_pkg_private_list_tmp})
|
||||
debug_message("Searching for package: ${_package}")
|
||||
set(PKG_CHECK ON)
|
||||
if(NOT "${_system_packages}" STREQUAL "")
|
||||
#message(STATUS "Checking ${_package} for SYSTEM PACKAGE: ${_system_packages}")
|
||||
#message(STATUS "Checking ${_package} for SYSTEM PACKAGE: ${_system_packages}")
|
||||
if("${_system_packages}" MATCHES "${_package}" )
|
||||
debug_message("Package ${_package} is SYSTEM PACKAGE!")
|
||||
debug_message("Package ${_package} is SYSTEM PACKAGE!")
|
||||
set(PKG_CHECK OFF)
|
||||
endif()
|
||||
endif()
|
||||
@ -193,7 +193,7 @@ endfunction()
|
||||
|
||||
function(vcpkg_fixup_pkgconfig)
|
||||
cmake_parse_arguments(_vfpkg "" "" "RELEASE_FILES;DEBUG_FILES;SYSTEM_LIBRARIES;SYSTEM_PACKAGES;IGNORE_FLAGS" ${ARGN})
|
||||
|
||||
|
||||
if(VCPKG_SYSTEM_LIBRARIES)
|
||||
list(APPEND _vfpkg_SYSTEM_LIBRARIES ${VCPKG_SYSTEM_LIBRARIES})
|
||||
endif()
|
||||
@ -206,16 +206,16 @@ function(vcpkg_fixup_pkgconfig)
|
||||
file(GLOB_RECURSE _vfpkg_RELEASE_FILES "${CURRENT_PACKAGES_DIR}/**/*.pc")
|
||||
list(FILTER _vfpkg_RELEASE_FILES EXCLUDE REGEX "${CURRENT_PACKAGES_DIR}/debug/")
|
||||
endif()
|
||||
|
||||
|
||||
if(NOT _vfpkg_DEBUG_FILES)
|
||||
file(GLOB_RECURSE _vfpkg_DEBUG_FILES "${CURRENT_PACKAGES_DIR}/debug/**/*.pc")
|
||||
list(FILTER _vfpkg_DEBUG_FILES INCLUDE REGEX "${CURRENT_PACKAGES_DIR}/debug/")
|
||||
endif()
|
||||
|
||||
#Absolute Unix like paths
|
||||
|
||||
#Absolute Unix like paths
|
||||
string(REGEX REPLACE "([a-zA-Z]):/" "/\\1/" _VCPKG_PACKAGES_DIR "${CURRENT_PACKAGES_DIR}")
|
||||
string(REGEX REPLACE "([a-zA-Z]):/" "/\\1/" _VCPKG_INSTALLED_DIR "${CURRENT_INSTALLED_DIR}")
|
||||
|
||||
|
||||
message(STATUS "Fixing pkgconfig - release")
|
||||
debug_message("Files: ${_vfpkg_RELEASE_FILES}")
|
||||
foreach(_file ${_vfpkg_RELEASE_FILES})
|
||||
@ -235,7 +235,7 @@ function(vcpkg_fixup_pkgconfig)
|
||||
file(WRITE "${_file}" "${_contents}")
|
||||
unset(PKG_LIB_SEARCH_PATH)
|
||||
endforeach()
|
||||
|
||||
|
||||
message(STATUS "Fixing pkgconfig - debug")
|
||||
debug_message("Files: ${_vfpkg_DEBUG_FILES}")
|
||||
foreach(_file ${_vfpkg_DEBUG_FILES})
|
||||
@ -257,17 +257,17 @@ function(vcpkg_fixup_pkgconfig)
|
||||
string(REPLACE "debug/lib" "lib" _contents "${_contents}") # the prefix will contain the debug keyword
|
||||
|
||||
string(REGEX REPLACE "^prefix=(\\\\)?\\\${prefix}(/debug)?" "prefix=\${pcfiledir}/${RELATIVE_PC_PATH}" _contents "${_contents}") # make pc file relocatable
|
||||
string(REPLACE "\${prefix}/debug" "\${prefix}" _contents "${_contents}") # replace remaining debug paths if they exist.
|
||||
string(REPLACE "\${prefix}/debug" "\${prefix}" _contents "${_contents}") # replace remaining debug paths if they exist.
|
||||
vcpkg_fixup_pkgconfig_check_libraries("DEBUG" _contents "${_vfpkg_SYSTEM_LIBRARIES}" "${_vfpkg_SYSTEM_PACKAGES}" "${_vfpkg_IGNORE_FLAGS}")
|
||||
file(WRITE "${_file}" "${_contents}")
|
||||
unset(PKG_LIB_SEARCH_PATH)
|
||||
endforeach()
|
||||
message(STATUS "Fixing pkgconfig --- finished")
|
||||
|
||||
set(VCPKG_FIXUP_PKGCONFIG_CALLED TRUE CACHE INTERNAL "See below" FORCE)
|
||||
# Variable to check if this function has been called!
|
||||
|
||||
set(VCPKG_FIXUP_PKGCONFIG_CALLED TRUE CACHE INTERNAL "See below" FORCE)
|
||||
# Variable to check if this function has been called!
|
||||
# Theoreotically vcpkg could look for *.pc files and automatically call this function
|
||||
# or check if this function has been called if *.pc files are detected.
|
||||
# or check if this function has been called if *.pc files are detected.
|
||||
# The same is true for vcpkg_fixup_cmake_targets
|
||||
endfunction()
|
||||
|
||||
|
@ -138,6 +138,7 @@ function(vcpkg_install_msbuild)
|
||||
/p:WindowsTargetPlatformVersion=${_csc_TARGET_PLATFORM_VERSION}
|
||||
/p:VcpkgTriplet=${TARGET_TRIPLET}
|
||||
"/p:VcpkgCurrentInstalledDir=${CURRENT_INSTALLED_DIR}"
|
||||
/p:VcpkgManifestInstall=false
|
||||
/m
|
||||
)
|
||||
|
||||
|
@ -43,6 +43,9 @@ if(CMD MATCHES "^BUILD$")
|
||||
if(NOT EXISTS ${CURRENT_PORT_DIR}/portfile.cmake)
|
||||
message(FATAL_ERROR "Port is missing portfile: ${CURRENT_PORT_DIR}/portfile.cmake")
|
||||
endif()
|
||||
if(NOT EXISTS ${CURRENT_PORT_DIR}/CONTROL AND NOT EXISTS ${CURRENT_PORT_DIR}/vcpkg.json)
|
||||
message(FATAL_ERROR "Port is missing control or manifest file: ${CURRENT_PORT_DIR}/{CONTROL,vcpkg.json}")
|
||||
endif()
|
||||
|
||||
unset(PACKAGES_DIR)
|
||||
unset(BUILDTREES_DIR)
|
||||
@ -77,33 +80,44 @@ if(CMD MATCHES "^BUILD$")
|
||||
elseif(CMD MATCHES "^CREATE$")
|
||||
file(TO_NATIVE_PATH ${VCPKG_ROOT_DIR} NATIVE_VCPKG_ROOT_DIR)
|
||||
file(TO_NATIVE_PATH ${DOWNLOADS} NATIVE_DOWNLOADS)
|
||||
if(EXISTS ${VCPKG_ROOT_DIR}/ports/${PORT}/portfile.cmake)
|
||||
message(FATAL_ERROR "Portfile already exists: '${NATIVE_VCPKG_ROOT_DIR}\\ports\\${PORT}\\portfile.cmake'")
|
||||
set(PORT_PATH "${VCPKG_ROOT_DIR}/ports/${PORT}")
|
||||
file(TO_NATIVE_PATH ${PORT_PATH} NATIVE_PORT_PATH)
|
||||
set(PORTFILE_PATH "${PORT_PATH}/portfile.cmake")
|
||||
file(TO_NATIVE_PATH ${PORTFILE_PATH} NATIVE_PORTFILE_PATH)
|
||||
set(MANIFEST_PATH "${PORT_PATH}/vcpkg.json")
|
||||
file(TO_NATIVE_PATH ${MANIFEST_PATH} NATIVE_MANIFEST_PATH)
|
||||
|
||||
if(EXISTS "${PORTFILE_PATH}")
|
||||
message(FATAL_ERROR "Portfile already exists: '${NATIVE_PORTFILE_PATH}'")
|
||||
endif()
|
||||
if(NOT FILENAME)
|
||||
get_filename_component(FILENAME "${URL}" NAME)
|
||||
endif()
|
||||
string(REGEX REPLACE "(\\.(zip|gz|tar|tgz|bz2))+\$" "" ROOT_NAME ${FILENAME})
|
||||
if(EXISTS ${DOWNLOADS}/${FILENAME})
|
||||
message(STATUS "Using pre-downloaded: ${NATIVE_DOWNLOADS}\\${FILENAME}")
|
||||
message(STATUS "If this is not desired, delete the file and ${NATIVE_VCPKG_ROOT_DIR}\\ports\\${PORT}")
|
||||
|
||||
set(DOWNLOAD_PATH "${DOWNLOADS}/${FILENAME}")
|
||||
file(TO_NATIVE_PATH ${DOWNLOAD_PATH} NATIVE_DOWNLOAD_PATH)
|
||||
|
||||
if(EXISTS "${DOWNLOAD_PATH}")
|
||||
message(STATUS "Using pre-downloaded: ${NATIVE_DOWNLOAD_PATH}")
|
||||
message(STATUS "If this is not desired, delete the file and ${NATIVE_PORT_PATH}")
|
||||
else()
|
||||
include(vcpkg_download_distfile)
|
||||
set(_VCPKG_INTERNAL_NO_HASH_CHECK "TRUE")
|
||||
set(_VCPKG_INTERNAL_NO_HASH_CHECK ON)
|
||||
vcpkg_download_distfile(ARCHIVE
|
||||
URLS ${URL}
|
||||
FILENAME ${FILENAME}
|
||||
)
|
||||
set(_VCPKG_INTERNAL_NO_HASH_CHECK "FALSE")
|
||||
set(_VCPKG_INTERNAL_NO_HASH_CHECK OFF)
|
||||
endif()
|
||||
file(SHA512 ${DOWNLOADS}/${FILENAME} SHA512)
|
||||
file(SHA512 ${DOWNLOAD_PATH} SHA512)
|
||||
|
||||
file(MAKE_DIRECTORY ${VCPKG_ROOT_DIR}/ports/${PORT})
|
||||
configure_file(${SCRIPTS}/templates/portfile.in.cmake ${VCPKG_ROOT_DIR}/ports/${PORT}/portfile.cmake @ONLY)
|
||||
configure_file(${SCRIPTS}/templates/CONTROL.in ${VCPKG_ROOT_DIR}/ports/${PORT}/CONTROL @ONLY)
|
||||
file(MAKE_DIRECTORY ${PORT_PATH})
|
||||
configure_file(${SCRIPTS}/templates/portfile.in.cmake ${PORTFILE_PATH} @ONLY)
|
||||
configure_file(${SCRIPTS}/templates/vcpkg.json.in ${MANIFEST_PATH} @ONLY)
|
||||
|
||||
message(STATUS "Generated portfile: ${NATIVE_VCPKG_ROOT_DIR}\\ports\\${PORT}\\portfile.cmake")
|
||||
message(STATUS "Generated CONTROL: ${NATIVE_VCPKG_ROOT_DIR}\\ports\\${PORT}\\CONTROL")
|
||||
message(STATUS "Generated portfile: ${NATIVE_PORTFILE_PATH}")
|
||||
message(STATUS "Generated manifest: ${NATIVE_MANIFEST_PATH}")
|
||||
message(STATUS "To launch an editor for these new files, run")
|
||||
message(STATUS " .\\vcpkg edit ${PORT}")
|
||||
endif()
|
||||
|
@ -1,10 +0,0 @@
|
||||
Source: @PORT@
|
||||
Version:
|
||||
Homepage:
|
||||
Description:
|
||||
Build-Depends:
|
||||
Default-Features:
|
||||
|
||||
Feature:
|
||||
Description:
|
||||
Build-Depends:
|
16
scripts/templates/vcpkg.json.in
Normal file
16
scripts/templates/vcpkg.json.in
Normal file
@ -0,0 +1,16 @@
|
||||
{
|
||||
"name": "@PORT@",
|
||||
"version-string": "",
|
||||
"homepage": "",
|
||||
"description": "",
|
||||
"dependencies": [],
|
||||
|
||||
"default-features": [],
|
||||
"features": [
|
||||
{
|
||||
"name": "",
|
||||
"description": "",
|
||||
"dependencies": []
|
||||
}
|
||||
]
|
||||
}
|
@ -51,9 +51,11 @@ if(MSVC)
|
||||
if(VCPKG_DEVELOPMENT_WARNINGS)
|
||||
string(REGEX REPLACE "[-/]W[0-4]" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
|
||||
|
||||
add_compile_options(-W4 -analyze)
|
||||
add_compile_options(-W4)
|
||||
if(VCPKG_COMPILER STREQUAL "clang")
|
||||
add_compile_options(-Wmissing-prototypes -Wno-missing-field-initializers)
|
||||
else()
|
||||
add_compile_options(-analyze)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
# Outputs to Cache: VCPKG_COMPILER
|
||||
function(vcpkg_detect_compiler)
|
||||
if(NOT DEFINED CACHE{VCPKG_COMPILER})
|
||||
message(STATUS "Detecting the C++ compiler in use")
|
||||
if(CMAKE_COMPILER_IS_GNUXX OR CMAKE_CXX_COMPILER_ID MATCHES "GNU")
|
||||
if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 6.0)
|
||||
message(FATAL_ERROR [[
|
||||
@ -45,6 +46,7 @@ If you would like to try anyway, pass --allowAppleClang to bootstrap.sh.
|
||||
set(VCPKG_COMPILER ${COMPILER}
|
||||
CACHE STRING
|
||||
"The compiler in use; one of gcc, clang, msvc")
|
||||
message(STATUS "Detecting the C++ compiler in use - ${VCPKG_COMPILER}")
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
|
@ -31,7 +31,7 @@ namespace vcpkg
|
||||
template<>
|
||||
struct ErrorHolder<std::string>
|
||||
{
|
||||
ErrorHolder() : m_is_error(false) {}
|
||||
ErrorHolder() : m_is_error(false) { }
|
||||
template<class U>
|
||||
ErrorHolder(U&& err) : m_is_error(true), m_err(std::forward<U>(err))
|
||||
{
|
||||
@ -53,7 +53,7 @@ namespace vcpkg
|
||||
struct ErrorHolder<std::error_code>
|
||||
{
|
||||
ErrorHolder() = default;
|
||||
ErrorHolder(const std::error_code& err) : m_err(err) {}
|
||||
ErrorHolder(const std::error_code& err) : m_err(err) { }
|
||||
|
||||
bool has_error() const { return bool(m_err); }
|
||||
|
||||
@ -79,8 +79,8 @@ namespace vcpkg
|
||||
struct ExpectedHolder
|
||||
{
|
||||
ExpectedHolder() = default;
|
||||
ExpectedHolder(const T& t) : t(t) {}
|
||||
ExpectedHolder(T&& t) : t(std::move(t)) {}
|
||||
ExpectedHolder(const T& t) : t(t) { }
|
||||
ExpectedHolder(T&& t) : t(std::move(t)) { }
|
||||
using pointer = T*;
|
||||
using const_pointer = const T*;
|
||||
T* get() { return &t; }
|
||||
@ -90,8 +90,8 @@ namespace vcpkg
|
||||
template<class T>
|
||||
struct ExpectedHolder<T&>
|
||||
{
|
||||
ExpectedHolder(T& t) : t(&t) {}
|
||||
ExpectedHolder() : t(nullptr) {}
|
||||
ExpectedHolder(T& t) : t(&t) { }
|
||||
ExpectedHolder() : t(nullptr) { }
|
||||
using pointer = T*;
|
||||
using const_pointer = T*;
|
||||
T* get() { return t; }
|
||||
@ -107,10 +107,10 @@ namespace vcpkg
|
||||
|
||||
// Constructors are intentionally implicit
|
||||
|
||||
ExpectedT(const S& s, ExpectedRightTag = {}) : m_s(s) {}
|
||||
ExpectedT(S&& s, ExpectedRightTag = {}) : m_s(std::move(s)) {}
|
||||
ExpectedT(const S& s, ExpectedRightTag = {}) : m_s(s) { }
|
||||
ExpectedT(S&& s, ExpectedRightTag = {}) : m_s(std::move(s)) { }
|
||||
|
||||
ExpectedT(const T& t, ExpectedLeftTag = {}) : m_t(t) {}
|
||||
ExpectedT(const T& t, ExpectedLeftTag = {}) : m_t(t) { }
|
||||
template<class = std::enable_if<!std::is_reference_v<T>>>
|
||||
ExpectedT(T&& t, ExpectedLeftTag = {}) : m_t(std::move(t))
|
||||
{
|
||||
@ -213,7 +213,7 @@ namespace vcpkg
|
||||
}
|
||||
else
|
||||
{
|
||||
return U{std::move(error()), expected_right_tag};
|
||||
return U{std::move(*this).error(), expected_right_tag};
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -59,6 +59,17 @@ namespace fs
|
||||
perms m_permissions;
|
||||
};
|
||||
|
||||
struct SystemHandle
|
||||
{
|
||||
using type = intptr_t; // HANDLE
|
||||
type system_handle = -1;
|
||||
|
||||
bool is_valid() const
|
||||
{
|
||||
return system_handle != -1;
|
||||
}
|
||||
};
|
||||
|
||||
#else
|
||||
|
||||
using stdfs::file_type;
|
||||
@ -71,6 +82,17 @@ namespace fs
|
||||
using stdfs::file_status::type;
|
||||
};
|
||||
|
||||
struct SystemHandle
|
||||
{
|
||||
using type = int; // file descriptor
|
||||
type system_handle = -1;
|
||||
|
||||
bool is_valid() const
|
||||
{
|
||||
return system_handle != -1;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
inline bool is_symlink(file_status s) noexcept
|
||||
@ -171,6 +193,9 @@ namespace vcpkg::Files
|
||||
virtual void current_path(const fs::path& path, std::error_code&) = 0;
|
||||
void current_path(const fs::path& path, LineInfo li);
|
||||
|
||||
virtual fs::SystemHandle try_take_exclusive_file_lock(const fs::path& path, std::error_code&) = 0;
|
||||
virtual void unlock_file_lock(fs::SystemHandle handle, std::error_code&) = 0;
|
||||
|
||||
virtual std::vector<fs::path> find_from_PATH(const std::string& name) const = 0;
|
||||
};
|
||||
|
||||
|
@ -109,11 +109,13 @@ namespace vcpkg::Json
|
||||
double number() const noexcept;
|
||||
StringView string() const noexcept;
|
||||
|
||||
const Array& array() const noexcept;
|
||||
Array& array() noexcept;
|
||||
const Array& array() const& noexcept;
|
||||
Array& array() & noexcept;
|
||||
Array&& array() && noexcept;
|
||||
|
||||
const Object& object() const noexcept;
|
||||
Object& object() noexcept;
|
||||
const Object& object() const& noexcept;
|
||||
Object& object() & noexcept;
|
||||
Object&& object() && noexcept;
|
||||
|
||||
static Value null(std::nullptr_t) noexcept;
|
||||
static Value boolean(bool) noexcept;
|
||||
@ -268,11 +270,141 @@ namespace vcpkg::Json
|
||||
underlying_t underlying_;
|
||||
};
|
||||
|
||||
// currently, a hard assertion on file errors
|
||||
struct ReaderError
|
||||
{
|
||||
virtual void add_missing_field(std::string&& type, std::string&& key) = 0;
|
||||
virtual void add_expected_type(std::string&& key, std::string&& expected_type) = 0;
|
||||
virtual void add_extra_fields(std::string&& type, std::vector<std::string>&& fields) = 0;
|
||||
virtual void add_mutually_exclusive_fields(std::string&& type, std::vector<std::string>&& fields) = 0;
|
||||
|
||||
virtual ~ReaderError() = default;
|
||||
};
|
||||
|
||||
struct Reader
|
||||
{
|
||||
explicit Reader(ReaderError* err) : err(err) { }
|
||||
|
||||
ReaderError& error() const { return *err; }
|
||||
|
||||
private:
|
||||
ReaderError* err;
|
||||
|
||||
template<class Visitor>
|
||||
using VisitorType = typename std::remove_reference_t<Visitor>::type;
|
||||
|
||||
template<class Visitor>
|
||||
Optional<VisitorType<Visitor>> internal_visit(const Value& value, StringView key, Visitor& visitor)
|
||||
{
|
||||
switch (value.kind())
|
||||
{
|
||||
using VK = Json::ValueKind;
|
||||
case VK::Null: return visitor.visit_null(*this, key);
|
||||
case VK::Boolean: return visitor.visit_boolean(*this, key, value.boolean());
|
||||
case VK::Integer: return visitor.visit_integer(*this, key, value.integer());
|
||||
case VK::Number: return visitor.visit_number(*this, key, value.number());
|
||||
case VK::String: return visitor.visit_string(*this, key, value.string());
|
||||
case VK::Array: return visitor.visit_array(*this, key, value.array());
|
||||
case VK::Object: return visitor.visit_object(*this, key, value.object());
|
||||
}
|
||||
|
||||
vcpkg::Checks::exit_fail(VCPKG_LINE_INFO);
|
||||
}
|
||||
|
||||
// returns whether the field was found, not whether it was valid
|
||||
template<class Visitor>
|
||||
bool internal_field(const Object& obj, StringView key, VisitorType<Visitor>& place, Visitor& visitor)
|
||||
{
|
||||
auto value = obj.get(key);
|
||||
if (!value)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Optional<VisitorType<Visitor>> opt = internal_visit(*value, key, visitor);
|
||||
|
||||
if (auto val = opt.get())
|
||||
{
|
||||
place = std::move(*val);
|
||||
}
|
||||
else
|
||||
{
|
||||
err->add_expected_type(key.to_string(), visitor.type_name().to_string());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public:
|
||||
template<class Visitor>
|
||||
void required_object_field(
|
||||
StringView type, const Object& obj, StringView key, VisitorType<Visitor>& place, Visitor&& visitor)
|
||||
{
|
||||
if (!internal_field(obj, key, place, visitor))
|
||||
{
|
||||
err->add_missing_field(type.to_string(), key.to_string());
|
||||
}
|
||||
}
|
||||
|
||||
template<class Visitor>
|
||||
void optional_object_field(const Object& obj, StringView key, VisitorType<Visitor>& place, Visitor&& visitor)
|
||||
{
|
||||
internal_field(obj, key, place, visitor);
|
||||
}
|
||||
|
||||
template<class Visitor>
|
||||
Optional<std::vector<VisitorType<Visitor>>> array_elements(const Array& arr, StringView key, Visitor&& visitor)
|
||||
{
|
||||
std::vector<VisitorType<Visitor>> result;
|
||||
for (const auto& el : arr)
|
||||
{
|
||||
auto opt = internal_visit(el, key, visitor);
|
||||
if (auto p = opt.get())
|
||||
{
|
||||
result.push_back(std::move(*p));
|
||||
}
|
||||
else
|
||||
{
|
||||
return nullopt;
|
||||
}
|
||||
}
|
||||
return std::move(result);
|
||||
}
|
||||
};
|
||||
|
||||
// Warning: NEVER use this type except as a CRTP base
|
||||
template<class Underlying>
|
||||
struct VisitorCrtpBase
|
||||
{
|
||||
// the following function must be defined by the Underlying class
|
||||
// const char* type_name();
|
||||
|
||||
// We do this auto dance since function bodies are checked _after_ typedefs in the superclass,
|
||||
// but function declarations are checked beforehand. Therefore, we can get C++ to use this typedef
|
||||
// only once the function bodies are checked by returning `auto` and specifying the
|
||||
// return type in the function body.
|
||||
auto visit_null(Reader&, StringView) { return Optional<typename Underlying::type>(nullopt); }
|
||||
auto visit_boolean(Reader&, StringView, bool) { return Optional<typename Underlying::type>(nullopt); }
|
||||
auto visit_integer(Reader& r, StringView field_name, int64_t i)
|
||||
{
|
||||
return static_cast<Underlying&>(*this).visit_number(r, field_name, static_cast<double>(i));
|
||||
}
|
||||
auto visit_number(Reader&, StringView, double) { return Optional<typename Underlying::type>(nullopt); }
|
||||
auto visit_string(Reader&, StringView, StringView) { return Optional<typename Underlying::type>(nullopt); }
|
||||
auto visit_array(Reader&, StringView, const Json::Array&)
|
||||
{
|
||||
return Optional<typename Underlying::type>(nullopt);
|
||||
}
|
||||
auto visit_object(Reader&, StringView, const Json::Object&)
|
||||
{
|
||||
return Optional<typename Underlying::type>(nullopt);
|
||||
}
|
||||
// we can't make the SMFs protected because of an issue with /permissive mode
|
||||
};
|
||||
|
||||
ExpectedT<std::pair<Value, JsonStyle>, std::unique_ptr<Parse::IParseError>> parse_file(
|
||||
const Files::Filesystem&, const fs::path&, std::error_code& ec) noexcept;
|
||||
ExpectedT<std::pair<Value, JsonStyle>, std::unique_ptr<Parse::IParseError>> parse(
|
||||
StringView text, const fs::path& filepath = "") noexcept;
|
||||
StringView text, const fs::path& filepath = {}) noexcept;
|
||||
|
||||
std::string stringify(const Value&, JsonStyle style);
|
||||
std::string stringify(const Object&, JsonStyle style);
|
||||
|
@ -8,6 +8,10 @@
|
||||
#include <vcpkg/base/stringview.h>
|
||||
#include <vcpkg/base/view.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <inttypes.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace vcpkg::Strings::details
|
||||
@ -48,6 +52,7 @@ namespace vcpkg::Strings::details
|
||||
}
|
||||
inline void append_internal(std::string& into, const char* v) { into.append(v); }
|
||||
inline void append_internal(std::string& into, const std::string& s) { into.append(s); }
|
||||
inline void append_internal(std::string& into, StringView s) { into.append(s.begin(), s.end()); }
|
||||
|
||||
template<class T, class = decltype(std::declval<const T&>().to_string(std::declval<std::string&>()))>
|
||||
void append_internal(std::string& into, const T& t)
|
||||
@ -60,6 +65,11 @@ namespace vcpkg::Strings::details
|
||||
{
|
||||
to_string(into, t);
|
||||
}
|
||||
|
||||
struct tolower_char
|
||||
{
|
||||
char operator()(char c) const { return (c < 'A' || c > 'Z') ? c : c - 'A' + 'a'; }
|
||||
};
|
||||
}
|
||||
|
||||
namespace vcpkg::Strings
|
||||
@ -117,6 +127,11 @@ namespace vcpkg::Strings
|
||||
|
||||
bool case_insensitive_ascii_equals(StringView left, StringView right);
|
||||
|
||||
template<class It>
|
||||
void ascii_to_lowercase(It first, It last)
|
||||
{
|
||||
std::transform(first, last, first, details::tolower_char{});
|
||||
}
|
||||
std::string ascii_to_lowercase(std::string&& s);
|
||||
|
||||
std::string ascii_to_uppercase(std::string&& s);
|
||||
@ -134,11 +149,11 @@ namespace vcpkg::Strings
|
||||
}
|
||||
|
||||
std::string output;
|
||||
output.append(transformer(*begin));
|
||||
append(output, transformer(*begin));
|
||||
for (auto it = std::next(begin); it != end; ++it)
|
||||
{
|
||||
output.append(delimiter);
|
||||
output.append(transformer(*it));
|
||||
append(output, transformer(*it));
|
||||
}
|
||||
|
||||
return output;
|
||||
@ -147,8 +162,8 @@ namespace vcpkg::Strings
|
||||
template<class Container, class Transformer>
|
||||
std::string join(const char* delimiter, const Container& v, Transformer transformer)
|
||||
{
|
||||
const auto begin = v.begin();
|
||||
const auto end = v.end();
|
||||
const auto begin = std::begin(v);
|
||||
const auto end = std::end(v);
|
||||
|
||||
return join(delimiter, begin, end, transformer);
|
||||
}
|
||||
@ -163,7 +178,7 @@ namespace vcpkg::Strings
|
||||
template<class Container>
|
||||
std::string join(const char* delimiter, const Container& v)
|
||||
{
|
||||
using Element = decltype(*v.begin());
|
||||
using Element = decltype(*std::begin(v));
|
||||
return join(delimiter, v, [](const Element& x) -> const Element& { return x; });
|
||||
}
|
||||
|
||||
@ -173,7 +188,7 @@ namespace vcpkg::Strings
|
||||
|
||||
void trim_all_and_remove_whitespace_strings(std::vector<std::string>* strings);
|
||||
|
||||
std::vector<std::string> split(const std::string& s, const char delimiter);
|
||||
std::vector<std::string> split(StringView s, const char delimiter);
|
||||
|
||||
const char* find_first_of(StringView searched, StringView candidates);
|
||||
|
||||
@ -193,6 +208,77 @@ namespace vcpkg::Strings
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Equivalent to one of the `::strto[T]` functions. Returns `nullopt` if there is an error.
|
||||
template<class T>
|
||||
Optional<T> strto(CStringView sv);
|
||||
|
||||
template<>
|
||||
inline Optional<double> strto<double>(CStringView sv)
|
||||
{
|
||||
char* endptr = nullptr;
|
||||
double res = strtod(sv.c_str(), &endptr);
|
||||
if (endptr == sv.c_str())
|
||||
{
|
||||
// no digits
|
||||
return nullopt;
|
||||
}
|
||||
// else, we may have HUGE_VAL but we expect the caller to deal with that
|
||||
return res;
|
||||
}
|
||||
|
||||
template<>
|
||||
inline Optional<long> strto<long>(CStringView sv)
|
||||
{
|
||||
char* endptr = nullptr;
|
||||
long res = strtol(sv.c_str(), &endptr, 10);
|
||||
if (endptr == sv.c_str())
|
||||
{
|
||||
// no digits
|
||||
return nullopt;
|
||||
}
|
||||
if (errno == ERANGE)
|
||||
{
|
||||
// out of bounds
|
||||
return nullopt;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
template<>
|
||||
inline Optional<long long> strto<long long>(CStringView sv)
|
||||
{
|
||||
char* endptr = nullptr;
|
||||
long long res = strtoll(sv.c_str(), &endptr, 10);
|
||||
if (endptr == sv.c_str())
|
||||
{
|
||||
// no digits
|
||||
return nullopt;
|
||||
}
|
||||
if (errno == ERANGE)
|
||||
{
|
||||
// out of bounds
|
||||
return nullopt;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
template<>
|
||||
inline Optional<int> strto<int>(CStringView sv)
|
||||
{
|
||||
auto res = strto<long>(sv);
|
||||
if (auto r = res.get())
|
||||
{
|
||||
if (*r < INT_MIN || *r > INT_MAX)
|
||||
{
|
||||
return nullopt;
|
||||
}
|
||||
return static_cast<int>(*r);
|
||||
}
|
||||
return nullopt;
|
||||
}
|
||||
|
||||
const char* search(StringView haystack, StringView needle);
|
||||
|
||||
bool contains(StringView haystack, StringView needle);
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
#include <vcpkg/base/optional.h>
|
||||
|
||||
#include <limits>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
@ -30,8 +31,8 @@ namespace vcpkg
|
||||
{
|
||||
}
|
||||
|
||||
constexpr StringView(const char* ptr, size_t size) : m_ptr(ptr), m_size(size) {}
|
||||
constexpr StringView(const char* b, const char* e) : m_ptr(b), m_size(static_cast<size_t>(e - b)) {}
|
||||
constexpr StringView(const char* ptr, size_t size) : m_ptr(ptr), m_size(size) { }
|
||||
constexpr StringView(const char* b, const char* e) : m_ptr(b), m_size(static_cast<size_t>(e - b)) { }
|
||||
|
||||
constexpr const char* begin() const { return m_ptr; }
|
||||
constexpr const char* end() const { return m_ptr + m_size; }
|
||||
@ -42,6 +43,23 @@ namespace vcpkg
|
||||
std::string to_string() const;
|
||||
void to_string(std::string& out) const;
|
||||
|
||||
constexpr StringView substr(size_t pos, size_t count = std::numeric_limits<size_t>::max()) const
|
||||
{
|
||||
if (pos > m_size)
|
||||
{
|
||||
return StringView();
|
||||
}
|
||||
|
||||
if (count > m_size - pos)
|
||||
{
|
||||
return StringView(m_ptr + pos, m_size - pos);
|
||||
}
|
||||
|
||||
return StringView(m_ptr + pos, count);
|
||||
}
|
||||
|
||||
constexpr char byte_at_index(size_t pos) const { return m_ptr[pos]; }
|
||||
|
||||
private:
|
||||
const char* m_ptr = 0;
|
||||
size_t m_size = 0;
|
||||
@ -49,4 +67,8 @@ namespace vcpkg
|
||||
|
||||
bool operator==(StringView lhs, StringView rhs) noexcept;
|
||||
bool operator!=(StringView lhs, StringView rhs) noexcept;
|
||||
bool operator<(StringView lhs, StringView rhs) noexcept;
|
||||
bool operator>(StringView lhs, StringView rhs) noexcept;
|
||||
bool operator<=(StringView lhs, StringView rhs) noexcept;
|
||||
bool operator>=(StringView lhs, StringView rhs) noexcept;
|
||||
}
|
||||
|
@ -32,15 +32,19 @@ namespace vcpkg
|
||||
|
||||
PackageSpec spec;
|
||||
std::string version;
|
||||
std::string description;
|
||||
std::string maintainer;
|
||||
int port_version = 0;
|
||||
std::vector<std::string> description;
|
||||
std::vector<std::string> maintainers;
|
||||
std::string feature;
|
||||
std::vector<std::string> default_features;
|
||||
std::vector<std::string> depends;
|
||||
std::vector<std::string> dependencies;
|
||||
std::string abi;
|
||||
Type type;
|
||||
};
|
||||
|
||||
bool operator==(const BinaryParagraph&, const BinaryParagraph&);
|
||||
bool operator!=(const BinaryParagraph&, const BinaryParagraph&);
|
||||
|
||||
struct BinaryControlFile
|
||||
{
|
||||
BinaryParagraph core_paragraph;
|
||||
|
@ -16,6 +16,12 @@ namespace vcpkg::Commands
|
||||
using CommandTypeB = void (*)(const VcpkgCmdArguments& args, const VcpkgPaths& paths);
|
||||
using CommandTypeC = void (*)(const VcpkgCmdArguments& args, Files::Filesystem& fs);
|
||||
|
||||
enum class DryRun : bool
|
||||
{
|
||||
No,
|
||||
Yes,
|
||||
};
|
||||
|
||||
namespace BuildExternal
|
||||
{
|
||||
void perform_and_exit(const VcpkgCmdArguments& args, const VcpkgPaths& paths, Triplet default_triplet);
|
||||
@ -86,11 +92,6 @@ namespace vcpkg::Commands
|
||||
void perform_and_exit(const VcpkgCmdArguments& args, const VcpkgPaths& paths);
|
||||
}
|
||||
|
||||
namespace Import
|
||||
{
|
||||
void perform_and_exit(const VcpkgCmdArguments& args, const VcpkgPaths& paths);
|
||||
}
|
||||
|
||||
namespace Integrate
|
||||
{
|
||||
extern const CommandStructure COMMAND_STRUCTURE;
|
||||
@ -146,9 +147,23 @@ namespace vcpkg::Commands
|
||||
void perform_and_exit(const VcpkgCmdArguments& args, const VcpkgPaths& paths);
|
||||
}
|
||||
|
||||
namespace FormatManifest
|
||||
{
|
||||
extern const CommandStructure COMMAND_STRUCTURE;
|
||||
void perform_and_exit(const VcpkgCmdArguments& args, const VcpkgPaths& paths);
|
||||
}
|
||||
|
||||
namespace SetInstalled
|
||||
{
|
||||
extern const CommandStructure COMMAND_STRUCTURE;
|
||||
void perform_and_exit_ex(const VcpkgCmdArguments& args,
|
||||
const VcpkgPaths& paths,
|
||||
const PortFileProvider::PathsPortFileProvider& provider,
|
||||
IBinaryProvider& binary_provider,
|
||||
const CMakeVars::CMakeVarProvider& cmake_vars,
|
||||
const std::vector<FullPackageSpec>& specs,
|
||||
const Build::BuildPackageOptions& install_plan_options,
|
||||
DryRun dry_run);
|
||||
void perform_and_exit(const VcpkgCmdArguments& args, const VcpkgPaths& paths, Triplet default_triplet);
|
||||
}
|
||||
|
||||
|
@ -162,5 +162,5 @@ namespace vcpkg::Dependencies
|
||||
|
||||
void print_plan(const ActionPlan& action_plan,
|
||||
const bool is_recursive = true,
|
||||
const fs::path& default_ports_dir = "");
|
||||
const fs::path& default_ports_dir = {});
|
||||
}
|
||||
|
@ -1,24 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <vcpkg/base/expected.h>
|
||||
|
||||
namespace vcpkg
|
||||
{
|
||||
struct ExpressionContext
|
||||
{
|
||||
// map of cmake variables and their values.
|
||||
const std::unordered_map<std::string, std::string>& cmake_context;
|
||||
|
||||
// The legacy context is a string (typically the name of the triplet).
|
||||
// An identifier was considered 'true' if it is a substring of this.
|
||||
// It is now used for backwards compatability diagnostic messages and
|
||||
// will be eventually removed.
|
||||
const std::string& legacy_context;
|
||||
};
|
||||
|
||||
// Evaluate simple vcpkg logic expressions. An identifier in the expression is considered 'true'
|
||||
// if it is a substring of the evaluation_context (typically the name of the triplet)
|
||||
ExpectedT<bool, std::string> evaluate_expression(const std::string& expression, const ExpressionContext& context);
|
||||
}
|
@ -18,6 +18,7 @@ namespace vcpkg::Metrics
|
||||
void track_metric(const std::string& name, double value);
|
||||
void track_buildtime(const std::string& name, double value);
|
||||
void track_property(const std::string& name, const std::string& value);
|
||||
void track_feature(const std::string& feature, bool value);
|
||||
|
||||
bool metrics_enabled();
|
||||
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
#include <vcpkg/base/expected.h>
|
||||
#include <vcpkg/base/optional.h>
|
||||
#include <vcpkg/platform-expression.h>
|
||||
#include <vcpkg/triplet.h>
|
||||
|
||||
namespace vcpkg::Parse
|
||||
@ -20,7 +21,7 @@ namespace vcpkg
|
||||
struct PackageSpec
|
||||
{
|
||||
PackageSpec() noexcept = default;
|
||||
PackageSpec(std::string name, Triplet triplet) : m_name(std::move(name)), m_triplet(triplet) {}
|
||||
PackageSpec(std::string name, Triplet triplet) : m_name(std::move(name)), m_triplet(triplet) { }
|
||||
|
||||
static std::vector<PackageSpec> to_package_specs(const std::vector<std::string>& ports, Triplet triplet);
|
||||
|
||||
@ -53,7 +54,7 @@ namespace vcpkg
|
||||
///
|
||||
struct FeatureSpec
|
||||
{
|
||||
FeatureSpec(const PackageSpec& spec, const std::string& feature) : m_spec(spec), m_feature(feature) {}
|
||||
FeatureSpec(const PackageSpec& spec, const std::string& feature) : m_spec(spec), m_feature(feature) { }
|
||||
|
||||
const std::string& name() const { return m_spec.name(); }
|
||||
const std::string& feature() const { return m_feature; }
|
||||
@ -123,10 +124,9 @@ namespace vcpkg
|
||||
|
||||
struct Dependency
|
||||
{
|
||||
Features depend;
|
||||
std::string qualifier;
|
||||
|
||||
static ExpectedS<Dependency> from_string(const std::string& input);
|
||||
std::string name;
|
||||
std::vector<std::string> features;
|
||||
PlatformExpression::Expr platform;
|
||||
};
|
||||
|
||||
struct ParsedQualifiedSpecifier
|
||||
@ -134,7 +134,7 @@ namespace vcpkg
|
||||
std::string name;
|
||||
Optional<std::vector<std::string>> features;
|
||||
Optional<std::string> triplet;
|
||||
Optional<std::string> qualifier;
|
||||
Optional<PlatformExpression::Expr> platform;
|
||||
};
|
||||
|
||||
Optional<std::string> parse_feature_name(Parse::ParserBase& parser);
|
||||
|
@ -4,6 +4,7 @@
|
||||
#include <vcpkg/packagespec.h>
|
||||
#include <vcpkg/textrowcol.h>
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
@ -14,9 +15,16 @@ namespace vcpkg::Parse
|
||||
struct ParseControlErrorInfo
|
||||
{
|
||||
std::string name;
|
||||
std::vector<std::string> missing_fields;
|
||||
std::vector<std::string> extra_fields;
|
||||
std::map<std::string, std::vector<std::string>> missing_fields;
|
||||
std::map<std::string, std::vector<std::string>> extra_fields;
|
||||
std::map<std::string, std::string> expected_types;
|
||||
std::map<std::string, std::vector<std::string>> mutually_exclusive_fields;
|
||||
std::string error;
|
||||
|
||||
bool has_error() const
|
||||
{
|
||||
return !missing_fields.empty() || !extra_fields.empty() || !expected_types.empty() || !error.empty();
|
||||
}
|
||||
};
|
||||
|
||||
template<class P>
|
||||
@ -26,17 +34,23 @@ namespace vcpkg::Parse
|
||||
|
||||
struct ParagraphParser
|
||||
{
|
||||
ParagraphParser(Paragraph&& fields) : fields(std::move(fields)) {}
|
||||
ParagraphParser(Paragraph&& fields) : fields(std::move(fields)) { }
|
||||
|
||||
std::string required_field(const std::string& fieldname);
|
||||
void required_field(const std::string& fieldname, std::string& out);
|
||||
std::string optional_field(const std::string& fieldname);
|
||||
void required_field(const std::string& fieldname, std::pair<std::string&, TextRowCol&> out);
|
||||
|
||||
std::string optional_field(const std::string& fieldname);
|
||||
void optional_field(const std::string& fieldname, std::pair<std::string&, TextRowCol&> out);
|
||||
|
||||
void add_type_error(const std::string& fieldname, const char* type) { expected_types[fieldname] = type; }
|
||||
|
||||
std::unique_ptr<ParseControlErrorInfo> error_info(const std::string& name) const;
|
||||
|
||||
private:
|
||||
Paragraph&& fields;
|
||||
std::vector<std::string> missing_fields;
|
||||
std::map<std::string, std::string> expected_types;
|
||||
};
|
||||
|
||||
ExpectedS<std::vector<std::string>> parse_default_features_list(const std::string& str,
|
||||
|
@ -10,11 +10,16 @@ namespace vcpkg::Paragraphs
|
||||
{
|
||||
using Paragraph = Parse::Paragraph;
|
||||
|
||||
ExpectedS<Paragraph> parse_single_paragraph(const std::string& str, const std::string& origin);
|
||||
ExpectedS<Paragraph> get_single_paragraph(const Files::Filesystem& fs, const fs::path& control_path);
|
||||
ExpectedS<std::vector<Paragraph>> get_paragraphs(const Files::Filesystem& fs, const fs::path& control_path);
|
||||
ExpectedS<std::vector<Paragraph>> parse_paragraphs(const std::string& str, const std::string& origin);
|
||||
|
||||
Parse::ParseExpected<SourceControlFile> try_load_port(const Files::Filesystem& fs, const fs::path& control_path);
|
||||
bool is_port_directory(const Files::Filesystem& fs, const fs::path& path);
|
||||
|
||||
Parse::ParseExpected<SourceControlFile> try_load_manifest(const Files::Filesystem& fs, const std::string& port_name, const fs::path& path_to_manifest, std::error_code& ec);
|
||||
|
||||
Parse::ParseExpected<SourceControlFile> try_load_port(const Files::Filesystem& fs, const fs::path& path);
|
||||
|
||||
ExpectedS<BinaryControlFile> try_load_cached_package(const VcpkgPaths& paths, const PackageSpec& spec);
|
||||
|
||||
|
73
toolsrc/include/vcpkg/platform-expression.h
Normal file
73
toolsrc/include/vcpkg/platform-expression.h
Normal file
@ -0,0 +1,73 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <vcpkg/base/expected.h>
|
||||
#include <vcpkg/base/stringview.h>
|
||||
|
||||
namespace vcpkg::PlatformExpression
|
||||
{
|
||||
// map of cmake variables and their values.
|
||||
using Context = std::unordered_map<std::string, std::string>;
|
||||
|
||||
namespace detail
|
||||
{
|
||||
struct ExprImpl;
|
||||
}
|
||||
struct Expr
|
||||
{
|
||||
static Expr Identifier(StringView id);
|
||||
static Expr Not(Expr&& e);
|
||||
static Expr And(std::vector<Expr>&& exprs);
|
||||
static Expr Or(std::vector<Expr>&& exprs);
|
||||
|
||||
// The empty expression is always true
|
||||
static Expr Empty() { return Expr(); }
|
||||
|
||||
// since ExprImpl is not yet defined, we need to define the ctor and dtor in the C++ file
|
||||
Expr();
|
||||
Expr(const Expr&);
|
||||
Expr(Expr&&);
|
||||
Expr& operator=(const Expr& e);
|
||||
Expr& operator=(Expr&&);
|
||||
|
||||
explicit Expr(std::unique_ptr<detail::ExprImpl>&& e);
|
||||
~Expr();
|
||||
|
||||
bool evaluate(const Context& context) const;
|
||||
bool is_empty() const { return !static_cast<bool>(underlying_); }
|
||||
|
||||
private:
|
||||
std::unique_ptr<detail::ExprImpl> underlying_;
|
||||
};
|
||||
|
||||
// Note: for backwards compatibility, in CONTROL files,
|
||||
// multiple binary operators are allowed to be next to one another; i.e.
|
||||
// (windows & arm) = (windows && arm) = (windows &&& arm), etc.
|
||||
enum class MultipleBinaryOperators
|
||||
{
|
||||
Deny,
|
||||
Allow,
|
||||
};
|
||||
|
||||
// platform expression parses the following :
|
||||
// <platform-expression>:
|
||||
// <platform-expression.not>
|
||||
// <platform-expression.and>
|
||||
// <platform-expression.or>
|
||||
// <platform-expression.simple>:
|
||||
// ( <platform-expression> )
|
||||
// <platform-expression.identifier>
|
||||
// <platform-expression.identifier>:
|
||||
// A lowercase alpha-numeric string
|
||||
// <platform-expression.not>:
|
||||
// <platform-expression.simple>
|
||||
// ! <platform-expression.simple>
|
||||
// <platform-expression.and>
|
||||
// <platform-expression.not>
|
||||
// <platform-expression.and> & <platform-expression.not>
|
||||
// <platform-expression.or>
|
||||
// <platform-expression.not>
|
||||
// <platform-expression.or> | <platform-expression.not>
|
||||
ExpectedS<Expr> parse_platform_expression(StringView expression, MultipleBinaryOperators multiple_binary_operators);
|
||||
}
|
@ -26,7 +26,7 @@ namespace vcpkg::PortFileProvider
|
||||
struct PathsPortFileProvider : Util::ResourceBase, PortFileProvider
|
||||
{
|
||||
explicit PathsPortFileProvider(const vcpkg::VcpkgPaths& paths,
|
||||
const std::vector<std::string>* ports_dirs_paths);
|
||||
const std::vector<std::string>& ports_dirs_paths);
|
||||
ExpectedS<const SourceControlFileLocation&> get_control_file(const std::string& src_name) const override;
|
||||
std::vector<const SourceControlFileLocation*> load_all_control_files() const override;
|
||||
|
||||
|
@ -1,13 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vcpkg/base/expected.h>
|
||||
#include <vcpkg/base/json.h>
|
||||
#include <vcpkg/base/span.h>
|
||||
#include <vcpkg/base/system.h>
|
||||
#include <vcpkg/base/system.print.h>
|
||||
#include <vcpkg/platform-expression.h>
|
||||
#include <vcpkg/packagespec.h>
|
||||
#include <vcpkg/paragraphparser.h>
|
||||
#include <vector>
|
||||
|
||||
namespace vcpkg
|
||||
{
|
||||
@ -28,14 +28,17 @@ namespace vcpkg
|
||||
static Type from_string(const std::string&);
|
||||
};
|
||||
|
||||
bool operator==(const Type&, const Type&);
|
||||
bool operator!=(const Type&, const Type&);
|
||||
|
||||
/// <summary>
|
||||
/// Port metadata of additional feature in a package (part of CONTROL file)
|
||||
/// </summary>
|
||||
struct FeatureParagraph
|
||||
{
|
||||
std::string name;
|
||||
std::string description;
|
||||
std::vector<Dependency> depends;
|
||||
std::vector<std::string> description;
|
||||
std::vector<Dependency> dependencies;
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
@ -45,13 +48,17 @@ namespace vcpkg
|
||||
{
|
||||
std::string name;
|
||||
std::string version;
|
||||
std::string description;
|
||||
std::string maintainer;
|
||||
int port_version = 0;
|
||||
std::vector<std::string> description;
|
||||
std::vector<std::string> maintainers;
|
||||
std::string homepage;
|
||||
std::vector<Dependency> depends;
|
||||
std::string documentation;
|
||||
std::vector<Dependency> dependencies;
|
||||
std::vector<std::string> default_features;
|
||||
std::string license; // SPDX license expression
|
||||
|
||||
Type type;
|
||||
std::string supports_expression;
|
||||
PlatformExpression::Expr supports_expression;
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
@ -69,9 +76,13 @@ namespace vcpkg
|
||||
}
|
||||
}
|
||||
|
||||
static Parse::ParseExpected<SourceControlFile> parse_manifest_file(const fs::path& path_to_manifest,
|
||||
const Json::Object& object);
|
||||
|
||||
static Parse::ParseExpected<SourceControlFile> parse_control_file(
|
||||
const fs::path& path_to_control, std::vector<Parse::Paragraph>&& control_paragraphs);
|
||||
|
||||
// Always non-null in non-error cases
|
||||
std::unique_ptr<SourceParagraph> core_paragraph;
|
||||
std::vector<std::unique_ptr<FeatureParagraph>> feature_paragraphs;
|
||||
|
||||
|
@ -35,8 +35,8 @@ namespace vcpkg
|
||||
/// <param name="triplet">Triplet</param>
|
||||
/// <param name="feature">Feature name</param>
|
||||
/// <returns>Iterator for found spec</returns>
|
||||
iterator find(const std::string& name, Triplet triplet, const std::string& feature = "");
|
||||
const_iterator find(const std::string& name, Triplet triplet, const std::string& feature = "") const;
|
||||
iterator find(const std::string& name, Triplet triplet, const std::string& feature = {});
|
||||
const_iterator find(const std::string& name, Triplet triplet, const std::string& feature = {}) const;
|
||||
|
||||
std::vector<std::unique_ptr<StatusParagraph>*> find_all(const std::string& name, Triplet triplet);
|
||||
|
||||
|
@ -106,32 +106,63 @@ namespace vcpkg
|
||||
|
||||
static void append_common_options(HelpTableFormatter& target);
|
||||
|
||||
constexpr static StringLiteral VCPKG_ROOT_DIR_ENV = "VCPKG_ROOT";
|
||||
constexpr static StringLiteral VCPKG_ROOT_DIR_ARG = "vcpkg-root";
|
||||
std::unique_ptr<std::string> vcpkg_root_dir;
|
||||
constexpr static StringLiteral MANIFEST_ROOT_DIR_ARG = "x-manifest-root";
|
||||
std::unique_ptr<std::string> manifest_root_dir;
|
||||
|
||||
constexpr static StringLiteral BUILDTREES_ROOT_DIR_ARG = "x-buildtrees-root";
|
||||
std::unique_ptr<std::string> buildtrees_root_dir;
|
||||
constexpr static StringLiteral DOWNLOADS_ROOT_DIR_ENV = "VCPKG_DOWNLOADS";
|
||||
constexpr static StringLiteral DOWNLOADS_ROOT_DIR_ARG = "downloads-root";
|
||||
std::unique_ptr<std::string> downloads_root_dir;
|
||||
constexpr static StringLiteral INSTALL_ROOT_DIR_ARG = "x-install-root";
|
||||
std::unique_ptr<std::string> install_root_dir;
|
||||
constexpr static StringLiteral PACKAGES_ROOT_DIR_ARG = "x-packages-root";
|
||||
std::unique_ptr<std::string> packages_root_dir;
|
||||
constexpr static StringLiteral SCRIPTS_ROOT_DIR_ARG = "x-scripts-root";
|
||||
std::unique_ptr<std::string> scripts_root_dir;
|
||||
|
||||
constexpr static StringLiteral DEFAULT_VISUAL_STUDIO_PATH_ENV = "VCPKG_VISUAL_STUDIO_PATH";
|
||||
std::unique_ptr<std::string> default_visual_studio_path;
|
||||
|
||||
constexpr static StringLiteral TRIPLET_ENV = "VCPKG_DEFAULT_TRIPLET";
|
||||
constexpr static StringLiteral TRIPLET_ARG = "triplet";
|
||||
std::unique_ptr<std::string> triplet;
|
||||
std::unique_ptr<std::vector<std::string>> overlay_ports;
|
||||
std::unique_ptr<std::vector<std::string>> overlay_triplets;
|
||||
constexpr static StringLiteral OVERLAY_PORTS_ARG = "overlay-ports";
|
||||
std::vector<std::string> overlay_ports;
|
||||
constexpr static StringLiteral OVERLAY_TRIPLETS_ARG = "overlay-triplets";
|
||||
std::vector<std::string> overlay_triplets;
|
||||
|
||||
std::vector<std::string> binarysources;
|
||||
constexpr static StringLiteral BINARY_SOURCES_ARG = "x-binarysource";
|
||||
std::vector<std::string> binary_sources;
|
||||
|
||||
constexpr static StringLiteral DEBUG_SWITCH = "debug";
|
||||
Optional<bool> debug = nullopt;
|
||||
constexpr static StringLiteral SEND_METRICS_SWITCH = "sendmetrics";
|
||||
Optional<bool> send_metrics = nullopt;
|
||||
// fully disable metrics -- both printing and sending
|
||||
constexpr static StringLiteral DISABLE_METRICS_ENV = "VCPKG_DISABLE_METRICS";
|
||||
constexpr static StringLiteral DISABLE_METRICS_SWITCH = "disable-metrics";
|
||||
Optional<bool> disable_metrics = nullopt;
|
||||
constexpr static StringLiteral PRINT_METRICS_SWITCH = "printmetrics";
|
||||
Optional<bool> print_metrics = nullopt;
|
||||
|
||||
// feature flags
|
||||
constexpr static StringLiteral FEATURE_FLAGS_ENV = "VCPKG_FEATURE_FLAGS";
|
||||
constexpr static StringLiteral FEATURE_FLAGS_ARG = "feature-flags";
|
||||
|
||||
constexpr static StringLiteral FEATURE_PACKAGES_SWITCH = "featurepackages";
|
||||
Optional<bool> feature_packages = nullopt;
|
||||
constexpr static StringLiteral BINARY_CACHING_FEATURE = "binarycaching";
|
||||
constexpr static StringLiteral BINARY_CACHING_SWITCH = "binarycaching";
|
||||
Optional<bool> binary_caching = nullopt;
|
||||
constexpr static StringLiteral COMPILER_TRACKING_FEATURE = "compilertracking";
|
||||
Optional<bool> compiler_tracking = nullopt;
|
||||
constexpr static StringLiteral MANIFEST_MODE_FEATURE = "manifests";
|
||||
Optional<bool> manifest_mode = nullopt;
|
||||
|
||||
bool binary_caching_enabled() const { return binary_caching.value_or(false); }
|
||||
bool compiler_tracking_enabled() const { return compiler_tracking.value_or(false); }
|
||||
|
||||
@ -142,6 +173,10 @@ namespace vcpkg
|
||||
|
||||
void imbue_from_environment();
|
||||
|
||||
void check_feature_flag_consistency() const;
|
||||
|
||||
void track_feature_flag_metrics() const;
|
||||
|
||||
private:
|
||||
std::unordered_map<std::string, Optional<std::vector<std::string>>> optional_command_arguments;
|
||||
};
|
||||
|
@ -67,11 +67,11 @@ namespace vcpkg
|
||||
std::string name;
|
||||
fs::path location;
|
||||
|
||||
TripletFile(const std::string& name, const fs::path& location) : name(name), location(location) {}
|
||||
TripletFile(const std::string& name, const fs::path& location) : name(name), location(location) { }
|
||||
};
|
||||
|
||||
VcpkgPaths(Files::Filesystem& filesystem, const VcpkgCmdArguments& args);
|
||||
~VcpkgPaths() noexcept;
|
||||
~VcpkgPaths();
|
||||
|
||||
fs::path package_dir(const PackageSpec& spec) const;
|
||||
fs::path build_info_file_path(const PackageSpec& spec) const;
|
||||
@ -84,7 +84,7 @@ namespace vcpkg
|
||||
|
||||
fs::path original_cwd;
|
||||
fs::path root;
|
||||
|
||||
fs::path manifest_root_dir;
|
||||
fs::path buildtrees;
|
||||
fs::path downloads;
|
||||
fs::path packages;
|
||||
@ -120,6 +120,9 @@ namespace vcpkg
|
||||
|
||||
const System::Environment& get_action_env(const Build::AbiInfo& abi_info) const;
|
||||
const std::string& get_triplet_info(const Build::AbiInfo& abi_info) const;
|
||||
bool manifest_mode_enabled() const { return !manifest_root_dir.empty(); }
|
||||
|
||||
void track_feature_flag_metrics() const;
|
||||
|
||||
private:
|
||||
std::unique_ptr<details::VcpkgPathsImpl> m_pimpl;
|
||||
|
@ -2,6 +2,9 @@
|
||||
#include <vcpkg/base/json.h>
|
||||
#include <vcpkg/base/stringview.h>
|
||||
#include <vcpkg/base/system.print.h>
|
||||
#include <vcpkg/base/unicode.h>
|
||||
|
||||
#include <vcpkg/platform-expression.h>
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
@ -17,6 +20,7 @@ namespace
|
||||
None,
|
||||
Utf8Decoder,
|
||||
JsonParser,
|
||||
PlatformExpr,
|
||||
};
|
||||
|
||||
struct FuzzArgs
|
||||
@ -57,10 +61,14 @@ namespace
|
||||
{
|
||||
kind = FuzzKind::Utf8Decoder;
|
||||
}
|
||||
else if (value == "platform-expr")
|
||||
{
|
||||
kind = FuzzKind::PlatformExpr;
|
||||
}
|
||||
else
|
||||
{
|
||||
System::print2(System::Color::error, "Invalid kind: ", value, "\n");
|
||||
System::print2(System::Color::error, " Expected one of: utf-8, json\n\n");
|
||||
System::print2(System::Color::error, " Expected one of: utf-8, json, platform-expr\n\n");
|
||||
print_help_and_exit(true);
|
||||
}
|
||||
}
|
||||
@ -120,6 +128,44 @@ Options:
|
||||
return std::move(ss).str();
|
||||
}
|
||||
|
||||
[[noreturn]] void fuzz_json_and_exit(StringView text)
|
||||
{
|
||||
auto res = Json::parse(text);
|
||||
if (!res)
|
||||
{
|
||||
Checks::exit_with_message(VCPKG_LINE_INFO, res.error()->format());
|
||||
}
|
||||
|
||||
Checks::exit_success(VCPKG_LINE_INFO);
|
||||
}
|
||||
|
||||
[[noreturn]] void fuzz_utf8_and_exit(StringView text)
|
||||
{
|
||||
auto res = Unicode::Utf8Decoder(text.begin(), text.end());
|
||||
for (auto ch : res)
|
||||
{
|
||||
(void)ch;
|
||||
}
|
||||
|
||||
Checks::exit_success(VCPKG_LINE_INFO);
|
||||
}
|
||||
|
||||
[[noreturn]] void fuzz_platform_expr_and_exit(StringView text)
|
||||
{
|
||||
auto res1 = PlatformExpression::parse_platform_expression(text, PlatformExpression::MultipleBinaryOperators::Deny);
|
||||
auto res2 = PlatformExpression::parse_platform_expression(text, PlatformExpression::MultipleBinaryOperators::Allow);
|
||||
|
||||
if (!res1)
|
||||
{
|
||||
Checks::exit_with_message(VCPKG_LINE_INFO, res1.error());
|
||||
}
|
||||
if (!res2)
|
||||
{
|
||||
Checks::exit_with_message(VCPKG_LINE_INFO, res2.error());
|
||||
}
|
||||
|
||||
Checks::exit_success(VCPKG_LINE_INFO);
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
@ -132,13 +178,11 @@ int main(int argc, char** argv)
|
||||
}
|
||||
|
||||
auto text = read_all_of_stdin();
|
||||
auto res = Json::parse(text);
|
||||
if (!res)
|
||||
switch (args.kind)
|
||||
{
|
||||
System::print2(System::Color::error, res.error()->format());
|
||||
}
|
||||
else
|
||||
{
|
||||
System::print2(System::Color::success, "success!");
|
||||
case FuzzKind::JsonParser: fuzz_json_and_exit(text);
|
||||
case FuzzKind::Utf8Decoder: fuzz_utf8_and_exit(text);
|
||||
case FuzzKind::PlatformExpr: fuzz_platform_expr_and_exit(text);
|
||||
default: Checks::exit_fail(VCPKG_LINE_INFO);
|
||||
}
|
||||
}
|
||||
|
@ -32,13 +32,13 @@ TEST_CASE ("VcpkgCmdArguments from lowercase argument sequence", "[arguments]")
|
||||
REQUIRE(v.print_metrics);
|
||||
REQUIRE(*v.print_metrics.get());
|
||||
|
||||
REQUIRE(v.overlay_ports->size() == 2);
|
||||
REQUIRE(v.overlay_ports->at(0) == "C:\\ports1");
|
||||
REQUIRE(v.overlay_ports->at(1) == "C:\\ports2");
|
||||
REQUIRE(v.overlay_ports.size() == 2);
|
||||
REQUIRE(v.overlay_ports.at(0) == "C:\\ports1");
|
||||
REQUIRE(v.overlay_ports.at(1) == "C:\\ports2");
|
||||
|
||||
REQUIRE(v.overlay_triplets->size() == 2);
|
||||
REQUIRE(v.overlay_triplets->at(0) == "C:\\tripletsA");
|
||||
REQUIRE(v.overlay_triplets->at(1) == "C:\\tripletsB");
|
||||
REQUIRE(v.overlay_triplets.size() == 2);
|
||||
REQUIRE(v.overlay_triplets.at(0) == "C:\\tripletsA");
|
||||
REQUIRE(v.overlay_triplets.at(1) == "C:\\tripletsB");
|
||||
}
|
||||
|
||||
TEST_CASE ("VcpkgCmdArguments from uppercase argument sequence", "[arguments]")
|
||||
@ -64,13 +64,13 @@ TEST_CASE ("VcpkgCmdArguments from uppercase argument sequence", "[arguments]")
|
||||
REQUIRE(v.print_metrics);
|
||||
REQUIRE(*v.print_metrics.get());
|
||||
|
||||
REQUIRE(v.overlay_ports->size() == 2);
|
||||
REQUIRE(v.overlay_ports->at(0) == "C:\\ports1");
|
||||
REQUIRE(v.overlay_ports->at(1) == "C:\\ports2");
|
||||
REQUIRE(v.overlay_ports.size() == 2);
|
||||
REQUIRE(v.overlay_ports.at(0) == "C:\\ports1");
|
||||
REQUIRE(v.overlay_ports.at(1) == "C:\\ports2");
|
||||
|
||||
REQUIRE(v.overlay_triplets->size() == 2);
|
||||
REQUIRE(v.overlay_triplets->at(0) == "C:\\tripletsA");
|
||||
REQUIRE(v.overlay_triplets->at(1) == "C:\\tripletsB");
|
||||
REQUIRE(v.overlay_triplets.size() == 2);
|
||||
REQUIRE(v.overlay_triplets.at(0) == "C:\\tripletsA");
|
||||
REQUIRE(v.overlay_triplets.at(1) == "C:\\tripletsB");
|
||||
}
|
||||
|
||||
TEST_CASE ("VcpkgCmdArguments from argument sequence with valued options", "[arguments]")
|
||||
|
@ -14,8 +14,10 @@ TEST_CASE ("parse depends", "[dependencies]")
|
||||
REQUIRE(w);
|
||||
auto& v = *w.get();
|
||||
REQUIRE(v.size() == 1);
|
||||
REQUIRE(v.at(0).depend.name == "liba");
|
||||
REQUIRE(v.at(0).qualifier == "windows");
|
||||
REQUIRE(v.at(0).name == "liba");
|
||||
REQUIRE(v.at(0).platform.evaluate({{"VCPKG_CMAKE_SYSTEM_NAME", ""}}));
|
||||
REQUIRE(v.at(0).platform.evaluate({{"VCPKG_CMAKE_SYSTEM_NAME", "WindowsStore"}}));
|
||||
REQUIRE(!v.at(0).platform.evaluate({{"VCPKG_CMAKE_SYSTEM_NAME", "Darwin"}}));
|
||||
}
|
||||
|
||||
TEST_CASE ("filter depends", "[dependencies]")
|
||||
@ -48,14 +50,17 @@ TEST_CASE ("parse feature depends", "[dependencies]")
|
||||
auto& v = *u_.get();
|
||||
REQUIRE(v.size() == 2);
|
||||
auto&& a0 = v.at(0);
|
||||
REQUIRE(a0.depend.name == "libwebp");
|
||||
REQUIRE(a0.depend.features.size() == 9);
|
||||
REQUIRE(a0.qualifier.empty());
|
||||
REQUIRE(a0.name == "libwebp");
|
||||
REQUIRE(a0.features.size() == 9);
|
||||
REQUIRE(a0.platform.is_empty());
|
||||
|
||||
auto&& a1 = v.at(1);
|
||||
REQUIRE(a1.depend.name == "libwebp");
|
||||
REQUIRE(a1.depend.features.size() == 2);
|
||||
REQUIRE(a1.qualifier == "!osx");
|
||||
REQUIRE(a1.name == "libwebp");
|
||||
REQUIRE(a1.features.size() == 2);
|
||||
REQUIRE(!a1.platform.is_empty());
|
||||
REQUIRE(a1.platform.evaluate({{"VCPKG_CMAKE_SYSTEM_NAME", ""}}));
|
||||
REQUIRE(a1.platform.evaluate({{"VCPKG_CMAKE_SYSTEM_NAME", "Linux"}}));
|
||||
REQUIRE_FALSE(a1.platform.evaluate({{"VCPKG_CMAKE_SYSTEM_NAME", "Darwin"}}));
|
||||
}
|
||||
|
||||
TEST_CASE ("qualified dependency", "[dependencies]")
|
||||
|
@ -28,8 +28,8 @@ static std::string mystringify(const Value& val) { return Json::stringify(val, J
|
||||
TEST_CASE ("JSON stringify weird strings", "[json]")
|
||||
{
|
||||
vcpkg::StringView str = U8_STR("😀 😁 😂 🤣 😃 😄 😅 😆 😉");
|
||||
REQUIRE(mystringify(Value::string(str)) == ('"' + str.to_string() + '"'));
|
||||
REQUIRE(mystringify(Value::string("\xED\xA0\x80")) == "\"\\ud800\""); // unpaired surrogate
|
||||
REQUIRE(mystringify(Value::string(str)) == ('"' + str.to_string() + "\"\n"));
|
||||
REQUIRE(mystringify(Value::string("\xED\xA0\x80")) == "\"\\ud800\"\n"); // unpaired surrogate
|
||||
}
|
||||
|
||||
TEST_CASE ("JSON parse keywords", "[json]")
|
||||
|
235
toolsrc/src/vcpkg-test/manifests.cpp
Normal file
235
toolsrc/src/vcpkg-test/manifests.cpp
Normal file
@ -0,0 +1,235 @@
|
||||
#include <catch2/catch.hpp>
|
||||
#include <vcpkg-test/util.h>
|
||||
|
||||
#include <vcpkg/base/json.h>
|
||||
#include <vcpkg/base/util.h>
|
||||
#include <vcpkg/paragraphs.h>
|
||||
#include <vcpkg/sourceparagraph.h>
|
||||
|
||||
using namespace vcpkg;
|
||||
using namespace vcpkg::Paragraphs;
|
||||
using namespace vcpkg::Test;
|
||||
|
||||
static Json::Object parse_json_object(StringView sv)
|
||||
{
|
||||
auto json = Json::parse(sv);
|
||||
// we're not testing json parsing here, so just fail on errors
|
||||
if (auto r = json.get())
|
||||
{
|
||||
return std::move(r->first.object());
|
||||
}
|
||||
else
|
||||
{
|
||||
Checks::exit_with_message(VCPKG_LINE_INFO, json.error()->format());
|
||||
}
|
||||
}
|
||||
|
||||
static Parse::ParseExpected<SourceControlFile> test_parse_manifest(StringView sv, bool expect_fail = false)
|
||||
{
|
||||
auto object = parse_json_object(sv);
|
||||
auto res = SourceControlFile::parse_manifest_file(fs::u8path("<test manifest>"), object);
|
||||
if (!res.has_value() && !expect_fail)
|
||||
{
|
||||
print_error_message(res.error());
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
TEST_CASE ("manifest construct minimum", "[manifests]")
|
||||
{
|
||||
auto m_pgh = test_parse_manifest(R"json({
|
||||
"name": "zlib",
|
||||
"version-string": "1.2.8"
|
||||
})json");
|
||||
|
||||
REQUIRE(m_pgh.has_value());
|
||||
auto& pgh = **m_pgh.get();
|
||||
|
||||
REQUIRE(pgh.core_paragraph->name == "zlib");
|
||||
REQUIRE(pgh.core_paragraph->version == "1.2.8");
|
||||
REQUIRE(pgh.core_paragraph->maintainers.empty());
|
||||
REQUIRE(pgh.core_paragraph->description.empty());
|
||||
REQUIRE(pgh.core_paragraph->dependencies.empty());
|
||||
}
|
||||
|
||||
TEST_CASE ("manifest construct maximum", "[manifests]")
|
||||
{
|
||||
auto m_pgh = test_parse_manifest(R"json({
|
||||
"name": "s",
|
||||
"version-string": "v",
|
||||
"maintainers": ["m"],
|
||||
"description": "d",
|
||||
"dependencies": ["bd"],
|
||||
"default-features": ["df"],
|
||||
"features": [
|
||||
{
|
||||
"name": "iroh",
|
||||
"description": "zuko's uncle",
|
||||
"dependencies": [
|
||||
{
|
||||
"name": "tea"
|
||||
},
|
||||
"firebending",
|
||||
{
|
||||
"name": "order.white-lotus",
|
||||
"features": [ "the-ancient-ways" ],
|
||||
"platform": "!(windows & arm)"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "zuko",
|
||||
"description": ["son of the fire lord", "firebending 師父"]
|
||||
}
|
||||
]
|
||||
})json");
|
||||
REQUIRE(m_pgh.has_value());
|
||||
auto& pgh = **m_pgh.get();
|
||||
|
||||
REQUIRE(pgh.core_paragraph->name == "s");
|
||||
REQUIRE(pgh.core_paragraph->version == "v");
|
||||
REQUIRE(pgh.core_paragraph->maintainers.size() == 1);
|
||||
REQUIRE(pgh.core_paragraph->maintainers[0] == "m");
|
||||
REQUIRE(pgh.core_paragraph->description.size() == 1);
|
||||
REQUIRE(pgh.core_paragraph->description[0] == "d");
|
||||
REQUIRE(pgh.core_paragraph->dependencies.size() == 1);
|
||||
REQUIRE(pgh.core_paragraph->dependencies[0].name == "bd");
|
||||
REQUIRE(pgh.core_paragraph->default_features.size() == 1);
|
||||
REQUIRE(pgh.core_paragraph->default_features[0] == "df");
|
||||
|
||||
REQUIRE(pgh.feature_paragraphs.size() == 2);
|
||||
|
||||
REQUIRE(pgh.feature_paragraphs[0]->name == "iroh");
|
||||
REQUIRE(pgh.feature_paragraphs[0]->description.size() == 1);
|
||||
REQUIRE(pgh.feature_paragraphs[0]->description[0] == "zuko's uncle");
|
||||
REQUIRE(pgh.feature_paragraphs[0]->dependencies.size() == 3);
|
||||
REQUIRE(pgh.feature_paragraphs[0]->dependencies[0].name == "tea");
|
||||
REQUIRE(pgh.feature_paragraphs[0]->dependencies[1].name == "firebending");
|
||||
REQUIRE(pgh.feature_paragraphs[0]->dependencies[2].name == "order.white-lotus");
|
||||
REQUIRE(pgh.feature_paragraphs[0]->dependencies[2].features.size() == 1);
|
||||
REQUIRE(pgh.feature_paragraphs[0]->dependencies[2].features[0] == "the-ancient-ways");
|
||||
REQUIRE_FALSE(pgh.feature_paragraphs[0]->dependencies[2].platform.evaluate({{"VCPKG_CMAKE_SYSTEM_NAME", ""}, {"VCPKG_TARGET_ARCHITECTURE", "arm"}}));
|
||||
REQUIRE(pgh.feature_paragraphs[0]->dependencies[2].platform.evaluate({{"VCPKG_CMAKE_SYSTEM_NAME", ""}, {"VCPKG_TARGET_ARCHITECTURE", "x86"}}));
|
||||
REQUIRE(pgh.feature_paragraphs[0]->dependencies[2].platform.evaluate({{"VCPKG_CMAKE_SYSTEM_NAME", "Linux"}, {"VCPKG_TARGET_ARCHITECTURE", "x86"}}));
|
||||
|
||||
REQUIRE(pgh.feature_paragraphs[1]->name == "zuko");
|
||||
REQUIRE(pgh.feature_paragraphs[1]->description.size() == 2);
|
||||
REQUIRE(pgh.feature_paragraphs[1]->description[0] == "son of the fire lord");
|
||||
REQUIRE(pgh.feature_paragraphs[1]->description[1] == "firebending 師父");
|
||||
}
|
||||
|
||||
TEST_CASE ("SourceParagraph manifest two dependencies", "[manifests]")
|
||||
{
|
||||
auto m_pgh = test_parse_manifest(R"json({
|
||||
"name": "zlib",
|
||||
"version-string": "1.2.8",
|
||||
"dependencies": ["z", "openssl"]
|
||||
})json");
|
||||
REQUIRE(m_pgh.has_value());
|
||||
auto& pgh = **m_pgh.get();
|
||||
|
||||
REQUIRE(pgh.core_paragraph->dependencies.size() == 2);
|
||||
REQUIRE(pgh.core_paragraph->dependencies[0].name == "z");
|
||||
REQUIRE(pgh.core_paragraph->dependencies[1].name == "openssl");
|
||||
}
|
||||
|
||||
TEST_CASE ("SourceParagraph manifest three dependencies", "[manifests]")
|
||||
{
|
||||
auto m_pgh = test_parse_manifest(R"json({
|
||||
"name": "zlib",
|
||||
"version-string": "1.2.8",
|
||||
"dependencies": ["z", "openssl", "xyz"]
|
||||
})json");
|
||||
REQUIRE(m_pgh.has_value());
|
||||
auto& pgh = **m_pgh.get();
|
||||
|
||||
REQUIRE(pgh.core_paragraph->dependencies.size() == 3);
|
||||
REQUIRE(pgh.core_paragraph->dependencies[0].name == "z");
|
||||
REQUIRE(pgh.core_paragraph->dependencies[1].name == "openssl");
|
||||
REQUIRE(pgh.core_paragraph->dependencies[2].name == "xyz");
|
||||
}
|
||||
|
||||
TEST_CASE ("SourceParagraph manifest construct qualified dependencies", "[manifests]")
|
||||
{
|
||||
auto m_pgh = test_parse_manifest(R"json({
|
||||
"name": "zlib",
|
||||
"version-string": "1.2.8",
|
||||
"dependencies": [
|
||||
{
|
||||
"name": "liba",
|
||||
"platform": "windows"
|
||||
},
|
||||
{
|
||||
"name": "libb",
|
||||
"platform": "uwp"
|
||||
}
|
||||
]
|
||||
})json");
|
||||
REQUIRE(m_pgh.has_value());
|
||||
auto& pgh = **m_pgh.get();
|
||||
|
||||
REQUIRE(pgh.core_paragraph->name == "zlib");
|
||||
REQUIRE(pgh.core_paragraph->version == "1.2.8");
|
||||
REQUIRE(pgh.core_paragraph->maintainers.empty());
|
||||
REQUIRE(pgh.core_paragraph->description.empty());
|
||||
REQUIRE(pgh.core_paragraph->dependencies.size() == 2);
|
||||
REQUIRE(pgh.core_paragraph->dependencies[0].name == "liba");
|
||||
REQUIRE(pgh.core_paragraph->dependencies[0].platform.evaluate({{"VCPKG_CMAKE_SYSTEM_NAME", ""}}));
|
||||
REQUIRE(pgh.core_paragraph->dependencies[1].name == "libb");
|
||||
REQUIRE(pgh.core_paragraph->dependencies[1].platform.evaluate({{"VCPKG_CMAKE_SYSTEM_NAME", "WindowsStore"}}));
|
||||
}
|
||||
|
||||
TEST_CASE ("SourceParagraph manifest default features", "[manifests]")
|
||||
{
|
||||
auto m_pgh = test_parse_manifest(R"json({
|
||||
"name": "a",
|
||||
"version-string": "1.0",
|
||||
"default-features": ["a1"]
|
||||
})json");
|
||||
REQUIRE(m_pgh.has_value());
|
||||
auto& pgh = **m_pgh.get();
|
||||
|
||||
REQUIRE(pgh.core_paragraph->default_features.size() == 1);
|
||||
REQUIRE(pgh.core_paragraph->default_features[0] == "a1");
|
||||
}
|
||||
|
||||
TEST_CASE ("SourceParagraph manifest description paragraph", "[manifests]")
|
||||
{
|
||||
auto m_pgh = test_parse_manifest(R"json({
|
||||
"name": "a",
|
||||
"version-string": "1.0",
|
||||
"description": ["line 1", "line 2", "line 3"]
|
||||
})json");
|
||||
REQUIRE(m_pgh.has_value());
|
||||
auto& pgh = **m_pgh.get();
|
||||
|
||||
REQUIRE(pgh.core_paragraph->description.size() == 3);
|
||||
REQUIRE(pgh.core_paragraph->description[0] == "line 1");
|
||||
REQUIRE(pgh.core_paragraph->description[1] == "line 2");
|
||||
REQUIRE(pgh.core_paragraph->description[2] == "line 3");
|
||||
}
|
||||
|
||||
TEST_CASE ("SourceParagraph manifest supports", "[manifests]")
|
||||
{
|
||||
auto m_pgh = test_parse_manifest(R"json({
|
||||
"name": "a",
|
||||
"version-string": "1.0",
|
||||
"supports": "!(windows | osx)"
|
||||
})json");
|
||||
REQUIRE(m_pgh.has_value());
|
||||
auto& pgh = **m_pgh.get();
|
||||
|
||||
REQUIRE(pgh.core_paragraph->supports_expression.evaluate({{"VCPKG_CMAKE_SYSTEM_NAME", "Linux"}}));
|
||||
REQUIRE_FALSE(pgh.core_paragraph->supports_expression.evaluate({{"VCPKG_CMAKE_SYSTEM_NAME", ""}}));
|
||||
REQUIRE_FALSE(pgh.core_paragraph->supports_expression.evaluate({{"VCPKG_CMAKE_SYSTEM_NAME", "Darwin"}}));
|
||||
}
|
||||
|
||||
TEST_CASE ("SourceParagraph manifest empty supports", "[manifests]")
|
||||
{
|
||||
auto m_pgh = test_parse_manifest(R"json({
|
||||
"name": "a",
|
||||
"version-string": "1.0",
|
||||
"supports": ""
|
||||
})json", true);
|
||||
REQUIRE_FALSE(m_pgh.has_value());
|
||||
}
|
@ -8,28 +8,28 @@
|
||||
namespace Strings = vcpkg::Strings;
|
||||
using vcpkg::Parse::Paragraph;
|
||||
|
||||
namespace {
|
||||
|
||||
auto test_parse_control_file(const std::vector<std::unordered_map<std::string, std::string>>& v)
|
||||
namespace
|
||||
{
|
||||
std::vector<Paragraph> pghs;
|
||||
for (auto&& p : v)
|
||||
auto test_parse_control_file(const std::vector<std::unordered_map<std::string, std::string>>& v)
|
||||
{
|
||||
pghs.emplace_back();
|
||||
for (auto&& kv : p)
|
||||
pghs.back().emplace(kv.first, std::make_pair(kv.second, vcpkg::Parse::TextRowCol{}));
|
||||
std::vector<Paragraph> pghs;
|
||||
for (auto&& p : v)
|
||||
{
|
||||
pghs.emplace_back();
|
||||
for (auto&& kv : p)
|
||||
pghs.back().emplace(kv.first, std::make_pair(kv.second, vcpkg::Parse::TextRowCol{}));
|
||||
}
|
||||
return vcpkg::SourceControlFile::parse_control_file("", std::move(pghs));
|
||||
}
|
||||
return vcpkg::SourceControlFile::parse_control_file("", std::move(pghs));
|
||||
}
|
||||
|
||||
auto test_make_binary_paragraph(const std::unordered_map<std::string, std::string>& v)
|
||||
{
|
||||
Paragraph pgh;
|
||||
for (auto&& kv : v)
|
||||
pgh.emplace(kv.first, std::make_pair(kv.second, vcpkg::Parse::TextRowCol{}));
|
||||
auto test_make_binary_paragraph(const std::unordered_map<std::string, std::string>& v)
|
||||
{
|
||||
Paragraph pgh;
|
||||
for (auto&& kv : v)
|
||||
pgh.emplace(kv.first, std::make_pair(kv.second, vcpkg::Parse::TextRowCol{}));
|
||||
|
||||
return vcpkg::BinaryParagraph(std::move(pgh));
|
||||
}
|
||||
return vcpkg::BinaryParagraph(std::move(pgh));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -45,9 +45,9 @@ TEST_CASE ("SourceParagraph construct minimum", "[paragraph]")
|
||||
|
||||
REQUIRE(pgh.core_paragraph->name == "zlib");
|
||||
REQUIRE(pgh.core_paragraph->version == "1.2.8");
|
||||
REQUIRE(pgh.core_paragraph->maintainer == "");
|
||||
REQUIRE(pgh.core_paragraph->description == "");
|
||||
REQUIRE(pgh.core_paragraph->depends.size() == 0);
|
||||
REQUIRE(pgh.core_paragraph->maintainers.empty());
|
||||
REQUIRE(pgh.core_paragraph->description.empty());
|
||||
REQUIRE(pgh.core_paragraph->dependencies.size() == 0);
|
||||
}
|
||||
|
||||
TEST_CASE ("SourceParagraph construct maximum", "[paragraph]")
|
||||
@ -65,15 +65,17 @@ TEST_CASE ("SourceParagraph construct maximum", "[paragraph]")
|
||||
|
||||
REQUIRE(pgh.core_paragraph->name == "s");
|
||||
REQUIRE(pgh.core_paragraph->version == "v");
|
||||
REQUIRE(pgh.core_paragraph->maintainer == "m");
|
||||
REQUIRE(pgh.core_paragraph->description == "d");
|
||||
REQUIRE(pgh.core_paragraph->depends.size() == 1);
|
||||
REQUIRE(pgh.core_paragraph->depends[0].depend.name == "bd");
|
||||
REQUIRE(pgh.core_paragraph->maintainers.size() == 1);
|
||||
REQUIRE(pgh.core_paragraph->maintainers[0] == "m");
|
||||
REQUIRE(pgh.core_paragraph->description.size() == 1);
|
||||
REQUIRE(pgh.core_paragraph->description[0] == "d");
|
||||
REQUIRE(pgh.core_paragraph->dependencies.size() == 1);
|
||||
REQUIRE(pgh.core_paragraph->dependencies[0].name == "bd");
|
||||
REQUIRE(pgh.core_paragraph->default_features.size() == 1);
|
||||
REQUIRE(pgh.core_paragraph->default_features[0] == "df");
|
||||
}
|
||||
|
||||
TEST_CASE ("SourceParagraph two depends", "[paragraph]")
|
||||
TEST_CASE ("SourceParagraph two dependencies", "[paragraph]")
|
||||
{
|
||||
auto m_pgh = test_parse_control_file({{
|
||||
{"Source", "zlib"},
|
||||
@ -83,12 +85,12 @@ TEST_CASE ("SourceParagraph two depends", "[paragraph]")
|
||||
REQUIRE(m_pgh.has_value());
|
||||
auto& pgh = **m_pgh.get();
|
||||
|
||||
REQUIRE(pgh.core_paragraph->depends.size() == 2);
|
||||
REQUIRE(pgh.core_paragraph->depends[0].depend.name == "z");
|
||||
REQUIRE(pgh.core_paragraph->depends[1].depend.name == "openssl");
|
||||
REQUIRE(pgh.core_paragraph->dependencies.size() == 2);
|
||||
REQUIRE(pgh.core_paragraph->dependencies[0].name == "z");
|
||||
REQUIRE(pgh.core_paragraph->dependencies[1].name == "openssl");
|
||||
}
|
||||
|
||||
TEST_CASE ("SourceParagraph three depends", "[paragraph]")
|
||||
TEST_CASE ("SourceParagraph three dependencies", "[paragraph]")
|
||||
{
|
||||
auto m_pgh = test_parse_control_file({{
|
||||
{"Source", "zlib"},
|
||||
@ -98,13 +100,13 @@ TEST_CASE ("SourceParagraph three depends", "[paragraph]")
|
||||
REQUIRE(m_pgh.has_value());
|
||||
auto& pgh = **m_pgh.get();
|
||||
|
||||
REQUIRE(pgh.core_paragraph->depends.size() == 3);
|
||||
REQUIRE(pgh.core_paragraph->depends[0].depend.name == "z");
|
||||
REQUIRE(pgh.core_paragraph->depends[1].depend.name == "openssl");
|
||||
REQUIRE(pgh.core_paragraph->depends[2].depend.name == "xyz");
|
||||
REQUIRE(pgh.core_paragraph->dependencies.size() == 3);
|
||||
REQUIRE(pgh.core_paragraph->dependencies[0].name == "z");
|
||||
REQUIRE(pgh.core_paragraph->dependencies[1].name == "openssl");
|
||||
REQUIRE(pgh.core_paragraph->dependencies[2].name == "xyz");
|
||||
}
|
||||
|
||||
TEST_CASE ("SourceParagraph construct qualified depends", "[paragraph]")
|
||||
TEST_CASE ("SourceParagraph construct qualified dependencies", "[paragraph]")
|
||||
{
|
||||
auto m_pgh = test_parse_control_file({{
|
||||
{"Source", "zlib"},
|
||||
@ -116,13 +118,13 @@ TEST_CASE ("SourceParagraph construct qualified depends", "[paragraph]")
|
||||
|
||||
REQUIRE(pgh.core_paragraph->name == "zlib");
|
||||
REQUIRE(pgh.core_paragraph->version == "1.2.8");
|
||||
REQUIRE(pgh.core_paragraph->maintainer == "");
|
||||
REQUIRE(pgh.core_paragraph->description == "");
|
||||
REQUIRE(pgh.core_paragraph->depends.size() == 2);
|
||||
REQUIRE(pgh.core_paragraph->depends[0].depend.name == "liba");
|
||||
REQUIRE(pgh.core_paragraph->depends[0].qualifier == "windows");
|
||||
REQUIRE(pgh.core_paragraph->depends[1].depend.name == "libb");
|
||||
REQUIRE(pgh.core_paragraph->depends[1].qualifier == "uwp");
|
||||
REQUIRE(pgh.core_paragraph->maintainers.empty());
|
||||
REQUIRE(pgh.core_paragraph->description.empty());
|
||||
REQUIRE(pgh.core_paragraph->dependencies.size() == 2);
|
||||
REQUIRE(pgh.core_paragraph->dependencies[0].name == "liba");
|
||||
REQUIRE(pgh.core_paragraph->dependencies[0].platform.evaluate({{"VCPKG_CMAKE_SYSTEM_NAME", ""}}));
|
||||
REQUIRE(pgh.core_paragraph->dependencies[1].name == "libb");
|
||||
REQUIRE(pgh.core_paragraph->dependencies[1].platform.evaluate({{"VCPKG_CMAKE_SYSTEM_NAME", "WindowsStore"}}));
|
||||
}
|
||||
|
||||
TEST_CASE ("SourceParagraph default features", "[paragraph]")
|
||||
@ -150,10 +152,10 @@ TEST_CASE ("BinaryParagraph construct minimum", "[paragraph]")
|
||||
|
||||
REQUIRE(pgh.spec.name() == "zlib");
|
||||
REQUIRE(pgh.version == "1.2.8");
|
||||
REQUIRE(pgh.maintainer == "");
|
||||
REQUIRE(pgh.description == "");
|
||||
REQUIRE(pgh.maintainers.empty());
|
||||
REQUIRE(pgh.description.empty());
|
||||
REQUIRE(pgh.spec.triplet().canonical_name() == "x86-windows");
|
||||
REQUIRE(pgh.depends.size() == 0);
|
||||
REQUIRE(pgh.dependencies.size() == 0);
|
||||
}
|
||||
|
||||
TEST_CASE ("BinaryParagraph construct maximum", "[paragraph]")
|
||||
@ -170,13 +172,15 @@ TEST_CASE ("BinaryParagraph construct maximum", "[paragraph]")
|
||||
|
||||
REQUIRE(pgh.spec.name() == "s");
|
||||
REQUIRE(pgh.version == "v");
|
||||
REQUIRE(pgh.maintainer == "m");
|
||||
REQUIRE(pgh.description == "d");
|
||||
REQUIRE(pgh.depends.size() == 1);
|
||||
REQUIRE(pgh.depends[0] == "bd");
|
||||
REQUIRE(pgh.maintainers.size() == 1);
|
||||
REQUIRE(pgh.maintainers[0] == "m");
|
||||
REQUIRE(pgh.description.size() == 1);
|
||||
REQUIRE(pgh.description[0] == "d");
|
||||
REQUIRE(pgh.dependencies.size() == 1);
|
||||
REQUIRE(pgh.dependencies[0] == "bd");
|
||||
}
|
||||
|
||||
TEST_CASE ("BinaryParagraph three depends", "[paragraph]")
|
||||
TEST_CASE ("BinaryParagraph three dependencies", "[paragraph]")
|
||||
{
|
||||
auto pgh = test_make_binary_paragraph({
|
||||
{"Package", "zlib"},
|
||||
@ -186,10 +190,10 @@ TEST_CASE ("BinaryParagraph three depends", "[paragraph]")
|
||||
{"Depends", "a, b, c"},
|
||||
});
|
||||
|
||||
REQUIRE(pgh.depends.size() == 3);
|
||||
REQUIRE(pgh.depends[0] == "a");
|
||||
REQUIRE(pgh.depends[1] == "b");
|
||||
REQUIRE(pgh.depends[2] == "c");
|
||||
REQUIRE(pgh.dependencies.size() == 3);
|
||||
REQUIRE(pgh.dependencies[0] == "a");
|
||||
REQUIRE(pgh.dependencies[1] == "b");
|
||||
REQUIRE(pgh.dependencies[2] == "c");
|
||||
}
|
||||
|
||||
TEST_CASE ("BinaryParagraph abi", "[paragraph]")
|
||||
@ -202,7 +206,7 @@ TEST_CASE ("BinaryParagraph abi", "[paragraph]")
|
||||
{"Abi", "abcd123"},
|
||||
});
|
||||
|
||||
REQUIRE(pgh.depends.size() == 0);
|
||||
REQUIRE(pgh.dependencies.size() == 0);
|
||||
REQUIRE(pgh.abi == "abcd123");
|
||||
}
|
||||
|
||||
@ -216,7 +220,7 @@ TEST_CASE ("BinaryParagraph default features", "[paragraph]")
|
||||
{"Default-Features", "a1"},
|
||||
});
|
||||
|
||||
REQUIRE(pgh.depends.size() == 0);
|
||||
REQUIRE(pgh.dependencies.size() == 0);
|
||||
REQUIRE(pgh.default_features.size() == 1);
|
||||
REQUIRE(pgh.default_features[0] == "a1");
|
||||
}
|
||||
@ -300,8 +304,8 @@ TEST_CASE ("parse paragraphs empty fields", "[paragraph]")
|
||||
|
||||
REQUIRE(pghs.size() == 1);
|
||||
REQUIRE(pghs[0].size() == 2);
|
||||
REQUIRE(pghs[0]["f1"].first == "");
|
||||
REQUIRE(pghs[0]["f2"].first == "");
|
||||
REQUIRE(pghs[0]["f1"].first.empty());
|
||||
REQUIRE(pghs[0]["f2"].first.empty());
|
||||
REQUIRE(pghs[0].size() == 2);
|
||||
}
|
||||
|
||||
@ -408,7 +412,7 @@ TEST_CASE ("BinaryParagraph serialize max", "[paragraph]")
|
||||
REQUIRE(pghs[0]["Version"].first == "1.2.8");
|
||||
REQUIRE(pghs[0]["Architecture"].first == "x86-windows");
|
||||
REQUIRE(pghs[0]["Multi-Arch"].first == "same");
|
||||
REQUIRE(pghs[0]["Description"].first == "first line\n second line");
|
||||
REQUIRE(pghs[0]["Description"].first == "first line\n second line");
|
||||
REQUIRE(pghs[0]["Depends"].first == "dep");
|
||||
REQUIRE(pghs[0]["Type"].first == "Port");
|
||||
}
|
||||
|
@ -37,7 +37,7 @@ static void features_check(Dependencies::InstallPlanAction& plan,
|
||||
for (auto&& feature_name : expected_features)
|
||||
{
|
||||
// TODO: see if this can be simplified
|
||||
if (feature_name == "core" || feature_name == "")
|
||||
if (feature_name == "core" || feature_name.empty())
|
||||
{
|
||||
REQUIRE((Util::find(feature_list, "core") != feature_list.end() ||
|
||||
Util::find(feature_list, "") != feature_list.end()));
|
||||
|
@ -72,6 +72,8 @@ static void inner(vcpkg::Files::Filesystem& fs, const VcpkgCmdArguments& args)
|
||||
}
|
||||
|
||||
const VcpkgPaths paths(fs, args);
|
||||
paths.track_feature_flag_metrics();
|
||||
|
||||
fs.current_path(paths.root, VCPKG_LINE_INFO);
|
||||
if (args.command == "install" || args.command == "remove" || args.command == "export" || args.command == "update")
|
||||
{
|
||||
@ -231,10 +233,11 @@ int main(const int argc, const char* const* const argv)
|
||||
|
||||
VcpkgCmdArguments args = VcpkgCmdArguments::create_from_command_line(fs, argc, argv);
|
||||
args.imbue_from_environment();
|
||||
args.check_feature_flag_consistency();
|
||||
|
||||
if (const auto p = args.disable_metrics.get()) Metrics::g_metrics.lock()->set_disabled(*p);
|
||||
if (const auto p = args.print_metrics.get()) Metrics::g_metrics.lock()->set_print_metrics(*p);
|
||||
if (const auto p = args.send_metrics.get()) Metrics::g_metrics.lock()->set_send_metrics(*p);
|
||||
if (const auto p = args.disable_metrics.get()) Metrics::g_metrics.lock()->set_disabled(*p);
|
||||
if (const auto p = args.debug.get()) Debug::g_debugging = *p;
|
||||
|
||||
if (args.send_metrics.has_value() && !Metrics::g_metrics.lock()->metrics_enabled())
|
||||
@ -248,6 +251,8 @@ int main(const int argc, const char* const* const argv)
|
||||
"Warning: passed either --printmetrics or --no-printmetrics, but metrics are disabled.\n");
|
||||
}
|
||||
|
||||
args.track_feature_flag_metrics();
|
||||
|
||||
if (Debug::g_debugging)
|
||||
{
|
||||
inner(fs, args);
|
||||
|
@ -10,6 +10,7 @@
|
||||
|
||||
#if !defined(_WIN32)
|
||||
#include <fcntl.h>
|
||||
#include <sys/file.h>
|
||||
#include <sys/stat.h>
|
||||
#endif
|
||||
|
||||
@ -839,6 +840,97 @@ namespace vcpkg::Files
|
||||
fs::stdfs::current_path(path, ec);
|
||||
}
|
||||
|
||||
virtual fs::SystemHandle try_take_exclusive_file_lock(const fs::path& path, std::error_code& ec) override
|
||||
{
|
||||
fs::SystemHandle res;
|
||||
|
||||
const auto system_file_name = path.native();
|
||||
#if defined(WIN32)
|
||||
constexpr static auto busy_error = ERROR_BUSY;
|
||||
const auto system_try_take_file_lock = [&] {
|
||||
auto handle = CreateFileW(
|
||||
system_file_name.c_str(),
|
||||
GENERIC_READ,
|
||||
0 /* no sharing */,
|
||||
nullptr /* no security attributes */,
|
||||
OPEN_ALWAYS,
|
||||
FILE_ATTRIBUTE_NORMAL,
|
||||
nullptr /* no template file */);
|
||||
if (handle == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
const auto err = GetLastError();
|
||||
if (err != ERROR_SHARING_VIOLATION)
|
||||
{
|
||||
ec.assign(err, std::system_category());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
res.system_handle = reinterpret_cast<intptr_t>(handle);
|
||||
return true;
|
||||
};
|
||||
#else // ^^^ WIN32 / !WIN32 vvv
|
||||
constexpr static auto busy_error = EBUSY;
|
||||
int fd = open(system_file_name.c_str(), 0);
|
||||
if (fd < 0)
|
||||
{
|
||||
ec.assign(errno, std::system_category());
|
||||
return res;
|
||||
}
|
||||
const auto system_try_take_file_lock = [&] {
|
||||
if (flock(fd, LOCK_EX | LOCK_NB) != 0)
|
||||
{
|
||||
if (errno != EWOULDBLOCK)
|
||||
{
|
||||
ec.assign(errno, std::system_category());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
res.system_handle = fd;
|
||||
return true;
|
||||
};
|
||||
#endif
|
||||
|
||||
if (system_try_take_file_lock() || ec)
|
||||
{
|
||||
return res;
|
||||
}
|
||||
|
||||
System::printf("Waiting to take filesystem lock on %s...\n", path.u8string());
|
||||
auto wait = std::chrono::milliseconds(100);
|
||||
// waits, at most, a second and a half.
|
||||
while (wait < std::chrono::milliseconds(1000))
|
||||
{
|
||||
std::this_thread::sleep_for(wait);
|
||||
if (system_try_take_file_lock() || ec)
|
||||
{
|
||||
return res;
|
||||
}
|
||||
wait *= 2;
|
||||
}
|
||||
|
||||
#if !defined(WIN32)
|
||||
close(fd);
|
||||
#endif
|
||||
ec.assign(busy_error, std::system_category());
|
||||
return res;
|
||||
}
|
||||
virtual void unlock_file_lock(fs::SystemHandle handle, std::error_code& ec) override
|
||||
{
|
||||
#if defined(WIN32)
|
||||
if (CloseHandle(reinterpret_cast<HANDLE>(handle.system_handle)) == 0)
|
||||
{
|
||||
ec.assign(GetLastError(), std::system_category());
|
||||
}
|
||||
#else
|
||||
if (flock(handle.system_handle, LOCK_UN) != 0 || close(handle.system_handle) != 0)
|
||||
{
|
||||
ec.assign(errno, std::system_category());
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
virtual std::vector<fs::path> find_from_PATH(const std::string& name) const override
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
|
@ -144,27 +144,35 @@ namespace vcpkg::Json
|
||||
return underlying_->string;
|
||||
}
|
||||
|
||||
const Array& Value::array() const noexcept
|
||||
const Array& Value::array() const& noexcept
|
||||
{
|
||||
vcpkg::Checks::check_exit(VCPKG_LINE_INFO, is_array());
|
||||
return underlying_->array;
|
||||
}
|
||||
Array& Value::array() noexcept
|
||||
Array& Value::array() & noexcept
|
||||
{
|
||||
vcpkg::Checks::check_exit(VCPKG_LINE_INFO, is_array());
|
||||
return underlying_->array;
|
||||
}
|
||||
Array&& Value::array() && noexcept
|
||||
{
|
||||
return std::move(this->array());
|
||||
}
|
||||
|
||||
const Object& Value::object() const noexcept
|
||||
const Object& Value::object() const& noexcept
|
||||
{
|
||||
vcpkg::Checks::check_exit(VCPKG_LINE_INFO, is_object());
|
||||
return underlying_->object;
|
||||
}
|
||||
Object& Value::object() noexcept
|
||||
Object& Value::object() & noexcept
|
||||
{
|
||||
vcpkg::Checks::check_exit(VCPKG_LINE_INFO, is_object());
|
||||
return underlying_->object;
|
||||
}
|
||||
Object&& Value::object() && noexcept
|
||||
{
|
||||
return std::move(this->object());
|
||||
}
|
||||
|
||||
Value::Value() noexcept = default;
|
||||
Value::Value(Value&&) noexcept = default;
|
||||
@ -601,35 +609,39 @@ namespace vcpkg::Json
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define SCANF sscanf_s
|
||||
#else
|
||||
#define SCANF sscanf
|
||||
#endif
|
||||
|
||||
// TODO: switch to `from_chars` once we are able to remove support for old compilers
|
||||
if (floating)
|
||||
{
|
||||
double res;
|
||||
if (SCANF(number_to_parse.c_str(), "%lf", &res) != 1)
|
||||
auto opt = Strings::strto<double>(number_to_parse);
|
||||
if (auto res = opt.get())
|
||||
{
|
||||
if (std::abs(*res) < INFINITY)
|
||||
{
|
||||
return Value::number(*res);
|
||||
}
|
||||
else
|
||||
{
|
||||
add_error(Strings::format("Floating point constant too big: %s", number_to_parse));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
add_error(Strings::format("Invalid floating point constant: %s", number_to_parse));
|
||||
return Value();
|
||||
}
|
||||
return Value::number(res);
|
||||
}
|
||||
else
|
||||
{
|
||||
int64_t res;
|
||||
if (SCANF(number_to_parse.c_str(), "%" SCNd64, &res) != 1)
|
||||
auto opt = Strings::strto<int64_t>(number_to_parse);
|
||||
if (auto res = opt.get())
|
||||
{
|
||||
return Value::integer(*res);
|
||||
}
|
||||
else
|
||||
{
|
||||
add_error(Strings::format("Invalid integer constant: %s", number_to_parse));
|
||||
return Value();
|
||||
}
|
||||
return Value::integer(res);
|
||||
}
|
||||
|
||||
#undef SCANF
|
||||
return Value();
|
||||
}
|
||||
|
||||
Value parse_keyword() noexcept
|
||||
@ -960,12 +972,15 @@ namespace vcpkg::Json
|
||||
for (auto code_point : Unicode::Utf8Decoder(sv.begin(), sv.end()))
|
||||
{
|
||||
// a. If C is listed in the "Code Point" column of Table 66, then
|
||||
const auto match = std::find_if(begin(escape_sequences), end(escape_sequences), [code_point](const std::pair<char32_t, const char*>& attempt) {
|
||||
return attempt.first == code_point;
|
||||
});
|
||||
const auto match = std::find_if(begin(escape_sequences),
|
||||
end(escape_sequences),
|
||||
[code_point](const std::pair<char32_t, const char*>& attempt) {
|
||||
return attempt.first == code_point;
|
||||
});
|
||||
// i. Set product to the string-concatenation of product and the escape sequence for C as
|
||||
// specified in the "Escape Sequence" column of the corresponding row.
|
||||
if (match != end(escape_sequences)) {
|
||||
if (match != end(escape_sequences))
|
||||
{
|
||||
buffer.append(match->second);
|
||||
continue;
|
||||
}
|
||||
@ -1086,18 +1101,21 @@ namespace vcpkg::Json
|
||||
{
|
||||
std::string res;
|
||||
Stringifier{style, res}.stringify(value, 0);
|
||||
res.push_back('\n');
|
||||
return res;
|
||||
}
|
||||
std::string stringify(const Object& obj, JsonStyle style)
|
||||
{
|
||||
std::string res;
|
||||
Stringifier{style, res}.stringify_object(obj, 0);
|
||||
res.push_back('\n');
|
||||
return res;
|
||||
}
|
||||
std::string stringify(const Array& arr, JsonStyle style)
|
||||
{
|
||||
std::string res;
|
||||
Stringifier{style, res}.stringify_array(arr, 0);
|
||||
res.push_back('\n');
|
||||
return res;
|
||||
}
|
||||
// } auto stringify()
|
||||
|
@ -144,6 +144,13 @@ namespace vcpkg::Parse
|
||||
optional_field(fieldname, {out, ignore});
|
||||
return out;
|
||||
}
|
||||
std::string ParagraphParser::required_field(const std::string& fieldname)
|
||||
{
|
||||
std::string out;
|
||||
TextRowCol ignore;
|
||||
optional_field(fieldname, {out, ignore});
|
||||
return out;
|
||||
}
|
||||
|
||||
std::unique_ptr<ParseControlErrorInfo> ParagraphParser::error_info(const std::string& name) const
|
||||
{
|
||||
@ -151,8 +158,9 @@ namespace vcpkg::Parse
|
||||
{
|
||||
auto err = std::make_unique<ParseControlErrorInfo>();
|
||||
err->name = name;
|
||||
err->extra_fields = Util::extract_keys(fields);
|
||||
err->missing_fields = std::move(missing_fields);
|
||||
err->extra_fields["CONTROL"] = Util::extract_keys(fields);
|
||||
err->missing_fields["CONTROL"] = std::move(missing_fields);
|
||||
err->expected_types = std::move(expected_types);
|
||||
return err;
|
||||
}
|
||||
return nullptr;
|
||||
@ -214,7 +222,7 @@ namespace vcpkg::Parse
|
||||
parser.add_error("triplet specifier not allowed in this context", loc);
|
||||
return nullopt;
|
||||
}
|
||||
return Dependency{{pqs.name, pqs.features.value_or({})}, pqs.qualifier.value_or({})};
|
||||
return Dependency{pqs.name, pqs.features.value_or({}), pqs.platform.value_or({})};
|
||||
});
|
||||
});
|
||||
if (!opt) return {parser.get_error()->format(), expected_right_tag};
|
||||
|
@ -10,10 +10,9 @@ namespace vcpkg::Strings::details
|
||||
static bool is_space(const char c) { return std::isspace(static_cast<unsigned char>(c)) != 0; }
|
||||
|
||||
// Avoids C4244 warnings because of char<->int conversion that occur when using std::tolower()
|
||||
static char tolower_char(const char c) { return (c < 'A' || c > 'Z') ? c : c - 'A' + 'a'; }
|
||||
static char toupper_char(const char c) { return (c < 'a' || c > 'z') ? c : c - 'a' + 'A'; }
|
||||
|
||||
static bool icase_eq(char a, char b) { return tolower_char(a) == tolower_char(b); }
|
||||
static bool icase_eq(char a, char b) { return tolower_char{}(a) == tolower_char{}(b); }
|
||||
|
||||
#if defined(_WIN32)
|
||||
static _locale_t& c_locale()
|
||||
@ -102,7 +101,7 @@ bool Strings::case_insensitive_ascii_equals(StringView left, StringView right)
|
||||
|
||||
std::string Strings::ascii_to_lowercase(std::string&& s)
|
||||
{
|
||||
std::transform(s.begin(), s.end(), s.begin(), &details::tolower_char);
|
||||
Strings::ascii_to_lowercase(s.begin(), s.end());
|
||||
return std::move(s);
|
||||
}
|
||||
|
||||
@ -157,7 +156,7 @@ void Strings::trim_all_and_remove_whitespace_strings(std::vector<std::string>* s
|
||||
Util::erase_remove_if(*strings, [](const std::string& s) { return s.empty(); });
|
||||
}
|
||||
|
||||
std::vector<std::string> Strings::split(const std::string& s, const char delimiter)
|
||||
std::vector<std::string> Strings::split(StringView s, const char delimiter)
|
||||
{
|
||||
std::vector<std::string> output;
|
||||
auto first = s.begin();
|
||||
|
@ -71,7 +71,7 @@ namespace vcpkg
|
||||
return result.front();
|
||||
}
|
||||
|
||||
StringView::StringView(const std::string& s) : m_ptr(s.data()), m_size(s.size()) {}
|
||||
StringView::StringView(const std::string& s) : m_ptr(s.data()), m_size(s.size()) { }
|
||||
|
||||
std::string StringView::to_string() const { return std::string(m_ptr, m_size); }
|
||||
void StringView::to_string(std::string& s) const { s.append(m_ptr, m_size); }
|
||||
@ -82,4 +82,13 @@ namespace vcpkg
|
||||
}
|
||||
|
||||
bool operator!=(StringView lhs, StringView rhs) noexcept { return !(lhs == rhs); }
|
||||
|
||||
bool operator<(StringView lhs, StringView rhs) noexcept
|
||||
{
|
||||
return std::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
|
||||
}
|
||||
|
||||
bool operator>(StringView lhs, StringView rhs) noexcept { return rhs < lhs; }
|
||||
bool operator<=(StringView lhs, StringView rhs) noexcept { return !(rhs < lhs); }
|
||||
bool operator>=(StringView lhs, StringView rhs) noexcept { return !(lhs < rhs); }
|
||||
}
|
||||
|
@ -1048,7 +1048,7 @@ std::string vcpkg::generate_nuspec(const VcpkgPaths& paths,
|
||||
auto& version = scf.core_paragraph->version;
|
||||
std::string description =
|
||||
Strings::concat("NOT FOR DIRECT USE. Automatically generated cache package.\n\n",
|
||||
scf.core_paragraph->description,
|
||||
Strings::join("\n ", scf.core_paragraph->description),
|
||||
"\n\nVersion: ",
|
||||
version,
|
||||
"\nTriplet/Compiler hash: ",
|
||||
|
@ -6,6 +6,7 @@
|
||||
|
||||
#include <vcpkg/binaryparagraph.h>
|
||||
#include <vcpkg/paragraphparser.h>
|
||||
#include <vcpkg/paragraphs.h>
|
||||
|
||||
namespace vcpkg
|
||||
{
|
||||
@ -13,6 +14,7 @@ namespace vcpkg
|
||||
{
|
||||
static const std::string PACKAGE = "Package";
|
||||
static const std::string VERSION = "Version";
|
||||
static const std::string PORT_VERSION = "Port-Version";
|
||||
static const std::string ARCHITECTURE = "Architecture";
|
||||
static const std::string MULTI_ARCH = "Multi-Arch";
|
||||
}
|
||||
@ -24,7 +26,7 @@ namespace vcpkg
|
||||
static const std::string DESCRIPTION = "Description";
|
||||
static const std::string MAINTAINER = "Maintainer";
|
||||
static const std::string DEPENDS = "Depends";
|
||||
static const std::string DEFAULTFEATURES = "Default-Features";
|
||||
static const std::string DEFAULT_FEATURES = "Default-Features";
|
||||
static const std::string TYPE = "Type";
|
||||
}
|
||||
|
||||
@ -48,15 +50,38 @@ namespace vcpkg
|
||||
this->version = parser.optional_field(Fields::VERSION);
|
||||
this->feature = parser.optional_field(Fields::FEATURE);
|
||||
|
||||
this->description = parser.optional_field(Fields::DESCRIPTION);
|
||||
this->maintainer = parser.optional_field(Fields::MAINTAINER);
|
||||
auto pv_str = parser.optional_field(Fields::PORT_VERSION);
|
||||
this->port_version = 0;
|
||||
if (!pv_str.empty())
|
||||
{
|
||||
auto pv_opt = Strings::strto<int>(pv_str);
|
||||
if (auto pv = pv_opt.get())
|
||||
{
|
||||
this->port_version = *pv;
|
||||
}
|
||||
else
|
||||
{
|
||||
parser.add_type_error(Fields::PORT_VERSION, "a non-negative integer");
|
||||
}
|
||||
}
|
||||
|
||||
this->description = Strings::split(parser.optional_field(Fields::DESCRIPTION), '\n');
|
||||
for (auto& desc : this->description)
|
||||
{
|
||||
desc = Strings::trim(std::move(desc));
|
||||
}
|
||||
this->maintainers = Strings::split(parser.optional_field(Fields::MAINTAINER), '\n');
|
||||
for (auto& maintainer : this->maintainers)
|
||||
{
|
||||
maintainer = Strings::trim(std::move(maintainer));
|
||||
}
|
||||
|
||||
this->abi = parser.optional_field(Fields::ABI);
|
||||
|
||||
std::string multi_arch;
|
||||
parser.required_field(Fields::MULTI_ARCH, multi_arch);
|
||||
|
||||
this->depends = Util::fmap(
|
||||
this->dependencies = Util::fmap(
|
||||
parse_qualified_specifier_list(parser.optional_field(Fields::DEPENDS)).value_or_exit(VCPKG_LINE_INFO),
|
||||
[](const ParsedQualifiedSpecifier& dep) {
|
||||
// for compatibility with previous vcpkg versions, we discard all irrelevant information
|
||||
@ -64,7 +89,7 @@ namespace vcpkg
|
||||
});
|
||||
if (!this->is_feature())
|
||||
{
|
||||
this->default_features = parse_default_features_list(parser.optional_field(Fields::DEFAULTFEATURES))
|
||||
this->default_features = parse_default_features_list(parser.optional_field(Fields::DEFAULT_FEATURES))
|
||||
.value_or_exit(VCPKG_LINE_INFO);
|
||||
}
|
||||
|
||||
@ -87,16 +112,17 @@ namespace vcpkg
|
||||
const std::vector<FeatureSpec>& deps)
|
||||
: spec(spgh.name, triplet)
|
||||
, version(spgh.version)
|
||||
, port_version(spgh.port_version)
|
||||
, description(spgh.description)
|
||||
, maintainer(spgh.maintainer)
|
||||
, maintainers(spgh.maintainers)
|
||||
, feature()
|
||||
, default_features(spgh.default_features)
|
||||
, depends()
|
||||
, dependencies()
|
||||
, abi(abi_tag)
|
||||
, type(spgh.type)
|
||||
{
|
||||
this->depends = Util::fmap(deps, [](const FeatureSpec& spec) { return spec.spec().name(); });
|
||||
Util::sort_unique_erase(this->depends);
|
||||
this->dependencies = Util::fmap(deps, [](const FeatureSpec& spec) { return spec.spec().name(); });
|
||||
Util::sort_unique_erase(this->dependencies);
|
||||
}
|
||||
|
||||
BinaryParagraph::BinaryParagraph(const SourceParagraph& spgh,
|
||||
@ -105,16 +131,17 @@ namespace vcpkg
|
||||
const std ::vector<FeatureSpec>& deps)
|
||||
: spec(spgh.name, triplet)
|
||||
, version()
|
||||
, port_version()
|
||||
, description(fpgh.description)
|
||||
, maintainer()
|
||||
, maintainers()
|
||||
, feature(fpgh.name)
|
||||
, default_features()
|
||||
, depends()
|
||||
, dependencies()
|
||||
, abi()
|
||||
, type(spgh.type)
|
||||
{
|
||||
this->depends = Util::fmap(deps, [](const FeatureSpec& spec) { return spec.spec().name(); });
|
||||
Util::sort_unique_erase(this->depends);
|
||||
this->dependencies = Util::fmap(deps, [](const FeatureSpec& spec) { return spec.spec().name(); });
|
||||
Util::sort_unique_erase(this->dependencies);
|
||||
}
|
||||
|
||||
std::string BinaryParagraph::displayname() const
|
||||
@ -131,29 +158,157 @@ namespace vcpkg
|
||||
return Strings::format("%s_%s_%s", this->spec.name(), this->version, this->spec.triplet());
|
||||
}
|
||||
|
||||
void serialize(const BinaryParagraph& pgh, std::string& out_str)
|
||||
bool operator==(const BinaryParagraph& lhs, const BinaryParagraph& rhs)
|
||||
{
|
||||
out_str.append("Package: ").append(pgh.spec.name()).push_back('\n');
|
||||
if (!pgh.version.empty())
|
||||
out_str.append("Version: ").append(pgh.version).push_back('\n');
|
||||
else if (pgh.is_feature())
|
||||
out_str.append("Feature: ").append(pgh.feature).push_back('\n');
|
||||
if (!pgh.depends.empty())
|
||||
if (lhs.spec != rhs.spec) return false;
|
||||
if (lhs.version != rhs.version) return false;
|
||||
if (lhs.port_version != rhs.port_version) return false;
|
||||
if (lhs.description != rhs.description) return false;
|
||||
if (lhs.maintainers != rhs.maintainers) return false;
|
||||
if (lhs.feature != rhs.feature) return false;
|
||||
if (lhs.default_features != rhs.default_features) return false;
|
||||
if (lhs.dependencies != rhs.dependencies) return false;
|
||||
if (lhs.abi != rhs.abi) return false;
|
||||
if (lhs.type != rhs.type) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool operator!=(const BinaryParagraph& lhs, const BinaryParagraph& rhs) { return !(lhs == rhs); }
|
||||
|
||||
static void serialize_string(StringView name, const std::string& field, std::string& out_str)
|
||||
{
|
||||
if (field.empty())
|
||||
{
|
||||
out_str.append("Depends: ");
|
||||
out_str.append(Strings::join(", ", pgh.depends));
|
||||
out_str.push_back('\n');
|
||||
return;
|
||||
}
|
||||
|
||||
out_str.append("Architecture: ").append(pgh.spec.triplet().to_string()).push_back('\n');
|
||||
out_str.append("Multi-Arch: same\n");
|
||||
out_str.append(name.begin(), name.end()).append(": ").append(field).push_back('\n');
|
||||
}
|
||||
static void serialize_array(StringView name,
|
||||
const std::vector<std::string>& array,
|
||||
std::string& out_str,
|
||||
const char* joiner = ", ")
|
||||
{
|
||||
if (array.empty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!pgh.maintainer.empty()) out_str.append("Maintainer: ").append(pgh.maintainer).push_back('\n');
|
||||
if (!pgh.abi.empty()) out_str.append("Abi: ").append(pgh.abi).push_back('\n');
|
||||
if (!pgh.description.empty()) out_str.append("Description: ").append(pgh.description).push_back('\n');
|
||||
out_str.append(name.begin(), name.end()).append(": ");
|
||||
out_str.append(Strings::join(joiner, array));
|
||||
out_str.push_back('\n');
|
||||
}
|
||||
static void serialize_paragraph(StringView name, const std::vector<std::string>& array, std::string& out_str)
|
||||
{
|
||||
serialize_array(name, array, out_str, "\n ");
|
||||
}
|
||||
|
||||
out_str.append("Type: ").append(Type::to_string(pgh.type)).push_back('\n');
|
||||
if (!pgh.default_features.empty())
|
||||
out_str.append("Default-Features: ").append(Strings::join(", ", pgh.default_features)).push_back('\n');
|
||||
void serialize(const BinaryParagraph& pgh, std::string& out_str)
|
||||
{
|
||||
const size_t initial_end = out_str.size();
|
||||
|
||||
serialize_string(Fields::PACKAGE, pgh.spec.name(), out_str);
|
||||
|
||||
serialize_string(Fields::VERSION, pgh.version, out_str);
|
||||
if (pgh.port_version != 0)
|
||||
{
|
||||
out_str.append(Fields::PORT_VERSION).append(": ").append(std::to_string(pgh.port_version)).push_back('\n');
|
||||
}
|
||||
|
||||
if (pgh.is_feature())
|
||||
{
|
||||
serialize_string(Fields::FEATURE, pgh.feature, out_str);
|
||||
}
|
||||
|
||||
if (!pgh.dependencies.empty())
|
||||
{
|
||||
serialize_array(Fields::DEPENDS, pgh.dependencies, out_str);
|
||||
}
|
||||
|
||||
serialize_string(Fields::ARCHITECTURE, pgh.spec.triplet().to_string(), out_str);
|
||||
serialize_string(Fields::MULTI_ARCH, "same", out_str);
|
||||
|
||||
serialize_paragraph(Fields::MAINTAINER, pgh.maintainers, out_str);
|
||||
|
||||
serialize_string(Fields::ABI, pgh.abi, out_str);
|
||||
|
||||
serialize_paragraph(Fields::DESCRIPTION, pgh.description, out_str);
|
||||
|
||||
serialize_string(Fields::TYPE, Type::to_string(pgh.type), out_str);
|
||||
serialize_array(Fields::DEFAULT_FEATURES, pgh.default_features, out_str);
|
||||
|
||||
// sanity check the serialized data
|
||||
const auto my_paragraph = out_str.substr(initial_end);
|
||||
auto parsed_paragraph = Paragraphs::parse_single_paragraph(
|
||||
out_str.substr(initial_end), "vcpkg::serialize(const BinaryParagraph&, std::string&)");
|
||||
if (!parsed_paragraph.has_value())
|
||||
{
|
||||
Checks::exit_with_message(VCPKG_LINE_INFO,
|
||||
R"([sanity check] Failed to parse a serialized binary paragraph.
|
||||
Please open an issue at https://github.com/microsoft/vcpkg, with the following output:
|
||||
Error: %s
|
||||
|
||||
=== Serialized BinaryParagraph ===
|
||||
%s
|
||||
)",
|
||||
parsed_paragraph.error(),
|
||||
my_paragraph);
|
||||
}
|
||||
|
||||
auto binary_paragraph = BinaryParagraph(*parsed_paragraph.get());
|
||||
if (binary_paragraph != pgh)
|
||||
{
|
||||
const auto& join_str = R"(", ")";
|
||||
Checks::exit_with_message(
|
||||
VCPKG_LINE_INFO,
|
||||
R"([sanity check] The serialized binary paragraph was different from the original binary paragraph.
|
||||
Please open an issue at https://github.com/microsoft/vcpkg, with the following output:
|
||||
|
||||
=== Original BinaryParagraph ===
|
||||
spec: "%s"
|
||||
version: "%s"
|
||||
port_version: %d
|
||||
description: ["%s"]
|
||||
maintainers: ["%s"]
|
||||
feature: "%s"
|
||||
default_features: ["%s"]
|
||||
dependencies: ["%s"]
|
||||
abi: "%s"
|
||||
type: %s
|
||||
|
||||
=== Serialized BinaryParagraph ===
|
||||
spec: "%s"
|
||||
version: "%s"
|
||||
port_version: %d
|
||||
description: ["%s"]
|
||||
maintainers: ["%s"]
|
||||
feature: "%s"
|
||||
default_features: ["%s"]
|
||||
dependencies: ["%s"]
|
||||
abi: "%s"
|
||||
type: %s
|
||||
)",
|
||||
pgh.spec.to_string(),
|
||||
pgh.version,
|
||||
pgh.port_version,
|
||||
Strings::join(join_str, pgh.description),
|
||||
Strings::join(join_str, pgh.maintainers),
|
||||
pgh.feature,
|
||||
Strings::join(join_str, pgh.default_features),
|
||||
Strings::join(join_str, pgh.dependencies),
|
||||
pgh.abi,
|
||||
Type::to_string(pgh.type),
|
||||
binary_paragraph.spec.to_string(),
|
||||
binary_paragraph.version,
|
||||
binary_paragraph.port_version,
|
||||
Strings::join(join_str, binary_paragraph.description),
|
||||
Strings::join(join_str, binary_paragraph.maintainers),
|
||||
binary_paragraph.feature,
|
||||
Strings::join(join_str, binary_paragraph.default_features),
|
||||
Strings::join(join_str, binary_paragraph.dependencies),
|
||||
binary_paragraph.abi,
|
||||
Type::to_string(binary_paragraph.type));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -153,14 +153,14 @@ namespace vcpkg::Build
|
||||
std::string first_arg = args.command_arguments.at(0);
|
||||
|
||||
auto binaryprovider =
|
||||
create_binary_provider_from_configs(paths, args.binarysources).value_or_exit(VCPKG_LINE_INFO);
|
||||
create_binary_provider_from_configs(paths, args.binary_sources).value_or_exit(VCPKG_LINE_INFO);
|
||||
|
||||
const FullPackageSpec spec = Input::check_and_get_full_package_spec(
|
||||
std::move(first_arg), default_triplet, COMMAND_STRUCTURE.example_text);
|
||||
|
||||
Input::check_triplet(spec.package_spec.triplet(), paths);
|
||||
|
||||
PathsPortFileProvider provider(paths, args.overlay_ports.get());
|
||||
PathsPortFileProvider provider(paths, args.overlay_ports);
|
||||
const auto port_name = spec.package_spec.name();
|
||||
const auto* scfl = provider.get_control_file(port_name).get();
|
||||
|
||||
|
@ -14,6 +14,7 @@ namespace vcpkg
|
||||
local_variables.emplace_back("BUILDTREES_DIR", paths.buildtrees);
|
||||
local_variables.emplace_back("_VCPKG_INSTALLED_DIR", paths.installed);
|
||||
local_variables.emplace_back("DOWNLOADS", paths.downloads);
|
||||
local_variables.emplace_back("VCPKG_MANIFEST_INSTALL", "OFF");
|
||||
return System::make_basic_cmake_cmd(paths.get_tool_exe(Tools::CMAKE), cmake_script, local_variables);
|
||||
}
|
||||
}
|
||||
|
@ -22,16 +22,16 @@ namespace vcpkg::Commands::BuildExternal
|
||||
const ParsedArguments options = args.parse_arguments(COMMAND_STRUCTURE);
|
||||
|
||||
auto binaryprovider =
|
||||
create_binary_provider_from_configs(paths, args.binarysources).value_or_exit(VCPKG_LINE_INFO);
|
||||
create_binary_provider_from_configs(paths, args.binary_sources).value_or_exit(VCPKG_LINE_INFO);
|
||||
|
||||
const FullPackageSpec spec = Input::check_and_get_full_package_spec(
|
||||
std::string(args.command_arguments.at(0)), default_triplet, COMMAND_STRUCTURE.example_text);
|
||||
Input::check_triplet(spec.package_spec.triplet(), paths);
|
||||
|
||||
auto overlays = args.overlay_ports ? *args.overlay_ports : std::vector<std::string>();
|
||||
auto overlays = args.overlay_ports;
|
||||
overlays.insert(overlays.begin(), args.command_arguments.at(1));
|
||||
|
||||
PortFileProvider::PathsPortFileProvider provider(paths, &overlays);
|
||||
PortFileProvider::PathsPortFileProvider provider(paths, overlays);
|
||||
auto maybe_scfl = provider.get_control_file(spec.package_spec.name());
|
||||
|
||||
Checks::check_exit(
|
||||
|
@ -14,7 +14,7 @@
|
||||
#include <vcpkg/help.h>
|
||||
#include <vcpkg/input.h>
|
||||
#include <vcpkg/install.h>
|
||||
#include <vcpkg/logicexpression.h>
|
||||
#include <vcpkg/platform-expression.h>
|
||||
#include <vcpkg/packagespec.h>
|
||||
#include <vcpkg/vcpkglib.h>
|
||||
|
||||
@ -171,7 +171,7 @@ namespace vcpkg::Commands::CI
|
||||
}
|
||||
|
||||
std::string traits_block;
|
||||
if (test.abi_tag != "")
|
||||
if (!test.abi_tag.empty())
|
||||
{
|
||||
traits_block += Strings::format(R"(<trait name="abi_tag" value="%s" />)", test.abi_tag);
|
||||
}
|
||||
@ -226,26 +226,11 @@ namespace vcpkg::Commands::CI
|
||||
const InstallPlanAction* install_plan)
|
||||
{
|
||||
auto&& scfl = install_plan->source_control_file_location.value_or_exit(VCPKG_LINE_INFO);
|
||||
const std::string& supports_expression = scfl.source_control_file->core_paragraph->supports_expression;
|
||||
if (supports_expression.empty())
|
||||
{
|
||||
return true; // default to 'supported'
|
||||
}
|
||||
const auto& supports_expression = scfl.source_control_file->core_paragraph->supports_expression;
|
||||
PlatformExpression::Context context =
|
||||
var_provider.get_tag_vars(install_plan->spec).value_or_exit(VCPKG_LINE_INFO);
|
||||
|
||||
ExpressionContext context = {var_provider.get_tag_vars(install_plan->spec).value_or_exit(VCPKG_LINE_INFO),
|
||||
install_plan->spec.triplet().canonical_name()};
|
||||
auto maybe_result = evaluate_expression(supports_expression, context);
|
||||
if (auto b = maybe_result.get())
|
||||
return *b;
|
||||
else
|
||||
{
|
||||
System::print2(System::Color::error,
|
||||
"Error: while processing ",
|
||||
install_plan->spec.to_string(),
|
||||
"\n",
|
||||
maybe_result.error());
|
||||
Checks::exit_fail(VCPKG_LINE_INFO);
|
||||
}
|
||||
return supports_expression.evaluate(context);
|
||||
}
|
||||
|
||||
static std::unique_ptr<UnknownCIPortsResults> find_unknown_ports_for_ci(
|
||||
@ -272,13 +257,13 @@ namespace vcpkg::Commands::CI
|
||||
};
|
||||
|
||||
std::vector<PackageSpec> packages_with_qualified_deps;
|
||||
auto has_qualifier = [](Dependency const& dep) { return !dep.qualifier.empty(); };
|
||||
auto has_qualifier = [](Dependency const& dep) { return !dep.platform.is_empty(); };
|
||||
for (auto&& spec : specs)
|
||||
{
|
||||
auto&& scfl = provider.get_control_file(spec.package_spec.name()).value_or_exit(VCPKG_LINE_INFO);
|
||||
if (Util::any_of(scfl.source_control_file->core_paragraph->depends, has_qualifier) ||
|
||||
if (Util::any_of(scfl.source_control_file->core_paragraph->dependencies, has_qualifier) ||
|
||||
Util::any_of(scfl.source_control_file->feature_paragraphs,
|
||||
[&](auto&& pgh) { return Util::any_of(pgh->depends, has_qualifier); }))
|
||||
[&](auto&& pgh) { return Util::any_of(pgh->dependencies, has_qualifier); }))
|
||||
{
|
||||
packages_with_qualified_deps.push_back(spec.package_spec);
|
||||
}
|
||||
@ -385,7 +370,7 @@ namespace vcpkg::Commands::CI
|
||||
if (args.binary_caching_enabled())
|
||||
{
|
||||
binaryproviderStorage =
|
||||
create_binary_provider_from_configs(paths, args.binarysources).value_or_exit(VCPKG_LINE_INFO);
|
||||
create_binary_provider_from_configs(paths, args.binary_sources).value_or_exit(VCPKG_LINE_INFO);
|
||||
}
|
||||
|
||||
IBinaryProvider& binaryprovider = binaryproviderStorage ? *binaryproviderStorage : null_binary_provider();
|
||||
@ -412,7 +397,7 @@ namespace vcpkg::Commands::CI
|
||||
|
||||
StatusParagraphs status_db = database_load_check(paths);
|
||||
|
||||
PortFileProvider::PathsPortFileProvider provider(paths, args.overlay_ports.get());
|
||||
PortFileProvider::PathsPortFileProvider provider(paths, args.overlay_ports);
|
||||
auto var_provider_storage = CMakeVars::make_triplet_cmake_var_provider(paths);
|
||||
auto& var_provider = *var_provider_storage;
|
||||
|
||||
|
@ -42,7 +42,6 @@ namespace vcpkg::Commands
|
||||
{"update", &Update::perform_and_exit},
|
||||
{"edit", &Edit::perform_and_exit},
|
||||
{"create", &Create::perform_and_exit},
|
||||
{"import", &Import::perform_and_exit},
|
||||
{"cache", &Cache::perform_and_exit},
|
||||
{"portsdiff", &PortsDiff::perform_and_exit},
|
||||
{"autocomplete", &Autocomplete::perform_and_exit},
|
||||
@ -51,6 +50,7 @@ namespace vcpkg::Commands
|
||||
{"x-ci-clean", &CIClean::perform_and_exit},
|
||||
{"x-history", &PortHistory::perform_and_exit},
|
||||
{"x-vsinstances", &X_VSInstances::perform_and_exit},
|
||||
{"x-format-manifest", &FormatManifest::perform_and_exit},
|
||||
};
|
||||
return t;
|
||||
}
|
||||
@ -89,8 +89,7 @@ namespace vcpkg::Commands::Fetch
|
||||
namespace vcpkg::Commands::Hash
|
||||
{
|
||||
const CommandStructure COMMAND_STRUCTURE = {
|
||||
Strings::format("The argument should be a file path\n%s",
|
||||
create_example_string("hash boost_1_62_0.tar.bz2")),
|
||||
Strings::format("The argument should be a file path\n%s", create_example_string("hash boost_1_62_0.tar.bz2")),
|
||||
1,
|
||||
2,
|
||||
{},
|
||||
|
@ -251,7 +251,7 @@ namespace vcpkg::Commands::DependInfo
|
||||
Input::check_triplet(spec.package_spec.triplet(), paths);
|
||||
}
|
||||
|
||||
PathsPortFileProvider provider(paths, args.overlay_ports.get());
|
||||
PathsPortFileProvider provider(paths, args.overlay_ports);
|
||||
auto var_provider_storage = CMakeVars::make_triplet_cmake_var_provider(paths);
|
||||
auto& var_provider = *var_provider_storage;
|
||||
|
||||
|
@ -39,7 +39,7 @@ namespace vcpkg::Commands::Env
|
||||
|
||||
const ParsedArguments options = args.parse_arguments(COMMAND_STRUCTURE);
|
||||
|
||||
PortFileProvider::PathsPortFileProvider provider(paths, args.overlay_ports.get());
|
||||
PortFileProvider::PathsPortFileProvider provider(paths, args.overlay_ports);
|
||||
auto var_provider_storage = CMakeVars::make_triplet_cmake_var_provider(paths);
|
||||
auto& var_provider = *var_provider_storage;
|
||||
|
||||
|
@ -94,7 +94,7 @@ namespace vcpkg::Export::IFW
|
||||
package_xml_file_path.generic_u8string());
|
||||
|
||||
auto deps = Strings::join(
|
||||
",", binary_paragraph.depends, [](const std::string& dep) { return "packages." + dep + ":"; });
|
||||
",", binary_paragraph.dependencies, [](const std::string& dep) { return "packages." + dep + ":"; });
|
||||
|
||||
if (!deps.empty()) deps = "\n <Dependencies>" + deps + "</Dependencies>";
|
||||
|
||||
@ -175,7 +175,7 @@ namespace vcpkg::Export::IFW
|
||||
</Package>
|
||||
)###",
|
||||
action.spec.name(),
|
||||
safe_rich_from_plain_text(binary_paragraph.description),
|
||||
safe_rich_from_plain_text(Strings::join("\n", binary_paragraph.description)),
|
||||
binary_paragraph.version,
|
||||
create_release_date()),
|
||||
VCPKG_LINE_INFO);
|
||||
|
100
toolsrc/src/vcpkg/commands.format-manifest.cpp
Normal file
100
toolsrc/src/vcpkg/commands.format-manifest.cpp
Normal file
@ -0,0 +1,100 @@
|
||||
#include "pch.h"
|
||||
|
||||
#include <vcpkg/base/checks.h>
|
||||
#include <vcpkg/base/files.h>
|
||||
#include <vcpkg/base/json.h>
|
||||
#include <vcpkg/base/system.debug.h>
|
||||
#include <vcpkg/commands.h>
|
||||
#include <vcpkg/portfileprovider.h>
|
||||
|
||||
namespace vcpkg::Commands::FormatManifest
|
||||
{
|
||||
|
||||
static constexpr StringLiteral OPTION_ALL = "--all";
|
||||
|
||||
const CommandSwitch FORMAT_SWITCHES[] = {
|
||||
{ OPTION_ALL, "Format all ports' manifest files." }
|
||||
};
|
||||
|
||||
const CommandStructure COMMAND_STRUCTURE = {
|
||||
create_example_string(R"###(x-format-manifest --all)###"),
|
||||
0,
|
||||
SIZE_MAX,
|
||||
{
|
||||
FORMAT_SWITCHES,
|
||||
{},
|
||||
{}
|
||||
},
|
||||
nullptr,
|
||||
};
|
||||
|
||||
void perform_and_exit(const VcpkgCmdArguments& args, const VcpkgPaths& paths)
|
||||
{
|
||||
auto parsed_args = args.parse_arguments(COMMAND_STRUCTURE);
|
||||
|
||||
std::vector<fs::path> files_to_format;
|
||||
|
||||
auto& fs = paths.get_filesystem();
|
||||
bool has_error = false;
|
||||
|
||||
if (Util::Sets::contains(parsed_args.switches, OPTION_ALL))
|
||||
{
|
||||
for (const auto& dir : fs::directory_iterator(paths.ports))
|
||||
{
|
||||
auto manifest_path = dir.path() / fs::u8path("vcpkg.json");
|
||||
if (fs.exists(manifest_path))
|
||||
{
|
||||
files_to_format.push_back(std::move(manifest_path));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto& arg : args.command_arguments)
|
||||
{
|
||||
auto path = fs::u8path(arg);
|
||||
if (path.is_relative())
|
||||
{
|
||||
path = paths.original_cwd / path;
|
||||
}
|
||||
files_to_format.push_back(std::move(path));
|
||||
}
|
||||
|
||||
for (const auto& path : files_to_format)
|
||||
{
|
||||
std::error_code ec;
|
||||
Debug::print("Formatting ", path.u8string(), "\n");
|
||||
auto parsed_json_opt = Json::parse_file(fs, path, ec);
|
||||
if (ec)
|
||||
{
|
||||
System::printf(System::Color::error, "Failed to read %s: %s\n", path.u8string(), ec.message());
|
||||
has_error = true;
|
||||
}
|
||||
|
||||
if (auto pr = parsed_json_opt.get())
|
||||
{
|
||||
fs.write_contents(path, Json::stringify(pr->first, Json::JsonStyle{}), ec);
|
||||
}
|
||||
else
|
||||
{
|
||||
System::printf(System::Color::error, "Failed to parse %s: %s\n", path.u8string(), parsed_json_opt.error()->format());
|
||||
has_error = true;
|
||||
}
|
||||
|
||||
if (ec)
|
||||
{
|
||||
System::printf(System::Color::error, "Failed to write %s: %s\n", path.u8string(), ec.message());
|
||||
has_error = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (has_error)
|
||||
{
|
||||
Checks::exit_fail(VCPKG_LINE_INFO);
|
||||
}
|
||||
else
|
||||
{
|
||||
System::print2("Succeeded in formatting the manifest files.\n");
|
||||
Checks::exit_success(VCPKG_LINE_INFO);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,126 +0,0 @@
|
||||
#include "pch.h"
|
||||
|
||||
#include <vcpkg/base/files.h>
|
||||
#include <vcpkg/commands.h>
|
||||
#include <vcpkg/help.h>
|
||||
#include <vcpkg/paragraphs.h>
|
||||
#include <vcpkg/statusparagraph.h>
|
||||
|
||||
namespace vcpkg::Commands::Import
|
||||
{
|
||||
struct Binaries
|
||||
{
|
||||
std::vector<fs::path> dlls;
|
||||
std::vector<fs::path> libs;
|
||||
};
|
||||
|
||||
static void check_is_directory(const LineInfo& line_info, const Files::Filesystem& fs, const fs::path& dirpath)
|
||||
{
|
||||
Checks::check_exit(line_info, fs.is_directory(dirpath), "The path %s is not a directory", dirpath.string());
|
||||
}
|
||||
|
||||
static Binaries find_binaries_in_dir(const Files::Filesystem& fs, const fs::path& path)
|
||||
{
|
||||
auto files = fs.get_files_recursive(path);
|
||||
|
||||
check_is_directory(VCPKG_LINE_INFO, fs, path);
|
||||
|
||||
Binaries binaries;
|
||||
for (auto&& file : files)
|
||||
{
|
||||
if (fs.is_directory(file)) continue;
|
||||
const auto ext = file.extension();
|
||||
if (ext == ".dll")
|
||||
binaries.dlls.push_back(std::move(file));
|
||||
else if (ext == ".lib")
|
||||
binaries.libs.push_back(std::move(file));
|
||||
}
|
||||
return binaries;
|
||||
}
|
||||
|
||||
static void copy_files_into_directory(Files::Filesystem& fs,
|
||||
const std::vector<fs::path>& files,
|
||||
const fs::path& destination_folder)
|
||||
{
|
||||
std::error_code ec;
|
||||
fs.create_directory(destination_folder, ec);
|
||||
|
||||
for (auto const& src_path : files)
|
||||
{
|
||||
const fs::path dest_path = destination_folder / src_path.filename();
|
||||
fs.copy(src_path, dest_path, fs::copy_options::overwrite_existing);
|
||||
}
|
||||
}
|
||||
|
||||
static void place_library_files_in(Files::Filesystem& fs,
|
||||
const fs::path& include_directory,
|
||||
const fs::path& project_directory,
|
||||
const fs::path& destination_path)
|
||||
{
|
||||
check_is_directory(VCPKG_LINE_INFO, fs, include_directory);
|
||||
check_is_directory(VCPKG_LINE_INFO, fs, project_directory);
|
||||
check_is_directory(VCPKG_LINE_INFO, fs, destination_path);
|
||||
const Binaries debug_binaries = find_binaries_in_dir(fs, project_directory / "Debug");
|
||||
const Binaries release_binaries = find_binaries_in_dir(fs, project_directory / "Release");
|
||||
|
||||
const fs::path destination_include_directory = destination_path / "include";
|
||||
fs.copy(include_directory,
|
||||
destination_include_directory,
|
||||
fs::copy_options::recursive | fs::copy_options::overwrite_existing);
|
||||
|
||||
copy_files_into_directory(fs, release_binaries.dlls, destination_path / "bin");
|
||||
copy_files_into_directory(fs, release_binaries.libs, destination_path / "lib");
|
||||
|
||||
std::error_code ec;
|
||||
fs.create_directory(destination_path / "debug", ec);
|
||||
copy_files_into_directory(fs, debug_binaries.dlls, destination_path / "debug" / "bin");
|
||||
copy_files_into_directory(fs, debug_binaries.libs, destination_path / "debug" / "lib");
|
||||
}
|
||||
|
||||
static void do_import(const VcpkgPaths& paths,
|
||||
const fs::path& include_directory,
|
||||
const fs::path& project_directory,
|
||||
const BinaryParagraph& control_file_data)
|
||||
{
|
||||
auto& fs = paths.get_filesystem();
|
||||
const fs::path library_destination_path = paths.package_dir(control_file_data.spec);
|
||||
std::error_code ec;
|
||||
fs.create_directory(library_destination_path, ec);
|
||||
place_library_files_in(paths.get_filesystem(), include_directory, project_directory, library_destination_path);
|
||||
|
||||
const fs::path control_file_path = library_destination_path / "CONTROL";
|
||||
fs.write_contents(control_file_path, Strings::serialize(control_file_data), VCPKG_LINE_INFO);
|
||||
}
|
||||
|
||||
const CommandStructure COMMAND_STRUCTURE = {
|
||||
create_example_string(R"(import C:\path\to\CONTROLfile C:\path\to\includedir C:\path\to\projectdir)"),
|
||||
3,
|
||||
3,
|
||||
{},
|
||||
nullptr,
|
||||
};
|
||||
|
||||
void perform_and_exit(const VcpkgCmdArguments& args, const VcpkgPaths& paths)
|
||||
{
|
||||
Util::unused(args.parse_arguments(COMMAND_STRUCTURE));
|
||||
|
||||
const fs::path control_file_path(args.command_arguments[0]);
|
||||
const fs::path include_directory(args.command_arguments[1]);
|
||||
const fs::path project_directory(args.command_arguments[2]);
|
||||
|
||||
const auto pghs = Paragraphs::get_single_paragraph(paths.get_filesystem(), control_file_path);
|
||||
Checks::check_exit(VCPKG_LINE_INFO,
|
||||
pghs.get() != nullptr,
|
||||
"Invalid control file %s for package",
|
||||
control_file_path.generic_u8string(),
|
||||
"\n",
|
||||
pghs.error());
|
||||
|
||||
StatusParagraph spgh;
|
||||
spgh.package = BinaryParagraph(*pghs.get());
|
||||
auto& control_file_data = spgh.package;
|
||||
|
||||
do_import(paths, include_directory, project_directory, control_file_data);
|
||||
Checks::exit_success(VCPKG_LINE_INFO);
|
||||
}
|
||||
}
|
@ -14,14 +14,22 @@ namespace vcpkg::Commands::List
|
||||
{
|
||||
if (full_desc)
|
||||
{
|
||||
System::printf("%-50s %-16s %s\n", pgh.package.displayname(), pgh.package.version, pgh.package.description);
|
||||
System::printf("%-50s %-16s %s\n",
|
||||
pgh.package.displayname(),
|
||||
pgh.package.version,
|
||||
Strings::join("\n ", pgh.package.description));
|
||||
}
|
||||
else
|
||||
{
|
||||
std::string description;
|
||||
if (!pgh.package.description.empty())
|
||||
{
|
||||
description = pgh.package.description[0];
|
||||
}
|
||||
System::printf("%-50s %-16s %s\n",
|
||||
vcpkg::shorten_text(pgh.package.displayname(), 50),
|
||||
vcpkg::shorten_text(pgh.package.version, 16),
|
||||
vcpkg::shorten_text(pgh.package.description, 51));
|
||||
vcpkg::shorten_text(description, 51));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -20,15 +20,22 @@ namespace vcpkg::Commands::Search
|
||||
{
|
||||
if (full_desc)
|
||||
{
|
||||
System::printf(
|
||||
"%-20s %-16s %s\n", source_paragraph.name, source_paragraph.version, source_paragraph.description);
|
||||
System::printf("%-20s %-16s %s\n",
|
||||
source_paragraph.name,
|
||||
source_paragraph.version,
|
||||
Strings::join("\n ", source_paragraph.description));
|
||||
}
|
||||
else
|
||||
{
|
||||
std::string description;
|
||||
if (!source_paragraph.description.empty())
|
||||
{
|
||||
description = source_paragraph.description[0];
|
||||
}
|
||||
System::printf("%-20s %-16s %s\n",
|
||||
vcpkg::shorten_text(source_paragraph.name, 20),
|
||||
vcpkg::shorten_text(source_paragraph.version, 16),
|
||||
vcpkg::shorten_text(source_paragraph.description, 81));
|
||||
vcpkg::shorten_text(description, 81));
|
||||
}
|
||||
}
|
||||
|
||||
@ -37,13 +44,17 @@ namespace vcpkg::Commands::Search
|
||||
auto full_feature_name = Strings::concat(name, "[", feature_paragraph.name, "]");
|
||||
if (full_desc)
|
||||
{
|
||||
System::printf("%-37s %s\n", full_feature_name, feature_paragraph.description);
|
||||
System::printf("%-37s %s\n", full_feature_name, Strings::join("\n ", feature_paragraph.description));
|
||||
}
|
||||
else
|
||||
{
|
||||
System::printf("%-37s %s\n",
|
||||
vcpkg::shorten_text(full_feature_name, 37),
|
||||
vcpkg::shorten_text(feature_paragraph.description, 81));
|
||||
std::string description;
|
||||
if (!feature_paragraph.description.empty())
|
||||
{
|
||||
description = feature_paragraph.description[0];
|
||||
}
|
||||
System::printf(
|
||||
"%-37s %s\n", vcpkg::shorten_text(full_feature_name, 37), vcpkg::shorten_text(description, 81));
|
||||
}
|
||||
}
|
||||
|
||||
@ -66,7 +77,7 @@ namespace vcpkg::Commands::Search
|
||||
const ParsedArguments options = args.parse_arguments(COMMAND_STRUCTURE);
|
||||
const bool full_description = Util::Sets::contains(options.switches, OPTION_FULLDESC);
|
||||
|
||||
PathsPortFileProvider provider(paths, args.overlay_ports.get());
|
||||
PathsPortFileProvider provider(paths, args.overlay_ports);
|
||||
auto source_paragraphs =
|
||||
Util::fmap(provider.load_all_control_files(),
|
||||
[](auto&& port) -> const SourceControlFile* { return port->source_control_file.get(); });
|
||||
@ -84,24 +95,40 @@ namespace vcpkg::Commands::Search
|
||||
}
|
||||
else
|
||||
{
|
||||
const auto& icontains = Strings::case_insensitive_ascii_contains;
|
||||
|
||||
// At this point there is 1 argument
|
||||
auto&& args_zero = args.command_arguments[0];
|
||||
const auto contained_in = [&args_zero](const auto& s) {
|
||||
return Strings::case_insensitive_ascii_contains(s, args_zero);
|
||||
};
|
||||
for (const auto& source_control_file : source_paragraphs)
|
||||
{
|
||||
auto&& sp = *source_control_file->core_paragraph;
|
||||
|
||||
const bool contains_name = icontains(sp.name, args_zero);
|
||||
if (contains_name || icontains(sp.description, args_zero))
|
||||
bool found_match = contained_in(sp.name);
|
||||
if (!found_match)
|
||||
{
|
||||
found_match = std::any_of(sp.description.begin(), sp.description.end(), contained_in);
|
||||
}
|
||||
|
||||
if (found_match)
|
||||
{
|
||||
do_print(sp, full_description);
|
||||
}
|
||||
|
||||
for (auto&& feature_paragraph : source_control_file->feature_paragraphs)
|
||||
{
|
||||
if (contains_name || icontains(feature_paragraph->name, args_zero) ||
|
||||
icontains(feature_paragraph->description, args_zero))
|
||||
bool found_match_for_feature = found_match;
|
||||
if (!found_match_for_feature)
|
||||
{
|
||||
found_match_for_feature = contained_in(feature_paragraph->name);
|
||||
}
|
||||
if (!found_match_for_feature)
|
||||
{
|
||||
found_match_for_feature = std::any_of(
|
||||
feature_paragraph->description.begin(), feature_paragraph->description.end(), contained_in);
|
||||
}
|
||||
|
||||
if (found_match_for_feature)
|
||||
{
|
||||
do_print(sp.name, *feature_paragraph, full_description);
|
||||
}
|
||||
|
@ -27,52 +27,27 @@ namespace vcpkg::Commands::SetInstalled
|
||||
nullptr,
|
||||
};
|
||||
|
||||
void perform_and_exit(const VcpkgCmdArguments& args, const VcpkgPaths& paths, Triplet default_triplet)
|
||||
void perform_and_exit_ex(const VcpkgCmdArguments& args,
|
||||
const VcpkgPaths& paths,
|
||||
const PortFileProvider::PathsPortFileProvider& provider,
|
||||
IBinaryProvider& binary_provider,
|
||||
const CMakeVars::CMakeVarProvider& cmake_vars,
|
||||
const std::vector<FullPackageSpec>& specs,
|
||||
const Build::BuildPackageOptions& install_plan_options,
|
||||
DryRun dry_run)
|
||||
{
|
||||
// input sanitization
|
||||
const ParsedArguments options = args.parse_arguments(COMMAND_STRUCTURE);
|
||||
|
||||
const std::vector<FullPackageSpec> specs = Util::fmap(args.command_arguments, [&](auto&& arg) {
|
||||
return Input::check_and_get_full_package_spec(
|
||||
std::string(arg), default_triplet, COMMAND_STRUCTURE.example_text);
|
||||
});
|
||||
|
||||
for (auto&& spec : specs)
|
||||
{
|
||||
Input::check_triplet(spec.package_spec.triplet(), paths);
|
||||
}
|
||||
|
||||
auto binaryprovider =
|
||||
create_binary_provider_from_configs(paths, args.binarysources).value_or_exit(VCPKG_LINE_INFO);
|
||||
|
||||
const bool dry_run = Util::Sets::contains(options.switches, OPTION_DRY_RUN);
|
||||
|
||||
const Build::BuildPackageOptions install_plan_options = {
|
||||
Build::UseHeadVersion::NO,
|
||||
Build::AllowDownloads::YES,
|
||||
Build::OnlyDownloads::NO,
|
||||
Build::CleanBuildtrees::YES,
|
||||
Build::CleanPackages::YES,
|
||||
Build::CleanDownloads::YES,
|
||||
Build::DownloadTool::BUILT_IN,
|
||||
Build::FailOnTombstone::NO,
|
||||
};
|
||||
|
||||
PortFileProvider::PathsPortFileProvider provider(paths, args.overlay_ports.get());
|
||||
auto cmake_vars = CMakeVars::make_triplet_cmake_var_provider(paths);
|
||||
|
||||
// We have a set of user-requested specs.
|
||||
// We need to know all the specs which are required to fulfill dependencies for those specs.
|
||||
// Therefore, we see what we would install into an empty installed tree, so we can use the existing code.
|
||||
auto action_plan = Dependencies::create_feature_install_plan(provider, *cmake_vars, specs, {});
|
||||
auto action_plan = Dependencies::create_feature_install_plan(provider, cmake_vars, specs, {});
|
||||
|
||||
for (auto&& action : action_plan.install_actions)
|
||||
{
|
||||
action.build_options = install_plan_options;
|
||||
}
|
||||
|
||||
cmake_vars->load_tag_vars(action_plan, provider);
|
||||
Build::compute_all_abis(paths, action_plan, *cmake_vars, {});
|
||||
cmake_vars.load_tag_vars(action_plan, provider);
|
||||
Build::compute_all_abis(paths, action_plan, cmake_vars, {});
|
||||
|
||||
std::set<std::string> all_abis;
|
||||
|
||||
@ -116,7 +91,7 @@ namespace vcpkg::Commands::SetInstalled
|
||||
|
||||
Dependencies::print_plan(action_plan, true, paths.ports);
|
||||
|
||||
if (dry_run)
|
||||
if (dry_run == DryRun::Yes)
|
||||
{
|
||||
Checks::exit_success(VCPKG_LINE_INFO);
|
||||
}
|
||||
@ -125,12 +100,55 @@ namespace vcpkg::Commands::SetInstalled
|
||||
Install::KeepGoing::NO,
|
||||
paths,
|
||||
status_db,
|
||||
args.binary_caching_enabled() ? *binaryprovider : null_binary_provider(),
|
||||
*cmake_vars);
|
||||
args.binary_caching_enabled() ? binary_provider : null_binary_provider(),
|
||||
cmake_vars);
|
||||
|
||||
System::print2("\nTotal elapsed time: ", summary.total_elapsed_time, "\n\n");
|
||||
|
||||
Checks::exit_success(VCPKG_LINE_INFO);
|
||||
}
|
||||
|
||||
void perform_and_exit(const VcpkgCmdArguments& args, const VcpkgPaths& paths, Triplet default_triplet)
|
||||
{
|
||||
// input sanitization
|
||||
const ParsedArguments options = args.parse_arguments(COMMAND_STRUCTURE);
|
||||
|
||||
const std::vector<FullPackageSpec> specs = Util::fmap(args.command_arguments, [&](auto&& arg) {
|
||||
return Input::check_and_get_full_package_spec(
|
||||
std::string(arg), default_triplet, COMMAND_STRUCTURE.example_text);
|
||||
});
|
||||
|
||||
for (auto&& spec : specs)
|
||||
{
|
||||
Input::check_triplet(spec.package_spec.triplet(), paths);
|
||||
}
|
||||
|
||||
auto binary_provider =
|
||||
create_binary_provider_from_configs(paths, args.binary_sources).value_or_exit(VCPKG_LINE_INFO);
|
||||
|
||||
const bool dry_run = Util::Sets::contains(options.switches, OPTION_DRY_RUN);
|
||||
|
||||
const Build::BuildPackageOptions install_plan_options = {
|
||||
Build::UseHeadVersion::NO,
|
||||
Build::AllowDownloads::YES,
|
||||
Build::OnlyDownloads::NO,
|
||||
Build::CleanBuildtrees::YES,
|
||||
Build::CleanPackages::YES,
|
||||
Build::CleanDownloads::YES,
|
||||
Build::DownloadTool::BUILT_IN,
|
||||
Build::FailOnTombstone::NO,
|
||||
};
|
||||
|
||||
PortFileProvider::PathsPortFileProvider provider(paths, args.overlay_ports);
|
||||
auto cmake_vars = CMakeVars::make_triplet_cmake_var_provider(paths);
|
||||
|
||||
perform_and_exit_ex(args,
|
||||
paths,
|
||||
provider,
|
||||
*binary_provider,
|
||||
*cmake_vars,
|
||||
specs,
|
||||
install_plan_options,
|
||||
dry_run ? DryRun::Yes : DryRun::No);
|
||||
}
|
||||
}
|
||||
|
@ -43,12 +43,12 @@ namespace vcpkg::Commands::Upgrade
|
||||
const KeepGoing keep_going = to_keep_going(Util::Sets::contains(options.switches, OPTION_KEEP_GOING));
|
||||
|
||||
auto binaryprovider =
|
||||
create_binary_provider_from_configs(paths, args.binarysources).value_or_exit(VCPKG_LINE_INFO);
|
||||
create_binary_provider_from_configs(paths, args.binary_sources).value_or_exit(VCPKG_LINE_INFO);
|
||||
|
||||
StatusParagraphs status_db = database_load_check(paths);
|
||||
|
||||
// Load ports from ports dirs
|
||||
PortFileProvider::PathsPortFileProvider provider(paths, args.overlay_ports.get());
|
||||
PortFileProvider::PathsPortFileProvider provider(paths, args.overlay_ports);
|
||||
auto var_provider_storage = CMakeVars::make_triplet_cmake_var_provider(paths);
|
||||
auto& var_provider = *var_provider_storage;
|
||||
|
||||
|
@ -53,7 +53,7 @@ namespace vcpkg::Dependencies
|
||||
{
|
||||
}
|
||||
|
||||
Cluster(const PackageSpec& spec, const SourceControlFileLocation& scfl) : m_spec(spec), m_scfl(scfl) {}
|
||||
Cluster(const PackageSpec& spec, const SourceControlFileLocation& scfl) : m_spec(spec), m_scfl(scfl) { }
|
||||
|
||||
bool has_feature_installed(const std::string& feature) const
|
||||
{
|
||||
@ -124,12 +124,11 @@ namespace vcpkg::Dependencies
|
||||
bool requires_qualified_resolution = false;
|
||||
for (const Dependency& dep : *qualified_deps)
|
||||
{
|
||||
if (dep.qualifier.empty())
|
||||
if (dep.platform.is_empty())
|
||||
{
|
||||
Util::Vectors::append(
|
||||
&dep_list,
|
||||
FullPackageSpec({dep.depend.name, m_spec.triplet()}, dep.depend.features)
|
||||
.to_feature_specs({"default"}, {"default"}));
|
||||
Util::Vectors::append(&dep_list,
|
||||
FullPackageSpec({dep.name, m_spec.triplet()}, dep.features)
|
||||
.to_feature_specs({"default"}, {"default"}));
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -684,7 +683,7 @@ namespace vcpkg::Dependencies
|
||||
const std::vector<Dependency>* paragraph_depends = nullptr;
|
||||
if (spec.feature() == "core")
|
||||
{
|
||||
paragraph_depends = &clust.m_scfl.source_control_file->core_paragraph->depends;
|
||||
paragraph_depends = &clust.m_scfl.source_control_file->core_paragraph->dependencies;
|
||||
}
|
||||
else if (spec.feature() == "default")
|
||||
{
|
||||
@ -697,12 +696,12 @@ namespace vcpkg::Dependencies
|
||||
"Package %s does not have a %s feature",
|
||||
spec.name(),
|
||||
spec.feature());
|
||||
paragraph_depends = &maybe_paragraph.value_or_exit(VCPKG_LINE_INFO).depends;
|
||||
paragraph_depends = &maybe_paragraph.value_or_exit(VCPKG_LINE_INFO).dependencies;
|
||||
}
|
||||
|
||||
// And it has at least one qualified dependency
|
||||
if (paragraph_depends &&
|
||||
Util::any_of(*paragraph_depends, [](auto&& dep) { return !dep.qualifier.empty(); }))
|
||||
Util::any_of(*paragraph_depends, [](auto&& dep) { return !dep.platform.is_empty(); }))
|
||||
{
|
||||
// Add it to the next batch run
|
||||
qualified_dependencies.emplace_back(spec);
|
||||
@ -795,7 +794,7 @@ namespace vcpkg::Dependencies
|
||||
{
|
||||
struct BaseEdgeProvider : Graphs::AdjacencyProvider<PackageSpec, const Cluster*>
|
||||
{
|
||||
BaseEdgeProvider(const ClusterGraph& parent) : m_parent(parent) {}
|
||||
BaseEdgeProvider(const ClusterGraph& parent) : m_parent(parent) { }
|
||||
|
||||
std::string to_string(const PackageSpec& spec) const override { return spec.to_string(); }
|
||||
const Cluster* load_vertex_data(const PackageSpec& spec) const override
|
||||
|
@ -19,7 +19,7 @@ namespace vcpkg::Export::Chocolatey
|
||||
static constexpr auto CONTENT_TEMPLATE = R"(<dependency id="@PACKAGE_ID@" version="[@PACKAGE_VERSION@]" />)";
|
||||
|
||||
std::string nuspec_dependencies;
|
||||
for (const std::string& depend : binary_paragraph.depends)
|
||||
for (const std::string& depend : binary_paragraph.dependencies)
|
||||
{
|
||||
auto found = packages_version.find(depend);
|
||||
if (found == packages_version.end())
|
||||
@ -68,8 +68,8 @@ namespace vcpkg::Export::Chocolatey
|
||||
Strings::replace_all(std::move(nuspec_file_content), "@PACKAGE_VERSION@", package_version->second);
|
||||
nuspec_file_content = Strings::replace_all(
|
||||
std::move(nuspec_file_content), "@PACKAGE_MAINTAINER@", chocolatey_options.maybe_maintainer.value_or(""));
|
||||
nuspec_file_content =
|
||||
Strings::replace_all(std::move(nuspec_file_content), "@PACKAGE_DESCRIPTION@", binary_paragraph.description);
|
||||
nuspec_file_content = Strings::replace_all(
|
||||
std::move(nuspec_file_content), "@PACKAGE_DESCRIPTION@", Strings::join("\n", binary_paragraph.description));
|
||||
nuspec_file_content =
|
||||
Strings::replace_all(std::move(nuspec_file_content), "@EXPORTED_ROOT_DIR@", exported_root_dir);
|
||||
nuspec_file_content = Strings::replace_all(std::move(nuspec_file_content),
|
||||
|
@ -589,13 +589,17 @@ With a project open, go to Tools->NuGet Package Manager->Package Manager Console
|
||||
|
||||
void perform_and_exit(const VcpkgCmdArguments& args, const VcpkgPaths& paths, Triplet default_triplet)
|
||||
{
|
||||
if (paths.manifest_mode_enabled())
|
||||
{
|
||||
Checks::exit_with_message(VCPKG_LINE_INFO, "vcpkg export does not support manifest mode, in order to allow for future design considerations. You may use export in classic mode by running vcpkg outside of a manifest-based project.");
|
||||
}
|
||||
const StatusParagraphs status_db = database_load_check(paths);
|
||||
const auto opts = handle_export_command_arguments(args, default_triplet, status_db);
|
||||
for (auto&& spec : opts.specs)
|
||||
Input::check_triplet(spec.triplet(), paths);
|
||||
|
||||
// Load ports from ports dirs
|
||||
PortFileProvider::PathsPortFileProvider provider(paths, args.overlay_ports.get());
|
||||
PortFileProvider::PathsPortFileProvider provider(paths, args.overlay_ports);
|
||||
|
||||
// create the plan
|
||||
std::vector<ExportPlanAction> export_plan = Dependencies::create_export_plan(opts.specs, status_db);
|
||||
|
@ -84,9 +84,10 @@ namespace vcpkg::Install
|
||||
|
||||
const std::string filename = file.filename().generic_u8string();
|
||||
if (fs::is_regular_file(status) && (Strings::case_insensitive_ascii_equals(filename, "CONTROL") ||
|
||||
Strings::case_insensitive_ascii_equals(filename, "vcpkg.json") ||
|
||||
Strings::case_insensitive_ascii_equals(filename, "BUILD_INFO")))
|
||||
{
|
||||
// Do not copy the control file
|
||||
// Do not copy the control file or manifest file
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -530,6 +531,14 @@ namespace vcpkg::Install
|
||||
&get_all_port_names,
|
||||
};
|
||||
|
||||
const CommandStructure MANIFEST_COMMAND_STRUCTURE = {
|
||||
create_example_string("install --triplet x64-windows"),
|
||||
0,
|
||||
0,
|
||||
{INSTALL_SWITCHES, INSTALL_SETTINGS},
|
||||
nullptr,
|
||||
};
|
||||
|
||||
static void print_cmake_information(const BinaryParagraph& bpgh, const VcpkgPaths& paths)
|
||||
{
|
||||
static const std::regex cmake_library_regex(R"(\badd_library\(([^\$\s\)]+)\s)",
|
||||
@ -645,20 +654,10 @@ namespace vcpkg::Install
|
||||
void perform_and_exit(const VcpkgCmdArguments& args, const VcpkgPaths& paths, Triplet default_triplet)
|
||||
{
|
||||
// input sanitization
|
||||
const ParsedArguments options = args.parse_arguments(COMMAND_STRUCTURE);
|
||||
const ParsedArguments options = args.parse_arguments(paths.manifest_mode_enabled() ? MANIFEST_COMMAND_STRUCTURE : COMMAND_STRUCTURE);
|
||||
|
||||
auto binaryprovider =
|
||||
create_binary_provider_from_configs(paths, args.binarysources).value_or_exit(VCPKG_LINE_INFO);
|
||||
|
||||
const std::vector<FullPackageSpec> specs = Util::fmap(args.command_arguments, [&](auto&& arg) {
|
||||
return Input::check_and_get_full_package_spec(
|
||||
std::string(arg), default_triplet, COMMAND_STRUCTURE.example_text);
|
||||
});
|
||||
|
||||
for (auto&& spec : specs)
|
||||
{
|
||||
Input::check_triplet(spec.package_spec.triplet(), paths);
|
||||
}
|
||||
create_binary_provider_from_configs(paths, args.binary_sources).value_or_exit(VCPKG_LINE_INFO);
|
||||
|
||||
const bool dry_run = Util::Sets::contains(options.switches, OPTION_DRY_RUN);
|
||||
const bool use_head_version = Util::Sets::contains(options.switches, (OPTION_USE_HEAD_VERSION));
|
||||
@ -672,10 +671,6 @@ namespace vcpkg::Install
|
||||
|
||||
auto& fs = paths.get_filesystem();
|
||||
|
||||
// create the plan
|
||||
System::print2("Computing installation plan...\n");
|
||||
StatusParagraphs status_db = database_load_check(paths);
|
||||
|
||||
Build::DownloadTool download_tool = Build::DownloadTool::BUILT_IN;
|
||||
if (use_aria2) download_tool = Build::DownloadTool::ARIA2;
|
||||
|
||||
@ -690,11 +685,54 @@ namespace vcpkg::Install
|
||||
Build::FailOnTombstone::NO,
|
||||
};
|
||||
|
||||
//// Load ports from ports dirs
|
||||
PortFileProvider::PathsPortFileProvider provider(paths, args.overlay_ports.get());
|
||||
PortFileProvider::PathsPortFileProvider provider(paths, args.overlay_ports);
|
||||
auto var_provider_storage = CMakeVars::make_triplet_cmake_var_provider(paths);
|
||||
auto& var_provider = *var_provider_storage;
|
||||
|
||||
if (paths.manifest_mode_enabled())
|
||||
{
|
||||
std::error_code ec;
|
||||
const auto path_to_manifest = paths.manifest_root_dir / "vcpkg.json";
|
||||
auto res = Paragraphs::try_load_manifest(paths.get_filesystem(), "user manifest", path_to_manifest, ec);
|
||||
|
||||
if (ec)
|
||||
{
|
||||
Checks::exit_with_message(VCPKG_LINE_INFO, "Failed to load manifest file (%s): %s\n",
|
||||
path_to_manifest.u8string(), ec.message());
|
||||
}
|
||||
|
||||
std::vector<FullPackageSpec> specs;
|
||||
if (auto val = res.get())
|
||||
{
|
||||
for (auto& dep : (*val)->core_paragraph->dependencies)
|
||||
{
|
||||
specs.push_back(Input::check_and_get_full_package_spec(
|
||||
std::move(dep.name), default_triplet, COMMAND_STRUCTURE.example_text));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
print_error_message(res.error());
|
||||
Checks::exit_fail(VCPKG_LINE_INFO);
|
||||
}
|
||||
|
||||
Commands::SetInstalled::perform_and_exit_ex(args, paths, provider, *binaryprovider, var_provider, specs, install_plan_options, dry_run ? Commands::DryRun::Yes : Commands::DryRun::No);
|
||||
}
|
||||
|
||||
const std::vector<FullPackageSpec> specs = Util::fmap(args.command_arguments, [&](auto&& arg) {
|
||||
return Input::check_and_get_full_package_spec(
|
||||
std::string(arg), default_triplet, COMMAND_STRUCTURE.example_text);
|
||||
});
|
||||
|
||||
for (auto&& spec : specs)
|
||||
{
|
||||
Input::check_triplet(spec.package_spec.triplet(), paths);
|
||||
}
|
||||
|
||||
// create the plan
|
||||
System::print2("Computing installation plan...\n");
|
||||
StatusParagraphs status_db = database_load_check(paths);
|
||||
|
||||
// Note: action_plan will hold raw pointers to SourceControlFileLocations from this map
|
||||
auto action_plan = Dependencies::create_feature_install_plan(provider, var_provider, specs, status_db);
|
||||
|
||||
|
@ -1,320 +0,0 @@
|
||||
#include "pch.h"
|
||||
|
||||
#include <vcpkg/base/parse.h>
|
||||
#include <vcpkg/base/strings.h>
|
||||
#include <vcpkg/base/system.print.h>
|
||||
#include <vcpkg/logicexpression.h>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace vcpkg
|
||||
{
|
||||
using vcpkg::Parse::ParseError;
|
||||
|
||||
enum class Identifier
|
||||
{
|
||||
invalid, // not a recognized identifier
|
||||
x64,
|
||||
x86,
|
||||
arm,
|
||||
arm64,
|
||||
|
||||
windows,
|
||||
linux,
|
||||
osx,
|
||||
uwp,
|
||||
android,
|
||||
emscripten,
|
||||
wasm32,
|
||||
|
||||
static_link,
|
||||
};
|
||||
|
||||
// logic expression supports the following :
|
||||
// primary-expression:
|
||||
// ( logic-expression )
|
||||
// identifier
|
||||
// identifier:
|
||||
// alpha-numeric string of characters
|
||||
// logic-expression: <- this is the entry point
|
||||
// not-expression
|
||||
// not-expression | logic-expression
|
||||
// not-expression & logic-expression
|
||||
// not-expression:
|
||||
// ! primary-expression
|
||||
// primary-expression
|
||||
//
|
||||
// | and & have equal precidence and cannot be used together at the same nesting level
|
||||
// for example a|b&c is not allowd but (a|b)&c and a|(b&c) are allowed.
|
||||
class ExpressionParser : public Parse::ParserBase
|
||||
{
|
||||
public:
|
||||
ExpressionParser(const std::string& str, const ExpressionContext& context) :
|
||||
Parse::ParserBase(str, "CONTROL"), evaluation_context(context)
|
||||
{
|
||||
{
|
||||
auto override_vars = evaluation_context.cmake_context.find("VCPKG_DEP_INFO_OVERRIDE_VARS");
|
||||
if (override_vars != evaluation_context.cmake_context.end())
|
||||
{
|
||||
auto cmake_list = Strings::split(override_vars->second, ';');
|
||||
for (auto& override_id : cmake_list)
|
||||
{
|
||||
if (!override_id.empty())
|
||||
{
|
||||
if (override_id[0] == '!')
|
||||
{
|
||||
context_override.insert({override_id.substr(1), false});
|
||||
}
|
||||
else
|
||||
{
|
||||
context_override.insert({override_id, true});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
skip_whitespace();
|
||||
|
||||
final_result = logic_expression();
|
||||
|
||||
if (!at_eof())
|
||||
{
|
||||
add_error("invalid logic expression, unexpected character");
|
||||
}
|
||||
}
|
||||
|
||||
bool get_result() const { return final_result; }
|
||||
|
||||
private:
|
||||
const ExpressionContext& evaluation_context;
|
||||
std::map<std::string, bool> context_override;
|
||||
|
||||
bool final_result;
|
||||
|
||||
static bool is_identifier_char(char32_t ch)
|
||||
{
|
||||
return is_upper_alpha(ch) || is_lower_alpha(ch) || is_ascii_digit(ch) || ch == '-';
|
||||
}
|
||||
|
||||
// Legacy evaluation only searches for substrings. Use this only for diagnostic purposes.
|
||||
bool evaluate_identifier_legacy(const std::string name) const
|
||||
{
|
||||
return evaluation_context.legacy_context.find(name) != std::string::npos;
|
||||
}
|
||||
|
||||
static Identifier string2identifier(const std::string& name)
|
||||
{
|
||||
static const std::map<std::string, Identifier> id_map = {
|
||||
{"x64", Identifier::x64},
|
||||
{"x86", Identifier::x86},
|
||||
{"arm", Identifier::arm},
|
||||
{"arm64", Identifier::arm64},
|
||||
{"windows", Identifier::windows},
|
||||
{"linux", Identifier::linux},
|
||||
{"osx", Identifier::osx},
|
||||
{"uwp", Identifier::uwp},
|
||||
{"android", Identifier::android},
|
||||
{"emscripten", Identifier::emscripten},
|
||||
{"wasm32", Identifier::wasm32},
|
||||
{"static", Identifier::static_link},
|
||||
};
|
||||
|
||||
auto id_pair = id_map.find(name);
|
||||
|
||||
if (id_pair == id_map.end())
|
||||
{
|
||||
return Identifier::invalid;
|
||||
}
|
||||
|
||||
return id_pair->second;
|
||||
}
|
||||
|
||||
bool true_if_exists_and_equal(const std::string& variable_name, const std::string& value)
|
||||
{
|
||||
auto iter = evaluation_context.cmake_context.find(variable_name);
|
||||
if (iter == evaluation_context.cmake_context.end())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return iter->second == value;
|
||||
}
|
||||
|
||||
// If an identifier is on the explicit override list, return the override value
|
||||
// Otherwise fall back to the built in logic to evaluate
|
||||
// All unrecognized identifiers are an error
|
||||
bool evaluate_identifier_cmake(const std::string name, const SourceLoc& loc)
|
||||
{
|
||||
auto id = string2identifier(name);
|
||||
|
||||
switch (id)
|
||||
{
|
||||
case Identifier::invalid:
|
||||
// Point out in the diagnostic that they should add to the override list because that is what
|
||||
// most users should do, however it is also valid to update the built in identifiers to recognize
|
||||
// the name.
|
||||
add_error("Unrecognized identifer name. Add to override list in triplet file.", loc);
|
||||
break;
|
||||
|
||||
case Identifier::x64: return true_if_exists_and_equal("VCPKG_TARGET_ARCHITECTURE", "x64");
|
||||
case Identifier::x86: return true_if_exists_and_equal("VCPKG_TARGET_ARCHITECTURE", "x86");
|
||||
case Identifier::arm:
|
||||
// For backwards compatability arm is also true for arm64.
|
||||
// This is because it previously was only checking for a substring.
|
||||
return true_if_exists_and_equal("VCPKG_TARGET_ARCHITECTURE", "arm") ||
|
||||
true_if_exists_and_equal("VCPKG_TARGET_ARCHITECTURE", "arm64");
|
||||
case Identifier::arm64: return true_if_exists_and_equal("VCPKG_TARGET_ARCHITECTURE", "arm64");
|
||||
case Identifier::windows: return true_if_exists_and_equal("VCPKG_CMAKE_SYSTEM_NAME", "") || true_if_exists_and_equal("VCPKG_CMAKE_SYSTEM_NAME", "WindowsStore");
|
||||
case Identifier::linux: return true_if_exists_and_equal("VCPKG_CMAKE_SYSTEM_NAME", "Linux");
|
||||
case Identifier::osx: return true_if_exists_and_equal("VCPKG_CMAKE_SYSTEM_NAME", "Darwin");
|
||||
case Identifier::uwp: return true_if_exists_and_equal("VCPKG_CMAKE_SYSTEM_NAME", "WindowsStore");
|
||||
case Identifier::android: return true_if_exists_and_equal("VCPKG_CMAKE_SYSTEM_NAME", "Android");
|
||||
case Identifier::emscripten: return true_if_exists_and_equal("VCPKG_CMAKE_SYSTEM_NAME", "Emscripten");
|
||||
case Identifier::wasm32: return true_if_exists_and_equal("VCPKG_TARGET_ARCHITECTURE", "wasm32");
|
||||
case Identifier::static_link: return true_if_exists_and_equal("VCPKG_LIBRARY_LINKAGE", "static");
|
||||
}
|
||||
|
||||
return evaluation_context.legacy_context.find(name) != std::string::npos;
|
||||
}
|
||||
|
||||
bool evaluate_identifier(const std::string name, const SourceLoc& loc)
|
||||
{
|
||||
if (!context_override.empty())
|
||||
{
|
||||
auto override_id = context_override.find(name);
|
||||
if (override_id != context_override.end())
|
||||
{
|
||||
return override_id->second;
|
||||
}
|
||||
// Fall through to use the cmake logic if the id does not have an override
|
||||
}
|
||||
|
||||
bool legacy = evaluate_identifier_legacy(name);
|
||||
bool cmake = evaluate_identifier_cmake(name, loc);
|
||||
if (legacy != cmake)
|
||||
{
|
||||
// Legacy evaluation only used the name of the triplet, now we use the actual
|
||||
// cmake variables. This has the potential to break custom triplets.
|
||||
// For now just print a message, this will need to change once we start introducing
|
||||
// new variables that did not exist previously (such as host-*)
|
||||
System::print2("Warning: qualifier has changed meaning recently:\n ", name, '\n');
|
||||
}
|
||||
return cmake;
|
||||
}
|
||||
|
||||
// identifier:
|
||||
// alpha-numeric string of characters
|
||||
bool identifier_expression()
|
||||
{
|
||||
auto start_loc = cur_loc();
|
||||
std::string name = match_zero_or_more(is_identifier_char).to_string();
|
||||
|
||||
if (name.empty())
|
||||
{
|
||||
add_error("unexpected character in logic expression");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool result = evaluate_identifier(name, start_loc);
|
||||
skip_whitespace();
|
||||
return result;
|
||||
}
|
||||
|
||||
// not-expression:
|
||||
// ! primary-expression
|
||||
// primary-expression
|
||||
bool not_expression()
|
||||
{
|
||||
if (cur() == '!')
|
||||
{
|
||||
next();
|
||||
skip_whitespace();
|
||||
return !primary_expression();
|
||||
}
|
||||
|
||||
return primary_expression();
|
||||
}
|
||||
|
||||
template<char oper, char other, bool operation(bool, bool)>
|
||||
bool logic_expression_helper(bool seed)
|
||||
{
|
||||
do
|
||||
{
|
||||
// Support chains of the operator to avoid breaking backwards compatability
|
||||
while (next() == oper)
|
||||
{
|
||||
};
|
||||
skip_whitespace();
|
||||
seed = operation(not_expression(), seed);
|
||||
|
||||
} while (cur() == oper);
|
||||
|
||||
if (cur() == other)
|
||||
{
|
||||
add_error("mixing & and | is not allowed, use () to specify order of operations");
|
||||
}
|
||||
|
||||
skip_whitespace();
|
||||
return seed;
|
||||
}
|
||||
static bool and_helper(bool left, bool right) { return left && right; }
|
||||
static bool or_helper(bool left, bool right) { return left || right; }
|
||||
|
||||
// logic-expression: <- entry point
|
||||
// not-expression
|
||||
// not-expression | logic-expression
|
||||
// not-expression & logic-expression
|
||||
bool logic_expression()
|
||||
{
|
||||
auto result = not_expression();
|
||||
|
||||
switch (cur())
|
||||
{
|
||||
case '|':
|
||||
{
|
||||
return logic_expression_helper<'|', '&', or_helper>(result);
|
||||
}
|
||||
case '&':
|
||||
{
|
||||
return logic_expression_helper<'&', '|', and_helper>(result);
|
||||
}
|
||||
default: return result;
|
||||
}
|
||||
}
|
||||
|
||||
// primary-expression:
|
||||
// ( logic-expression )
|
||||
// identifier
|
||||
bool primary_expression()
|
||||
{
|
||||
if (cur() == '(')
|
||||
{
|
||||
next();
|
||||
skip_whitespace();
|
||||
bool result = logic_expression();
|
||||
if (cur() != ')')
|
||||
{
|
||||
add_error("missing closing )");
|
||||
return result;
|
||||
}
|
||||
next();
|
||||
skip_whitespace();
|
||||
return result;
|
||||
}
|
||||
|
||||
return identifier_expression();
|
||||
}
|
||||
};
|
||||
|
||||
ExpectedT<bool, std::string> evaluate_expression(const std::string& expression, const ExpressionContext& context)
|
||||
{
|
||||
ExpressionParser parser(expression, context);
|
||||
|
||||
if (auto err = parser.get_error())
|
||||
{
|
||||
return err->format();
|
||||
}
|
||||
|
||||
return parser.get_result();
|
||||
}
|
||||
}
|
@ -153,6 +153,8 @@ namespace vcpkg::Metrics
|
||||
Json::Array buildtime_names;
|
||||
Json::Array buildtime_times;
|
||||
|
||||
Json::Object feature_flags;
|
||||
|
||||
void track_property(const std::string& name, const std::string& value)
|
||||
{
|
||||
properties.insert_or_replace(name, Json::Value::string(value));
|
||||
@ -168,6 +170,10 @@ namespace vcpkg::Metrics
|
||||
buildtime_names.push_back(Json::Value::string(name));
|
||||
buildtime_times.push_back(Json::Value::number(value));
|
||||
}
|
||||
void track_feature(const std::string& name, bool value)
|
||||
{
|
||||
feature_flags.insert(name, Json::Value::boolean(value));
|
||||
}
|
||||
|
||||
std::string format_event_data_template() const
|
||||
{
|
||||
@ -226,6 +232,7 @@ namespace vcpkg::Metrics
|
||||
base_data.insert("name", Json::Value::string("commandline_test7"));
|
||||
base_data.insert("properties", Json::Value::object(std::move(props_plus_buildtimes)));
|
||||
base_data.insert("measurements", Json::Value::object(measurements.clone()));
|
||||
base_data.insert("feature-flags", Json::Value::object(feature_flags.clone()));
|
||||
}
|
||||
|
||||
return Json::stringify(arr, vcpkg::Json::JsonStyle());
|
||||
@ -356,6 +363,15 @@ namespace vcpkg::Metrics
|
||||
g_metricmessage.track_property(name, value);
|
||||
}
|
||||
|
||||
void Metrics::track_feature(const std::string& name, bool value)
|
||||
{
|
||||
if (!metrics_enabled())
|
||||
{
|
||||
return;
|
||||
}
|
||||
g_metricmessage.track_feature(name, value);
|
||||
}
|
||||
|
||||
void Metrics::upload(const std::string& payload)
|
||||
{
|
||||
if (!metrics_enabled())
|
||||
|
@ -64,7 +64,8 @@ namespace vcpkg
|
||||
{
|
||||
return parse_qualified_specifier(spec_as_string)
|
||||
.then([&](ParsedQualifiedSpecifier&& p) -> ExpectedS<FullPackageSpec> {
|
||||
if (p.qualifier) return "Error: qualifier not allowed in this context: " + spec_as_string + "\n";
|
||||
if (p.platform)
|
||||
return "Error: platform specifier not allowed in this context: " + spec_as_string + "\n";
|
||||
auto triplet = p.triplet ? Triplet::from_canonical_name(std::move(*p.triplet.get())) : default_triplet;
|
||||
return FullPackageSpec({p.name, triplet}, p.features.value_or({}));
|
||||
});
|
||||
@ -97,7 +98,7 @@ namespace vcpkg
|
||||
{
|
||||
return parse_qualified_specifier(name).then([&](ParsedQualifiedSpecifier&& pqs) -> ExpectedS<Features> {
|
||||
if (pqs.triplet) return "Error: triplet not allowed in this context: " + name + "\n";
|
||||
if (pqs.qualifier) return "Error: qualifier not allowed in this context: " + name + "\n";
|
||||
if (pqs.platform) return "Error: platform specifier not allowed in this context: " + name + "\n";
|
||||
return Features{pqs.name, pqs.features.value_or({})};
|
||||
});
|
||||
}
|
||||
@ -107,8 +108,10 @@ namespace vcpkg
|
||||
return Parse::ParserBase::is_lower_alpha(ch) || Parse::ParserBase::is_ascii_digit(ch) || ch == '-';
|
||||
}
|
||||
|
||||
static bool is_feature_name_char(char32_t ch) {
|
||||
// TODO: we do not intend underscores to be valid, however there is currently a feature using them (libwebp[vwebp_sdl]).
|
||||
static bool is_feature_name_char(char32_t ch)
|
||||
{
|
||||
// TODO: we do not intend underscores to be valid, however there is currently a feature using them
|
||||
// (libwebp[vwebp_sdl]).
|
||||
// TODO: we need to rename this feature, then remove underscores from this list.
|
||||
return is_package_name_char(ch) || ch == '_';
|
||||
}
|
||||
@ -127,11 +130,15 @@ namespace vcpkg
|
||||
using Parse::ParserBase;
|
||||
auto ret = parser.match_zero_or_more(is_feature_name_char).to_string();
|
||||
auto ch = parser.cur();
|
||||
if (ParserBase::is_upper_alpha(ch) || ch == '_')
|
||||
|
||||
// ignores the feature name vwebp_sdl as a back-compat thing
|
||||
const bool has_underscore = std::find(ret.begin(), ret.end(), '_') != ret.end() && ret != "vwebp_sdl";
|
||||
if (has_underscore || ParserBase::is_upper_alpha(ch))
|
||||
{
|
||||
parser.add_error("invalid character in feature name (must be lowercase, digits, '-')");
|
||||
return nullopt;
|
||||
}
|
||||
|
||||
if (ret.empty())
|
||||
{
|
||||
parser.add_error("expected feature name (must be lowercase, digits, '-')");
|
||||
@ -224,6 +231,7 @@ namespace vcpkg
|
||||
if (ch == '(')
|
||||
{
|
||||
auto loc = parser.cur_loc();
|
||||
std::string platform_string;
|
||||
int depth = 1;
|
||||
while (depth > 0 && (ch = parser.next()) != 0)
|
||||
{
|
||||
@ -232,12 +240,19 @@ namespace vcpkg
|
||||
}
|
||||
if (depth > 0)
|
||||
{
|
||||
parser.add_error("unmatched open braces in qualifier", loc);
|
||||
parser.add_error("unmatched open braces in platform specifier", loc);
|
||||
return nullopt;
|
||||
}
|
||||
ret.qualifier = std::string(
|
||||
(++loc.it).pointer_to_current(),
|
||||
parser.it().pointer_to_current());
|
||||
platform_string.append((++loc.it).pointer_to_current(), parser.it().pointer_to_current());
|
||||
auto platform_opt = PlatformExpression::parse_platform_expression(platform_string, PlatformExpression::MultipleBinaryOperators::Allow);
|
||||
if (auto platform = platform_opt.get())
|
||||
{
|
||||
ret.platform = std::move(*platform);
|
||||
}
|
||||
else
|
||||
{
|
||||
parser.add_error(platform_opt.error(), loc);
|
||||
}
|
||||
parser.next();
|
||||
}
|
||||
// This makes the behavior of the parser more consistent -- otherwise, it will skip tabs and spaces only if
|
||||
|
@ -67,7 +67,7 @@ namespace vcpkg::Paragraphs
|
||||
}
|
||||
|
||||
public:
|
||||
PghParser(StringView text, StringView origin) : Parse::ParserBase(text, origin) {}
|
||||
PghParser(StringView text, StringView origin) : Parse::ParserBase(text, origin) { }
|
||||
|
||||
ExpectedS<std::vector<Paragraph>> get_paragraphs()
|
||||
{
|
||||
@ -86,7 +86,7 @@ namespace vcpkg::Paragraphs
|
||||
}
|
||||
};
|
||||
|
||||
static ExpectedS<Paragraph> parse_single_paragraph(const std::string& str, const std::string& origin)
|
||||
ExpectedS<Paragraph> parse_single_paragraph(const std::string& str, const std::string& origin)
|
||||
{
|
||||
auto pghs = PghParser(str, origin).get_paragraphs();
|
||||
|
||||
@ -128,16 +128,67 @@ namespace vcpkg::Paragraphs
|
||||
return PghParser(str, origin).get_paragraphs();
|
||||
}
|
||||
|
||||
bool is_port_directory(const Files::Filesystem& fs, const fs::path& path)
|
||||
{
|
||||
return fs.exists(path / fs::u8path("CONTROL")) || fs.exists(path / fs::u8path("vcpkg.json"));
|
||||
}
|
||||
|
||||
ParseExpected<SourceControlFile> try_load_manifest(const Files::Filesystem& fs, const std::string& port_name, const fs::path& path_to_manifest, std::error_code& ec)
|
||||
{
|
||||
auto error_info = std::make_unique<ParseControlErrorInfo>();
|
||||
auto res = Json::parse_file(fs, path_to_manifest, ec);
|
||||
if (ec) return error_info;
|
||||
|
||||
if (auto val = res.get())
|
||||
{
|
||||
if (val->first.is_object())
|
||||
{
|
||||
return SourceControlFile::parse_manifest_file(path_to_manifest, val->first.object());
|
||||
}
|
||||
else
|
||||
{
|
||||
error_info->name = port_name;
|
||||
error_info->error = "Manifest files must have a top-level object";
|
||||
return error_info;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
error_info->name = port_name;
|
||||
error_info->error = res.error()->format();
|
||||
return error_info;
|
||||
}
|
||||
}
|
||||
|
||||
ParseExpected<SourceControlFile> try_load_port(const Files::Filesystem& fs, const fs::path& path)
|
||||
{
|
||||
const auto path_to_control = path / "CONTROL";
|
||||
const auto path_to_manifest = path / fs::u8path("vcpkg.json");
|
||||
const auto path_to_control = path / fs::u8path("CONTROL");
|
||||
if (fs.exists(path_to_manifest)) {
|
||||
vcpkg::Checks::check_exit(
|
||||
VCPKG_LINE_INFO,
|
||||
!fs.exists(path_to_control),
|
||||
"Found both manifest and CONTROL file in port %s; please rename one or the other",
|
||||
path.u8string());
|
||||
|
||||
std::error_code ec;
|
||||
auto res = try_load_manifest(fs, path.filename().u8string(), path_to_manifest, ec);
|
||||
if (ec)
|
||||
{
|
||||
auto error_info = std::make_unique<ParseControlErrorInfo>();
|
||||
error_info->name = path.filename().u8string();
|
||||
error_info->error = Strings::format("Failed to load manifest file for port: %s\n", path_to_manifest.u8string(), ec.message());
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
ExpectedS<std::vector<Paragraph>> pghs = get_paragraphs(fs, path_to_control);
|
||||
if (auto vector_pghs = pghs.get())
|
||||
{
|
||||
return SourceControlFile::parse_control_file(path_to_control, std::move(*vector_pghs));
|
||||
}
|
||||
auto error_info = std::make_unique<ParseControlErrorInfo>();
|
||||
error_info->name = path.filename().generic_u8string();
|
||||
error_info->name = path.filename().u8string();
|
||||
error_info->error = pghs.error();
|
||||
return error_info;
|
||||
}
|
||||
|
471
toolsrc/src/vcpkg/platform-expression.cpp
Normal file
471
toolsrc/src/vcpkg/platform-expression.cpp
Normal file
@ -0,0 +1,471 @@
|
||||
#include "pch.h"
|
||||
|
||||
#include <vcpkg/base/parse.h>
|
||||
#include <vcpkg/base/strings.h>
|
||||
#include <vcpkg/base/system.print.h>
|
||||
#include <vcpkg/platform-expression.h>
|
||||
|
||||
#include <string>
|
||||
#include <variant>
|
||||
#include <vector>
|
||||
|
||||
namespace vcpkg::PlatformExpression
|
||||
{
|
||||
using vcpkg::Parse::ParseError;
|
||||
|
||||
enum class Identifier
|
||||
{
|
||||
invalid = -1, // not a recognized identifier
|
||||
x86,
|
||||
x64,
|
||||
arm,
|
||||
arm64,
|
||||
wasm32,
|
||||
|
||||
windows,
|
||||
linux,
|
||||
osx,
|
||||
uwp,
|
||||
android,
|
||||
emscripten,
|
||||
|
||||
static_link,
|
||||
};
|
||||
|
||||
static Identifier string2identifier(StringView name)
|
||||
{
|
||||
static const std::map<StringView, Identifier> id_map = {
|
||||
{"x86", Identifier::x86},
|
||||
{"x64", Identifier::x64},
|
||||
{"arm", Identifier::arm},
|
||||
{"arm64", Identifier::arm64},
|
||||
{"wasm32", Identifier::wasm32},
|
||||
{"windows", Identifier::windows},
|
||||
{"linux", Identifier::linux},
|
||||
{"osx", Identifier::osx},
|
||||
{"uwp", Identifier::uwp},
|
||||
{"android", Identifier::android},
|
||||
{"emscripten", Identifier::emscripten},
|
||||
{"static", Identifier::static_link},
|
||||
};
|
||||
|
||||
auto id_pair = id_map.find(name);
|
||||
|
||||
if (id_pair == id_map.end())
|
||||
{
|
||||
return Identifier::invalid;
|
||||
}
|
||||
|
||||
return id_pair->second;
|
||||
}
|
||||
|
||||
namespace detail
|
||||
{
|
||||
struct ExprIdentifier
|
||||
{
|
||||
std::string identifier;
|
||||
};
|
||||
struct ExprNot
|
||||
{
|
||||
std::unique_ptr<ExprImpl> expr;
|
||||
};
|
||||
struct ExprAnd
|
||||
{
|
||||
std::vector<ExprImpl> exprs;
|
||||
};
|
||||
struct ExprOr
|
||||
{
|
||||
std::vector<ExprImpl> exprs;
|
||||
};
|
||||
|
||||
struct ExprImpl
|
||||
{
|
||||
std::variant<ExprIdentifier, ExprNot, ExprAnd, ExprOr> underlying;
|
||||
|
||||
explicit ExprImpl(ExprIdentifier e) : underlying(std::move(e)) { }
|
||||
explicit ExprImpl(ExprNot e) : underlying(std::move(e)) { }
|
||||
explicit ExprImpl(ExprAnd e) : underlying(std::move(e)) { }
|
||||
explicit ExprImpl(ExprOr e) : underlying(std::move(e)) { }
|
||||
|
||||
ExprImpl clone() const
|
||||
{
|
||||
struct Visitor
|
||||
{
|
||||
ExprImpl operator()(const ExprIdentifier& e) { return ExprImpl(e); }
|
||||
ExprImpl operator()(const ExprNot& e)
|
||||
{
|
||||
return ExprImpl(ExprNot{std::make_unique<ExprImpl>(e.expr->clone())});
|
||||
}
|
||||
ExprImpl operator()(const ExprAnd& e)
|
||||
{
|
||||
ExprAnd res;
|
||||
for (const auto& expr : e.exprs)
|
||||
{
|
||||
res.exprs.push_back(expr.clone());
|
||||
}
|
||||
return ExprImpl(std::move(res));
|
||||
}
|
||||
ExprImpl operator()(const ExprOr& e)
|
||||
{
|
||||
ExprOr res;
|
||||
for (const auto& expr : e.exprs)
|
||||
{
|
||||
res.exprs.push_back(expr.clone());
|
||||
}
|
||||
return ExprImpl(std::move(res));
|
||||
}
|
||||
};
|
||||
return std::visit(Visitor{}, underlying);
|
||||
}
|
||||
};
|
||||
|
||||
class ExpressionParser : public Parse::ParserBase
|
||||
{
|
||||
public:
|
||||
ExpressionParser(StringView str, MultipleBinaryOperators multiple_binary_operators) : Parse::ParserBase(str, "CONTROL"), multiple_binary_operators(multiple_binary_operators) { }
|
||||
|
||||
MultipleBinaryOperators multiple_binary_operators;
|
||||
|
||||
bool allow_multiple_binary_operators() const
|
||||
{
|
||||
return multiple_binary_operators == MultipleBinaryOperators::Allow;
|
||||
}
|
||||
|
||||
PlatformExpression::Expr parse()
|
||||
{
|
||||
skip_whitespace();
|
||||
|
||||
auto res = expr();
|
||||
|
||||
if (!at_eof())
|
||||
{
|
||||
add_error("invalid logic expression, unexpected character");
|
||||
}
|
||||
|
||||
return Expr(std::make_unique<ExprImpl>(std::move(res)));
|
||||
}
|
||||
|
||||
private:
|
||||
// <platform-expression.and>
|
||||
// <platform-expression.not>
|
||||
// <platform-expression.and> & <platform-expression.not>
|
||||
// <platform-expression.or>
|
||||
// <platform-expression.not>
|
||||
// <platform-expression.or> | <platform-expression.not>
|
||||
|
||||
static bool is_identifier_char(char32_t ch)
|
||||
{
|
||||
return is_lower_alpha(ch) || is_ascii_digit(ch);
|
||||
}
|
||||
|
||||
// <platform-expression>:
|
||||
// <platform-expression.not>
|
||||
// <platform-expression.and>
|
||||
// <platform-expression.or>
|
||||
ExprImpl expr()
|
||||
{
|
||||
auto result = expr_not();
|
||||
|
||||
switch (cur())
|
||||
{
|
||||
case '|':
|
||||
{
|
||||
ExprOr e;
|
||||
e.exprs.push_back(std::move(result));
|
||||
return expr_binary<'|', '&'>(std::move(e));
|
||||
}
|
||||
case '&':
|
||||
{
|
||||
ExprAnd e;
|
||||
e.exprs.push_back(std::move(result));
|
||||
return expr_binary<'&', '|'>(std::move(e));
|
||||
}
|
||||
default: return result;
|
||||
}
|
||||
}
|
||||
|
||||
// <platform-expression.simple>:
|
||||
// ( <platform-expression> )
|
||||
// <platform-expression.identifier>
|
||||
ExprImpl expr_simple()
|
||||
{
|
||||
if (cur() == '(')
|
||||
{
|
||||
next();
|
||||
skip_whitespace();
|
||||
auto result = expr();
|
||||
if (cur() != ')')
|
||||
{
|
||||
add_error("missing closing )");
|
||||
return result;
|
||||
}
|
||||
next();
|
||||
skip_whitespace();
|
||||
return result;
|
||||
}
|
||||
|
||||
return expr_identifier();
|
||||
}
|
||||
|
||||
// <platform-expression.identifier>:
|
||||
// A lowercase alpha-numeric string
|
||||
ExprImpl expr_identifier()
|
||||
{
|
||||
std::string name = match_zero_or_more(is_identifier_char).to_string();
|
||||
|
||||
if (name.empty())
|
||||
{
|
||||
add_error("unexpected character in logic expression");
|
||||
}
|
||||
|
||||
skip_whitespace();
|
||||
return ExprImpl{ExprIdentifier{name}};
|
||||
}
|
||||
|
||||
// <platform-expression.not>:
|
||||
// <platform-expression.simple>
|
||||
// ! <platform-expression.simple>
|
||||
ExprImpl expr_not()
|
||||
{
|
||||
if (cur() == '!')
|
||||
{
|
||||
next();
|
||||
skip_whitespace();
|
||||
return ExprImpl(ExprNot{std::make_unique<ExprImpl>(expr_simple())});
|
||||
}
|
||||
|
||||
return expr_simple();
|
||||
}
|
||||
|
||||
template<char oper, char other, class ExprKind>
|
||||
ExprImpl expr_binary(ExprKind&& seed)
|
||||
{
|
||||
do
|
||||
{
|
||||
// Support chains of the operator to avoid breaking backwards compatibility
|
||||
do
|
||||
{
|
||||
next();
|
||||
} while (allow_multiple_binary_operators() && cur() == oper);
|
||||
|
||||
skip_whitespace();
|
||||
seed.exprs.push_back(expr_not());
|
||||
} while (cur() == oper);
|
||||
|
||||
if (cur() == other)
|
||||
{
|
||||
add_error("mixing & and | is not allowed; use () to specify order of operations");
|
||||
}
|
||||
|
||||
skip_whitespace();
|
||||
return ExprImpl(std::move(seed));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
using namespace detail;
|
||||
|
||||
Expr::Expr() = default;
|
||||
Expr::Expr(Expr&& other) = default;
|
||||
Expr& Expr::operator=(Expr&& other) = default;
|
||||
|
||||
Expr::Expr(const Expr& other)
|
||||
{
|
||||
if (other.underlying_)
|
||||
{
|
||||
underlying_ = std::make_unique<ExprImpl>(other.underlying_->clone());
|
||||
}
|
||||
}
|
||||
Expr& Expr::operator=(const Expr& other)
|
||||
{
|
||||
if (other.underlying_)
|
||||
{
|
||||
if (this->underlying_)
|
||||
{
|
||||
*this->underlying_ = other.underlying_->clone();
|
||||
}
|
||||
else
|
||||
{
|
||||
this->underlying_ = std::make_unique<ExprImpl>(other.underlying_->clone());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
this->underlying_.reset();
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
Expr::Expr(std::unique_ptr<ExprImpl>&& e) : underlying_(std::move(e)) { }
|
||||
Expr::~Expr() = default;
|
||||
|
||||
Expr Expr::Identifier(StringView id)
|
||||
{
|
||||
return Expr(std::make_unique<ExprImpl>(ExprImpl{ExprIdentifier{id.to_string()}}));
|
||||
}
|
||||
Expr Expr::Not(Expr&& e) { return Expr(std::make_unique<ExprImpl>(ExprImpl{ExprNot{std::move(e.underlying_)}})); }
|
||||
Expr Expr::And(std::vector<Expr>&& exprs)
|
||||
{
|
||||
std::vector<ExprImpl> impls;
|
||||
for (auto& e : exprs)
|
||||
{
|
||||
impls.push_back(std::move(*e.underlying_));
|
||||
}
|
||||
return Expr(std::make_unique<ExprImpl>(ExprAnd{std::move(impls)}));
|
||||
}
|
||||
Expr Expr::Or(std::vector<Expr>&& exprs)
|
||||
{
|
||||
std::vector<ExprImpl> impls;
|
||||
for (auto& e : exprs)
|
||||
{
|
||||
impls.push_back(std::move(*e.underlying_));
|
||||
}
|
||||
return Expr(std::make_unique<ExprImpl>(ExprOr{std::move(impls)}));
|
||||
}
|
||||
|
||||
bool Expr::evaluate(const Context& context) const
|
||||
{
|
||||
if (!underlying_)
|
||||
{
|
||||
return true; // empty expression is always true
|
||||
}
|
||||
|
||||
std::map<std::string, bool> override_ctxt;
|
||||
{
|
||||
auto override_vars = context.find("VCPKG_DEP_INFO_OVERRIDE_VARS");
|
||||
if (override_vars != context.end())
|
||||
{
|
||||
auto cmake_list = Strings::split(override_vars->second, ';');
|
||||
for (auto& override_id : cmake_list)
|
||||
{
|
||||
if (!override_id.empty())
|
||||
{
|
||||
if (override_id[0] == '!')
|
||||
{
|
||||
override_ctxt.insert({override_id.substr(1), false});
|
||||
}
|
||||
else
|
||||
{
|
||||
override_ctxt.insert({override_id, true});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct Visitor
|
||||
{
|
||||
const Context& context;
|
||||
const std::map<std::string, bool>& override_ctxt;
|
||||
|
||||
bool true_if_exists_and_equal(const std::string& variable_name, const std::string& value) const
|
||||
{
|
||||
auto iter = context.find(variable_name);
|
||||
if (iter == context.end())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return iter->second == value;
|
||||
}
|
||||
|
||||
bool visit(const ExprImpl& e) const { return std::visit(*this, e.underlying); }
|
||||
|
||||
bool operator()(const ExprIdentifier& expr) const
|
||||
{
|
||||
if (!override_ctxt.empty())
|
||||
{
|
||||
auto override_id = override_ctxt.find(expr.identifier);
|
||||
if (override_id != override_ctxt.end())
|
||||
{
|
||||
return override_id->second;
|
||||
}
|
||||
// Fall through to use the cmake logic if the id does not have an override
|
||||
}
|
||||
|
||||
auto id = string2identifier(expr.identifier);
|
||||
switch (id)
|
||||
{
|
||||
case Identifier::invalid:
|
||||
// Point out in the diagnostic that they should add to the override list because that is what
|
||||
// most users should do, however it is also valid to update the built in identifiers to
|
||||
// recognize the name.
|
||||
System::printf(System::Color::error,
|
||||
"Error: Unrecognized identifer name %s. Add to override list in triplet file.\n",
|
||||
expr.identifier);
|
||||
return false;
|
||||
case Identifier::x64: return true_if_exists_and_equal("VCPKG_TARGET_ARCHITECTURE", "x64");
|
||||
case Identifier::x86: return true_if_exists_and_equal("VCPKG_TARGET_ARCHITECTURE", "x86");
|
||||
case Identifier::arm:
|
||||
// For backwards compatability arm is also true for arm64.
|
||||
// This is because it previously was only checking for a substring.
|
||||
return true_if_exists_and_equal("VCPKG_TARGET_ARCHITECTURE", "arm") ||
|
||||
true_if_exists_and_equal("VCPKG_TARGET_ARCHITECTURE", "arm64");
|
||||
case Identifier::arm64: return true_if_exists_and_equal("VCPKG_TARGET_ARCHITECTURE", "arm64");
|
||||
case Identifier::windows:
|
||||
return true_if_exists_and_equal("VCPKG_CMAKE_SYSTEM_NAME", "") ||
|
||||
true_if_exists_and_equal("VCPKG_CMAKE_SYSTEM_NAME", "WindowsStore");
|
||||
case Identifier::linux: return true_if_exists_and_equal("VCPKG_CMAKE_SYSTEM_NAME", "Linux");
|
||||
case Identifier::osx: return true_if_exists_and_equal("VCPKG_CMAKE_SYSTEM_NAME", "Darwin");
|
||||
case Identifier::uwp: return true_if_exists_and_equal("VCPKG_CMAKE_SYSTEM_NAME", "WindowsStore");
|
||||
case Identifier::android: return true_if_exists_and_equal("VCPKG_CMAKE_SYSTEM_NAME", "Android");
|
||||
case Identifier::emscripten:
|
||||
return true_if_exists_and_equal("VCPKG_CMAKE_SYSTEM_NAME", "Emscripten");
|
||||
case Identifier::wasm32: return true_if_exists_and_equal("VCPKG_TARGET_ARCHITECTURE", "wasm32");
|
||||
case Identifier::static_link: return true_if_exists_and_equal("VCPKG_LIBRARY_LINKAGE", "static");
|
||||
default:
|
||||
Checks::exit_with_message(
|
||||
VCPKG_LINE_INFO,
|
||||
"vcpkg bug: string2identifier returned a value that we don't recognize: %d\n",
|
||||
static_cast<int>(id));
|
||||
}
|
||||
}
|
||||
|
||||
bool operator()(const ExprNot& expr) const {
|
||||
bool res = visit(*expr.expr);
|
||||
return !res;
|
||||
}
|
||||
|
||||
bool operator()(const ExprAnd& expr) const
|
||||
{
|
||||
bool valid = true;
|
||||
|
||||
// we want to print errors in all expressions, so we check all of the expressions all the time
|
||||
for (const auto& e : expr.exprs)
|
||||
{
|
||||
valid &= visit(e);
|
||||
}
|
||||
|
||||
return valid;
|
||||
}
|
||||
|
||||
bool operator()(const ExprOr& expr) const
|
||||
{
|
||||
bool valid = false;
|
||||
// we want to print errors in all expressions, so we check all of the expressions all the time
|
||||
for (const auto& e : expr.exprs)
|
||||
{
|
||||
valid |= visit(e);
|
||||
}
|
||||
return valid;
|
||||
}
|
||||
};
|
||||
|
||||
return Visitor{context, override_ctxt}.visit(*underlying_);
|
||||
}
|
||||
|
||||
ExpectedS<Expr> parse_platform_expression(StringView expression, MultipleBinaryOperators multiple_binary_operators)
|
||||
{
|
||||
auto parser = ExpressionParser(expression, multiple_binary_operators);
|
||||
auto res = parser.parse();
|
||||
|
||||
if (auto p = parser.extract_error())
|
||||
{
|
||||
return p->format();
|
||||
}
|
||||
else
|
||||
{
|
||||
return res;
|
||||
}
|
||||
}
|
||||
}
|
@ -25,40 +25,35 @@ namespace vcpkg::PortFileProvider
|
||||
}
|
||||
|
||||
PathsPortFileProvider::PathsPortFileProvider(const vcpkg::VcpkgPaths& paths,
|
||||
const std::vector<std::string>* ports_dirs_paths)
|
||||
const std::vector<std::string>& ports_dirs_paths)
|
||||
: filesystem(paths.get_filesystem())
|
||||
{
|
||||
auto& fs = paths.get_filesystem();
|
||||
if (ports_dirs_paths)
|
||||
for (auto&& overlay_path : ports_dirs_paths)
|
||||
{
|
||||
for (auto&& overlay_path : *ports_dirs_paths)
|
||||
if (!overlay_path.empty())
|
||||
{
|
||||
if (!overlay_path.empty())
|
||||
auto overlay = fs::u8path(overlay_path);
|
||||
if (overlay.is_absolute())
|
||||
{
|
||||
auto overlay = fs::u8path(overlay_path);
|
||||
if (overlay.is_absolute())
|
||||
{
|
||||
overlay = fs.canonical(VCPKG_LINE_INFO, overlay);
|
||||
}
|
||||
else
|
||||
{
|
||||
overlay = fs.canonical(VCPKG_LINE_INFO, paths.original_cwd / overlay);
|
||||
}
|
||||
|
||||
Debug::print("Using overlay: ", overlay.u8string(), "\n");
|
||||
|
||||
Checks::check_exit(VCPKG_LINE_INFO,
|
||||
filesystem.exists(overlay),
|
||||
"Error: Path \"%s\" does not exist",
|
||||
overlay.string());
|
||||
|
||||
Checks::check_exit(VCPKG_LINE_INFO,
|
||||
fs::is_directory(fs.status(VCPKG_LINE_INFO, overlay)),
|
||||
"Error: Path \"%s\" must be a directory",
|
||||
overlay.string());
|
||||
|
||||
ports_dirs.emplace_back(overlay);
|
||||
overlay = fs.canonical(VCPKG_LINE_INFO, overlay);
|
||||
}
|
||||
else
|
||||
{
|
||||
overlay = fs.canonical(VCPKG_LINE_INFO, paths.original_cwd / overlay);
|
||||
}
|
||||
|
||||
Debug::print("Using overlay: ", overlay.u8string(), "\n");
|
||||
|
||||
Checks::check_exit(
|
||||
VCPKG_LINE_INFO, filesystem.exists(overlay), "Error: Path \"%s\" does not exist", overlay.string());
|
||||
|
||||
Checks::check_exit(VCPKG_LINE_INFO,
|
||||
fs::is_directory(fs.status(VCPKG_LINE_INFO, overlay)),
|
||||
"Error: Path \"%s\" must be a directory",
|
||||
overlay.string());
|
||||
|
||||
ports_dirs.emplace_back(overlay);
|
||||
}
|
||||
}
|
||||
ports_dirs.emplace_back(paths.ports);
|
||||
@ -75,7 +70,7 @@ namespace vcpkg::PortFileProvider
|
||||
for (auto&& ports_dir : ports_dirs)
|
||||
{
|
||||
// Try loading individual port
|
||||
if (filesystem.exists(ports_dir / "CONTROL"))
|
||||
if (Paragraphs::is_port_directory(filesystem, ports_dir))
|
||||
{
|
||||
auto maybe_scf = Paragraphs::try_load_port(filesystem, ports_dir);
|
||||
if (auto scf = maybe_scf.get())
|
||||
@ -94,10 +89,14 @@ namespace vcpkg::PortFileProvider
|
||||
Checks::exit_with_message(
|
||||
VCPKG_LINE_INFO, "Error: Failed to load port from %s", spec, ports_dir.u8string());
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
else if (filesystem.exists(ports_dir / spec / "CONTROL"))
|
||||
|
||||
auto ports_spec = ports_dir / spec;
|
||||
if (Paragraphs::is_port_directory(filesystem, ports_spec))
|
||||
{
|
||||
auto found_scf = Paragraphs::try_load_port(filesystem, ports_dir / spec);
|
||||
auto found_scf = Paragraphs::try_load_port(filesystem, ports_spec);
|
||||
if (auto scf = found_scf.get())
|
||||
{
|
||||
if (scf->get()->core_paragraph->name == spec)
|
||||
@ -133,7 +132,7 @@ namespace vcpkg::PortFileProvider
|
||||
for (auto&& ports_dir : ports_dirs)
|
||||
{
|
||||
// Try loading individual port
|
||||
if (filesystem.exists(ports_dir / "CONTROL"))
|
||||
if (Paragraphs::is_port_directory(filesystem, ports_dir))
|
||||
{
|
||||
auto maybe_scf = Paragraphs::try_load_port(filesystem, ports_dir);
|
||||
if (auto scf = maybe_scf.get())
|
||||
|
@ -215,6 +215,10 @@ namespace vcpkg::Remove
|
||||
|
||||
void perform_and_exit(const VcpkgCmdArguments& args, const VcpkgPaths& paths, Triplet default_triplet)
|
||||
{
|
||||
if (paths.manifest_mode_enabled())
|
||||
{
|
||||
Checks::exit_with_message(VCPKG_LINE_INFO, "vcpkg remove does not support manifest mode. In order to remove dependencies, you will need to edit your manifest (vcpkg.json).");
|
||||
}
|
||||
const ParsedArguments options = args.parse_arguments(COMMAND_STRUCTURE);
|
||||
|
||||
StatusParagraphs status_db = database_load_check(paths);
|
||||
@ -228,7 +232,7 @@ namespace vcpkg::Remove
|
||||
}
|
||||
|
||||
// Load ports from ports dirs
|
||||
PortFileProvider::PathsPortFileProvider provider(paths, args.overlay_ports.get());
|
||||
PortFileProvider::PathsPortFileProvider provider(paths, args.overlay_ports);
|
||||
|
||||
specs = Util::fmap(Update::find_outdated_packages(provider, status_db),
|
||||
[](auto&& outdated) { return outdated.spec; });
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user